简介:本资源是一份面向深度学习初学者与计算机视觉实践者的YOLO目标检测系统性学习文档,聚焦算法原理、实现步骤与实验对比,帮助读者快速掌握主流目标检测技术选型与落地要点。文档为单个13KB的Word文件(.docx),结构清晰覆盖六大模块:深度学习与目标检测发展脉络(含AlexNet、Faster R-CNN、SSD等关键节点)、两阶段与单阶段算法对比分析、YOLO核心原理与Darknet架构解析、数据集制作与模型训练实操指引(附配套方法说明指引)、YOLO实验结果及与Faster R-CNN、SSD在精度与速度上的量化对比、章节总结与适用场景建议。内容兼顾理论演进与工程实践,特别适合高校学生、转行学习者及需快速理解目标检测技术栈的开发者入门与复盘。目前已有373人学习下载,文档精炼实用,可作为课程补充材料、项目预研参考或面试知识梳理依据。
1. 为什么毕业答辩前一周还在调 YOLO 的 anchor 尺寸?——一份能直接交稿、能跑通、能讲清楚的深度学习目标检测毕设方案
这不是一篇讲“YOLO 多牛”的科普文,而是一份我带过三届本科生毕设、帮两个实验室快速搭起工业级检测 demo 后,反向沉淀下来的「可交付方案」。它解决的不是“什么是深度学习”,而是:当导师说‘你得有个完整 pipeline’、当答辩 PPT 要求‘展示训练过程+对比实验+可视化结果’、当你在 GitHub 上搜了 27 个 YOLO 项目却卡在 VOC 格式转 COCO 报错时,你手头真正需要的那一套东西。整套方案基于 YOLOv5(Darknet 衍生体系中最易落地的稳定分支),覆盖从数据标注规范、训练日志解读、mAP 计算逻辑,到如何用一张表说清 YOLO vs Faster R-CNN vs SSD 的真实差距——不是论文里写的理论值,而是你在 i5-8300H + GTX 1650 笔记本上实测出来的 FPS 和 mAP@0.5。它不假设你会写 C++ 扩展,也不要求你配 CUDA 11.3;它默认你只有 Anaconda、Python 3.8、一台能跑 PyTorch 的机器,和一份必须两周内交初稿的 deadline。如果你正卡在“数据集做完了但 eval 不出结果”“训练 loss 下降但测试框全是乱的”“答辩被问‘为什么不用 YOLOv8’答不上来”,那这份方案就是为你写的。
2. 总体架构设计:YOLOv5s 四层结构与五个核心模块的职责边界
YOLOv5 并非黑匣子,它的可复现性恰恰来自清晰的分层。我们不从“网络图有多深”讲起,而是按实际工程流拆解:数据输入 → 特征提取 → 检测头输出 → 后处理 → 评估反馈。这五步环环相扣,任何一环参数错位,都会导致最终 bbox 偏移、漏检或误检。下面这张结构不是示意图,而是你train.py启动后真实走过的控制流。
2.1 数据输入层:VOC 格式是底线,但 XML 解析必须加容错
YOLO 官方推荐使用.txt标签(归一化坐标),但绝大多数公开数据集(如 PASCAL VOC、自采图像)以 XML 存储。强行用脚本暴力转换会埋下大坑——比如<bndbox>中xmin=0但xmax=1(单像素框)、<name>包含空格或中文、<difficult>标签未过滤。这些在训练时不会报错,但会导致compute_loss()中target张量 shape 错配,最终表现为 loss 突然飙升或 nan。
我们采用xml_to_yolo.py(随方案附赠)进行鲁棒转换,关键逻辑如下:
# xml_to_yolo.py 关键片段 import xml.etree.ElementTree as ET from pathlib import Path def convert_xml_to_txt(xml_path: Path, classes: list, out_dir: Path): tree = ET.parse(xml_path) root = tree.getroot() size = root.find('size') w = int(size.find('width').text) h = int(size.find('height').text) # 【容错点1】跳过无 object 的 XML,避免生成空 txt objects = root.findall('object') if not objects: return lines = [] for obj in objects: name = obj.find('name').text.strip() if name not in classes: # 【容错点2】跳过未声明的类别,不报错但 warn print(f"Warning: unknown class '{name}' in {xml_path}") continue bndbox = obj.find('bndbox') xmin = max(0, int(bndbox.find('xmin').text)) # 【容错点3】强制裁剪到图像边界 ymin = max(0, int(bndbox.find('ymin').text)) xmax = min(w, int(bndbox.find('xmax').text)) ymax = min(h, int(bndbox.find('ymax').text)) if xmax <= xmin or ymax <= ymin: # 【容错点4】过滤退化框 continue # 归一化并转为 YOLO 格式:cls_id x_center y_center width height x_center = ((xmin + xmax) / 2) / w y_center = ((ymin + ymax) / 2) / h box_w = (xmax - xmin) / w box_h = (ymax - ymin) / h cls_id = classes.index(name) lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}") # 写入同名 .txt,路径与 images 对齐 txt_path = out_dir / f"{xml_path.stem}.txt" txt_path.write_text("\n".join(lines), encoding="utf-8")提示:此脚本会生成
classes.txt(按顺序列出所有类别),该文件必须与data.yaml中names:字段严格一致,否则model.names加载错误,plot_one_box()绘图时 label 显示为数字而非文字。
2.2 特征提取层:Backbone 选型不是越深越好,YOLOv5s 的 29 层恰是平衡点
YOLOv5 提供 s/m/l/x 四种尺寸,但毕设场景下YOLOv5s 是唯一推荐起点。原因很实际:
- 参数量仅 7.2M,RTX 3060 训练 batch_size=16 时显存占用 < 4GB,避免因 OOM 中断训练;
- 在 VOC07+12 上 mAP@0.5 达 73.1%,比 Faster R-CNN(R-50-FPN)高 1.2 个百分点,且推理速度达 142 FPS(Tesla T4);
- 其 CSPDarknet53 backbone 中的 Cross Stage Partial 结构,天然缓解梯度消失,使小样本(<500 张图)也能收敛。
我们不替换 backbone,但必须理解其输出张量结构。YOLOv5s 在三个尺度(stride=8/16/32)输出特征图,对应P3/P4/P5。每个尺度的 detection head 输出(batch, 3*(5+num_classes), H, W)张量。例如P3(80×80)输出(1, 3×(5+2), 80, 80),其中3是 anchor 数量,5是(x,y,w,h,obj_conf),2是两类目标的 class_conf。这个结构决定了后续 loss 计算和 NMS 的粒度。
2.3 检测头与损失函数:CIoU Loss 是精度提升的关键,但需配合 GIoU 正则项
YOLOv5 默认使用 CIoU Loss(Complete IoU),它不仅惩罚 bbox 坐标偏移,还引入长宽比一致性约束和中心点距离项。但实测发现:单独用 CIoU 会导致小目标召回率下降 5%~8%。原因是 CIoU 对小框的中心点距离项过于敏感,轻微抖动即大幅增加 loss。
解决方案是在models/yolov5s.yaml中微调 head 配置,加入 GIoU 正则项(已集成在utils/loss.py中):
# models/yolov5s.yaml 修改处(仅 head 部分) head: [[-1, 1, Conv, [512, 1, 1]], [-1, 1, nn.Upsample, [None, 2, 'nearest']], [[-1, 6], 1, Concat, [1]], # cat backbone P4 [-1, 3, C3, [512, False]], # detect layer 1 (80x80) [-1, 1, Conv, [256, 1, 1]], [-1, 1, nn.Upsample, [None, 2, 'nearest']], [[-1, 4], 1, Concat, [1]], # cat backbone P3 [-1, 3, C3, [256, False]], # detect layer 2 (40x40) [-1, 1, Conv, [128, 1, 1]], [-1, 1, nn.Upsample, [None, 2, 'nearest']], [[-1, 2], 1, Concat, [1]], # cat backbone P2 —— 注意:此处新增 P2 分支 [-1, 3, C3, [128, False]], # detect layer 3 (20x20) —— 新增小目标检测头设计说明:原 YOLOv5s 只有 P3/P4/P5 三层检测,新增 P2 分支(20×20)专用于小目标(<32×32 像素)。该修改需同步更新
data.yaml中anchors:,补充一组更小的 anchor(如[10,13, 16,30, 33,23]),并在train.py中设置--multi-scale启用多尺度训练。这是我们在某高校智能仓储 demo 中将螺丝钉(15×15px)检出率从 61% 提升至 89% 的关键改动。
2.4 后处理层:NMS 阈值不是固定 0.45,要按场景动态调整
YOLO 输出的是密集预测框(每张图约 25k 个),NMS(非极大值抑制)负责去重。官方默认iou_thres=0.45,但这是在 COCO 上调优的结果。你的数据集若目标密集(如 PCB 元件、水果堆叠),该值会导致大量漏检;若目标稀疏(如高空无人机识别),则可能保留过多冗余框。
我们采用两阶段 NMS:
- 粗筛:
iou_thres=0.65,快速剔除明显重叠框; - 精筛:对剩余框按
conf排序,对每个框计算其与更高置信度框的 IoU,仅当IoU > 0.3时才抑制——这保留了中等置信度但空间分离的框。
代码实现位于utils/general.py的non_max_suppression()函数,关键修改:
# utils/general.py 中 non_max_suppression 函数节选 def non_max_suppression(...): # ... 前置逻辑省略 # 第一阶段:高 IoU 阈值粗筛 i = torchvision.ops.nms(boxes, scores, iou_thres=0.65) boxes = boxes[i] scores = scores[i] classes = classes[i] # 第二阶段:动态 IoU 抑制(仅对 conf > 0.3 的框启用) keep = [] for j in range(len(boxes)): if scores[j] < 0.3: keep.append(j) continue # 计算当前框与所有更高 conf 框的 IoU ious = box_iou(boxes[j].unsqueeze(0), boxes[:j]) # 注意:只与前面框比较 if (ious > 0.3).sum() == 0: # 无高 IoU 框则保留 keep.append(j) keep = torch.tensor(keep) return boxes[keep], scores[keep], classes[keep]参数说明:
iou_thres=0.65和conf_thres=0.3是经 5 类工业数据集验证的稳健组合。若你的场景要求高召回(如安防预警),可将conf_thres降至 0.15;若要求高精度(如医疗影像),则提高至 0.4。
2.5 评估反馈层:mAP@0.5:0.95 不是必须,但 mAP@0.5 必须手算验证
YOLO 训练日志中的metrics/mAP_0.5是模型在 IoU=0.5 阈值下的平均精度,但它由val.py自动计算,容易掩盖细节问题。毕设答辩时,评委常问:“你这个 72.3% 是怎么算出来的?”——此时若只答“代码跑出来的”,可信度归零。
我们必须手动复现 mAP@0.5 计算流程。核心是Precision-Recall 曲线下的面积,步骤如下:
- 对所有预测框按
conf降序排列; - 设定 IoU 阈值
0.5,对每个预测框匹配 GT(一对一,一个 GT 只能被匹配一次); - 统计 TP(正确匹配)、FP(无匹配 GT)、FN(GT 未被匹配);
- 计算 Precision = TP/(TP+FP),Recall = TP/(TP+FN);
- 绘制 P-R 曲线,用 11-point 插值法计算 AP(Average Precision)。
随方案附赠calc_map_manual.py,输入val_labels/和val_predictions/目录,输出详细匹配日志:
python calc_map_manual.py \ --gt-dir ./data/VOCdevkit/VOC2007/Annotations/ \ --pred-dir ./runs/val/exp/labels/ \ --classes "person,car" \ --iou-thres 0.5输出示例:
Class: person | Total GT: 127 | TP: 112 | FP: 18 | FN: 15 | Precision: 0.861 | Recall: 0.882 | AP@0.5: 0.871 Class: car | Total GT: 89 | TP: 76 | FP: 9 | FN: 13 | Precision: 0.894 | Recall: 0.854 | AP@0.5: 0.872 mAP@0.5: 0.8715设计说明:该脚本不依赖
pycocotools,纯 NumPy 实现,确保在无网络环境也能运行。它还会生成pr_curve.png,答辩时可直接截图放入 PPT,证明你真正理解评估逻辑。
3. 数据工程实践:从原始图像到可训练数据集的七步标准化流水线
数据质量决定模型上限。我们见过太多毕设失败案例:不是模型不行,而是数据没做好。下面这套七步法,是某公司产线缺陷检测项目落地前,团队强制执行的 checklist。每一步都有明确交付物和验收标准,杜绝“我以为标好了”。
3.1 图像采集规范:分辨率、光照、背景三要素缺一不可
- 分辨率:统一缩放至
640×480或1280×720(保持 16:9),禁止原始手机图(4000×3000)直接训练——YOLO 输入固定为640×640,超大图 resize 会模糊小目标; - 光照:避免强反光与阴影。实测显示,同一组螺丝图像,在 LED 均匀光源下 mAP 比自然光高 9.3%;
- 背景:纯色(灰/白/黑)优于复杂背景。若无法控制,需在标注时额外标记
occluded属性(后续用于 loss 加权)。
交付物:
images/目录下所有.jpg文件,用exiftool *.jpg | grep "Image Size"验证尺寸一致性。
3.2 标注工具选型:LabelImg 是起点,但必须禁用“自动保存”
LabelImg 界面友好,但默认开启Auto Save mode会导致:
- 标注中途崩溃,未手动
Ctrl+S则丢失全部进度; Save As时误选.xml覆盖原图,造成数据污染。
强制操作:
- 启动 LabelImg 后,点击
View → Auto Save mode关闭; - 标注完一张图,必须按
Ctrl+S保存,再按D切到下一张; - 所有 XML 文件必须与图像同名,存放于
Annotations/目录。
避坑:LabelImg 生成的 XML 中
<filename>字段默认为绝对路径。需用fix_xml_filename.py批量修正为相对路径(仅文件名),否则xml_to_yolo.py解析失败。
3.3 类别标准化:合并近义词、剔除低频类、定义层级关系
常见错误:将car、automobile、vehicle作为三类标注;或对person标注standing/sitting子类。YOLO 是 flat 分类,不支持层级。
标准化流程:
- 统计所有
<name>出现频次(用count_classes.py); - 合并频次 < 5 的类别(如
truck→car,bus→car); - 删除纯噪声类(如
blurry、unknown); - 输出
classes_standardized.txt,作为data.yaml的唯一依据。
# count_classes.py from collections import Counter import xml.etree.ElementTree as ET import glob names = [] for xml in glob.glob("Annotations/*.xml"): tree = ET.parse(xml) for obj in tree.findall('object'): names.append(obj.find('name').text.strip()) counter = Counter(names) print("Class frequency:") for cls, cnt in counter.most_common(): print(f" {cls}: {cnt}")3.4 数据集划分:train/val/test 比例不是 7:2:1,而是按 GT 数量切分
YOLO 的train.py按图像数划分,但若某张图含 50 个目标,另一张仅 1 个,则简单按图数分会导致 val 集 GT 总数严重失衡。正确做法是:先统计所有 GT 实例总数,再按比例分配图像,确保 val 集 GT 数 ≈ 总数 × 0.2。
我们用split_dataset.py实现:
# split_dataset.py import random from collections import defaultdict def count_objects_in_xml(xml_path): tree = ET.parse(xml_path) return len(tree.findall('object')) # 统计每张图的 GT 数量 img_obj_count = {} for xml in glob.glob("Annotations/*.xml"): img_obj_count[xml] = count_objects_in_xml(xml) # 按 GT 数量降序排列,优先将高密度图分入 train sorted_imgs = sorted(img_obj_count.items(), key=lambda x: x[1], reverse=True) total_objs = sum(count for _, count in sorted_imgs) # 计算目标 val GT 数 val_target = int(total_objs * 0.2) val_imgs = [] val_objs = 0 for xml, cnt in sorted_imgs: if val_objs < val_target: val_imgs.append(xml) val_objs += cnt else: break # 剩余为 train,test 从 train 中随机抽 10% train_imgs = [x for x in sorted_imgs if x[0] not in val_imgs] test_imgs = random.sample(train_imgs, k=int(len(train_imgs)*0.1)) # 生成 train.txt/val.txt/test.txt with open("ImageSets/Main/train.txt", "w") as f: for xml, _ in train_imgs: f.write(f"{Path(xml).stem}\n") # ... 同理生成 val.txt test.txt验收标准:
train.txt含 427 行,val.txt含 112 行,但val目录下所有 XML 的总 object 数必须在total_objs*0.2 ± 5%范围内。
3.5 数据增强配置:Mosaic 是双刃剑,小数据集必须关闭
YOLOv5 默认启用 Mosaic(四图拼接),它大幅提升小目标检测能力,但代价是:
- 训练初期 loss 波动剧烈,收敛慢;
- 若你的数据集 < 300 张,Mosaic 会制造大量无效拼接(如三张图无目标,一张图有目标),导致模型学偏。
毕设推荐配置:
- 数据量 ≥ 1000 张:启用 Mosaic(
--mosaic 1.0); - 数据量 300~1000 张:启用 MixUp(
--mixup 0.5),更温和; - 数据量 < 300 张:关闭所有增强(
--mosaic 0.0 --mixup 0.0 --copy-paste 0.0),靠预训练权重迁移学习。
血泪经验:某同学用 217 张安全帽图像训练,坚持开 Mosaic,训练 300 epoch 后 val mAP 仅 41.2%;关闭后重训,200 epoch 达 68.5%。增强不是越多越好,是越准越好。
3.6 标签清洗:用verify_labels.py扫描三类致命错误
即使标注完成,仍存在隐性错误:
- 坐标越界:
xmax > width,resize 后变成负坐标; - 标签缺失:XML 有
<object>但无<bndbox>; - 类别错位:
<name>为空字符串或全空格。
verify_labels.py一次性扫描并修复:
# verify_labels.py def verify_single_xml(xml_path): try: tree = ET.parse(xml_path) root = tree.getroot() size = root.find('size') w = int(size.find('width').text) h = int(size.find('height').text) for i, obj in enumerate(root.findall('object')): bndbox = obj.find('bndbox') if bndbox is None: print(f"ERROR: {xml_path} object {i} missing bndbox") continue xmin = int(bndbox.find('xmin').text) xmax = int(bndbox.find('xmax').text) if xmax > w or xmin < 0: print(f"FIXED: {xml_path} object {i} x out of bound") bndbox.find('xmin').text = str(max(0, xmin)) bndbox.find('xmax').text = str(min(w, xmax)) # 同理检查 y 和 name name = obj.find('name').text.strip() if not name: print(f"ERROR: {xml_path} object {i} empty name") tree.write(xml_path, encoding="utf-8") except Exception as e: print(f"CRITICAL: {xml_path} parse failed: {e}") for xml in glob.glob("Annotations/*.xml"): verify_single_xml(xml)注意:运行此脚本前务必备份
Annotations/目录。它会直接修改 XML,但只修复坐标越界,其他错误需人工确认。
3.7 格式转换与验证:voc2yolo.py输出后,必须用check_dataset.py二次校验
xml_to_yolo.py生成labels/后,不代表万事大吉。常见问题:
.txt文件名与.jpg不匹配(大小写、下划线);- 某些
.txt为空(对应无目标图像),但 YOLO 要求每张图必须有.txt; classes.txt顺序与data.yaml不一致。
check_dataset.py执行三项校验:
# check_dataset.py def validate_dataset(img_dir, label_dir, classes_file): img_files = set([p.stem for p in Path(img_dir).glob("*.jpg")]) label_files = set([p.stem for p in Path(label_dir).glob("*.txt")]) # 1. 图像与标签文件名是否完全一致 diff = img_files ^ label_files if diff: print(f"ERROR: Mismatched files: {diff}") return False # 2. 每个 .txt 是否至少有一行(允许空目标,但需写 '0' 行) for txt in Path(label_dir).glob("*.txt"): if not txt.read_text().strip(): print(f"WARNING: {txt} is empty, adding dummy line") txt.write_text("0 0.5 0.5 0.1 0.1\n") # 占位,不影响训练 # 3. classes.txt 是否与 data.yaml 一致 with open(classes_file) as f: classes = [l.strip() for l in f if l.strip()] with open("data.yaml") as f: yaml_data = yaml.safe_load(f) if classes != yaml_data["names"]: print(f"ERROR: classes.txt != data.yaml names") return False print("Dataset validation PASSED") return True交付物:运行
python check_dataset.py --img-dir images/ --label-dir labels/ --classes classes.txt,输出Dataset validation PASSED即为合格。
4. 训练与调优实战:从第一次 loss 下降到稳定收敛的十二个关键决策点
训练不是启动train.py就完事。YOLO 的收敛高度依赖超参组合,而这些组合没有银弹。下面这十二个决策点,是我带学生时记录的“高频翻车现场”,每个都附带现象、根因和可立即执行的 fix。
4.1 避坑:学习率设置错误——现象:loss 从 3.2 突降至 0.8 后震荡不降
- 现象:
train_batch0.jpg显示 bbox 严重偏移,results.csv中train/box_loss在 epoch 5 后剧烈波动(±0.5); - 原因:
lr0=0.01过大,尤其当使用预训练权重(--weights yolov5s.pt)时,底层特征提取器已收敛,过大 lr 会破坏其权重; - 解决:小数据集(<500 张)必须用
--lr0 0.001,并启用--warmup-epochs 3。Warmup 阶段 lr 从 0 线性增至 0.001,让模型平滑适应。
4.2 避坑:Batch Size 与显存的虚假平衡——现象:设置 batch_size=32 后 GPU 利用率仅 40%
- 现象:
nvidia-smi显示 GPU-Util 40%,但train.py日志中mem显存占用 98%,训练速度反而比 batch_size=16 慢; - 原因:YOLOv5 的
auto-batch功能在显存不足时自动降低 batch_size,但未同步调整lr,导致有效 lr 过小; - 解决:禁用 auto-batch,手动设置
--batch-size 16,并按比例缩放 lr:--lr0 0.001→--lr0 0.0005(因 batch_size 减半)。
4.3 避坑:Anchor 匹配失效——现象:train_batch0.jpg中大量真目标无预测框,或框集中在图像边缘
- 现象:
results.csv中train/obj_loss极高(>1.5),val/box_loss低但val/obj_loss高; - 原因:你的数据集目标尺寸与默认 anchor(COCO 适配)严重不匹配。例如检测微小电路元件(20×20px),而默认最小 anchor 为
10×13,但长宽比不匹配; - 解决:运行
python utils/autoanchor.py -f data.yaml -n 9重新聚类 anchor。-n 9指定 3 个尺度 × 3 个 anchor,输出新 anchor 写入data.yaml。
4.4 避坑:类别不平衡未加权——现象:多数类 mAP > 85%,少数类(如fire_extinguisher)mAP < 20%
- 现象:
val_batch0_labels.jpg中少数类 GT 清晰可见,但val_batch0_pred.jpg无对应预测; - 原因:YOLO 的
cls_loss默认均等加权,少数类梯度被淹没; - 解决:在
data.yaml中添加class_weights: [1.0, 1.0, 2.5](按names顺序),数值为1 / (class_freq / total_freq),用count_classes.py输出的频次计算。
4.5 避坑:验证集泄露——现象:val mAP 75% 但测试集 mAP 仅 42%
- 现象:
val_batch0_pred.jpg效果惊艳,但用独立测试集test/运行val.py时效果断崖下跌; - 原因:
val.txt中混入了与train.txt同一场景的图像(如不同角度拍摄的同一台设备),模型记住了场景纹理而非目标特征; - 解决:按拍摄时间/设备 ID 划分,确保
val/和train/图像来自完全独立的采集批次。用exiftool -DateTimeOriginal *.jpg查看时间戳。
4.6 避坑:预训练权重路径错误——现象:loss 从 5.0 缓慢下降至 4.8 后停滞,model.names为空
- 现象:
train.py启动时无 warning,但model.names为[],plot_one_box()绘图 label 显示0; - 原因:
--weights yolov5s.pt指向的是官方 release 的.pt,但该文件model.names为['person', 'bicycle', ...],与你的classes.txt不符; - 解决:下载
yolov5s.pt后,用torch.load()读取,修改model.names为你自己的列表,再torch.save()回新文件。
4.7 避坑:多尺度训练未生效——现象:小目标检测率低,val_batch0_pred.jpg中小框稀疏
- 现象:
train.py日志中img_size始终显示640,无变化; - 原因:未启用
--multi-scale参数,或--img 640覆盖了 multi-scale; - 解决:删除
--img 640,仅用--multi-scale,YOLO 会自动在[480, 512, ..., 832]范围内随机缩放。
4.8 避坑:冻结 backbone 时机错误——现象:训练 100 epoch 后 loss 仍 > 2.0
- 现象:
train.py中--freeze 10,但 epoch 10 后 loss 未明显下降; - 原因:冻结应在 warmup 后、正式训练前。
--freeze 10表示冻结前 10 层,但 YOLOv5s backbone 有 29 层,应冻结--freeze 10指前 10 个模块(实际是 CSP1、CSP2 等); - 解决:查看
models/common.py中C3模块数量,YOLOv5s 为 5 个,故--freeze 5冻结全部 backbone,--freeze 0不冻结。
4.9 避坑:数据增强强度超标——现象:train_batch0.jpg中目标扭曲变形,颜色失真
- 现象:
results.csv中train/cls_loss极高(>3.0),val/cls_loss却很低; - 原因:
hyp.scratch-low.yaml中hsv_h=0.015(色相扰动)过大,导致同类目标颜色分布发散; - 解决:小数据集用
hyp.finetune.yaml,其中hsv_h=0.005,hsv_s=0.7,hsv_v=0.4更保守。
4.10 避坑:早停策略激进——现象:epoch 80 自动停止,但val/mAP_0.5在 epoch 75~79 持续上升
- 现象:
train.py日志末尾Stopping training early as no improvement observed; - 原因:
--patience 100是默认值,但--patience 50更稳妥; - 解决:显式传参
--patience 50,并监控val/mAP_0.5而非val/box_loss,因后者在后期易震荡。
4.11 避坑:模型保存路径混乱——现象:weights/best.pt与weights/last.pt性能相近,但找不到最佳 epoch 模型
- 现象:
results.csv显示 epoch 127 mAP 最高,但
本文还有配套的精品资源,点击获取