ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

交通灯与交通标志检测实战:基于YOLOV8的完整训练到部署方案

交通灯与交通标志检测实战:基于YOLOV8的完整训练到部署方案

交通灯和交通标志检测这个方向,算是目标检测里最贴近实际落地的场景之一。不管是自动驾驶感知、辅助驾驶预警,还是智慧交通的路口监控,第一件事就是把红绿灯状态和路边标志牌准确找出来。这几年经常有人问我这类项目怎么入门,网上教程虽多,但大多是零散片段:给你一个训练好的权重,却不讲数据集怎么标;讲了数据集,又不教你怎么部署成能用的系统。这次分享的是一套我实际跑通的完整方案,从数据集整理、YOLOV8训练、精度调优到Web端实时展示,一条龙走下来,目标是让拿到这套内容的人能真正复现,而不是看完还是一头雾水。

这套系统适合三类人:一是正在做课程设计或毕业设计的学生,需要一套能演示、能讲解的完整项目;二是刚接触目标检测、想系统走一遍训练全流程的开发者;三是有交通场景检测需求、想快速搭一个原型验证效果的工程师。阅读之前需要你对Python有基本认识,知道pip和conda怎么用就行,模型训练部分我会按步骤讲清楚,跟着操作就能出结果。

1. 项目整体拆解:为什么交通标志检测值得自己做一套

先把这个项目的葫芦里卖的什么药说清楚。

1.1 这个项目到底解决了什么问题

交通灯和交通标志检测,在实际工程里最让人头疼的往往不是模型本身,而是三个互相咬合的问题。

第一是数据。公开数据集虽然不少,但直接拿来训模型,经常遇到类别对不上、图像分辨率太低、光照场景单一的问题。很多公开数据集里面的标志是欧洲或美国标准,放到国内路况下,警告标志、禁令标志的样式差异很大,直接迁移过来效果会打折扣。这套项目直接用的是按国内常见标志体系整理的数据集,标注文件用YOLO格式,省去了格式转换的时间。

第二是训练链路。很多人卡在环境配置和训练脚本上,装CUDA装了半天,跑起来又报显存不足,或者train.py改到一半不知道参数怎么调。这套方案把训练入口做成一键脚本,看起来是个小细节,实际上对新手非常关键——不用理解ultralytics包源码也能先跑通,再逐步深入。

第三是结果展示。模型训好了,不能只在终端打印一串坐标框,别人看不懂,自己也没法直观评估效果。项目里做了Web前端展示,把检测框实时画到图片或视频流上,接口留的是标准HTTP服务,很方便扩展到摄像头输入。

这三个问题解决之后,这个项目的价值就不只是一个模型权重,而是一套完整的“数据-训练-部署”闭环,这也是它区别于普通代码仓库的最大差异。

1.2 为什么是YOLOV8而不是其他模型

模型选型这块,我对比过几代YOLO,也试过Faster R-CNN和SSD,最终定型在YOLOV8上,原因有三点。

一是精度和速度的平衡点更合理。交通标志这类目标,很多是远距离小目标,Faster R-CNN精度虽高但推理速度上不去,嵌入式部署很吃力;SSD速度快但小目标召回率偏低。YOLOV8在COCO数据集上的表现说明它在同等算力下能拿到更好的mAP,实测在路口场景下,地图标注的小标志牌也能有不错召回。

二是工程化程度高。ultralytics这个框架把训练、验证、导出、推理全链路打包了,模型结构改起来也灵活,这对后面要做改进创新点很有价值。框架本身还有一个优点——代码注释清楚,遇到问题去GitHub翻issue,关键词一搜基本都能找到答案,对学习者很友好。

三是生态兼容性。YOLOV8的导出功能支持ONNX、TensorRT、OpenVINO这些格式,意味着训练完后可以灵活选部署路径,这一点在后面Web展示和边缘设备部署时特别重要。如果你换别的模型,比如YOLOV5,也不是不行,但V8的anchor-free设计让训练收敛更省心,这对新手来说体验差异很明显。

1.3 项目文件结构解读

拿到源码包后,我建议不要急着运行,先把目录结构看清楚。一个清晰的项目通常是这样组织的:

