1. 项目概述从工地安全到算法落地最近在做一个挺有意思的项目给一个大型建筑集团做了一套反光衣穿戴检测与预警系统。起因是他们工地上出了几次小事故虽然没造成严重后果但管理层意识到单纯靠安全员巡查和口头提醒很难百分百确保每个进入危险区域的工人都按规定穿好了反光衣。尤其是在夜间、隧道或者光线不好的仓库里这个问题更突出。他们找到我问能不能用技术手段解决目标很明确实时、自动、准确。接到需求后我脑子里第一个蹦出来的就是目标检测。这活儿太适合它了从监控画面里把“人”这个目标框出来再判断这个人身上有没有穿“反光衣”。YOLO系列自然是首选速度快精度也不错适合部署在需要实时响应的场景。当时YOLOv8刚发布不久看论文和社区反馈它在精度和速度的平衡上做得更好还提供了非常友好的Python接口和丰富的预训练模型从快速验证到深度定制都很方便。所以技术栈就定下来了YOLOv8做核心检测模型PyQt5来搭建一个给安全管理人员用的操作界面后端用Python把数据流、模型推理和预警逻辑串起来。这套系统最终要达成的效果是连接工地已有的摄像头视频流实时进入系统YOLOv8模型逐帧分析一旦检测到有未穿反光衣的人员进入预设的警戒区域比如大型机械操作区、材料装卸区系统立即触发预警。预警方式可以多样比如在监控室的屏幕上用红色框高亮显示违规人员并弹出提示或者通过声光报警器在现场发出警示甚至可以将违规截图和记录通过API推送到管理人员的手机上。这不仅仅是“检测”更是一个完整的“感知-分析-决策-响应”闭环把深度学习从实验室代码变成了真正提升安全生产水平的工具。2. 核心思路与系统设计拆解2.1 为什么是YOLOv8—— 模型选型背后的考量在目标检测领域选择很多从老牌的Faster R-CNN到新秀DETR为什么偏偏是YOLOv8这得从实际项目需求说起。首先我们的场景是实时视频流分析。工地摄像头可能输出25帧甚至30帧每秒的视频这意味着留给单帧图片分析的时间非常短通常要求在40毫秒以内完成预处理、推理和后处理才能保证视频播放的流畅性和预警的实时性。YOLO系列一贯以“快”著称其“You Only Look Once”的单阶段检测思想省去了候选区域生成的步骤天生就比两阶段检测器快。YOLOv8在v5和v7的基础上进一步优化了网络结构和训练策略在保持速度优势的同时精度尤其是mAP指标还有所提升这对于需要平衡“快”和“准”的工业场景来说是个很划算的选择。其次部署友好度极高。Ultralytics官方提供的ultralytics库其API设计得非常简洁。训练自己的数据集几行代码就能搞定进行模型导出支持ONNX、TensorRT、OpenVINO等多种格式方便后续部署到不同的硬件平台从服务器到边缘计算盒子NVIDIA Jetson、RK3588等。我们项目后期就有计划在一些没有网络覆盖的临时工地部署边缘设备YOLOv8的这种灵活性大大减少了我们的工作量。再者社区生态和可改进空间。YOLOv8虽然新但社区活跃各种改进方案、魔改模块的讨论和代码很多。比如项目中我们发现反光衣在强光直射下会产生大面积高光容易导致漏检。我们后来就借鉴了社区里一些针对小目标和遮挡问题的改进思路对neck和head部分做了微调。如果选择一个太过冷门或固化的框架这种程度的定制化会困难得多。注意模型选型没有绝对的最好只有最合适。如果您的场景对精度要求极高且可以接受秒级的延迟那么两阶段检测器或者Vision Transformer为基础的检测器可能更优。但对于绝大多数需要实时响应的安防、巡检类项目YOLOv8目前是一个稳健的起点。2.2 系统架构全景图从数据流到预警触发光有一个好模型不够得把它嵌入到一个能跑起来的系统里。整个系统的架构可以分成五个核心层我把它画成了一个简单的数据流图这里用文字描述数据输入层负责接入视频流。支持多种来源RTSP流主流摄像头协议、本地视频文件用于测试和复盘、以及USB摄像头。这一层使用OpenCV的VideoCapture模块实现关键是要处理好不同来源的帧率、分辨率差异并保证视频帧的稳定读取避免丢帧导致分析遗漏。智能分析层这是系统的大脑核心就是YOLOv8模型。它的工作流程是预处理将从输入层拿到的每一帧图像缩放到模型要求的尺寸如640x640并进行归一化。模型推理将预处理后的图像张量送入加载好的YOLOv8模型可以是.pt权重文件或转换后的.onnx等格式得到原始的预测输出。后处理对模型的原始输出进行解码。这包括应用置信度阈值比如只保留置信度大于0.5的预测框和NMS非极大值抑制来去除重复的、重叠的框。最终我们得到这一帧图像中所有检测到的目标信息包括类别“人”、“穿反光衣的人”、置信度以及边界框坐标。业务逻辑层这一层赋予系统“智慧”。它接收分析层的结果并执行具体的业务规则。区域入侵检测我们可以在视频画面上预先划定一个或多个多边形警戒区域ROI。业务逻辑层会判断检测到的“人”或“未穿反光衣的人”的边界框中心点是否落在了警戒区域内。只有进入指定区域的行为才触发预警避免了非工作区域的误报。预警判断与过滤为了避免同一个人在短时间内连续触发报警造成骚扰这里会加入简单的滤波逻辑。例如设置一个“静默时间”如10秒同一个目标ID在触发一次预警后10秒内不再对同一目标进行预警。目标跟踪可选进阶为了更精确地判断行为和进行目标ID管理可以引入轻量化的目标跟踪算法如ByteTrack或DeepSORT。这能解决人在画面中移动时被重复识别为多个新目标的问题使预警更准确数据统计更可靠。预警输出层负责将业务逻辑层的判断结果以多种形式通知给相关人员。界面可视化在PyQt5界面上用不同颜色的框绿色代表合规红色代表违规实时绘制检测结果并在违规发生时在界面侧边栏或弹窗中显示警告信息、截图。声光报警通过串口或网络协议控制现场的声光报警器实现物理层面的即时提醒。数据持久化与推送将每一次预警事件时间、位置、截图保存到数据库如SQLite或MySQL并可通过调用企业微信、钉钉的Webhook接口将预警消息推送到安全管理群。人机交互层由PyQt5构建的桌面图形界面。它不仅是结果的展示窗口也是系统的控制中心。管理人员可以通过它启动/停止检测。加载不同的视频源或模型。动态地在视频画面上绘制、调整警戒区域。查看历史预警记录和统计报表。调整检测参数如置信度阈值、NMS阈值。这五层结构清晰耦合度低。例如未来如果想换用YOLOv9或DETR模型大部分工作只需集中在“智能分析层”进行替换如果想增加短信报警也只需在“预警输出层”新增一个模块。这种设计保证了系统的可维护性和可扩展性。3. 数据集构建与模型训练实战3.1 反光衣数据集的“坑”与应对之道模型要训得好数据得先喂饱、喂好。反光衣检测这个任务在数据准备上就有几个特有的难点我踩过坑也总结了一些方法。难点一场景复杂多样。工地环境千差万别晴天、阴天、夜晚、隧道内、强光逆光、雨雪天气。反光衣的反光材料在不同光照条件下外观差异巨大。白天可能只是一件普通的荧光色马甲夜晚在车灯或探照灯下则会呈现大面积的亮白色高光区域。如果数据集只包含单一场景模型必然过拟合在实际部署中表现糟糕。应对策略多渠道收集不要只盯着一个工地的摄像头录视频。我们通过合作获取了多个不同工地、不同时段早中晚、不同天气下的监控素材。同时也在开源数据集网站如Roboflow、Kaggle上寻找包含安全背心safety vest的图片进行补充。数据增强的针对性使用在训练时除了常规的翻转、旋转、裁剪要特别注重模拟光照变化。我们大量使用了色彩抖动调整亮度、对比度、饱和度和添加模拟光斑的增强方法让模型学会不被极端光照条件迷惑。定义清晰的类别我们最终定义了三个类别person普通人、person_with_vest穿反光衣的人、vest脱下的或悬挂的反光衣。定义vest类别有助于系统发现“反光衣已配备但未穿着”的情况提升管理粒度。难点二目标尺度变化大与遮挡。摄像头有近景有远景工人可能离镜头很近全身占据大部分画面也可能很远只占几十个像素。而且工地上设备、材料多人体经常被部分遮挡。应对策略多尺度训练YOLOv8本身就有多尺度训练的策略我们在配置中保持开启。同时在收集数据时刻意包含了大量远景小人物的图片。关键点标注可选进阶对于遮挡情况单纯的边界框BBox标注信息损失严重。我们尝试了对一小部分数据增加关键点标注如头顶、左右肩、左右髋训练一个带关键点检测头的模型。当人体被遮挡时即使框不全通过关键点也能更好地推断人的姿态和是否穿着反光衣因为反光衣通常覆盖肩部。但这会显著增加标注成本和模型复杂度需权衡利弊。我们的数据集最终规格总图像数约8500张自制6500张 开源2000张。标注工具使用labelImg进行边界框标注格式为YOLO格式每个图片对应一个.txt文件内容为class_id x_center y_center width_height坐标已归一化。数据集划分按8:1:1划分为训练集、验证集、测试集。验证集必须包含所有光照和场景类型用于真实反映模型泛化能力。3.2 YOLOv8模型训练参数调优与损失函数观察有了高质量的数据集训练就是水到渠成但其中也有不少技巧。这里以Ultralytics的API为例。第一步环境搭建与数据准备# 创建虚拟环境强烈推荐避免包冲突 conda create -n yolov8 python3.8 conda activate yolov8 # 安装ultralytics pip install ultralytics # 准备数据集目录结构 datasets/ └── safety_vest/ ├── train/ │ ├── images/ │ └── labels/ ├── val/ │ ├── images/ │ └── labels/ └── test/ ├── images/ └── labels/然后创建一个data.yaml配置文件指明路径和类别# data.yaml path: /path/to/datasets/safety_vest # 数据集根目录 train: train/images val: val/images test: test/images nc: 3 # 类别数量 names: [person, person_with_vest, vest] # 类别名称第二步启动训练与核心参数解析from ultralytics import YOLO # 加载一个预训练模型推荐加速收敛 model YOLO(yolov8n.pt) # 这里用nano版本举例实际可选s/m/l/x # 开始训练 results model.train( datadata.yaml, epochs100, # 迭代轮数根据数据集大小调整 imgsz640, # 输入图像尺寸 batch16, # 批次大小取决于GPU内存 device0, # 使用GPU 0如果是CPU则设为cpu workers4, # 数据加载线程数 optimizerAdamW, # 优化器SGD或AdamW lr00.01, # 初始学习率 lrf0.01, # 最终学习率因子 (lr0 * lrf) weight_decay0.0005, # 权重衰减防止过拟合 saveTrue, save_period10, # 每10个epoch保存一次检查点 projectruns/train, # 训练结果保存目录 namevest_det_v1, # 本次实验名称 exist_okTrue, # 允许覆盖同名实验 pretrainedTrue, # 使用预训练权重 ampTrue # 自动混合精度训练节省显存加速训练 )关键参数经验谈imgsz图像尺寸默认640是一个很好的平衡点。增大尺寸如1280可以提升对小目标的检测能力但会大幅增加显存消耗和推理时间。我们的场景中远景人物像素较少尝试过增大到896mAP提升了约2%但推理速度下降了40%。需要根据实际硬件和实时性要求权衡。batch批次大小在GPU显存允许的情况下尽可能设大。大的batch size能使梯度估计更准确训练更稳定。通常从16开始尝试如果爆显存可以尝试使用ampTrue混合精度或减小imgsz。optimizer优化器YOLOv8默认使用SGD。对于我们的数据集我发现使用AdamW配合适当的热身warmup策略在初期收敛更快。可以在训练配置里添加warmup_epochs3等参数。lr0学习率这是最重要的超参数之一。0.01是一个常见的起点。务必使用学习率调度器YOLOv8默认包含。训练过程中如果发现损失loss剧烈震荡或很早就不再下降很可能就是学习率太大了。第三步监控训练过程与模型评估训练开始后Ultralytics会实时输出日志并在runs/train/vest_det_v1目录下生成一系列重要文件。损失曲线图losses.png重点观察train/box_loss,train/cls_loss,val/box_loss,val/cls_loss。理想情况是训练损失和验证损失都平稳下降且两者之间的差距泛化间隙不大。如果验证损失很早就开始上升而训练损失持续下降这是典型的过拟合信号需要增加数据增强、使用DropOut、或者加大weight_decay。性能指标图results.png关注metrics/mAP50-95(B)这是COCO评估标准下的平均精度是最核心的指标。metrics/precision和metrics/recall也要看。我们的目标是让精度和召回率都达到一个较高的水平并且平衡。如果精度高但召回率低说明模型太“保守”很多该检出的目标没检出来反之则误报太多。验证集预测样本val_batchX_pred.jpg直观查看模型在未见过的数据上的表现。重点关注那些预测错误的样本是漏检了错检了还是框不准这些样本是下一步改进模型或数据集的直接依据。实操心得训练时不要一上来就跑很多轮。先设置一个较小的epoch如50用最快的速度跑完观察损失曲线和验证指标的趋势。如果趋势健康再延长训练轮数。这样可以节省大量试错时间。另外一定要在测试集完全未参与训练和验证调整的数据上做最终评估这才是模型真实水平的体现。4. PyQt5界面开发与系统集成4.1 设计一个功能完备且易用的GUI模型训练好了是一个.pt文件但它自己不会工作。我们需要一个界面把它“包”起来让非技术人员也能方便地使用。PyQt5是一个成熟且强大的选择它能做出非常专业的桌面应用界面。我们的主界面设计围绕几个核心功能模块展开视频显示区占据界面主要部分用于实时显示摄像头画面以及模型绘制上去的检测框、警戒区域。控制面板视频源控制下拉菜单或文件选择按钮用于切换RTSP流地址、本地视频文件或摄像头索引。模型加载按钮加载训练好的最佳权重best.pt或优化后的ONNX模型。检测开关开始/停止检测的按钮。参数调节提供滑动条或输入框让用户能实时调整置信度阈值和NMS阈值。置信度阈值调高检测框更少但更可靠调低可能检出更多目标但也包含更多误报。NMS阈值控制重叠框的合并程度。预警与绘图交互区区域绘制工具提供按钮如“开始绘制多边形”、“矩形绘制”、“清除区域”允许用户在视频显示区用鼠标点击绘制警戒区域。这些区域的坐标会被保存下来。预警信息列表一个表格或列表控件实时滚动显示触发的预警信息包括时间、违规类型、位置等。系统状态与统计区显示当前帧率FPS、已处理帧数、检测到的目标数量等实时状态信息以及历史违规数据的简单统计图表如柱状图显示不同时段的违规次数。界面的布局可以使用PyQt5的QHBoxLayout和QVBoxLayout进行灵活组合确保在不同分辨率下都能有较好的显示效果。4.2 多线程架构解决GUI“卡死”的关键这是开发中最容易踩坑的地方。深度学习模型推理尤其是用CPU时和视频解码都是耗时操作。如果把这些操作都放在PyQt5的主线程即GUI线程里那么只要模型一开始推理界面就会完全卡住无法响应任何点击和刷新用户体验极差。解决方案是多线程。我们将耗时的任务放到独立的工作线程Worker Thread中去执行。具体实现思路主线程GUI线程只负责界面的绘制、用户事件的响应点击按钮、拖动滑块以及从工作线程接收结果并更新UI。视频采集线程专门负责从RTSP流或摄像头中循环读取视频帧。这个线程需要稳定运行并将读取到的每一帧图像放入一个线程安全的队列如Python的queue.Queue中。模型推理线程从视频帧队列中获取图像进行预处理调用YOLOv8模型进行推理然后进行后处理。将处理结果包括画好框的图像、检测到的目标列表放入另一个结果队列。业务逻辑与预警线程可选从结果队列中获取数据执行区域入侵判断、预警过滤等业务逻辑并生成预警事件。通信机制PyQt5提供了pyqtSignal和pyqtSlot机制用于安全地在工作线程和主线程之间传递数据。例如推理线程完成一帧的处理后发射一个携带结果图像的信号主线程中有一个槽函数连接到这个信号一旦收到信号就将新图像更新到界面的QLabel上显示。# 一个简化的信号定义示例 from PyQt5.QtCore import QThread, pyqtSignal, QObject import cv2 class VideoThread(QThread): # 定义一个信号用于传递帧和结果 change_pixmap_signal pyqtSignal(np.ndarray, list) def __init__(self): super().__init__() self._run_flag True self.video_source 0 # 摄像头索引或视频路径 def run(self): cap cv2.VideoCapture(self.video_source) while self._run_flag: ret, frame cap.read() if ret: # 这里可以调用一个函数进行推理返回画好框的image和results_list processed_frame, results self.detect_frame(frame) # 发射信号将处理后的帧和结果传给主线程 self.change_pixmap_signal.emit(processed_frame, results) else: break cap.release() def stop(self): self._run_flag False self.wait() # 在主窗口类中连接信号到槽函数 class MainWindow(QMainWindow): def __init__(self): super().__init__() # ... 初始化UI ... self.thread VideoThread() self.thread.change_pixmap_signal.connect(self.update_image) self.thread.start() def update_image(self, cv_img, results): # 将OpenCV图像转换为Qt格式并显示在Label上 # 同时可以根据results更新预警信息列表等 pass通过这种设计GUI界面始终保持流畅响应而繁重的计算任务在后台默默进行二者互不干扰。5. 工程化部署与性能优化实战5.1 模型加速从PyTorch到ONNX与TensorRT训练出的.pt模型在Python环境下用ultralytics直接推理很方便但在生产环境中我们往往追求极致的推理速度。这时就需要进行模型转换和加速。1. 导出为ONNX格式ONNX是一种开放的模型格式可以作为中间桥梁将模型部署到多种不同的推理引擎上。YOLOv8导出ONNX非常简单from ultralytics import YOLO model YOLO(path/to/best.pt) model.export(formatonnx, imgsz640, simplifyTrue, opset12)关键参数simplifyTrue应用ONNX Simplifier简化计算图有时能提升推理速度。opset12指定ONNX算子集版本一般12或以上兼容性较好。导出后你可以使用onnxruntime库进行推理它通常比直接使用PyTorch有速度提升尤其是在CPU上。2. 进阶加速TensorRT如果你有NVIDIA GPUTensorRT是终极加速方案。它能对模型进行深度优化包括层融合、精度校准FP16/INT8、内核自动调优等通常能带来数倍甚至十数倍的性能提升。转换流程大致如下将ONNX模型用TensorRT的trtexec工具或Python API进行转换生成.engine文件。在Python中使用TensorRT的运行时Runtime加载.engine文件进行推理。这个过程相对复杂涉及到环境配置CUDA, cuDNN, TensorRT版本要严格匹配、处理YOLOv8输出节点的适配等问题。一个常见的坑是TensorRT转换时可能不支持模型中的某些特殊算子需要自定义插件plugin或寻找替代实现。对于YOLOv8社区已经有比较成熟的转换脚本可以大大降低难度。实测对比在我们的场景下RTX 3060 GPU输入尺寸640x640PyTorch (ultralytics): ~12 ms/帧 (约83 FPS)ONNXRuntime (GPU): ~8 ms/帧 (约125 FPS)TensorRT (FP16): ~3 ms/帧 (约333 FPS) 可以看到TensorRT带来了质的飞跃。对于需要处理多路视频流的服务器这个优化至关重要。5.2 应对复杂场景提升模型鲁棒性的技巧即使有了好的数据和训练模型在实际部署中仍会遇到意想不到的挑战。分享几个我们遇到并解决的典型问题问题1强光下的高光过曝。反光衣在探照灯直射下变成一片“死白”丢失所有纹理特征导致模型漏检。解决思路数据层面在数据集中增加更多此类极端过曝的样本并进行标注。可以尝试在图像增强时模拟这种高光效果。模型层面在预处理阶段加入局部对比度增强如CLAHE或Retinex等算法尝试恢复过曝区域的细节。但要注意这些图像处理操作本身会增加计算开销。后处理层面当检测到“人”但未检测到“反光衣”时如果该人物区域的平均像素亮度值极高可以结合这个上下文信息将其判断为“疑似未穿反光衣”触发一个置信度较低的预警交由人工复核。这是一种多模态信息融合的思路。问题2小尺度目标远景人物检测困难。在监控画面中远处的人物可能只有几十像素高反光衣区域更是只有十几个像素。解决思路修改模型结构YOLOv8的Neck部分FPN/PANet负责多尺度特征融合。可以尝试加强浅层特征包含更多细节信息向检测头的传递。社区有一些针对小目标改进的Neck设计如BiFPN、ASFF等可以尝试替换。调整Anchor或检测头YOLOv8已经使用了Anchor-Free机制但可以关注其检测头中用于预测小目标的特征图尺度。确保有足够精细的特征图用于小目标检测。推理时使用更大分辨率虽然会变慢但在关键区域如入口的分析上可以尝试将输入图像裁剪或缩放到更大尺寸如1280x1280再进行检测。问题3相似物干扰。工地上的黄色安全帽、橙色警示牌、甚至某些颜色的工作服在颜色和形状上可能与反光衣局部相似造成误检。解决思路增加困难负样本把这些容易误检的物体作为负样本不标注或标注为背景加入到数据集中让模型学会区分。利用时序信息反光衣的误检可能是闪烁的、不稳定的。而真正穿在身上的反光衣其位置和状态在连续帧间是连贯的。可以引入一个简单的基于轨迹的滤波只有被连续多帧如5帧都检测到的“反光衣”目标才被认为是有效的。这能滤除大量的瞬时误报。6. 常见问题排查与项目心得6.1 开发与部署中的典型“坑”这里整理了一份我们项目中遇到的实际问题及解决方案希望能帮你避坑。问题现象可能原因排查步骤与解决方案训练时loss为NaN1. 学习率(lr0)设置过高。2. 数据标注有严重错误如坐标超出图像范围。3. 数据中存在损坏的图片。1. 立即停止训练将学习率降低一个数量级如从0.01降到0.001重试。2. 使用脚本检查所有标注文件的坐标值是否在[0,1]范围内。3. 使用PIL或OpenCV尝试读取所有训练图片排除无法读取的文件。模型在验证集上精度(mAP)始终很低1. 数据集质量差标注不准或类别不平衡。2. 模型复杂度与数据量不匹配数据少模型大过拟合。3. 训练轮数不够未收敛。1. 可视化验证集的预测结果看是定位不准还是分类错误。针对性地清洗数据。2. 换用更小的模型如YOLOv8n或使用更强的数据增强如mosaic, mixup。3. 增加训练轮数(epochs)观察loss是否还在下降。PyQt5界面视频显示卡顿1. 未使用多线程推理阻塞了GUI主线程。2. 在GUI线程中进行了耗时的图像格式转换如cv2到Qt。3. 每帧都更新UI频率过高。1.必须将视频读取和模型推理放入独立线程。2. 将图像转换操作也放在工作线程中完成主线程只接收并显示最终结果。3. 可以限制UI更新频率例如推理可能达到30FPS但界面显示可以限制在15-20FPS足够流畅且减轻主线程压力。ONNX或TensorRT模型推理结果与PyTorch不一致1. 导出时预处理归一化、通道顺序不一致。2. 后处理解码方式、NMS实现不一致。3. TensorRT的FP16/INT8量化引入了精度误差。1. 确保导出和推理时图像的预处理步骤除以255均值标准差归一化完全一致。2. 仔细对比PyTorch和ONNX/TensorRT推理后的原始输出在应用NMS之前看是否一致。从官方或可靠来源获取对应引擎的后处理代码。3. 对于TensorRT先使用FP32模式验证正确性再尝试FP16。INT8量化需要校准集操作更复杂。检测框闪烁同一目标在连续帧中ID跳变未使用目标跟踪算法每帧独立检测无法关联同一目标在不同帧中的身份。引入轻量级跟踪器如ByteTrack。它在YOLO检测结果的基础上利用运动信息和外观相似度进行关联能有效稳定目标ID为基于轨迹的预警过滤打下基础。RTSP流经常断连或延迟大网络不稳定或摄像头编码流参数过高。1. 使用OpenCV的VideoCapture时设置CAP_PROP_BUFFERSIZE为较小的值如1减少缓冲区延迟。2. 在代码中增加重连机制当检测到帧读取超时或失败时重新初始化视频捕获对象。3. 如果可能请求摄像头输出子码流较低分辨率、较低码率的流用于分析主码流用于存储。6.2 项目回顾与经验之谈做完这个项目最大的感触是把一个深度学习模型变成真正可用的系统模型开发本身可能只占30%的功夫剩下的70%是数据工程、软件工程和解决无数意想不到的脏活累活。关于数据“数据决定上限模型逼近上限”这句话是真理。在反光衣项目上我们花了超过一半的时间在数据收集、清洗和标注上。特别是针对那些“难样本”极端光照、严重遮挡、奇异姿态的收集对最终模型鲁棒性的提升效果远大于换一个更复杂的模型结构。建立一个持续的数据闭环很重要系统上线后把那些误检、漏检的案例自动保存下来定期加入训练集进行迭代优化模型会越来越“聪明”。关于工程化代码的健壮性和可维护性至关重要。一开始为了快所有功能都写在一个脚本里。后来加功能、改bug变得异常痛苦。尽早进行模块化设计将视频处理、模型推理、业务逻辑、界面控制分开定义清晰的接口。做好日志记录这样当系统在客户现场出现问题时你可以通过日志快速定位是视频源断了、模型加载失败了还是某个业务规则判断异常。关于性能评估性能一定要在目标硬件和真实数据流上进行。在开发机上跑一个视频文件测出的FPS和在生产服务器上处理4路RTSP流时的FPS完全是两回事。要考虑磁盘IO、网络带宽、GPU内存共享、多进程/线程竞争等综合因素。性能优化是一个从算法、代码到硬件配置的全链条工作。最后一点也是最重要的一点理解业务。我们不是在做单纯的“目标检测”学术研究而是在做“反光衣穿戴预警系统”。这意味着你需要和安全管理员沟通了解他们的工作流程预警信息以什么形式呈现最有效报警后希望系统自动执行什么动作历史数据需要统计哪些维度这些业务需求直接决定了你系统逻辑的设计。比如他们可能不需要每一帧都检测对固定区域可以每5帧检测一次以节省算力他们可能更关心“未穿反光衣进入核心危险区域”的事件而对在休息区未穿的行为可以忽略。让技术深度服务于业务逻辑这个项目才算真正成功。