☰
YOLO目标检测入门实战:原理拆解、训练配置与避坑指南
2026/11/3 2:58:05 网站建设 项目流程

简介:《深度学习目标检测文档》是一份面向计算机视觉入门者与算法实践者的专题学习材料,围绕YOLO目标检测展开,帮助读者梳理从深度学习发展到主流检测框架的知识脉络。包内仅含1个docx文件,压缩包约13KB,轻量便于检索与批注;内容覆盖深度学习关键时间节点、目标检测演进,以及Faster R-CNN、SSD与YOLO的架构对比,并延伸到YOLO算法原理、数据集制作与自有数据训练步骤、实验结果和小结。读者可据此建立两阶段与单阶段检测算法的对照框架,理解Darknet网络在速度与识别率之间的权衡,并结合实验部分思考YOLO相对Faster R-CNN、SSD的优势与不足。已有374人学习,适合课程复习、课题调研或目标检测方案入门参考。

1. 从一份文档说起:为什么入门目标检测先啃 YOLO 这条线

上个月有个做嵌入式视觉的朋友把这份《深度学习目标检测文档.docx》甩给我,说车间流水线上想做个缺陷件检测,从零开始该怎么读。我翻了一遍,发现它恰好构成一条完整的入门链路:先用一节的篇幅把深度学习的发展节点串起来,再把 Faster R-CNN、SSD、YOLO 三代目标检测算法摆到一张桌子上对比,接着落到 YOLO 的 Darknet 网络结构、数据集制作、训练步骤和实验结论。它适合两类人:一类是刚接触目标检测、需要一份能照着走的流程的;另一类是写过图像分类、手里有标注数据却在训练配置上卡住、模型死活不收敛的。目标检测这两年的落地门槛降得很快,但把一份方法论文档读成能跑的工程,中间隔着的全是血泪经验,下面按文档骨架逐段拆。

2. 文档骨架拆解:六章结构怎么对应一条可复现的链路

2.1 目录与章节职责:从时间线到实验结论的递进

这份文档的六章不是平行罗列,是一条单向递进的路:第 1 章讲深度学习发展史,解决「这东西从哪来」;第 2 章讲目标检测发展史并横向对比 Faster R-CNN、SSD、YOLO,解决「为什么选它」;第 3 章单独深挖 YOLO 的实现与原理,解决「它内部怎么运转」;第 4 章给数据集制作和训练步骤,解决「怎么动手」;第 5 章放实验结果,解决「跑完怎么证明有效」;第 6 章收口。

读的时候不要平铺直叙地从头读到尾,要按用途分配精力:

章节核心内容建议读法产出的东西
第 1 章深度学习发展节点略读,建立时间轴一张时间线笔记
第 2 章两阶段与单阶段算法对比精读,重点看取舍选型依据
第 3 章YOLO 原理与 Darknet精读,配合论文结构草图
第 4 章数据集制作与训练照着做可训练的模型
第 5 章实验结果与对比精读,学实验设计对比表
第 6 章结果小结略读结论句

第 1 章那部分写法上比较讨巧,只要求写关键时间节点:九十年代前后传统方法起步,2012 年 AlexNet 在 ImageNet 上的突破把深度学习推到台前,之后 VGG、GoogLeNet、ResNet 一层层把网络做深做稳。这条线的价值不在于记住年份,而在于让你明白 YOLO 不是凭空冒出来的,它是卷积网络算力红利吃到一定程度后的必然产物。带残差连接的深层主干、GPU 并行、更大的数据集,这三样凑齐了,实时检测才有讨论的前提。

第 2 章是整份文档信息密度最高的一章,四个小节分别是发展史、Faster R-CNN、SSD、YOLO。这个顺序是刻意排的:先讲两阶段的经典网络建立「检测 = 找框 + 分类」的直觉,再讲单阶段怎么把两步合成一步,最后讲 YOLO 怎么把这一步做到最快。你要是在这一章读懂了「候选框从哪来」这个问题,后面第 3 章的原理就不会觉得突兀。

2.2 三种算法怎么摆:两阶段与单阶段的取舍表

文档里对三者的定位写得比较克制,我按实际工程的感受把它摊开:

维度Faster R-CNNSSDYOLO
检测范式两阶段单阶段单阶段
候选框来源RPN 网络生成预设先验框网格直接回归
推理速度慢,逐候选框处理快最快,全图一次前向
小目标表现较好多尺度特征图,中等偏上早期版本偏弱,后续版本改善
典型场景离线高精度质检、医疗影像通用检测、边缘设备实时视频流、产线在线检测