traffic-sign-detection/ ├── dataset/ # 数据集总目录 │ ├── images/ # 训练与验证图像 │ │ ├── train/ │ │ └── val/ │ ├── labels/ # YOLO格式标注文件 │ │ ├── train/ │ │ └── val/ │ ├── data.yaml # 数据集配置文件 │ └── classes.txt # 类别清单 ├── models/ # 模型配置与结构文件 │ ├── yolo_improved.yaml # 改进后的模型结构 │ └── yolo_baseline.yaml # 基线模型结构 ├── runs/ # 训练输出目录(权重、日志、曲线) ├── scripts/ # 一键启动脚本 │ ├── train.sh │ ├── predict.sh │ └── export.sh ├── web_app/ # Web展示模块 │ ├── app.py # Flask/FastAPI后端 │ ├── templates/ │ ├── static/ │ └── uploads/ ├── utils/ # 数据处理与可视化工具 ├── requirements.txt └── README.md

先对照目录看一遍,能把训练流程中数据流向、权重产出、前端调用关系理清楚。很多初学者喜欢直接跑train.py,报错后改一个文件再报错,这种折腾方式效率很低。花20分钟搞清楚文件结构,后面调试能省下两小时。

2. 数据集是检测系统的命根子:标注与预处理全解析

模型训练界有句话:Garbage in, garbage out。对交通标志检测来说尤其如此,数据质量直接决定mAP上限。

2.1 数据来源与总量设计

这套数据集以公开数据集为基础做增广整理,然后补充了一部分自采的真实场景图。总量上我建议不少于8000张,其中包含交通灯的图像约4000张,包含各类标志牌的约6000张,两者有重叠。8000张这个数量级对YOLOV8来说是一个性价比很高的起点——太少容易过拟合,太多标注成本又太大。

需要多说一句的是类别分布。如果你打算做的是交通灯状态识别,需要区分红、黄、绿三种灯,而不只是"交通灯"一个大类。很多初学者容易忽略这个细节,结果模型确实框出了交通灯,但判断不了当前是什么灯。交通标志方面,常见的做法是区分警告标志(黄底黑图案)、禁令标志(红圈)、指示标志(蓝底)再加限速标志。完整类别设计我后面会细讲。

注意:如果分类过多且部分类别样本极少,模型很容易学成“背景检测器”。宁可把相似类别合并,也不要为了凑类别数量而牺牲数据平衡。起步阶段6-10个类别足够撑起一个演示效果很完整的系统。

2.2 标注规范与类别策略

标注工作看起来是体力活,但里面的门道不少。用LabelImg或者XAnyLabeling都可以,导出YOLO格式就行,每个txt文件内容格式为:

<类别ID> <x_center> <y_center> <width> <height>

所有坐标都是相对图像宽高的归一化数值。比如一张1920宽、1080高的图中,某个标志的中心在(960, 540),宽高分别为(300, 300),那对应的标注行就是:

3 0.5 0.5 0.15625 0.27778

坐标计算不复杂,但标注时有两个实操经验特别重要。

第一,标志牌的外接框不要留太多余白。有人习惯把车身的反光也框进去,或者框得比标志大一圈,这样会让模型学到多余的背景信息,后期检测框不紧致。正确的做法是让标注框刚好贴合标志外缘。

第二,被遮挡的标志也要标。比如一辆公交车挡住了一半限速牌,很多标注员会跳过不标,但这恰恰是提升模型鲁棒性的关键样本。模型在训练时学到"即使部分遮挡也能识别",推理时碰到真实路口的遮挡情况就不会漏检。

类别清单建议按照项目提供的classes.txt顺序来,训练前要仔细核对该文件与data.yaml中names字段是否一致,我这里给一个参考结构:

0: red_light 1: yellow_light 2: green_light 3: warning_sign 4: prohibition_sign 5: mandatory_sign 6: speed_limit_sign

实际上我试过把速度限制标志单独拆成"限速40、限速60、限速80"等子类,效果也不错,但前提是每个子类都有足够的样本量。样本不足时,合并成一个大类会更稳妥。

2.3 数据预处理流程详解

数据预处理不是一个花哨的步骤,但它决定了训练时模型看到的数据分布。我这里按实际执行的顺序说。

