ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

YOLOv5源码深度剖析:从架构设计到Debug实战准备

YOLOv5源码深度剖析:从架构设计到Debug实战准备 1. 项目概述为什么要做YOLOv5深度剖析1.1 核心需求解析从调包到懂原理先交代一下背景。YOLOv5从2020年发布到现在已经成了目标检测领域绕不开的一个名字。GitHub上的Star数说明一切但更关键的是无论是学术界做实验、工业界做落地还是学生党做毕业设计YOLOv5几乎都是默认的起点。然而我观察到一个很普遍的现象大部分人在用YOLOv5的时候停留在改改yaml、跑跑train.py、看看结果的层面上一旦遇到loss不收敛、检测精度上不去、模型推理速度慢这类问题就完全不知道从哪下手。这个系列文章的初衷就一句话带你真正读懂YOLOv5的源码而不是只会调参。作为系列第一篇本篇聚焦两件事——YOLOv5的整体架构设计思路以及为后续源码debug需要做的准备工作。换句话说读完这一篇你应该能做到两件事第一别人问你YOLOv5的Backbone、Neck、Head分别是什么你能讲清楚它们各自做了什么、为什么这样设计第二你自己能搭建一套完整的debug环境跟着后续文章一步步在源码里打断点、看变量、理清数据流动的每一个环节。这篇文章适合谁三类人。第一类是已经跑通YOLOv5训练、想进一步理解原理的研究生和工程师第二类是准备用YOLOv5做毕设或比赛、需要写技术文档但怕讲不清楚的学生第三类是刚接触目标检测、想找一个经典框架作为源码阅读入口的初学者。如果你属于这三类中的任何一类这篇文章就是为你准备的。1.2 为什么选择YOLOv5这个版本这里有一个绕不开的问题现在YOLOv8、YOLOv9甚至YOLOv10都出来了为什么还要花时间去啃YOLOv5的源码我的回答是YOLOv5是源码结构最清晰、工程化最完善、社区讨论最充分的一个版本。YOLOv8之后的版本虽然精度更高但代码做了大量的合并和抽象——比如用统一的BaseModel来管理所有detect的head——对于新手来说反而难以看清一帧图像从输入到输出到底经过了哪些计算。而YOLOv5的代码结构非常直接models/yolo.py里那个DetectionModel类把Backbone、Neck、Head的构建逻辑写得明明白白非常适合作为源码阅读的起点。还有一个很现实的原因YOLOv5的部署生态太成熟了。TensorRT加速、OpenVINO转换、Jetson Nano部署、Android端移植……你在网上能搜到的绝大多数部署教程都是基于YOLOv5的。如果你想把检测算法真正落地到实际项目中掌握YOLOv5的源码细节几乎是一个必备技能。而且YOLOv5到现在仍然在维护ultralytics团队直到2024年底还在发布bug修复和小的改进这说明它在工业界的生命力依然很强。2. YOLOv5整体架构拆解从宏观到微观理解网络设计2.1 输入端的自适应锚框与数据增强YOLOv5的pipeline是从输入端开始的但这里的输入端远不止读一张图片那么简单。首先是自适应锚框计算。YOLOv5延续了YOLOv3/v4的锚框机制但又做了一个很关键的改进——它会根据你训练数据集中标注框的尺寸通过k-means聚类算法自动重新计算锚框的大小。在官方代码里train.py加载模型时会自动检查是否需要重新计算锚框如果检测到你的数据标注分布和默认锚框差异太大它会打印一条提示自动用你的数据重新聚类。这个设计的合理性在于锚框的本质是先验位置猜测。如果你要检测的是行人长条形和车辆扁宽形默认的锚框比例可能就不太合适。自动重算锚框相当于在训练开始前就把先验知识调整到更匹配你的数据分布能显著加快收敛速度。不过要注意锚框重算只在训练前做一次不是动态的所以不用担心额外的计算开销。其次是Mosaic数据增强。这个策略在YOLOv5中起到了至关重要的作用它把4张训练图片随机缩放、裁剪、拼接成一张极大地丰富了训练样本的上下文信息——比如一张拼接图里可能同时出现一个完整的车和半个行人模型被迫学会在复杂背景下检测小目标。Mosaic的实现代码在utils/datasets.py的load_mosaic函数里它的核心逻辑是用随机生成的拼接点坐标把4张图分别裁剪后粘贴到一张画布上。初次读这段代码的人容易晕的地方在于坐标变换我会在后续的debug文章中带着大家逐步调试这个函数把索引计算讲明白。另外还有自适应图片缩放。YOLOv5在推理时会自动把输入图片缩放到640x640或其他尺度但为了减少黑边、提高推理速度它做了一个很巧妙的处理计算缩放后的尺寸并让它对32取整也就是stride的倍数然后给不足的部分填充灰边。这个逻辑在utils/augmentations.py的letterbox函数里代码很简短但很多人在自己写推理脚本时忽略了这一步导致输入尺寸不对、检测结果错位。2.2 BackboneCSPDarknet53的核心设计思路YOLOv5的Backbone沿用了Darknet系列的设计但引入了CSPCross Stage Partial结构。这个结构最初来自CSPNet论文核心思想是把特征图沿通道方向分成两部分一部分经过密集的卷积块另一部分直接和卷积结果拼接。这样做的直接好处是减少了重复梯度信息、降低了计算量同时保持了特征提取能力。在YOLOv5源码里models/common.py定义了C3模块——这是CSP结构的YOLOv5实现版本。C3模块接收三个参数c1, c2, n分别代表输入通道数、输出通道数、Bottleneck重复次数。它内部先用一个1x1卷积将输入特征图分成两条路径主路径经过n个Bottleneck另一条路径直接走恒等映射最后两个路径拼接在一起再用一个1x1卷积调整通道数。我在实际调试中经常在这个模块打断点观察中间变量的shape变化你会发现一个关键细节Bottleneck的shortcut参数是True还是False会直接影响梯度能否跨层传播。当shortcut为True时残差连接让深层网络更容易训练这也是YOLOv5在深层网络如yolov5l、yolov5x中依然能稳定收敛的原因之一。Backbone内部还有一个很容易被人忽略的设计Focus模块在新版本中已经被6x6卷积替代但旧版源码里保留着。Focus模块的做法是把输入图片按像素位置隔行采样拼成4张缩小版的特征图再经过卷积提取特征。它的本质是一种无损的下采样操作和步长为2的卷积相比Focus模块能把信息更完整地保留下来。我第一次debug这个模块的时候就通过观察tensor的shape变化理解了它的工作原理——输入[1,3,640,640]经过Focus变成[1,12,320,320]通道数扩大4倍、宽高减半正好是隔行采样的结果。2.3 NeckPANet如何实现多尺度特征融合检测网络要处理的最大挑战之一是目标尺度差异——一张航拍图里既有占地几十米的建筑物也有几个像素的小车。为了让网络同时具备检测大目标和小目标的能力YOLOv5在Backbone和Head之间加了一个Neck结构采用的是PANetPath Aggregation Network的设计。PANet的核心思想是**“顶到底”和“底到顶”的双向路径增强**。代码里通过upsample和concat操作实现特征融合先将深层的小特征图如20x20上采样与浅层的大特征图如40x40拼接再把拼接后的特征图经过卷积形成包含多尺度信息的特征表示。这样设计的好处很直观浅层特征图保留了丰富的空间细节小目标的位置深层特征图有更强的语义信息目标的类别PANet让两者充分融合各自取长补短。在models/yolo.py的DetectionModel中Neck部分的构建逻辑并不像Backbone那样一目了然因为它是在parse_model函数里通过循环解析yaml配置网络结构来动态构建的。如果你直接读parse_model的代码会看到很多关于通道数计算的逻辑这是最容易让人头晕的地方。我的建议是先不看parse_model的实现而是先打印出模型结构对照yaml配置逐个核对等理解了整体结构之后再回头读parse_model的代码这样会轻松很多。后面的debug系列我会专门演示如何用一行代码打印模型结构和参数数量。2.4 Head与损失函数检测头这样输出最终结果YOLOv5的Head部分不再使用YOLOv3/v4的纯卷积输出而是在每一层特征图上用1x1卷积预测三个量类别概率、目标置信度objectness和边界框坐标。源码中可以看到每个检测层输出的通道数是(4 1 num_classes) * 3——4是框坐标x、y、w、h1是目标置信度num_classes是类别数3是每个特征图位置有3个锚框。损失函数的设计是YOLOv5的一个精髓。它由三部分组成box损失CIoU Loss、obj损失BCEWithLogitsLoss和目标类别损失BCEWithLogitsLoss。其中CIoU损失除了考虑预测框和真实框的IoU还引入了中心点距离和宽高比的惩罚项解决了IoU损失在预测框和真实框不重叠时梯度消失的问题。obj损失特别有意思——YOLOv5给正样本和负样本分配了不同的权重让模型更关注难分类的样本。另一个值得特别说明的设计是正负样本分配策略。YOLOv5将真实框的中心点所在的网格以及相邻的两个网格都作为正样本的来源每个真实框最多可以匹配3个锚框。相比YOLOv3的单网格匹配这种多网格多锚框的分配策略极大地增加了正样本数量缓解了正负样本严重不平衡的问题同时还加速了收敛。我强烈建议你在debug时重点观察build_targets函数的运行过程——它是一个动态构建匹配关系的过程数据的shape变化非常频繁很容易绕晕。这一块我会在系列的第二篇文章里做逐行级别的debug演示。3. 源码debug准备环境搭建与工具链选型3.1 Python环境与依赖配置详解在深入源码之前先把debug环境准备到位。我用的是最常见的配置组合Python 3.8 PyTorch 1.13 CUDA 11.7 YOLOv5官方最新release代码。之所以选这个组合主要是因为它经过了最充分的验证网上能搜到几乎所有可能遇到的问题的解决方案。如果你用的是更新的PyTorch 2.x版本在大部分场景下也能正常工作但要注意个别API的变化比如torch.jit相关的修改。创建独立虚拟环境是第一优先级的事情建议使用conda。命令行执行conda create -n yolov5 python3.8 -y然后conda activate yolov5。进入环境后依次安装PyTorch和依赖库。强烈建议先装PyTorch再装requirements.txt否则pip可能会自动给你装一个CPU版本的torch后面跑训练的时候才发现CUDA不可用非常耽误时间。requirements.txt里需要特别关注的几个库包括opencv-python图像读取和预处理的基础、numpy几乎所有数值计算都依赖它、matplotlib画训练曲线、PyYAML读取模型和数据的yaml配置、tqdm显示训练进度条。这些库一般不会有什么坑但opencv-python和opencv-contrib-python不要同时安装它们之间的头文件冲突会导致编译错误。如果你安装依赖的时候遇到了torchvision版本不匹配的问题建议到PyTorch官网找对应CUDA版本的安装命令用--index-url指定正确的源来安装。3.2 IDE与调试工具的选择debug级的源码阅读调试工具的选择直接决定了你的学习效率。我个人的经验是PyCharm Professional版是首选其次是VSCode Python插件。PyCharm的断点调试界面非常直观尤其是watches窗口和变量查看窗口配合Step IntoF7和Step OverF8操作能让你非常清晰地跟踪每一行代码的执行过程。而且PyCharm支持在断点命中时直接查看任意表达式的值配合Console窗口甚至可以在调试过程中动态执行代码修改变量值这是理解源码逻辑的利器。VSCode的优势在于轻量、免费、跨平台配合Python插件和内置Debugger也能达到近似的效果。如果你在服务器上用命令行调试我推荐pdb或者ipdb——在代码里写上from ipdb import set_trace; set_trace()运行到这一行就会进入交互式调试模式。不过这种方式的体验和IDE断点差距比较大我一般只在远程服务器上快速定位问题时才用。这里有一个很重要的理念想分享debug不是出了问题才用的工具而应该成为你阅读未知代码的主要手段。我看到太多人读源码的方式是逐行看一遍感觉自己看懂了但实际运行的时候完全不是那么回事。正确的方式是在关键函数入口处打断点运行程序观察变量的实际shape和值顺着代码的实际执行路径一步步走下去。这种方法能帮你建立代码文字和运行时行为之间的映射关系——这正是源码阅读中最难跨越的一步。3.3 测试图片与预训练权重准备为了debug方便我们需要准备一份最小可运行的环境一张测试图片、一份权重文件、一份数据集配置。测试图片建议准备两三张包含不同大小目标的图片——既能测大目标也能测小目标。你可以先从官方仓库的data/images目录拿现成的图片也可以用自己的图片。关键是你要对图片内容很熟悉知道每个目标大概在什么位置这样在debug预测结果时才能判断网络输出是否合理。权重文件直接用官方提供的预训练权重就好。去YOLOv5官方仓库的release页面下载yolov5s.pt约14MB这是最小的模型debug时前向推理速度快适合学习。如果你后续要自己训练再根据你的任务选择合适的预训练权重和参数。下载完把权重文件放在项目根目录下的weights文件夹里或者直接在detect.py里指定路径。最后是数据集配置这里以官方coco128为例它包含128张图片和标注是一个迷你版COCO数据集。官方仓库的拉取命令一般是git clone整个项目然后在你用python train.py --data coco128.yaml训练时代码会自动下载coco128数据集。如果你只是想先跑通detect流程做源码分析其实不需要数据集光是图片预训练权重就够了。3.4 项目结构与关键文件导航如果把YOLOv5源码当成一本书先看懂目录结构就相当于看了目录。整个项目的核心文件分布如下detect.py和train.py两个入口文件一个做推理、一个做训练models/网络结构定义yolo.py是核心包含了DetectionModel类和Detect类common.py定义了大量基础组件Conv、Bottleneck、C3、SPPF、Concat等yolov5s.yaml等文件定义了不同规模的网络结构utils/辅助工具datasets.py负责数据加载和增强Mosaic、letterbox都在这里loss.py封装了损失函数ComputeLoss类是理解训练流程的核心plots.py负责画图包括预测结果可视化data/数据集配置和超参数配置coco128.yaml是数据集的入口hyp.scratch-low.yaml是超参数配置对新手来说最容易犯的错误是一上来就从头到尾顺序读代码——从import torch这行开始一直读到结尾。正确的方法是先了解模块之间的调用关系然后在关键节点打断点。我的建议阅读顺序是先跑通detect.py打断点观察DetectionModel的forward过程再跑train.py关注ComputeLoss的调用和backward过程。在动手debug之前先用python detect.py --weights yolov5s.pt --source data/images --conf-thres 0.25命令跑一遍确认整个环境能正常工作再开始打断点调试。4. 第一次debug实操从推理入口开始4.1 从detect.py出发完整跟踪一帧图像的推理流程现在正式进入debug实战。用PyCharm打开YOLOv5工程在detect.py的run()函数里的model DetectMultiBackend(weights, devicedevice, dnndnn...)这一行打个断点然后用debug模式运行detect.py命令行参数保持默认即可。第一次运行到这里你要关注的是DetectMultiBackend这个类的初始化逻辑。它在《models/common.py》里被定义会根据你传入的权重文件格式自动选择加载方式。如果是pt格式它会调用torch.load加载权重然后取出其中的model对象ckpt[model].float().eval()。这里有一个关键细节保存权重文件的时候还会带上训练时的超参数hyp、optimizer状态字典等信息所以加载的时候要ckpt[model]而不是ckpt[model].half()——不同版本的save操作可能存在细节差异。继续往下走很快会走到model model.to(device)和model.eval()这是把模型放到GPU/CPU上并切换到推理模式。eval模式很重要它会关闭dropout和batch norm的running statistics更新确保推理结果稳定可复现。然后代码会读取你输入的图片文件对每一张图片调用letterbox函数进行尺寸归一化再通过torch.from_numpy转成tensor、归一化到0-1之间、增加一个batch维度最终得到模型的输入。这个过程中最值得关注的是数据格式的变换。一张HWC格式的OpenCV图片取值范围0-255通道顺序BGR经过变换变成CHW格式的tensor取值范围0-1通道顺序RGB这个变换通常在LoadImages类的__next__方法里完成。如果你在调试过程中发现检测结果的颜色异常比如红色和蓝色对调大概率就是这里没有正确做BGR到RGB的通道转换。4.2 深入models/yolo.py拆解DetectionModel的forward过程图片经过预处理后会进入model(x)调用。这时候你在models/yolo.py的DetectionModel.forward方法上打断点会看到一个分支判断——如果是推理模式self.training为False会直接走self.predict(x)如果是在训练模式下则会走完整的包含损失计算的前向过程。两个分支调的代码完全不同这是一个非常重要的区分点很多初学者在这里困惑了很久。继续顺时针往下进入predict方法后实际执行的是self.model(x)这里的self.model是一个nn.Sequential容器它按照yaml配置文件的顺序串联了Backbone的所有层、Neck的所有层和最后的Detect检测头。Debug时你可以在return之前看一下预测结果的shape。以640x640的输入为例会得到三个不同尺度的输出每个输出的shape是[1, 3, 20, 20, 85]、[1, 3, 40, 40, 85]、[1, 3, 80, 80, 85]假设COCO数据集是80类85 4个坐标 1个置信度 80个类别概率。三个尺度分别对应20x20小特征图检测大目标、40x40中等特征图检测中等目标、80x80大特征图检测小目标。要重点观察的内容是每层输出的85维向量中前5个数和后80个数的数值范围有明显差异。前5个数坐标和置信度经过sigmoid激活值在0-1之间后80个类别概率也经过了sigmoid理论上可以理解为每个类别的概率。但模型输出的是原始logits而不是最终概率NMS之前还需要经过sigmoid和坐标解码操作这部分代码在non_max_suppression函数里。理解了这一点你才能看得懂为什么输出是原始特征图上的数值而不是IoU已经算好的最终框坐标。4.3 几个实用的断点设置技巧在debug过程中以下几个位置是黄金断点能让你最大化理解YOLOv5的运作机制第一个必打的断点在utils/loss.py的ComputeLoss.__call__方法里。这里是训练流程的核心环节class所有的正负样本匹配、损失计算、损失加权都发生在这里。你会看到build_targets函数如何通过anchor的IoU匹配构建训练标签也能直观看到三个损失分量box、obj、cls的计算过程。debug这里需要一点耐心因为涉及到很多张量的维度变化运算建议配合PyCharm的Evaluate功能直接查看复杂的张量表达式。第二个必打的断点在utils/datasets.py的load_mosaic函数里。理解Mosaic数据增强的实现逻辑是理解为什么YOLOv5训练能这么快收敛的关键。用Step Into逐行过一遍这个函数你会看到4张图片是如何通过仿射变换粘贴到画布中的以及边界处如何处理。debug这个函数有个小技巧把输入图片可视化用cv2.imshow或plt.imshow看一眼Mosaic拼接的中间结果比纯粹看shape变化更直观。第三个值得关注的位置是models/common.py中的Detect.forward方法。训练和推理模式下的输出差异在这里体现得最明显。你可以在training为False时打断点对比推理模式下输出和训练模式下输出的区别——推理模式多了一步decode的过程把特征图上的原始值解码成真实坐标和置信度。这个是理解训练和推理为什么代码路径不同的关键。4.4 推理结果的可视化与验证当模型完成前向推理输出经NMS筛选后得到最终的检测结果detect.py会调用Annotator类在原始图片上画框。你可以选择一个简单的验证方法跑一张包含明显目标的图片打印输出的每个检测框的坐标、置信度和类别ID人工判断这个结果是否合理。比如经典的bus.jpg测试图片你会得到多个行人框、一个公交车框置信度通常在0.8以上。如果检测结果完全错乱大量错误框、置信度偏低、甚至没有检测到目标问题大概率出在以下几个环节图片的BGR/RGB通道转换错误、letterbox变换时填充比例没有记录导致坐标偏移、模型权重的加载方式不对加载成训练模式而非eval模式。把断点打在non_max_suppression的输入处观察原始输出是否合理——如果原始输出里所有的置信度都接近于零说明网络本身没有正常工作问题在网络或输入如果原始输出很合理但NMS之后结果很差问题就出在后处理过程。我的经验是不要一开始就追着bug往深处钻把端到端的工具链能跑通当作最基本的前提。如果你能通过debug的形式完整跟踪一张图片从读入到输出检测框的全过程并且每个环节的数据变化都心中有数那YOLOv5的推理流程对你来说就是透明的了。5. 常见问题与排查技巧实录5.1 环境配置阶段的典型问题环境配置阶段的坑在YOLOv5里格外多我把最典型的几个问题整理成了一张速查表问题现象常见原因解决方案torch.cuda.is_available()返回False安装了CPU版PyTorch卸载后按CUDA版本重装GPU版pip uninstall torch torchvision再从官网复制对应命令安装运行detect.py时报ModuleNotFoundError: No module named torchvisionrequirements.txt中自动安装的torchvision和torch版本不匹配手动指定版本安装pip install torchvision0.14.1与torch 1.13.1配套打开摄像头实时检测时报错Could not initialize numpy arrayOpenCV版本与numpy不兼容pip install numpy1.23.5然后重启Python进程加载权重时报Missing key(s) in state_dict权重文件和代码版本不兼容确保权重来自同一个官方仓库分支下载最新的yolov5s.pt替换旧文件显卡显存不足报CUDA out of memory模型太大或batch size太大换yolov5s或yolov5n模型减小batch size关闭其他占用显存的程序最让人困惑的一个问题是明明按教程一步步装了依赖但程序运行时还是会报Segmentation fault (core dumped)。这个问题在Linux服务器上尤其常见通常和OpenCV的libGL冲突有关。解决方案是安装libgl1-mesa库apt-get install libgl1 libglib2.0-0。另外如果你在Windows上使用PyCharm需要确保编辑器运行时的Python解释器是你创建的conda环境而不是系统默认的Python——这个低级错误我见过太多次了。5.2 Debug过程中遇到的高频困惑在实际debug YOLOv5的过程中有几个困惑基本每个人都会遇到。第一个困惑是tensor的device不匹配。训练时模型在GPU上如果你手动构造了一个tensor但忘了指定device就会报Expected all tensors to be on the same device。解决方案有两种在创建tensor时加.to(device)或者在模型前向传播前用.to(device)统一转换。我在调试时经常会写一行辅助代码def dbg(x): print(x.shape, x.device, x.dtype)然后插在关键节点这样能快速定位是哪个tensor的device出了问题。第二个困惑是大批量数据下的shape变化。YOLOv5支持多尺度训练每过10个epoch输入图片的尺寸就会在320到640之间随机变化。这意味着同一个模型在训练过程中会接收到多个尺寸的输入产生的特征图shape也随之改变。如果你在某个固定shape上打断点、并在那里检查结果下一次跑到这个断点时shape可能就变了。解决的办法是不要硬编码形状假设而是始终通过.shape动态获取或者打印出shape之后对比一下是否和预期一致。第三个困惑是非极大值抑制NMS后检测框数量为0。从debug的角度看你需要确认NMS的阈值是否合理。如果conf-thres设得太高比如0.9模型输出的低置信度框就全被过滤了如果iou-thres设得太低比如0.1大量的重叠框会被合并导致漏检。建议在debug时先设一个低的conf-thres0.01观察NMS前的检测框数量确认模型本身能正常输出目标再逐步调高阈值到0.25或0.5这个过程会让你对阈值的敏感度有直观感受。5.3 避坑经验我能给你的一些独门心得最后分享几个我在长期debug YOLOv5源码过程中总结出来的独门心得。心得一善用torch.summary或参数打印来验证网络结构。在加载模型后用一行代码print(model)你就能看到整个模型的层级结构。再用torchsummary.summary(model, input_size(3,640,640))能看到每个层的输出shape和参数量。这个信息能帮你判断模型有没有被正确创建也能帮你理解每个模块的输入输出规格。我的经验是拿yolov5s.yaml配置逐行对照打印结果既复习了网络结构又验证了代码没有写错。心得二把复杂的张量运算拆成多个小步骤。YOLOv5某些代码比如build_targets函数包含大量的索引操作、expand操作和view操作如果一气呵成地读完会非常难理解。我的做法是在连续的多行代码处都加上断点逐行执行并打印中间结果把每一步的shape变化记录下来形成一个脉络图。这样做虽然慢但效果极好一旦理清了逻辑就不会再忘。心得三利用小数据集做一个小规模验证。不要一上来就用全部的训练集做debug。复制train.py的配置改成一个极小的参数组合——比如batch size2、epochs1、图片尺寸160x160、只取50张图片的数据子集。这样一轮训练可能只要十几秒你就有机会在训练过程中随时打断点、查看中间状态、反复实验不同的修改方案。我用这个方式优化过几处自定义检测头的代码效率比在大数据集上反复训练高了一个数量级。心得四把代码改动记录和debug日志写在一起。用Notion或者Markdown文件维护一个源码笔记每读一个函数就写一段自己的理解搭配实际的debug截图和shape记录。这个笔记不需要多正式关键在于帮助自己建立体系化的知识树。后续当你需要修改或复用某个模块时翻笔记比重新读源码快得多。写到这里YOLOv5的架构分析和源码debug准备就算告一段落了。这套环境和方法我已经带过很多人完整走过一遍只要耐住性子把前面这些步骤走稳后面的源码阅读会变得非常顺滑。下一篇我准备深入detect.py的完整推理链路带着你一步一步debug完整个NMS和坐标解码过程把每个步骤的张量变化在文章里完整还原。
返回列表