提示:文档里写「前者识别率高,但是速度慢,后者速度快,但是识别率低一点」时,主语指的是紧挨着的 Faster R-CNN 和 SSD。这种指代在口头讲解里没问题,但写进正式材料一定要改成全称,否则读者很容易把「前者」误认成 SSD。

选型的判断标准其实就一条:你的场景能不能容忍延迟。产线上相机一秒拍三十帧,每帧都要在几十毫秒内出结果,两阶段网络基本没有讨论空间;反过来,如果你做的是离线复检,一晚上跑几万张图,那多花点时间换几个点的 mAP 完全值得。文档把这条取舍讲清楚了,但没给量化门槛,我自己习惯用「单帧耗时是否超过业务节拍的三分之一」来划界,超过就往单阶段走。

2.3 把文档变成可执行清单:哪些章节必须配实验

文档是方法描述,不是命令手册,第 4 章虽然写了数据集制作和训练步骤,但具体命令、配置文件改哪里,原文是另附文档的。所以拿到手第一件事是把六章翻译成一份可勾选的清单:

# 1. 环境与代码:先确认能编译出 darknet 可执行文件 git clone <检测框架仓库> && cd darknet make -j$(nproc) # 2. 数据目录:按 images/labels 分开,train/val 再分层 mkdir -p dataset/images/{train,val} dataset/labels/{train,val} backup # 3. 先跑通官方小模型,验证环境没问题,再换自己的数据 ./darknet detector test cfg/coco.data cfg/yolov3.cfg yolov3.weights data/dog.jpg

这三步的意义在于分层验证:先证明框架能编译,再证明预训练权重能推理,最后才动自己的数据。很多人跳过前两步直接上自定义数据,一出问题就分不清是环境、是权重还是数据的问题,排查成本翻好几倍。

清单剩下两项是配置和评估,分别对应第 4 章和第 5 章:改data和cfg两个文件,跑完训练后用验证集算 mAP。文档第 5 章只给了结论性的描述——YOLO 速度快、识别率有优势,但可能在精度上略逊于两阶段网络——没给具体的评估脚本和指标口径,这部分要自己补,后面第 6 章会讲怎么补得像样。

3. 算法章节的原理拆解:YOLO 怎么把检测做成一次回归

3.1 从候选框到一次前向:两阶段与单阶段的分水岭

理解 YOLO 的第一步是理解它反叛了什么。两阶段网络的流程是:先用选择性搜索或者 RPN 网络在一张图上生成一两千个可能包含目标的候选框,再把这些框逐个送进分类头做类别判断和坐标精修。整个过程像是先撒网再逐个挑鱼,准是准,但每一个候选框都要过一次网络,时间全耗在这儿了。

单阶段网络把这两步压成一步:在特征图的每个位置上预先铺好一组先验框,网络对每个位置直接输出「这里有没有目标、是什么类别、框要往哪个方向修正」。SSD 就是这么干的,它在不同尺度的特征图上分别预测,浅层管小目标、深层管大目标,速度一下就上来了,但小目标和密集场景下容易漏。

YOLO 更进一步,它连先验框的修正都不按位置单独算,而是把整张图切成 S×S 的网格,让每个网格单元负责预测中心点落在它内部的目标。这个设计的关键在于「一次前向出全部结果」:输入一张图,网络输出一个张量,张量里已经包含了所有框的坐标、置信度和类别概率,不需要任何后处理循环去遍历候选区域。文档第 3 章讲的 「Yolo 算法实现及其原理」,核心就是这件事——把检测问题重写成回归问题。

这么做的代价也很明显。一个网格只能预测固定数量的框,两个目标的中心点落在同一个格子里,网络就抓瞎了;小目标本身占的像素少,落在粗糙网格里几乎无法定位。后续版本用锚框、多尺度预测、特征金字塔这些手段在补,但「网格分配」这个根基没变,你调参的时候遇到的大部分玄学问题,追到根上都是网格和锚框的分配不合理。

3.2 Darknet 主干与输出张量:7×7×30 这类维度怎么读