首先是图像统一尺寸。YOLOV8默认训练尺寸是640x640,但这不意味着所有原始图都要resize到640。我建议先用脚本统计所有图像的宽高分布,把长宽比差异特别大的图先处理掉或做padding。实际做法是:如果原始图本身接近正方形,直接resize问题不大;如果原图是1920x1080的全景图,建议先做切片或手工裁剪,把关键目标区域切出来,再丢进训练集。否则目标在resize后变得很小,特征基本丢失。

其次是图像增强策略。ultralytics自带了丰富的增强参数,比如随机翻转、旋转、亮度对比度扰动、马赛克增强等。针对交通场景,多云的天气下亮度变化、黄昏时色温偏移都是很常见的干扰,建议把hsv_h、hsv_s、hsv_v三个参数分别设为0.02、0.6、0.5,这样做可以让模型对光线变化不那么敏感。但旋转角度不宜太大,标志牌在真实场景中不会倒过来,设置degrees=10就足够了,别设成90度翻转。

最后是脏数据清洗。跑一轮基线模型后,把预测出的低置信度检测框抽出来人工看一下,你会发现有些标注框本身位置就是错的,把这些错误标注修正可以明显提升mAP。我碰到过一个典型的例子:有一批标注把"红绿灯"框成了整个灯杆,模型学出来的检测框奇形怪状,清洗之后掉点直接补回来2个mAP点。这类返工很枯燥,但非常值得。

2.4 数据集划分的讲究

训练集、验证集、测试集这三者的划分看起来简单,实际上对结果评估影响非常大。

常规做法是8:1:1随机划分,但对交通场景,我更推荐按场景来源划分。如果数据集里既有白天城市路口、又有夜间高速、还有雨天场景,随机划分可能导致所有雨天场景都进了训练集,验证集里几乎没有雨天样本——这会高估模型在真实场景的表现。

具体操作上,先按场景属性给图像打标签,再在每种场景内做随机划分,保证每个集合里白天、夜间、雨天的比例大致一致。另外,同一个标志在不同帧中会出现多次,这种相似图像要尽量放进同一个集合,避免验证集和训练集高度重合,否则测出来的mAP虚高,没有参考价值。

划分完成后,可以额外抽一组真实环境图像作为"验收集",用于最终部署前的验收测试。这组图不要参与训练,也不要参与常规验证,只在最后检验模型真实效果时使用。这样能避免“实验室指标很好看,上路一测就露馅”的尴尬。

3. 环境搭建与一键训练:从零到出权重的完整链路

很多项目卡在第一步环境搭建上。其实无非是装Python、装CUDA、装PyTorch、装ultralytics,以及安装相应的依赖库。

3.1 环境配置清单

给一个可参考的稳定版本组合:

Python 3.10 CUDA 11.8 PyTorch 2.0.0 ultralytics 8.x opencv-python 4.8 Flask 2.3

建议用conda创建独立虚拟环境,不要直接在base环境里装,不然装坏了一次要重配整个环境。安装命令大致如下:

conda create -n traffic python=3.10 -y conda activate traffic pip install torch==2.0.0 torchvision==0.15.0 \ --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics opencv-python flask

装完验证CUDA是否可用:

import torch print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0))

如果输出False,先别急着重装torch,先查一下显卡驱动版本和CUDA版本的匹配关系。很多情况下是驱动版本较老,只支持到CUDA 11.2,那装CUDA 11.8的PyTorch就会失败或回退到CPU推理,训练速度会慢到让人崩溃。

关于显存,YOLOV8s尺寸的模型在batch size 16的情况下大约需要8-10GB显存。如果你只有6GB显存,可以改用YOLOV8n,或者把batch size调到4,一样能训练,只是慢一些。在我自己的机器上,一张消费级显卡训完350个epoch大约需要4-6小时,这个速度完全可以接受。

3.2 超参数选择原则

ultralytics训练脚本的默认参数已经适用于大多数场景,但对交通标志检测,我觉得有几个参数值得根据实际情况调整。

epoch数建议设置在300以上。交通标志是小目标,收敛比大目标慢不少,200个epoch时mAP还在爬坡。loss曲线看起来已经很低,但小目标类别仍欠拟合,这点和通用检测任务体验不太一样。

图像尺寸imgsz设为640是默认选择,显存有余时也可以上到960。提高输入分辨率对提升小目标检测效果非常直接,但是推理速度会变慢。有个折中方案:训练时用960,推理时用640,这种方式在一些设备上可行,但如果训练和推理的分辨率差异过大,会有一定精度损失的间隙,需要实测判断。

