
简介基于YOLOv5 ROS部署版的行人与红绿灯识别项目是一套从模型训练到ROS实时推理的完整方案面向高校计算机、电子信息工程、数学等专业学生的课程设计、期末大作业或毕业设计也适合自动驾驶、智慧交通等场景的初步研究读者需具备一定深度学习与ROS基础能自行调试和扩展功能。压缩包共123个文件整体约83.87MB主要包含Python源码、YOLOv5网络配置yaml、训练权重pt、ROS消息定义msg、shell启动脚本sh、Dockerfile容器化部署文件以及说明文档md等类型覆盖模型依赖配置、目标检测、ROS分布式通信和容器化运行环境目录结构清晰便于按需查阅。目前已有1933人学习或下载在同类行人与红绿灯识别资源中具有一定热度。除可直接运行的源码与权重外还附带tutorial.ipynb交互式教程、yolov5网络结构说明和注意力机制报告可帮助理解检测原理、熟悉ROS集成流程并在此基础上进行二次开发例如替换数据集、调整模型参数或增加交通标志识别功能以满足科研或课程设计的个性化需求。1. YOLOv5 ROS 部署版行人和红绿灯识别这份资源先解决哪一段问题课程设计或毕设最卡人的环节往往不是把模型训到多高的 mAP而是把训练好的 YOLOv5 接进 ROS 机器人让它对着摄像头实时出框。这份基于 YOLOv5 ROS 部署版实现行人和红绿灯识别的资源就是为这个场景打包的源码、权重、说明文档都在一个 rar 里。它解决的具体问题是——图像话题进来、检测结果以 ROS 话题发出去、行人和红绿灯都被框出来不用再从零拼工程。适合有 Python 基础、能看懂 YOLOv5 推理流程、想在机器人或 gazebo 仿真上做目标识别验证的人。如果你已经用自己的数据训过 YOLOv5这套部署版的节点结构和话题设计也能直接迁移。2. 环境与依赖Ubuntu 20.04 ROS Noetic 下把 YOLOv5 部署版跑起来2.1 选型为什么 Noetic 是这套部署版最省事的发行版ROS 1 的 Noetic 是最后一个原生支持 Python 3 的 ROS 1 发行版这个点对 YOLOv5 极其关键。YOLOv5 官方代码要求 Python 3.8 以上Ubuntu 20.04 默认就是 Python 3.8装上 ROS Noetic 之后rospy、cv_bridge、OpenCV、numpy 用的是同一套 Python 3.8 解释器几乎不会有 ABI 冲突。反观 Ubuntu 22.04 装 ROS 2 Humble这套部署版里的节点写法多半是 rospy要改成 rclpy 重构一遍用 ROS Melodic 则是 Python 2 时代的老发行版跟 YOLOv5 直接不兼容。所以拿到资源先看环境要求照着 Noetic 走是最稳的。我在 DeepLab 时代吃过一次亏当时图省事在 Ubuntu 18.04 上装 ROS MelodicPython 2.7 环境里硬塞 YOLOcv_bridge 编译了整整一下午话题图像编码还对不上。后来换 Noetic 全程顺利。对这份部署版我的建议就一句别在发行版上搞创新系统 Ubuntu 20.04、ROS Noetic、Python 3.8三个版本锁死后面所有坑都少一半。环境安装有两条路我分别说下取舍官方二进制安装ROS 官方 apt 源 rosdep步骤全有文档适合要深度定制 ROS 组件的场景但 ROS 依赖较多第一次装大概要 30~60 分钟。鱼香ROS一键安装开源社区开发者维护的一键脚本可以在终端里运行覆盖系统依赖、桌面完整版、rosdep 初始化对纯为了跑通检测的课程设计场景省时有效。# 方案一官方二进制安装核心三步 sudo sh -c echo deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main /etc/apt/sources.list.d/ros-latest.list sudo apt update sudo apt install ros-noetic-desktop-full -y sudo apt install python3-rosdep -y sudo rosdep init rosdep update # 方案二鱼香ROS一键安装交互式选择 Noetic 桌面完整版 # 安装脚本以开源项目 fishros 页面提供的命令为准 wget http://fishros.com/install -O fishros chmod x fishros ./fishros逻辑说明方案一的 sources.list 写入 ROS 官方源后desktop-full 会把 roscore、rviz、gazebo 一把装齐rosdep 负责后续工作空间里的依赖解析。方案二的脚本是交互式的初次运行会让你选择版本选 noetic 后它会把环境变量、rosdep 都配好省去手工步骤但要注意脚本需要网络连续断网重跑即可。参数说明如果你只用检测不跑 gazebodesktop-full 可以换成 ros-noetic-ros-base少装几百 MB 仿真组件。装完别忘了执行echo source /opt/ros/noetic/setup.bash ~/.bashrc否则每个新终端都要手动 source。检查是否装好跑一下rosversion -d应该输出 noetic。提示以下所有命令都假定你在 Ubuntu 20.04 ROS Noetic 环境下执行改发行版后需重新适配。YOLOv5 本身的依赖用 pip 管理路径要和 ROS 环境隔离。我的常用做法是 ROS 节点走系统 Python模型推理走 conda 虚拟环境两边用 ROS 话题通信互不干扰# 创建 yolov5 专用 conda 环境避免污染系统 Python3.8 conda create -n yolov5 python3.8 -y conda activate yolov5 pip install torch1.10.0 torchvision0.11.0 --index-url https://download.pytorch.org/whl/cu113 pip install -r requirements.txt # YOLOv5 官方依赖清单参数说明torch 和 torchvision 版本一定要对应官方 requirements.txt 里一般写一版但你本机 CUDA 驱动版本若高于 11.3可以用 update 参数换对应 wheel。conda 环境里不需要装 rospy因为 ROS 节点和推理模块通过话题和消息类型交互在节点侧 import 即可。2.2 从 Dockerfile 和 setup.cfg 逆推作者的依赖设计解压 rar 后我在看 README 之前会先扫一眼 Dockerfile 和 setup.cfg因为这两个文件把作者的依赖设计暴露得很彻底。Dockerfile 的 FROM 行最关键。如果是nvidia/cuda:11.x-base-ubuntu20.04说明推理依赖 GPU权重是 PyTorch 的 .pttorch 版本不能乱换如果是python:3.8-slim说明作者只做了 CPU demo你本地没显卡也能跑。Dockerfile 里 apt-get install 的包名列表也值得抄ros-noetic-ros-base和python3-opencv是常见组合说明作者在容器内只保留了最小 ROS 内核加 OpenCV。我在没装带桌面的 Ubuntu 机器上复现时直接照 Dockerfile 的 apt 列表装依赖是最快的。不过需要注意Docker 容器里跑 roscore 和真机不一样要处理 network host 或者共享 /dev 摄像头设备权限。课程设计如果不需要容器化我可以只看 Dockerfile 的依赖版本不跑 docker。setup.cfg 干的事更具体它是 Python 包的安装元数据。部署版里出现 setup.cfg说明作者把节点代码整理成了可被 catkin 安装的 ROS 包常见内容长这样# setup.cfg 示例声明脚本安装位置 [develop] script_dir$base/lib/yolov5_ros [install] install_scripts$base/lib/yolov5_ros含义让 catkin 在 build 和 install 时把可执行脚本放到 lib/yolov5_ros 目录下这样rosrun yolov5_ros detect.py才能找到命令。如果你在本地执行 rosrun 报 command not found九成是 setup.cfg 缺失或 install 模式没走回到工作空间根目录重新 catkin_make install 就能解决。2.3 文件清单每个文件在链路里的角色资源里这幅文件列表我按使用顺序给你排个表| 文件 | 角色 | 什么时候用 | | setup.cfg | 节点包的安装元数据 | 首次 catkin_make 前确认它存在 | | Dockerfile | 容器化环境定义 | 想跑容器部署或照抄依赖版本时 | | tutorial.ipynb | Jupyter 单图复现教程 | 上 ROS 前先验证权重是否加载正确 | | bus.jpg / zidane.jpg | YOLOv5 官方测试图 | 判断模型是否正常出框 | | README.md | 项目使用与启动步骤 | 跑之前必读 | | yolov5_network.md | 网络结构说明 | 想换骨干网络或看结构细节时 | | 注意力机制报告.md | 课程设计报告素材 | 写论文、答辩前整理改进点时 |bus.jpg 和 zidane.jpg 是 YOLOv5 官方仓库自带的测试图片它们的出现说明这份部署版基于官方代码库包装而不是从某个魔改分支出发。意味着官方 YOLOv5 的参数体系、训练入口、后处理逻辑都能复用后续你想换自己的数据集训练衔接成本很低。注意力机制报告则点明了作者的改进方向多半是在 C3 模块后嵌了 SE 或 CBAM 注意力模块报告里通常有网络结构图和消融对比这块能直接当作课程设计的「模型改进」章节素材。3. 检测节点与话题链路把识别结果发出去是部署版和纯 YOLOv5 的最大区别3.1 图像从 camera 到推理节点的完整数据流纯 YOLOv5 脚本的输入一般是图片路径或 cv2.VideoCapture 读帧部署版则把输入源换成了 ROS 话题。最常见的拓扑是这样的订阅话题/camera/image_raw消息类型 sensor_msgs/Image发布话题/yolov5/detections自定义检测结果消息发布可视化/yolov5/visualization画了框的 sensor_msgs/Image之所以用话题而不是直接访问摄像头原因在于机器人上摄像头往往挂在另一个进程甚至另一台机器上话题解耦了图像生产和图像消费。你在 gazebo 仿真里挂一个摄像头插件它照样会往 /camera/image_raw 上发图ROS 机械臂和移动机器人上的感知模块都这么接。这也是 YOLOv5 部署版和纯脚本很大一个区别点。节点骨架我拆给你看#!/usr/bin/env python3 # detect_node.py —— 部署版检测节点标准骨架 import rospy import numpy as np import cv2 from sensor_msgs.msg import Image from cv_bridge import CvBridge class YoloDetector: def __init__(self): self.bridge CvBridge() rospy.init_node(yolov5_detector) self.sub rospy.Subscriber(/camera/image_raw, Image, self.callback, queue_size1) self.pub rospy.Publisher(/yolov5/visualization, Image, queue_size1) def callback(self, msg): # ROS Image - OpenCV BGR 矩阵 frame self.bridge.imgmsg_to_cv2(msg, bgr8) # 推理 后处理返回检测框 dets self.infer(frame) # 画框得到可视化图 vis self.draw(frame, dets) # OpenCV 矩阵 - ROS Image 发布 self.pub.publish(self.bridge.cv2_to_imgmsg(vis, bgr8)) def infer(self, frame): pass # 第 4 章展开 def draw(self, frame, dets): for x1, y1, x2, y2, conf, cls in dets: cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2) return frame if __name__ __main__: YoloDetector() rospy.spin()逻辑说明回调函数每收到一帧先由 cv_bridge 把 sensor_msgs/Image 转成 OpenCV 的 BGR 矩阵推理后画框再转回 Image 消息发布。cv_bridge 是 ROS 图像话题和 cv2 矩阵间的唯一标准通道编码参数 bgr8 必须和发布端编码一致否则颜色会错乱。参数说明订阅和发布端 queue_size 都设 1这是故意为之。检测推理本身就耗时队列长了会堆积旧帧话题越读越滞后丢帧比积压更健康。我在真机上还会在 callback 里加个时间戳判断超过 500ms 没新图像就预警排查摄像头掉线。启动验证的时候用 roslaunch 文件把节点和参数统一管理会让效率好很多这也是 README 大概率给出的方式!-- yolov5_ros.launch —— 部署版启动文件骨架 -- launch node nameyolov5_detector pkgyolov5_ros typedetect.py outputscreen param nameweights value$(find yolov5_ros)/weights/best.pt/ param nameconf_thres value0.25/ param nameiou_thres value0.45/ param nameimgsz value640/ /node /launch代码说明param 标签把这些阈值参数暴露到 ROS 参数服务器调试时可以用rosparam set /yolov5_detector/imgsz 960动态改不需要改代码重启对调参很有用。weights 路径用 $(find yolov5_ros) 定位即使工作空间目录挪了位置也不会写死。参数说明实际发布前先用rostopic list确认 /camera/image_raw 存在用rostopic hz /camera/image_raw看帧率。很多新手上来就 roslaunch结果订阅话题没数据回调从不触发表现是节点启动了但没任何输出排查思路应该是先去查上游图像源。3.2 权重加载与类别过滤person 和 traffic light 的 ID 对应关系YOLOv5 官方预训练权重跑在 COCO 80 类上行人和红绿灯都在其中。COCO 类别列表里person 的 ID 是 0traffic light 的 ID 是 9部署版做类别过滤的动作一般长这样# 推理结果 det 每行为 [x1, y1, x2, y2, conf, class] CLASSES {0: person, 9: traffic_light} def filter_classes(det): # 只保留 id 在 CLASSES 里的检测框 keep [i for i, d in enumerate(det) if int(d[5]) in CLASSES] return det[keep]逻辑说明det 是 NMS 输出的二维数组最后一列是类别 ID。用目标 ID 在预设字典里的索引过滤能把 car、dog 这类干扰全部剔除。部署场景里这个过滤不只是为了显示干净更多是减少下游逻辑误触发——比如你后面接行人跟随car 的误检就会让机器人乱动。参数说明如果还有别的需求类别在 CLASSES 里加 ID 即可。但要注意红绿灯在 COCO 里只有 traffic light 一个 ID不区分红灯绿灯黄灯。部署版里如果只出框不判颜色那说明作者只做了检测识别想判红绿需要拿检测框 ROI 再做颜色分割这通常是独立的逻辑节点不是 YOLOv5 的活。3.3 README 与 yolov5_network.md 里值得抄的关键参数课程设计配套的说明文档一定写了他调好的一组参数。我最关注的四个| 参数 | 默认值 | 作用 | 调参场景 | | conf_thres | 0.25 | 置信度阈值 | 小目标漏检时调低 | | iou_thres | 0.45 | NMS 重叠抑制 | 重叠框多时调低 | | imgsz | 640 | 推理输入尺寸 | 显存够时上调提升小目标 | | max_det | 300 | 每帧最大框数 | 话题带宽受限时调小 |yolov5_network.md 如果写全了会有模型结构图和每层输出张量尺寸。它的价值在你想换骨干网络时能立刻看懂哪里要改注意力机制报告则是课程设计的论文素材作者会在报告里给出加了注意力模块前后的 mAP 变化这份对比表对于答辩时解释「为什么选择这个模型」很有用。我的建议是先把 README 里的启动命令完全走一遍再回头读网络说明文档不然你对节点的理解停在「能跑」而不是「为什么这么跑」。4. 推理代码与后处理同一帧图像上怎么同时输出框、类别与置信度4.1 推理主循环逐段拆解部署版的推理流程其实和官方 YOLOv5 的 detect.py 一模一样区别只在输入来源是 ROS 话题。核心步骤五段加载权重、预处理、前向、后处理、坐标还原。下面按部署版的代码习惯拆一遍其中 letterbox 和坐标还原是踩坑率最重的两段# infer.py —— 部署版推理函数关键实现 import torch import numpy as np import cv2 def letterbox(img, new_shape640, stride32): # 计算缩放比保持长宽比短边补灰 h, w img.shape[:2] r min(new_shape / h, new_shape / w) new_w, new_h int(round(w * r)), int(round(h * r)) dw, dh (new_shape - new_w) // 2, (new_shape - new_h) // 2 img cv2.resize(img, (new_w, new_h)) top, bottom dh, new_shape - new_h - dh left, right dw, new_shape - new_w - dw img cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value(114, 114, 114)) return img, (r, dw, dh) def preprocess(img): img, meta letterbox(img, 640, 32) img img[:, :, ::-1].transpose(2, 0, 1) # BGR - RGB, HWC - CHW img np.ascontiguousarray(img) tensor torch.from_numpy(img).float() / 255.0 return tensor.unsqueeze(0), meta逻辑说明letterbox 返回了两个关键值缩放比 r 和灰边偏移 dw/dh。这两组值在后处理还原坐标时必须用上。颜色通道 BGR 转 RGB 是因为 YOLOv5 权重在 RGB 输入上训练保持这个顺序模型输出才稳。除以 255 是归一化和训练时保持一致。参数说明new_shape640 是输入尺寸stride32 保证缩放宽高能被模型 5 次下采样后的 32 整除否则特征图尺寸和原图对不上。如果你的显存只有 4G可以尝试 416反过来对红绿灯小目标960 能明显提升召回代价是前向耗时约翻倍。前向推理和后处理接在后面def infer(model, img_tensor, meta): # 前向推理拿到三尺度原始输出 with torch.no_grad(): pred model(img_tensor)[0] # non_max_suppression 去重输出 [x1, y1, x2, y2, conf, class] det non_max_suppression(pred, conf_thres0.25, iou_thres0.45, max_det300)[0] if det is None: return np.empty((0, 6)) r, dw, dh meta # 坐标还原减去 padding除以缩放比 det[:, :4] - torch.tensor([dw, dh, dw, dh], devicedet.device) det[:, :4] / r return det.cpu().numpy()逻辑说明还原坐标是后处理里最容易翻车的一步。letterbox 在预处理时给图片四周加了灰边模型输出的框坐标是基于加边后的图算的不减掉 padding 不除以缩放比画出来的框整体向左上偏移并且偏小。很多同学说「检测框位置不对」九成是这个还原没写对。参数说明conf_thres 和 iou_thres 的作用前面提过这里说下 max_det300官方默认值对单目视频够用但 ROS 话题发布带宽有限300 个框全画出来一帧可能几 MB建议场景里压到 50~100。conf_thres 对红绿灯经常要单独降到 0.15这个策略在 4.2 展开。4.2 后处理 NMS置信度阈值和 IoU 阈值怎么调部署场景下面临不同光照和目标大小同一组阈值很难同时满足行人和红绿灯。实测下来我最常用的一组经验值| 场景 | conf_thres | iou_thres | 备注 | | 室内行人检测 | 0.35 | 0.45 | 环境干净适当提高置信度减少误检 | | 户外红绿灯识别 | 0.15~0.2 | 0.5 | 目标小、亮度高模型置信度天然偏低 | | 多人密集场景 | 0.25 | 0.3 | 压重叠框避免同一个行人画多个框 |红绿灯在画面里通常只占几十甚至十几个像素模型给出的置信度普遍在 0.2~0.3 徘徊。如果你全局用 0.25远处红绿灯会直接漏检。所以部署版里推荐按类别分档思路是后处理拿到检测结果后先按 class 分组对 traffic light 单独放宽阈值def adaptive_threshold(det): # 行人用高阈值红绿灯用低阈值 person_thres, light_thres 0.35, 0.15 keep [] for d in det: thres light_thres if int(d[5]) 9 else person_thres if d[4] thres: keep.append(d) return np.array(keep).reshape(-1, 6)参数说明这种分档写法不会把行人的误检带进来又保住了小目标召回是课程设计答辩时一个很自然的「工程改进点」。实际调试时我建议把 conf 和 iou 通过 ROS 参数暴露出来跑一段 rosbag 回放边看结果边调比一遍遍改代码重启节点高效得多。4.3 tutorial.ipynb先跑通单张图再上 ROS 话题包里的 tutorial.ipynb 是作者给的验证路径价值是把「模型能不能跑」和「ROS 能不能跑」两个变量解耦。严格按 notebook 顺序执行导入模型和类别映射对 bus.jpg 做单张推理确认 person 出框对 zidane.jpg 做单张推理确认 person 出框把检测结果可视化保存到本地这四步走完权重和 torch 依赖就验证通过了。如果 notebook 阶段就报 ImportError说明依赖没装齐先回第 2 章补环境如果 bus.jpg 上没框但 zidane.jpg 有多半是 conf_thres 设太高或模型权重和类别不匹配——这两个文件一张是大场景多行人一张是单人近景出框数量差异本身就是最好的阈值参考。我的习惯是 notebook 阶段就把 conf_thres 从 0.25 往下逐档试 0.2 / 0.15观察哪一档两张图都能接受把这一档作为 ROS 节点的初始值。5. 避坑与常见问题ROS 部署 YOLOv5 最容易翻车的五个点部署类项目跟纯训练不一样很多问题不是模型效果不好而是环境、消息、坐标、设备这四层里任何一层出问题表现都极其相似——节点没输出、框位置不对、只有 CPU 在跑。下面是课程设计群和论坛里被问得最多的五类问题我按现象→原因→解决给你拆透。坑一rosrun 报 command not found包明明在工作空间里现象按 README 执行rosrun yolov5_ros detect.py终端提示找不到包名或命令。原因多半是没 source devel 目录或者 setup.cfg 的 install_scripts 没生效可执行脚本没进 devel/lib。另一种可能是包目录本身没被 catkin 识别比如缺少 package.xml。解决先source ~/catkin_ws/devel/setup.bash还是不行就进工作空间根目录重新执行catkin_make install让 setup.cfg 生效。另外确认包内 detect.py 第一行是#!/usr/bin/env python3并且文件有可执行权限否则 rosrun 即使找到了文件也会报 Permission denied。最后用rospack find yolov5_ros验证包路径输出空就说明 catkin 没发现这个包。坑二cv_bridge 与 Python 环境 ABI 冲突import 直接崩现象节点启动后 callback 一触发就报 boost::python 相关错误或者 import cv_bridge 直接段错误终端没有任何可读的 Python traceback。原因Noetic 的 cv_bridge 绑定的是系统 Python 3.8你在 conda 环境里 import 时如果 conda Python 版本不是 3.8会同时加载系统原生库和 conda 的 Python 库ABI 不一致直接崩。这个坑在 Ubuntu 20.04 装 Anaconda 后特别常见因为 .bashrc 里 conda 提前激活系统 Python 和 conda Python 互相打架。解决最稳妥的架构是 ROS 节点全部跑系统 Python3模型推理单独放 conda 环境两边用话题通信。如果一定要在 conda 环境里跑就退出 conda 后用pip install cv-bridge重新装与 Python 3.8 匹配的版本再手工把系统 cv_bridge 库路径指到 conda 里。我一般还会检查python3 -c import cv_bridge能否在系统 Python 下正常用它当基准判断到底是环境问题还是代码问题。坑三检测框整体偏移位置对但坐标不对现象框大体框在正确目标上但明显向左上偏移或者框比实际目标小一圈尤其在非 16:9 的原图上更明显。原因letterbox 预处理加了灰边模型输出坐标基于加边后的图后处理忘了减 padding、除以缩放比。这类问题在纯脚本里不太明显因为官方 detect.py 内部已经处理了部署版改过代码后很容易把这段还原逻辑丢掉。解决把 letterbox 返回的缩放比 r、dw、dh 一路传递到坐标还原处在 NMS 之后对所有框执行(box - [dw, dh, dw, dh]) / r。写完还原后打印一张原图画框验证框应该严丝合缝贴在目标上这是最直观的验收方式。另外注意 dw、dh 在 letterbox 里是除以 2 后的单边偏移还原时直接用不要再除一次。坑四GPU 占用高但推理还是秒级不如 CPU现象nvidia-smi 显示 GPU 已占用但每帧推理耗时 1 秒以上FPS 上不去甚至比纯 CPU 推理还慢。原因数据在 CPU 和 GPU 之间反复拷贝。常见是预处理用 OpenCV 做CPU前向放 GPU后处理又转回 numpyCPU或者权重加载时先 load 到 CPU 又 .to(cuda)造成张量所在设备混乱每次前向都触发隐式拷贝。解决预处理把 numpy 转 torch 后统一 .cuda()全链路上 GPU 张量后处理再转 numpy 用于画框。加载权重时显式attempt_load(best.pt, map_locationcuda:0)不要再调 .cpu()。推理前跑一次model(torch.zeros(1, 3, 640, 640).cuda())做 warmup消除首次 CUDA kernel 编译开销。坑五红绿灯大量漏检行人却很正常现象行人框很稳红绿灯只在近处大目标出现时出框远处全丢FPS 还正常看起来像是模型「选择性失明」。原因三个叠加——模型在 COCO 上本身对小型目标检测偏弱全局 conf_thres 设太高把置信度本来就低的红绿灯滤掉了输入分辨率 640 下远处红绿灯只有十几个像素letterbox 缩放后更小。解决对 traffic light 单独把阈值放到 0.15imgsz 从 640 提到 960显存够的前提或者把图像下半部分 ROI 单独送入推理红绿灯位置相对固定时这种方法效果最稳。做完这三件事再配合注意力机制小目标召回能救回不少这也是课程设计里能写进论文的调优过程。6. 换自己的数据集重训从部署版回迁到 YOLOv5 训练流程6.1 把 VOC 标注转成 YOLO 训练格式课程设计一般有自己采集的行人、红绿灯数据要重新训练的话先把标注转成 YOLO 的归一化 txt 格式。多数标注工具导出 VOC xml转换代码可以直接参照# voc_to_yolo.py —— 单张 xml 转 YOLO 标签 import xml.etree.ElementTree as ET def voc2yolo(xml_path, out_path, class_names): tree ET.parse(xml_path) root tree.getroot() size root.find(size) w, h int(size.find(width).text), int(size.find(height).text) lines [] for obj in root.findall(object): cls_id class_names.index(obj.find(name).text) box obj.find(bndbox) x1, y1 int(box.find(xmin).text), int(box.find(ymin).text) x2, y2 int(box.find(xmax).text), int(box.find(ymax).text) # 归一化到 0~1中心点 宽高 cx (x1 x2) / 2.0 / w cy (y1 y2) / 2.0 / h bw (x2 - x1) / w bh (y2 - y1) / h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) with open(out_path, w) as f: f.write(\n.join(lines))逻辑说明YOLO 标签每行五个数类别 ID、中心点 x、中心点 y、宽、高全部归一化到 0~1。类别的顺序以训练配置 data.yaml 的 names 列表为准这里最容易踩的坑是 xml 里类别名和 names 顺序对不上导致训练时 class index 越界。参数说明宽高归一化必须除以原图宽高转出的 txt 和图片同名、同目录放好后续直接交给 YOLOv5 的数据集加载器读取。提示转换脚本只处理 VOC xml如果你的标注是 COCO json把关键字段读出来按同样的归一化公式写一遍即可。6.2 训练命令与关键超参数官方 YOLOv5 的训练入口保持不动部署版不会改训练端。我一般用下面这组参数起步# 从 COCO 预训练继续 fine-tune注意不要用部署版 best.pt 做初始化 python train.py \ --data data/pedestrian_traffic.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --cache参数说明--weights 用官方 yolov5s.pt 而不是部署版的 best.pt因为部署版权重可能带注意力模块改动结构和原版 s 不一致加载会 shape mismatch。--img 640 与部署版推理的 imgsz 保持一致训练推理尺寸不一致会损失 mAP。batch 按显存调8~16 都是合理区间--cache 预加载数据集能大幅减少训练初期的 IO 等待。训练完在 runs/train/exp/weights/ 里拿 best.pt直接替换部署版 weights 目录下的权重把 data.yaml 的 names 也同步改掉。如果部署版加载时报类别数不匹配去代码里找 model 的 nc 参数改成你的类别数再加载。6.3 权重回导与部署验证三个固定检查项新权重放回部署版后别急着连真机我先跑三个固定检查best.pt 在 bus.jpg 上是否还出框验证模型没坏自己数据里的红绿灯图上是否按新类别出框坐标还原后框和原图物体是否对齐。三个都过再进话题链路看帧率。如果端侧推理低于 5 FPS优先把 imgsz 从 960 降回 640再考虑换 YOLOv5n 或轻量化注意力模块注意力机制报告里通常有结构对比选型时可以直接抄结论。我第一次回迁训练时就栽在 data.yaml 的 nc 上labels 里的类别 ID 从 1 开始写YOLO 标签里却全是 0训练时一直报 class index out of range。后来写了个脚本把所有 txt 标签第一列统计一遍发现最大值比 nc 大 1改完就通了。从那以后我每次换数据集都会先跑一遍统计脚本确认类别 ID 落在 [0, nc) 区间再进 ROS 链路。这套流程希望你用得上少走我当年的弯路。本文还有配套的精品资源点击获取