文档里提到 YOLO 背后是比较有名的 Darknet 网络,在速度和识别率之间做了很好的优化。这句话背后是一套很朴素的设计哲学:主干全部用 3×3 和 1×1 卷积堆,1×1 负责压通道数,3×3 负责提特征,不搞花哨的模块,尽量让每一层的计算都花在刀刃上。第一代的 Darknet 是 24 个卷积层加 2 个全连接层,后来的版本引入残差结构,把层数堆到几十层,但那个「轻量、高效、适合资源有限环境」的定位一直没丢。

真正需要读懂的是输出张量的形状。以第一代为例,输入 448×448 的图像被划成 7×7 的网格,每个格子预测 2 个边界框,每个框 5 个数(中心 x、中心 y、宽、高、置信度),再加 20 个类别的条件概率,所以单个格子的向量长度是 2×5+20=30,整个输出就是 7×7×30。

import numpy as np GRID = 7 # 网格划分数量,输入尺寸 / 步长 BOXES_PER_CELL = 2 # 每个格子预测的框数 NUM_CLASSES = 20 # 类别数,换自己的数据集必须改 # 网络最后一层展平后的长度:7 * 7 * (2*5 + 20) = 1470 flat_dim = GRID * GRID * (BOXES_PER_CELL * 5 + NUM_CLASSES) # 把它 reshape 回空间结构,方便按格子取值 pred = np.zeros((GRID, GRID, BOXES_PER_CELL * 5 + NUM_CLASSES)) cell_y, cell_x = 3, 5 # 假设要看第 3 行第 5 列这个格子 cell = pred[cell_y, cell_x] for b in range(BOXES_PER_CELL): x, y, w, h, conf = cell[b * 5:(b + 1) * 5] # x、y 是相对当前格子的偏移量(0~1),加上格子坐标再除以网格数才是全图归一化中心点 cx = (cell_x + x) / GRID cy = (cell_y + y) / GRID # w、h 是相对整图的比例,网络输出的是平方根,还原要再平方一次 bw, bh = w ** 2, h ** 2 print(f"box{b}: center=({cx:.3f},{cy:.3f}) size=({bw:.3f},{bh:.3f}) conf={conf:.3f}") # 后 20 位是类别条件概率,必须乘上框置信度才是该类的最终分数 cls_prob = cell[BOXES_PER_CELL * 5:] scores = conf * cls_prob

这段代码有三个参数值得单独说。GRID决定了定位精度,网格越细定位越准,但每个格子能看到的上下文越少,分类更容易错,7 这个数字是速度和精度折中的结果。BOXES_PER_CELL决定了同一位置能出几个框,设小了密集场景直接漏检,设大了正负样本比例失衡。NUM_CLASSES是最容易翻车的一个,换数据集忘了改,训练照样能跑,loss 也照样降,但检出来的类别全是乱的。

还有一步文档没细说但必须做的:非极大值抑制。7×7×2 一共能出 98 个框,真正有目标的可能就几个,剩下的都是置信度很低的噪声,以及同一个目标被相邻格子重复预测出来的重叠框。NMS 的做法是按置信度排序,保留最高的那个,然后把与它 IoU 超过阈值的框全部压掉,阈值一般取 0.4 到 0.5。这个阈值调低了会漏掉挨得近的目标,调高了会留一堆重复框,密集场景下要按实际数据试。

3.3 损失函数拆解:五项加权和里的权重玄机

YOLO 的损失函数是整个原理部分最值得抠的地方,因为训练不收敛十有八九出在这里。它由五项组成,全部用误差平方和,但权重不同。

第一项是负责检测目标的格子里的坐标误差,中心点 x、y 直接算误差,宽高先开平方再算,这样做的原因是小框对宽高的绝对误差更敏感,开方之后大小框的惩罚力度能拉平一些。第二项是这些格子里的置信度误差,目标是让网络学会说「这里有东西,我很有把握」。第三项是不含目标的格子的置信度误差,这一项占了绝大多数格子,如果和第一项同权重,网络会倾向于把所有格子都预测成没目标,所以必须降权。

LAMBDA_COORD = 5.0 # 坐标损失权重,让定位误差在总损失里占主导 LAMBDA_NOOBJ = 0.5 # 无目标格子的置信度权重,压低背景样本的影响 # 有目标的置信度项和类别项权重取 1.0,不额外缩放

这两个权重是 YOLO 能训起来的关键。LAMBDA_COORD取 5 是为了让网络重视定位——一张图里绝大部分格子没有目标,如果不把坐标项放大,梯度会被背景样本淹没,模型学到最后只会输出「这里什么都没有」。LAMBDA_NOOBJ取 0.5 是反向操作,把海量背景格子的置信度损失压下去,避免它们主导梯度。