batch size在训练稳定性考量下,能上16就上16。如果显存不足,可以开启梯度累积功能,本质上是模拟更大batch的效果。

数据加载方面,workers设为8能减少数据读取瓶颈,但在Windows平台上,workers过高有时反而会启动失败,需要留意。

我第一次训练时过度调参,结果精度反而不如官方默认参数加适当增广。后来学了一个比较聪明的做法:先跑一个baseline,拿到各项指标后,再做小范围偏移对比测试,比如只改动某一项增强参数,观察mAP变化,这样能可靠判断参数是否有效。很多刷惯比赛的开源作者会透露一个暗规则——大部分mAP提升来自数据清洗和增强策略,对模型结构的修改带来的是上限可能性的不同,但直接会反应在数值提升上的往往还是数据。

3.3 训练过程关键指标怎么看

训练启动后用TensorBoard或者在runs/detect/exp目录下观察results.png就够了。我通常会重点盯四个指标。

box_loss代表边界框回归的误差收敛情况,如果这个loss在训练后期还持续大幅震荡,说明学习率可能偏高了。val/box_loss和train/box_loss如果越拉越大,说明模型开始过拟合,应当考虑加数据增强或提前停止。

mAP50是IoU阈值为0.5时的平均精度,这个指标在交通场景里相对宽容,但接近1.0的mAP50并不能说明模型完美,建议同步盯一下mAP50-95,那个数值能反映框的精准程度,这个指标才是评价模型质量的分水岭。

小目标漏检的直观体现是recall偏低。如果recall一直上不去,最优先的排查思路不是换模型,而是回头看数据集中小目标的占比和标注质量。标注框是否过紧,小目标是否被过滤掉了,这两点是自检时的首选方向。

训练结束后,runs/detect/exp/weights目录下会有best.pt和last.pt。best.pt是按验证集mAP挑出来的最优权重,后续推理和部署都用它。

4. 模型推理与Web前端展示:做出能演示的成品系统

模型训好了,还有关键一步要走通:让它变成能被别人操作和看到的系统。这也是“项目成品感”的主要来源。

4.1 基于PyTorch的推理流程

用ultralytics库自带的predict方法做推理比较省事,但做项目展示时,我更推荐自己封装一个推理脚本,原因有两个:一是可以灵活控制输出结果格式,对接Web后端更方便;二是可以额外渲染统计信息,比如每类目标的个数和平均置信度,观众看到效果会更直观。

推理脚本的核心逻辑不复杂:

from ultralytics import YOLO model = YOLO("runs/detect/exp/weights/best.pt") def detect_image(image_path): results = model.predict(source=image_path, conf=0.35, imgsz=640) boxes = results[0].boxes class_names = results[0].names detections = [] for box in boxes: x1, y1, x2, y2 = box.xyxy[0].tolist() conf = box.conf[0].item() cls_id = int(box.cls[0].item()) detections.append({ "bbox": [x1, y1, x2, y2], "confidence": conf, "class_id": cls_id, "class_name": class_names[cls_id] }) return detections

这里的conf阈值怎么选有讲究。交通事故检测系统里,漏检比误检更危险,所以置信度阈值不宜定太高。0.3到0.4之间比较合适。我试过0.25,会误检很多背景中的红色圆形物体(比如红色招牌、车尾灯),0.35就能干净很多。

如果你要做实时视频检测,建议不要贪心直接对stream做推理,先抽帧标记,把每帧的检测结果存到队列中,再做绘制和推送。这样的好处是,即使某帧推理超时,视频流不会中断,体验上平滑很多。

推理这一层能顺带做个硬性卡点:检测到“红绿灯”类别后,可以加一个小逻辑判断灯色状态,如果接线了摄像头信息,能直接输出信号灯状态语义。这类小功能对项目展示来说是很加分的部分。

4.2 Web前端展示的实现思路

Web展示层选Flask就够用了。没有复杂的人工智能平台需求,轻量、直观、易改是三要素。架构上是典型的同步请求模式:后端提供上传接口,前端展示检测结果,上传的图片返回标注后的图像和JSON数据。

app.py代码梳理下来大概这样:

from flask import Flask, request, jsonify, render_template import cv2 import numpy as np import base64 app = Flask(__name__) @app.route("/", methods=["GET"]) def index(): return render_template("index.html") @app.route("/detect", methods=["POST"]) def detect(): file = request.files["image"] image_bytes = file.read() np_arr = np.frombuffer(image_bytes, np.uint8) img = cv2.imdecode(np_arr, cv2.IMREAD_COLOR) detections = detect_image(img) # 内部使用前文模型推理 # 在图像上绘制检测框和标签 for det in detections: x1, y1, x2, y2 = det["bbox"] label = f"{det['class_name']} {det['confidence']:.2f}" cv2.rectangle(img, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2) cv2.putText(img, label, (int(x1), int(y1) - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) # 转base64返回给前端 _, buffer = cv2.imencode(".jpg", img) img_base64 = base64.b64encode(buffer).decode("utf-8") return jsonify({"image": img_base64, "detections": detections})

前端页面不需要做得很复杂,一个上传按钮、一个预览区域、一个检测结果表格就足够了。配合Bootstrap写个简洁的布局,整个项目的完成度立刻上一个档次。

这里有一个细节容易被忽略:cv2默认使用BGR通道,前端展示的是RGB,如果不做转换,图像颜色会发蓝偏色。用cv2.imencode输出时其实问题不大,但如果你要用PIL输出,就需要先转换通道,否则会出现常见的“天空变黄、绿灯变蓝”的错色问题。

4.3 模型导出与边缘部署

Web演示跑通后,可以顺手把模型导出成不同格式,方便后续部署到不同设备。ultralytics的export一行命令就能搞定:

yolo export model=runs/detect/exp/weights/best.pt format=onnx opset=12

导出ONNX后,你可以用onnxruntime做推理,好处是不依赖PyTorch环境,部署到服务器时镜像体积小很多。如果再往后走,可以把ONNX转换为TensorRT引擎,在NVIDIA设备上做极速推理,这个步骤涉及更多配套工具和精度校准工作,但对有上路需求的项目来说基本是必经之路。

这里提醒一句:导出的onnx模型用onnxruntime推理时,输入输出的格式与ultralytics原生模型不同,尤其注意输入是归一化后还需要做letterbox预处理,输出需要经过NMS后处理。很多人在这一步卡住找不到原因,其实是把ultralytics框架默认帮你做的操作遗忘了。

5. 70+改进创新点的取舍:哪些值得做,哪些是噱头

这个项目标题中“70+全套改进创新点”很容易被误解。有些同学以为改进点越多越好,回头改模型时直接把手套网络全用上,效果反而更差。这里我愿意分享一些实测结论。

5.1 哪些改进真正有效

我自己的测试经验归结为三个有显著收益的方向。

第一个是可变形卷积。交通标志的形状有旋转和视角畸变,可变形卷积能根据输入内容自适应调整采样位置,让卷积核不再局限于矩形网格。换用DCNv2后,在旋转视角大的样本上检测精度提升比较明显。这个改进直观有效,但也有代价:推理速度下降约10%到15%,在资源受限设备上需要谨慎引入。

第二个是注意力机制。在C2f模块后串联SE或CBAM模块,可以提升网络对通道维度的注意力建模。但我的建议很明确——在baseline未过拟合的前提下,注意力机制在交通标志这类前景背景对比鲜明的任务中收益有限,更多是在极小目标层面上有增益,需结合数据增强一起使用。

第三个是检测头优化。YOLOV8默认是三个尺度的检测头,针对交通标志这种小目标为主的场景,可以把检测头扩展到四个尺度,额外增加一个针对更小目标的预测层。实测mAP50-95能提升约1.5到2个点,小目标召回率上升很明显。缺点是计算量增加。

至于那些花式组合的注意力模块或者多分支结构,如果在标准数据集上没有数值优势,说明该改进在你的数据场景里应用价值有限。这类工作改进点适合发论文做对比实验,但若想让系统在真实路口环境跑得又快又准,我的建议是优先确保数据质量,再做结构上的小步改良。

5.2 改进方向的落地建议

有位朋友跟我聊过,说他为了凑“创新点”,把三个注意力模块串在了一处,结果训练loss都降不下去。原因很直接:每个模块都会改变特征分布,串联过多而未经充分调参,模型难以收敛。正确做法是每次只加一个模块,跑一组实验,确认mAP提升了再加下一个。

