ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

YOLOv8行人检测项目全流程:从环境配置到部署实践

YOLOv8行人检测项目全流程:从环境配置到部署实践 简介基于YOLOv8的行人检测项目面向计算机视觉方向的高校学生、教师及企业开发者尤其适合课程设计、毕业设计、大作业或项目初期立项演示。压缩包共6个文件其中3个PyTorch权重文件含轻量版模型、新版本模型及训练得到的最佳权重可供模型加载与再训练2个Python脚本分别实现训练流程与视频目标检测1个数据说明文档帮助快速配置数据集整体仅15.89MB结构紧凑、上手门槛低。代码均已在作者本地运行通过输出核心指标曲线、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果及标签分布图可清晰呈现模型效果为课程答辩或毕设展示提供有力凭证。目前已有36人学习下载不仅是拿来即用的完整案例也适合在源码基础上修改以适配其他检测场景兼顾入门学习与二次开发。1. 别再急着解压YOLOv8 行人检测项目里真正值钱的是什么从各种渠道拿到「基于YOLOv8的行人检测项目.rar」这类压缩包第一步往往是解压后直接运行 train.py——三分钟后收获一个 ModuleNotFoundError 和满屏报错。这个项目讲的不是发明了更强的模型而是把 YOLOv8 行人检测从数据标注、训练到推理组织成一条能复用的流水线。解压后能看到数据集、data.yaml、训练入口和一批已训练权重换个场景重新标一批数据就能再训。适合做智慧安防、园区巡检、辅助驾驶感知的从业者也适合要用行人检测 YOLOv8组合交作业的学生。先说一个反直觉的结论这类项目最值钱的不是那几百兆权重而是数据格式和训练参数已经替你踩过一遍坑。下面从环境到训练再到部署把完整流程拆开讲。2. 解压后的第一件事项目目录解读与最小环境搭建拿到手的 .rar 解压后我不会先去读 README而是先列一遍目录。原因很简单这类项目大概率是从论文实验或者毕设工程里打包出来的里面既有核心代码也有一堆一次性产物旧权重、没用的数据集切片、甚至别人机器的绝对路径配置。先分清哪些是核心、哪些可以直接忽略能省掉后面大半天的排查时间。2.1 解压后先看目录分清核心文件和一次性文件常见目录结构大概是下面这样我按要不要动分了三类路径一般是什么要不要改datasets/images、datasets/labels训练图片和 YOLO 格式标注换成自己的数据data.yaml数据集路径、类别名每次训练前必改train.py 或 train.sh训练入口按需调参数weights/best.pt、weights/last.pt训练产物和断点做二次开发用runs/每次训练的日志、曲线、验证图只看不改requirements.txt依赖清单建议锁死版本如果压缩包里还套了一层同名文件夹先把路径里的中文和空格去掉。YOLOv8 的配置文件对空格能容忍但配合第三方库时经常出幺蛾子。另外runs/目录里往往有上一轮训练留下的 results.csv 和混淆矩阵这些是判断原项目训练得怎么样的最好材料别急着删。压缩包里的 README 我一般扫一眼但不全信——很多是作者给自己留的笔记命令是旧版本的真正可信的是 train.py 里的实际参数和 runs/ 里的日志。2.2 用 conda 装一个最小环境先 torch 后 ultralytics无论压缩包里的 requirements.txt 写了什么我习惯自己重建一个干净环境避免把原作者的依赖垃圾也装进来。顺序上有一个关键点先装 PyTorch再装 ultralytics。如果先装 ultralyticspip 会把它依赖的 torch 版本一起拉进来有时候和你显卡驱动对应的 CUDA 版本不一致后面跑起来才发现 GPU 根本没用上。这也是搜索yolov8环境配置时最容易踩的第一道坎。conda create -n yolo python3.10 -y conda activate yolo # 先装 GPU 版 torch1660Ti 用 cu118 这一套 pip install torch2.1.2 torchvision0.16.2 --index-url https://download.pytorch.org/whl/cu118 # 再装 ultralytics版本锁死避免 API 漂移 pip install ultralytics8.2.100说明几个参数python 3.10 是 ultralytics 支持得很好的版本3.12 也能跑但部分转 ONNX 的依赖容易踩坑--index-url指定的是 PyTorch 官方 wheel 源cu118 对应 CUDA 11.81660Ti 这类 Turing 架构显卡完全够用。最后锁死 8.2.100 而不是装 latest原因后面第 5 章会专门讲先记住锁版本这个习惯。装完先验证 GPU 是否真的参与计算这一步能过滤掉八成环境问题import torch print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0))如果输出True和显卡型号说明 PyTorch 的 CUDA 环境没问题。如果输出False多半是 torch 装成了 CPU 版重新按上面的命令行装一次即可。另外在终端里跑一下nvidia-smi确认驱动版本不要太老旧驱动对 CUDA 11.8 的兼容性有时候会莫名其妙出问题。提示切换显卡或换机器后训练前先跑一遍torch.cuda.is_available()避免在 CPU 上白耗半天。2.3 用官方权重验证环境一张图跑通推理环境就绪后不要直接跑原项目的训练脚本先用官方预训练权重跑一次推理。这样能把环境问题和项目代码问题隔离开如果官方权重能出框说明环境是好的问题在项目代码如果官方权重都报错那就回去查环境。from ultralytics import YOLO model YOLO(yolov8n.pt) # n 是体积最小的版本验证环境用正合适 results model.predict(street.jpg, conf0.25, device0) for r in results: for b in r.boxes: cls_id int(b.cls[0]) conf float(b.conf[0]) x1, y1, x2, y2 b.xyxy[0].tolist() print(cls_id, conf, (x1, y1, x2, y2))yolov8n.pt第一次使用会自动下载大概 6MB 多一点如果下载失败手动把权重文件放到当前目录再跑。conf0.25是置信度阈值低于这个值的框直接过滤device0指定第一张 GPU不写的话默认 CPU速度会慢到让你误以为程序卡死。打印出来的 cls_id 如果包含 0就是 COCO 的 person 类别说明这个模型本身就具备行人检测能力。推理脚本能出框意味着从安装、CUDA、权重加载到后处理的全链路都通了这时候再进项目代码的坑。2.4 确认网络结构从 yaml 到结构图很多下载这个项目的人会搜yolov8网络结构图那是为了画论文插图不是排查问题。日常开发里更需要确认的是当前装的 ultralytics 版本认不认识项目里用到的网络结构。做法是用官方 yaml 构建一次模型不加载权重from ultralytics import YOLO model YOLO(yolov8s.yaml) # 只构建结构不加载权重 print(model.model)如果项目里改过 head、加过注意力模块原作者的 yaml 可能和你装的版本不兼容这一步会直接抛异常。真正要画结构图时我一般把模型导出成 ONNX再用 netron 打开比手画或者打印参数列表直观得多。这一步同时也是后面部署到 RK3588 之类边缘设备的前置步骤提前把导出链路跑通能少踩很多板端工具链的坑。3. 准备行人数据集格式转换脚本与 data.yaml 的四个坑行人检测和通用目标检测最大的区别在数据行人是强变形目标姿态、遮挡、尺度变化都比车辆严重。而 YOLOv8 训练入口不挑数据来源它只认一种标注格式——每张图对应一个 txt每行是类别 中心x 中心y 宽 高坐标归一化到 [0,1]。所以拿到 COCO、VOC 原始标注第一步永远是转换。这一章把转换脚本和最容易踩的四个坑一起讲。3.1 行人数据从哪来COCO、VOC、CrowdHuman 与 SCB-Dataset3常见开源数据里挑行人COCO 的 person 类别category_id1数量多、场景杂适合做初始训练Pascal VOC 的 person 类别更干净适合小规模验证CrowdHuman 专门为密集行人设计单人框、遮挡多适合做难点增强SCB-Dataset3 是面向行人检测的国产数据集特点是复杂背景和相机视角更多样近年来在改进实验里被用得很多。选数据的核心不是哪个更好而是和你的落地场景像不像。做园区出入口的多找平视、近距离的数据做十字路口远距离感知的重点补充小目标行人。这个判断会直接影响后面要讲的 imgsz 参数。无论选哪个最后都要统一成 YOLO 格式并且最好只保留 person 一个类别——既然项目叫行人检测就不要把 rider、traffic light 混进来类别越多 mAP 越容易被稀释。3.2 把 VOC XML 转成 YOLO 格式转换脚本与边界处理VOC 的标注是 XML每个 object 里有个 bndbox 节点存的是绝对坐标 xmin/ymin/xmax/ymax。转 YOLO 格式要做的就是把绝对坐标变成相对图片宽高的归一化中心点坐标。转换脚本本身不难但边界处理才是容易翻车的地方import xml.etree.ElementTree as ET import os CLASSES [person] def voc_to_yolo(xml_path, out_dir): root ET.parse(xml_path).getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) lines [] for obj in root.iter(object): if obj.find(name).text not in CLASSES: continue box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) # 坐标越界裁剪标注经常超图片边界 x1 max(0, min(x1, w)); x2 max(0, min(x2, w)) y1 max(0, min(y1, h)); y2 max(0, min(y2, h)) if x2 - x1 3 or y2 - y1 3: continue # 过滤退化成线的坏标注 cx (x1 x2) / 2 / w cy (y1 y2) / 2 / h bw (x2 - x1) / w bh (y2 - y1) / h lines.append(f0 {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) if lines: out_name os.path.basename(xml_path).replace(.xml, .txt) with open(os.path.join(out_dir, out_name), w) as f: f.write(\n.join(lines))代码里两处值得注意一是坐标裁剪VOC 数据里存在 bndbox 超出图片宽高的脏标注不裁剪会出现中心点、宽高大于 1 的情况YOLOv8 训练时不一定会报错但 loss 曲线会异常二是过滤掉宽或高小于 3 像素的框这种框在缩放后几乎就是单个像素属于无效监督信号。转换完后用 wc -l 抽查几个 txt行数应该和 XML 里的 person 标注数对得上。3.3 把 COCO JSON 转成 YOLO 格式按类别过滤标注COCO 的标注是单个 JSON要把 instances 按 image_id 分组再用 bbox 字段转换。注意 COCO 的 bbox 格式是 [x, y, width, height]和 VOC 的 [x1, y1, x2, y2] 不一样抄代码时最容易在这出错import json from pathlib import Path def coco_to_yolo(json_path, out_dir, target_clsperson): coco json.loads(open(json_path, encodingutf-8).read()) cat_id next(c[id] for c in coco[categories] if c[name] target_cls) img_info {im[id]: im for im in coco[images]} # 只保留目标类别按图片 id 分组 anns_by_img {} for ann in coco[annotations]: if ann[category_id] ! cat_id: continue anns_by_img.setdefault(ann[image_id], []).append(ann) for img_id, anns in anns_by_img.items(): im img_info[img_id] w, h im[width], im[height] lines [] for ann in anns: x, y, bw, bh ann[bbox] # COCO: 左上角 宽高 cx (x bw / 2) / w cy (y bh / 2) / h lines.append(f0 {cx:.6f} {cy:.6f} {bw / w:.6f} {bh / h:.6f}) out Path(out_dir) / (im[file_name].rsplit(., 1)[0] .txt) out.write_text(\n.join(lines))这里按target_clsperson过滤后很多图片根本没有行人标注脚本就跳过不生成 txt。这正好契合 YOLOv8 的规则图片可以没有标注文件但不能有空的 txt——空 txt 在部分增强逻辑下会引发奇怪的 loss 波动。如果你希望这些图不参与训练在划分 train/val 时不包含它们即可。3.4 data.yaml 的写法与 train/val 划分转换完标注接下来写 data.yaml。这是整个项目里最容易被忽略、又最容易出问题的文件。一个能用的最小配置长这样path: /home/user/datasets/pedestrian train: images/train val: images/val names: 0: person三个坑需要说明。第一path是基准路径train和val会拼在它后面所以train: images/train实际指向/home/user/datasets/pedestrian/images/train如果把path写成相对路径一定要确认训练时的当前工作目录在哪我遇到过好几次在项目根目录能跑、换到子目录就报 dataset not found。第二nc类别数可以不写ultralytics 会从names推断但如果你写了nc: 1而 names 里有两个键它会按 names 为准容易造成误会建议直接不写。第三标注 txt 里的类别 id 必须和 names 的键对齐——转换脚本写死0names 里也必须是0: person一旦错位训练不会报错但 mAP 永远上不去。做数据划分时常见做法是按 8:2 随机分注意同一个视频序列的帧别拆散到两个集合否则验证集会泄漏。3.5 可视化检查标注训练前必做的十分钟转完格式、写完 yaml我强烈建议抽 5 张图把标注画出来看一眼。这一步能发现脚本没考虑到的坐标系问题比如某个数据集是 EXIF 旋转过的图宽高和实际显示不一致。可视化脚本很朴素import cv2 from pathlib import Path img_dir Path(datasets/pedestrian/images/train) for img_path in list(img_dir.iterdir())[:5]: img cv2.imread(str(img_path)) h, w img.shape[:2] txt img_path.with_suffix(.txt) if not txt.exists(): print(缺标注:, img_path.name) continue for line in txt.read_text().strip().splitlines(): _, cx, cy, bw, bh map(float, line.split()) x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.imshow(check, img) cv2.waitKey(0) cv2.destroyAllWindows()如果画出来的框整体左移、右移或者明显偏移基本可以断定是转换脚本坐标系错了如果框能正确框住行人再花两分钟把 train/val 的文件列表整理好训练数据才算真正准备好。这十分钟能拦下后面几小时的无效训练性价比非常高。4. 训练自己的行人检测模型命令、参数与损失曲线判断数据准备好了训练反而是整个项目里最不需要创造性的环节。YOLOv8 的命令行入口封装得很好关键在三点命令怎么写、参数怎么设、以及怎么判断训练有没有跑偏。很多人把yolov8训练自己的数据集理解成把 epochs 调大然后干等这是对算力的浪费。下面按我实际的调参顺序讲。4.1 最小训练命令从一条命令看懂训练产物以 1660Ti6GB 显存为例一条能直接跑的训练命令长这样yolo detect train \ modelyolov8s.pt \ datadata.yaml \ imgsz640 \ batch16 \ epochs100 \ device0 \ projectruns \ namepedestrianmodelyolov8s.pt用预训练权重做热启动比从头训练收敛快得多行人检测这种单类别任务s 版在精度和速度之间比较均衡。如果显存吃紧换成yolov8n.pt更保险。训练过程中终端会每 N 个 epoch 打一张表列里有 box_loss、cls_loss、dfl_loss 和 mAP0.5前几个 epoch mAP 是 0 很正常等类别 loss 降下来自然就上去了。结束后去runs/pedestrian/看产物weights/best.pt是验证集 mAP 最高的权重weights/last.pt是最后一个 epoch 的权重results.csv是每个 epoch 的全部指标明细还有验证集预测图和混淆矩阵。4.2 三个必调参数batch、imgsz、epochs很多下载的项目里作者会留一个我调好的参数但那是在他的显卡和数据量下调的。落到你自己机器上三个参数必须重新考虑参数默认值6GB 显存建议说明batch16816配 amp显存不够就减半优先保 imgszimgsz640640远处行人小就上 1280batch 要跟着减epochs100100 patience30提前停止开好别死等到 100imgsz是对行人检测影响最大的参数。行人尺寸分布极不均匀近处行人占满半张图远处行人只有十几个像素。640 下采样后小行人特征基本被抹掉所以场景里有远距离行人需求时我一般直接用 1280 训练代价是显存占用约 4 倍batch 相应减到 48。除了这三个还有两个小而重要的lr0控制初始学习率数据量小于 500 张时我一般手动降到 0.005patience是早停设为 30 意味着连续 30 个 epoch 验证 mAP 不涨就停避免干等。另外 ultralytics 默认开 mosaic 等数据增强小数据集不要关掉mosaic 相当于免费的合成样本8.2 版本在最后 10 个 epoch 会自动关闭 mosaic 做精调这是正常行为别以为是报错。4.3 画损失函数曲线判断训练是否健康训练跑起来后别只盯着进度条。我习惯每 20 个 epoch 就把results.csv拉出来画一次损失函数曲线图这是判断训练有没有跑偏最直接的信号。yolov8画损失函数曲线图这件事没有官方命令用 pandas matplotlib 二十行搞定import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/pedestrian/results.csv) df.columns [c.strip() for c in df.columns] # 列名带前导空格先清掉 fig, axes plt.subplots(1, 3, figsize(15, 4)) for ax, col in zip(axes, [train/box_loss, train/cls_loss, train/dfl_loss]): ax.plot(df[epoch], df[col]) ax.set_title(col) plt.tight_layout() plt.savefig(loss_curves.png, dpi150)健康的曲线是前 20 个 epoch 快速下降、之后缓慢趋平。如果把val/box_loss也画上去两条线一起看train 一直降、val 翘头就是过拟合这时候加大数据增强或减小模型规模都比硬扛 epochs 有效两条线同时走平说明模型容量到头了该加数据或换更大的模型。如果曲线抖动得很厉害先检查是不是 batch 太小。深度学习训练里玄学成分不少但损失曲线是少有的可靠信号——它如果异常后面 mAP 一定异常。4.4 中断恢复与迁移微调给自己留后悔药训练中断是常态断电、显存被别的进程占了、或者你发现参数设错了。ultralytics 提供了后悔药——断点续训yolo detect train resume modelruns/pedestrian/weights/last.ptresume会读取last.pt里保存的 epoch、优化器状态和学习率计划从断点继续而不是从头来。注意它恢复的是训练状态而不是单纯的模型权重所以不要用best.pt续训。续训后会在原 project/name 下新建一个目录保存后续结果找产出时别去错地方。另一个常见场景是小数据集迁移行人数据只有几百张时直接把 backbone 冻住只训练 headyolo detect train modelyolov8s.pt datadata.yaml freeze10freeze10表示冻结前 10 层YOLOv8s 的 backbone 基本覆盖显存占用更小、收敛更快且不容易在小数据上把预训练特征冲掉。第一轮训完想全量微调再用best.pt去掉 freeze 训一轮。提示resume 只认 last.pt别用 best.pt 续训。5. 行人检测常见问题排查五条现象级记录训练和部署里翻车是常态下面这五条是行人检测项目里见过最多、也最容易被带偏的问题。每条按现象→原因→解决写直接对照你自己的报错去查。5.1 loss 变 nan先查标签类别号再调学习率现象训练日志里第一个 epoch 的 loss 就是 nan或者跑几个 batch 后突然变 nan。 原因最常见是标注 txt 里的类别 id 越界比如 data.yaml 只定义了0: person但某个 txt 里第一列写成了1其次是学习率太大导致梯度爆炸或者有空 txt 文件参与训练。 解决先跑一遍 3.5 节的遍历代码再统计所有 txt 的类别 id 最大值和空文件数量确认标签没问题后把lr0从默认 0.01 降到 0.005 或 0.001。顺序不能反——标签问题是根因只调学习率是掩耳盗铃。5.2 CUDA out of memory6GB 显存的取舍现象torch.cuda.OutOfMemoryError或者训练刚启动几十秒就Killed。 原因1660Ti 只有 6GB 显存yolov8s imgsz640 batch32的组合本来就不现实另外 DataLoader 的多进程 worker 也会额外占显存workers 开太大同样会爆。 解决按 4.2 的参数表走——batch 降到 8 或 16开ampTrueworkers2~4还不行就换yolov8n或者把 imgsz 降到 480。记住一个原则对行人检测来说保 imgsz 比保 batch 更重要小 batch 配合小学习率一样能收敛。5.3 mAP 很高但漏检远处行人小目标问题现象验证集 mAP0.5 在 0.9 以上换成 1080p 视频后远处行人漏掉一半。 原因验证集里的标注框平均面积偏大真实场景的远处行人只有二三十像素。640 输入下采样 32 倍后这些行人的特征图区域只有一个点模型根本学不到这是行人。 解决训练和推理统一用imgsz1280batch 相应减半1280 也压不住就对原图切块推理SAHI 思路切成 4 块分别检测再合并数据层面补充小目标样本或对小目标做复制粘贴增强。别指望加个损失函数分支就能逆天改命输入分辨率不够什么 head 改进都白搭。5.4 导出 ONNX 后结果对不上预处理与 NMS 的锅现象.pt推理能框住行人转 ONNX 后用 onnxruntime 推理框少了、置信度也变了。 原因YOLOv8 推理流程是预处理letterbox 归一化→ 模型 → NMS导出 ONNX 时 NMS 默认被拆到模型外。onnxruntime 推理时如果 letterbox 填充方式、置信度阈值、iou 阈值和原来不一致输出自然对不上。 解决导出时固定格式常见做法是用 ultralytics 自带导出model.export(formatonnx, opset12, imgsz640)推理侧复用 ultralytics 的预处理逻辑不要自己另写一套最后拿同一张图跑.pt和 onnxruntime用脚本对比两边框坐标误差控制在几个像素内才算通过。5.5 换台机器就报错环境版本没锁死现象在自己机器上好好的把项目拷给别人或换台服务器import 直接报错或者同样的代码结果不同。 原因ultralytics 迭代快8.0 和 8.2 之间的 Python API 和命令行参数都有变化项目大概率只给了代码没给环境清单。 解决项目根目录放一份锁死的requirements.txt明确写ultralytics8.2.100、torch2.1.2、torchvision0.16.2换机器时用conda env export environment.yml导出完整环境。还有一个血泪经验写代码时别依赖过新的 API比如统一用model.predict()这种稳定接口别用只在某个小版本里出现过的参数。6. 把模型用起来视频计数、热力图与 RK3588 部署路径训练完的 best.pt 最终要落到场景里。下面讲三个最常用的落地动作视频推理、密度可视化、边缘设备部署。三者共用同一个模型但各有各的注意点。6.1 视频推理与行人计数最小脚本from ultralytics import YOLO import cv2 model YOLO(runs/pedestrian/weights/best.pt) cap cv2.VideoCapture(street.mp4) while cap.isOpened(): ok, frame cap.read() if not ok: break res model(frame, conf0.3, imgsz640, device0)[0] people 0 for b in res.boxes: if int(b.cls[0]) 0: people 1 x1, y1, x2, y2 map(int, b.xyxy[0]) cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(frame, fpeople: {people}, (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) cv2.imshow(pedestrian, frame) if cv2.waitKey(1) 27: break cap.release() cv2.destroyAllWindows()关键是把conf从训练时常用的 0.25 提到 0.3——视频场景下误检比漏检更影响体验略调高阈值能过滤掉大量抖动检测。要计数更准确就不要逐帧统计同一个人会被重复统计而是检测框中心点跨越画面设定直线时计数那是另一个话题。6.2 行人密度热力图用检测结果画出来的可视化搜yolov8可视化热力图时看到的大多是特征图可视化但对安防场景我更推荐用检测结果直接画密度把每个行人框的中心点叠加成高斯分布得到的热力图能直观展示拥挤区域。import numpy as np heat np.zeros((frame.shape[0], frame.shape[1]), dtypenp.float32) for b in res.boxes: x1, y1, x2, y2 map(int, b.xyxy[0]) cx, cy (x1 x2) // 2, (y1 y2) // 2 cv2.circle(heat, (cx, cy), 25, 1.0, -1) # 半径 25 像素 heat cv2.GaussianBlur(heat, (0, 0), sigmaX15) heatmap cv2.normalize(heat, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8) heatmap cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)sigmaX15和圆的半径决定热力图平滑程度大屏展示时半径调大做量化分析时调小。这个方法的好处在于不依赖模型内部特征框准了热力图就准排查问题也更直观。6.3 RK3588 部署路径从 .pt 到 .rknn 的常见做法边缘端部署是目前把这类项目产品化最常见的路径。以 RK3588 为例标准流程是best.pt 导出 ONNX再用 RKNN-Toolkit2 转成 .rknn最后在板端用 rknn-toolkit-lite2 的 Python API 推理。期间有两点要特别注意一是 RKNN 转模型默认做 INT8 量化行人这类小目标对量化误差很敏感精度可能掉 13 个点建议先用几百张训练图做量化校准二是 NMS 在导出时已经被拆掉板端要么自己实现 NMS要么走 RKNN 的后处理接口直接拿原始输出会看到一堆重叠框。我自己的教训是不要在 mAP 上过度自信。曾经把验证集 mAP 0.93 的模型直接部署到 RK3588现场视频里小目标全丢最后定位到是 INT8 量化对低分辨率行人特征图损伤太大。后来养成一个习惯任何模型上线前先挑 20 张最难的照片做人工验收肉眼过了再谈指标。这套流程从数据、训练到部署走完一遍后你会发现这类 YOLOv8 行人检测项目真正能带走的不是压缩包里那几个文件而是你亲手调过的参数和踩过的坑。希望帮到你。本文还有配套的精品资源点击获取
返回列表