第四项和第五项分别是有目标格子的置信度误差和类别误差,权重都取 1。类别误差只在格子里确实有目标时才计算,这一点和分类任务不一样——分类任务每张图都算损失,检测任务里背景格子不参与类别学习,因为它们本来就没有类别可言。

调这部分的时候有个血泪教训:不要凭感觉改这三个权重。我见过有人为了让框更准把LAMBDA_COORD调到 10,结果模型收敛到一半开始输出所有可能的框,置信度全是 0.3 左右,NMS 压都压不干净。真想改,一次只动一个,跑够足够轮次看验证集 mAP 再下结论。

4. 数据集与训练落地:照着第 4 章把流程跑通

4.1 标注格式与目录约定:txt 与 VOC、COCO 之间怎么转

文档第 4 章讲「制作数据集和训练自己的数据步骤」,思路是对的——收集图像、画框、打标签、训练——但落到具体格式上,不同框架的约定差别很大。YOLO 系列的约定是每张图配一个同名 txt,每行一个目标,五个字段。

# 每行:类别序号 中心x 中心y 宽 高,后四个全部归一化到 0~1 0 0.4821 0.5367 0.2130 0.3475 1 0.1120 0.8904 0.0876 0.1543

这五个数的含义要抠清楚:类别序号从 0 开始,对应classes.names里的行号,不是类别名字;x、y 是框中心点除以图像宽高,w、h 是框宽高除以图像宽高。注意是除以图像尺寸,不是除以框自身的尺寸,这一步搞反了训练能跑但框全飘。

大部分人的原始标注是 LabelImg 存出来的 VOC 格式 xml,或者用现成标注平台导出的 COCO json,都得转。常见做法是写个小脚本批量处理,别手工改。

import os import xml.etree.ElementTree as ET classes = ["scratch", "dent", "stain"] # 顺序必须和 names 文件一致 def voc_to_yolo(xml_path, txt_path): root = ET.parse(xml_path).getroot() # 图像真实尺寸要从 xml 的 size 节点读,不能从 bbox 反推 size = root.find("size") img_w = float(size.find("width").text) img_h = float(size.find("height").text) lines = [] for obj in root.iter("object"): name = obj.find("name").text if name not in classes: continue # 类别名拼错直接跳过,会静默丢样本 cls_id = classes.index(name) box = obj.find("bndbox") xmin = float(box.find("xmin").text) ymin = float(box.find("ymin").text) xmax = float(box.find("xmax").text) ymax = float(box.find("ymax").text) cx = (xmin + xmax) / 2.0 / img_w cy = (ymin + ymax) / 2.0 / img_h w = (xmax - xmin) / img_w h = (ymax - ymin) / img_h lines.append(f"{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}") with open(txt_path, "w") as f: f.write("\n".join(lines)) for fname in os.listdir("annotations"): stem = os.path.splitext(fname)[0] voc_to_yolo(f"annotations/{fname}", f"dataset/labels/train/{stem}.txt")

脚本里最容易被忽略的是size那段。有些标注工具导出的 xml 里 size 字段是空的或者写错的,这时候img_w、img_h就成了 0,除零会直接崩,但更阴的情况是写成了一个固定的 500×500,脚本不报错,标注全错位。稳妥的做法是转换完之后抽十张图把框画回原图上看一眼,肉眼验证比什么都靠谱。

目录按框架约定摆好,再生成 train.txt 和 val.txt 两个索引文件,每行一个图片的绝对路径或相对路径。路径这一步也常出问题,train.txt 里写/home/user/data/images/train/001.jpg这种绝对路径,换台机器就全废,我一般统一用相对于工程根目录的路径。

4.2 data 与 cfg 配置改动清单

数据摆好之后是改配置。.data文件管数据集层面的信息,内容不多但一个都不能错。

# obj.data classes = 3 # 类别数,必须和 names 行数一致 train = dataset/train.txt valid = dataset/val.txt names = data/classes.names backup = backup/ # 权重存放目录,训练中每个若干轮存一次

classes.names就一行一个类名,顺序对应标注里的序号。这个文件和.data里的classes数字必须严格一致,我一般写完数一遍行数再改数字,不靠记忆。

.cfg文件是网络结构,改的地方有三处,全都围绕类别数展开:

# 1. 每个检测头前的卷积层,filters = 3 * (classes + 5),3 是先验框数量 [convolutional] size=1 stride=1 pad=1 filters=24 # 3 * (3 + 5) = 24,改类别数这里必须跟着改 activation=linear # 2. 检测头本身,classes 和 anchors 都在这里 [yolo] mask = 6,7,8 anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 classes=3 num=9 # anchors 的对数,一般不改

第二处改动是yolo层里的classes,有几处检测头就改几处,改漏一个会出现维度对不上,编译期直接报错,这个算幸运的。真正麻烦的是filters,它和类别数是绑定关系,改类别不改filters是新手最常犯的错,后面避坑章会详细讲这个。

第三处是训练超参,在[net]段。batch和subdivisions的关系是「实际进显存的批次大小 = batch / subdivisions」,learning_rate起步一般 0.001 左右,max_batches按类别数经验取值,类别越多轮次越多,常见做法是不少于 2000 乘类别数。这些值没有绝对标准,但起步阶段别乱调,先用社区验证过的组合跑通再优化。

4.3 训练命令、日志解读与权重保存

命令本身很短,关键在参数和产物。

# 从零开始训练,用预训练主干加速收敛 ./darknet detector train data/obj.data cfg/yolo-obj.cfg darknet53.conv.74 -map -gpus 0,1 # 断点续训:直接传上一次保存的 last.weights ./darknet detector train data/obj.data cfg/yolo-obj.cfg backup/yolo-obj_last.weights -map

-map参数会让训练过程中定期在验证集上算 mAP,代价是训练变慢,但对判断模型到底学到没有非常关键。不加这个参数你只能看 loss,而 loss 降了 mAP 不涨的情况太常见了。-gpus指定多卡,单卡机器直接去掉。

训练日志里几列数字要会看。Region Avg IOU是预测框和真实框的平均交并比,这个值从 0.1 慢慢爬到 0.7 以上说明定位在收敛。Class是类别分类误差,Obj是有目标时的置信度误差,No Obj是背景的置信度误差,后者通常很小,如果它开始变大说明模型在乱给背景打高分。Avg Recall和count是召回率,count是参与统计的目标数,样本少的时候这列噪声很大。

权重文件按max_batches的节奏存在backup/目录里,命名一般是xxx_1000.weights、xxx_2000.weights加上一个xxx_last.weights和一个xxx_best.weights。选最终模型的时候不要看最后一轮,要看best,它是验证集 mAP 最高的那一版。这里有个后悔药式的细节:训练中途如果看到 mAP 已经明显见顶,继续跑只会过拟合,早点停。

5. 避坑与排查:从文档到跑通之间最容易翻车的五件事

5.1 网络结构与配置类的坑

现象:训练几十轮后 loss 掉到 0.0x 附近,看着很完美,但推理时框全糊在图像边缘,类别也是乱的。

原因基本锁定在filters和classes不匹配。检测头前那个 1×1 卷积的输出通道数必须正好等于锚框数乘以(类别数加 5),三个检测头就三个地方都要改。这个错误不一定会让训练崩掉,因为输出张量 reshape 的时候,多出来或者少掉的那几个通道可能被静默截断,网络照常学,学到的东西是错的。

解决办法是改完cfg之后用文本搜索把所有classes和filters数一遍,确认每个检测头前面那个卷积层的filters都等于 3×(classes+5)。更稳的做法是训练前跑一次前向,打印输出层的维度,和预期比一下。

现象:训练到几百轮 loss 突然变成 nan,或者直接飙到几千,曲线像断电一样。

原因通常是学习率太高,或者数据里有宽高为 0 的框。标注脚本里 xmax 和 xmin 相等、ymax 和 ymin 相等的情况,画框的时候手滑点两下就出来了,宽度归一化之后是 0,宽高开平方再取倒数,梯度直接爆掉。也可能是subdivisions设得比batch还大,实际批次变成 1,梯度方差极大。

解决办法是先扫一遍标注文件,找0 0 0 0 0或者后四位里有 0 的行,删掉或者修掉。然后检查batch和subdivisions的关系,实际批次大小控制在 16 到 64 之间。学习率从 0.001 起步,看到 loss 抖动剧烈就往下砍一个数量级。

5.2 数据集与标注类的坑

现象:训练 loss 正常下降,但日志里Avg Recall一直是 0,推理一张图都检不出来。