我建议按以下优先级来排布:先解决数据质量工事,再上小目标检测头优化,然后测试可变形卷积或注意力机制,最后再考虑改loss函数和NMS策略。这个顺序是建立在“逐步验证、持续对比”的原则上的,每一步改动都要有mAP支撑,不然就成了为了改而改。

另外还要说一句,改进点本身不只是训练前改模型结构,训练策略也算。比如Warmup、EMA、Cosine学习率调度、更强的数据增强策略,这些也算改进点,而且落地风险远比换结构要低得多。在方案落地时,把训练策略调整跟模型结构改进混在一起做对比实验,往往能得出“叠加效果好于单模块”的结论,这就是很好的系统性收益。

6. 常见问题与排查技巧实录

最后一部分,重点讲我实际踩过的坑。这些问题你在训练日志或者部署过程中都有一定概率遇到,提前知道排查路径,至少能省去一整天或两天的调试时间。

6.1 训练不收敛或显著过拟合

现象是train loss正常下降,val loss开始震荡甚至反弹。排查顺序通常是这样的:先确认验证集和训练集是否完全独立,有没有相似图像混入;再看数据增强是否开得足够大,必要时把mosaic概率提高一些;最后看模型容量和数据集规模的匹配情况,如果只有三千张图却直接用YOLOV8x,大概率过拟合,换成YOLOV8s反而更稳。

我还遇到过标注格式不统一导致loss曲线异常的情况:一部分标注是归一化坐标,另一部分是绝对像素坐标,混在一起之后loss直接发散。用脚本整体检查一下标注文件中坐标是否都小于1,这个问题几秒钟就能排查出来。

6.2 小目标检测效果差,漏检率偏高

先自查数据集里小目标占比,如果占比很低,模型根本没机会学到小目标的特征。统计脚本可以按框面积与图像面积比例分布来估算,一般小于0.01算小目标。

对策依次为:增加高分辨率图像的训练,imgsz从640提到960;使用四尺度检测头;对数据增强增加随机裁剪,模拟更多小目标出现;推理时使用TTA增强和多尺度推理,但这会增加推理时间,适合离线场景。不要一上来就改loss函数,small object的loss改动不好调,收益不一定对等。

6.3 部署阶段遇到的兼容性问题

常见的有三类:ONNX导出成功但推理报错,往往是输出解析部分出问题,用Netron看一眼输出节点名称,写对应解析逻辑即可;TensorRT版本不匹配导致引擎构建失败,建议直接换成与CUDA版本匹配的镜像环境,省去很多编译时间;Web服务的并发问题,Flask自带的开发服务器只适合单用户演示,多人同时访问会卡住,用gunicorn或uwsgi多进程部署即可。

我经历过一个更隐蔽的问题:模型在GPU上推理正常,在CPU环境却明显变慢。排查发现是ONNX模型没有对CPU做int8量化。如果目标是CPU部署,建议使用openvino导出格式或者对模型做INT8量化校准。这些都是发布时值得提前验证的环节。

6.4 数据集与推理结果的类别不一致

训练时data.yaml里的类别顺序和推理时读取的类别清单必须完全一致,否则检测框可能张冠李戴。见过一个有代表性的案例:训练时类别0是红灯,推理脚本里names列表第一位写的却是绿灯,输出的结果自然全乱了。解决方法是统一从data.yaml或classes.txt读取names,不要在一个项目里出现两套类别定义。

写在最后的一点个人体会

这类目标检测项目,最大的学习价值不在于“跑通代码”,而在于理解数据、模型、部署三者之间的耦合关系。我自己在反复调整的过程中体会最深的一点:很多精度瓶颈并不在模型结构,而在数据标注的一致性和场景覆盖度。你花一周时间调整模型结构,收益可能不如花两天时间修正一批标注框来得直接。这个规律,在交通灯和交通标志这类小目标、强上下文关联的任务上特别明显。

另外送大家一句实操心得:每次改动只做一件事,记录改动前后指标,不要多个变量一起动。这个习惯能让你每次实验都有明确结论,训练日志积累起来,才是真正属于你自己的调参经验库。希望这套从数据标注到Web部署的完整链路,能帮你少走一点我走过的弯路。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进