这是标注坐标系搞错时的典型表现。归一化时用的是「框宽高除以框宽高」,结果是 1,或者用像素坐标没归一化,值域跑到几百,网络输出被压到 0 到 1 之间,永远对不上。也可能是classes.names的顺序和标注文件里的类别序号错位,模型学到的东西和期望的类别完全无关。

解决办法是抽三张图,把 txt 里的五个数按图像尺寸还原成像素框,用 OpenCV 画回原图上存成图片看。我一般会写个十行的验证脚本,转换完标注必跑一次。这个动作花不了五分钟,能省掉后面几天的排查。

现象:训练集上检得很好,验证集 mAP 极低,甚至算出来是 0。

先查val.txt里的路径。相对路径是相对当前工作目录算的,训练脚本在哪个目录下执行,基准就跟着变。路径错的时候框架不一定报错,只是找不到图片,验证集实际上是空的,mAP 自然算不出来。

再查验证集的标注有没有跟着图片一起转换,很多人只转训练集,验证集忘了。还有一种情况是训练集和验证集用了同一批图像做数据增强后的副本,等于自己考自己,mAP 虚高,换真实场景就崩,这个得从数据划分阶段就避免,按时间或者按批次划分比随机划分更接近真实分布。

5.3 训练与资源类的坑

现象:代码在开发机上跑得好好的,换到训练服务器上第一轮就报显存不足,或者卡在加载数据半天不动。

显存问题看batch和subdivisions的实际比值,再看输入分辨率。分辨率翻倍,特征图面积翻四倍,显存吃紧是必然的。解决办法是优先降subdivisions的倍数、降分辨率,最后才考虑换卡。另外训练开始前用nvidia-smi看一眼是不是有残留进程占着显存,多卡训练时见过因为上一次异常退出没清干净,白排查两小时的情况。

加载慢一般是数据在机械盘上或者是网络挂载盘,随机读小文件性能极差。把数据集拷到本地 SSD 上,训练速度能差出好几倍。这个坑不显眼,但对迭代效率的影响非常大,我自己现在的习惯是开工第一件事就把数据落在本地盘。

6. 实验结果怎么写才站得住脚,以及文档的二次扩写思路

文档第 5 章有实验结果的意图,但只写到「YOLO 速度快、识别率有优势、可以对比 SSD 和 Faster R-CNN 来突出这一点」这个层面,还差一层能说服人的东西。要把这一章补成能拿出去讲的材料,关键是控制变量并给出可比数字。

指标Faster R-CNNSSDYOLO测量条件
mAP@0.5最高中等中等偏上同一验证集、同一 IoU 阈值
单帧推理耗时明显最长中等最短同一张卡、batch=1、关掉可视化
显存占用高低低训练时实际峰值
小目标召回较好中等偏弱按目标像素面积分桶统计

这张表比一句「YOLO 又快又准」有用得多,因为每个数字后面都跟着测量条件。实验设计上我最想提醒的是「单帧耗时要关掉可视化再测」,画框和存图的耗时能占到一半以上,混进去测出来的数字毫无意义。另外不要只报 mAP,把漏检和误检的典型图各贴两张,写明是什么原因——小目标、遮挡、类别混淆,读者信的就是这些失败案例。

要在这份文档上做二次扩写,我建议补三样东西。一是环境与版本表,把框架版本、GPU 型号、驱动和 CUDA 版本列清楚,别人复现的第一步就卡在这儿。二是消融对照,只改锚框尺寸或者只改输入分辨率跑几组,说明性能变化是从哪来的,这比横向比三种算法更有说服力。三是数据集的统计信息,各类别样本数、目标像素面积分布、标注框数量分布,看到目标普遍偏小你就知道为什么小目标召回低,这个因果链比任何结论句都硬。

最后说个自己的习惯。早年我写这类实验章节,喜欢把最好的一次结果贴上去,中间失败的几组全删掉,觉得这样显得模型稳定。后来被别人拿着文档复现、复现不出来、回来找我,那种场面很难看。从那以后我每次写实验部分都强制走一遍「换台机器、从空环境开始、只照文档做」的流程,凡是需要我口头补充才能跑通的地方,全部回来补进文档里。这份《深度学习目标检测文档.docx》本身骨架是完整的,缺的正是这些从文档到可执行之间的连接件,把上面这些补进去,它就是一份能直接交给下一个人接着干的手册。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询