简介:这是一份关于YOLOv8网络结构图的详细教程文档,面向目标检测初学者、算法工程师及需要绘制模型结构图的开发者。资料从整体架构切入,系统拆解Backbone、Neck、Head三大部分,逐一讲解卷积层、C2f模块、SPPF、上采样层、Concat层和检测头的设计原理与特征流向;不仅说明各模块如何协同完成多尺度目标检测,还提供了使用Visio、Graphviz、Mermaid、Netron等工具绘制结构图的完整流程与标注美化技巧。文档同时对比YOLOv5的C3与C2f差异,介绍注意力机制、轻量化网络等改进方向,并梳理目标检测、分类、分割等不同任务下的结构变化。资源为单个doc文件,约53KB,内容紧凑、层次清晰,便于随时查阅,目前已有2300人学习使用。通过这份文档,读者既能深入理解YOLOv8的架构逻辑,也能照着教程亲手绘制高质量网络结构图,为模型优化、论文写作和项目答辩提供有力支撑。 刚接触YOLOv8的读者,十有八九都会去搜那张传说中的YOLOv8网络结构图。搜出来的版本五花八门,有的把每个模块画得很精致,有的只画了主干连线,还有的干脆是YOLOv5的图改了个名字。我在初学阶段也被这些图坑过:背了几天,真到要改网络、调参、给团队讲技术方案的时候,连某条线为什么从这里连到那里都说不清楚。这篇教程想解决的就是这个问题——把YOLOv8网络结构图彻底讲透,并且教会你画出真正能用的结构图:每个方块代表什么、每个连接为什么存在、每个关键位置的张量形状是多少。无论你是刚开始学目标检测、准备训练自己的数据集,还是打算在YOLOv8上做结构改进,这张图都应该成为你手边最趁手的工具。下面的内容全部基于Ultralytics的YOLOv8官方实现,版本以8.0系列为准。
1. 先抓主干:YOLOv8的三段式骨架与张量流转
1.1 三段式分别干什么
YOLOv8整个网络可以粗暴地切成三段:
- Backbone(主干网络):从输入图像里逐级提取特征,越深分辨率越低、语义信息越强,越浅分辨率越高、细节信息越足。
- Neck(颈部网络):把Backbone不同层输出的特征做融合,常见结构是FPN+PAN。它的存在是为了让浅层的小目标细节和深层的大目标语义互相补充。
- Head(检测头):在融合后的特征上做分类和回归,输出目标框的位置和类别。
这三段不是YOLOv8首创,却是它做得比较均衡的一代。记住“主干提特征、颈部做融合、头部出结果”这个逻辑,后面看任何结构图都不会乱。
还有一点要先说清楚:YOLOv8是anchor-free的。这意味着检测头不再预设一堆固定尺寸的锚框,而是直接在特征图上预测每个位置到目标框四边的距离(通过DFL机制实现分布回归),并用分类分数直接充当置信度。这一点和YOLOv5的anchor-based设计差异很大,后面看Head时还会再展开。
1.2 一切从yaml开始:结构图的“源代码”长这样
很多人画结构图喜欢直接抄网上现成的,其实最权威的“结构图源代码”就在你下载的Ultralytics仓库里——每个模型对应一个yaml文件。以YOLOv8n为例,backbone部分长这样:
# YOLOv8n backbone(简化注释版) backbone: - [-1, 1, Conv, [64, 3, 2]] # 输入640x640x3 -> 输出320x320x16 - [-1, 1, Conv, [128, 3, 2]] # 320x320x16 -> 输出160x160x32 - [-1, 3, C2f, [128, True]] # 160x160x32 - [-1, 1, Conv, [256, 3, 2]] # 160x160x32 -> 输出80x80x64 - [-1, 6, C2f, [256, True]] # 80x80x64 - [-1, 1, Conv, [512, 3, 2]] # 80x80x64 -> 输出40x40x128 - [-1, 6, C2f, [512, True]] # 40x40x128 - [-1, 1, Conv, [1024, 3, 2]] # 40x40x128 -> 输出20x20x256 - [-1, 3, C2f, [1024, True]] # 20x20x256 - [-1, 1, SPPF, [1024, 5]] # 20x20x256每一个[-1, 1, Conv, [64, 3, 2]]都对应结构图上的一个方块。-1表示“输入来自上一层”,1表示该模块的重复次数乘depth_multiple,Conv/C2f/SPPF是模块类型,方括号里是模块参数:输出通道基数、卷积核大小、步长等。yaml里没有算出的东西,就是你需要自己在图画出来的东西。
1.3 主干上的shape流转:n/s/m/l/x有什么区别
yaml里的通道数是“基数”,实际通道数要乘width_multiple,模块重复次数要乘depth_multiple。以640×640输入、YOLOv8n为例:
| 层 | stride | 输出shape(v8n) | 说明 |
|---|---|---|---|
| Conv1 | 2 | 320×320×16 | 快速降分辨率到1/2 |
| Conv2 | 2 | 160×160×32 | 降到1/4 |
| C2f_1 | 1 | 160×160×32 | 1个Bottleneck |
| Conv3 | 2 | 80×80×64 | 降到1/8,输出记为P3 |
| C2f_2 | 1 | 80×80×64 | 2个Bottleneck |
| Conv4 | 2 | 40×40×128 | 降到1/16,输出记为P4 |
| C2f_3 | 1 | 40×40×128 | 2个Bottleneck |
| Conv5 | 2 | 20×20×256 | 降到1/32,输出记为P5 |
| C2f_4 | 1 | 20×20×256 | 1个Bottleneck |
| SPPF | 1 | 20×20×256 | 多尺度池化,尺寸不变 |
C2f的Bottleneck数量是repeat×depth_multiple取整后的结果。v8n和v8s的depth_multiple都是0.33,所以Backbone里的C2f基本是[1,2,2,1];v8m是[2,4,4,2];v8l和v8x是[3,6,6,3]。width_multiple则决定通道数:n是0.25,s是0.50,m是0.75,l是1.00,x是1.25。网上很多图画的是l版本,你拿它讲n版本,所有通道数字都是错的。这也是我强调“照着yaml自己算shape”的原因。
2. 关键模块逐个拆:C2f、SPPF与Detect Head的细节
2.1 Conv与Bottleneck:两个最基础的积木
YOLOv8里的Conv模块不是裸的卷积,而是Conv2d+BN+SiLU激活三件套。画图时看到Conv旁边标了k=3,s=2,意思就是用步长为2的3×3卷积做下采样,特征图尺寸减半、通道数按需变化。整个Backbone的降采样几乎全靠这类Conv完成,而不是靠池化。
Bottleneck则是C2f里的基本单元,结构是1×1卷积降通道,再接3×3卷积升通道,最后有一个残差连接(shortcut)。当shortcut=True时,输入和输出会逐元素相加,所以Bottleneck不会改变张量的H、W和通道数。这个设计借鉴了ResNet的思想,目的是在加深网络的同时稳住梯度。画结构图时记住一句话就行:Conv负责改变形状,Bottleneck负责“加深+提特征”,本身不改变形状。
2.2 C2f的精髓是concat,不是简单的残差
C2f是YOLOv8相对v5的C3模块最大的改动,也是最容易被画错的地方。它的计算流程是这样的:
- 输入x先过一个1×1卷积(cv1),把通道数扩到2倍。
- 把结果沿通道方向切成两半:一半直接留作后续concat,另一半进入一串Bottleneck。
- 每一个Bottleneck的输出都会被保留下来。
- 最后把所有保留下来分支沿通道concat,再过一次1×1卷积(cv2)压缩回目标通道数。
以v8n的第一个C2f(输入160×160×32)为例,数据流是这样:
| 步骤 | 操作 | 数据形状 |
|---|---|---|
| 输入 | x | 160×160×32 |
| cv1 | Conv1×1,通道扩到2倍 | 160×160×64 |
| split | 切成a、b两路 | 各160×160×32 |
| b0 | Bottleneck输出 | 160×160×32 |
| concat | a + b + b0 | 160×160×96 |
| cv2 | Conv1×1,压缩回目标通道 | 160×160×32 |
这里只有1个Bottleneck,所以concat分支数是3。如果Bottleneck数量为n,concat分支数就是n+2。看到区别了吗?C3模块只把最后一个Bottleneck的输出拿来做concat,而C2f把每个Bottleneck的输出都concat了,相当于把DenseNet“每层都保留中间特征”的思路搬了过来。这种密集连接的好处是梯度可以从深层直接流向浅层,特征复用率更高。你画图时如果只画“一个Bottleneck进、一个Bottleneck出”,就完全错过了这个模块的精髓。
2.3 SPPF:三个串联池化,别画成SPP
SPPF的作用是扩大感受野,让网络能看到更大范围的上下文信息。它内部其实很简单:输入先过一个1×1卷积把通道压到一半,然后连续做三次5×5的MaxPool(stride=1,padding=2),每次池化后都把结果保留,最后把“原始特征+三次池化结果”一共四份特征concat起来,再过1×1卷积恢复通道。
注意,池化不改变特征图的H和W,只负责扩大感受野。所以SPPF在结构图上画出来是“20×20×256输入,20×20×256输出”,中间经历c→c/2→4×(c/2)→c的通道变化。SPP是另一种老结构,用5、9、13三个不同尺寸的池化核并行池化再concat,计算量大得多。YOLOv8用的是SPPF,严格来说网上不少老图把这件事画错了,我在第4节会再展开。
2.4 Detect Head:decoupled加anchor-free,与v5划清界限
YOLOv8的检测头和v5最大的区别是:分类和回归分成两个分支(decoupled head),且没有objectness分支。每个检测头收到一张融合后的特征图,内部先接两个3×3卷积,然后分出两个分支:
- 分类分支:输出通道数等于类别数nc,直接输出每个位置属于各类别的概率。
- 回归分支:输出通道数固定为4×reg_max(默认reg_max=16,即64通道),表示目标框四条边距离的分布参数,后续通过DFL解码出具体坐标。
三个检测头分别挂在stride=8、16、32的特征图上,对应80×80、40×40、20×20(输入640×640时)。推理时,三个头的结果会被拉平成(bs, 8400, 4+nc)的输出,其中8400=80×80+40×40+20×20。画Head的时候,很多人只画一个“Detect”方块完事,但对想改Head、加注意力、做小目标优化的读者来说,内部这两个3×3卷积和两个分支必须画清楚,不然你根本不知道要把模块插在哪条支路上。
3. 怎么动手画一张带shape的专业结构图:工具、规范与流程
3.1 工具选择:draw.io足够,别折腾花哨软件
画结构图这件事,工具越简单越好。我自己用的最多的是draw.io(也叫diagrams.net),免费、免安装、浏览器直接打开,也支持VSCode插件,可以导出高清SVG/PNG,还能直接嵌入Markdown文档。PPT和Excalidraw也能画,但draw.io在画“带标注的复杂连线图”时效率最高,尤其是Neck部分那种交叉连线,排布起来很顺手。不建议一上来就折腾Visio或专业电路图软件,杀鸡不用牛刀。
3.2 绘制规范:颜色区分三段,shape写进每个方块
我建议你在开始画之前先定一套规范,否则画完自己过两天都看不懂:
- 用三种颜色区分三段:Backbone用蓝色系,Neck用绿色系,Head用橙色系。
- 矩形表示模块(Conv、C2f、SPPF),圆角矩形表示特征图或张量,箭头表示数据流方向,虚线表示跨层跳跃连接或concat来源。
- 每个模块方块上至少标三样东西:模块类型及关键参数(如
Conv k3 s2)、输出shape(如80×80×64)、在当前尺度下的stride。 - 在图的角落放一个图例,说明颜色和形状的含义。
这套规范不是强迫症,而是工程习惯。结构图最大的用途是给别人讲清楚你的网络改了哪里、每个张量走到哪一步是什么形状。没有shape的结构图,画了约等于没画。
3.3 完整绘制流程:从yaml到导出SVG
我画一张完整YOLOv8结构图的流程大概分五步,你可以直接照搬:
- 打开对应版本的yaml文件,把Backbone模块按顺序列成方块,算出每个方块的输出shape(见第1节表格法)。
- 标出三个特征出口P3(80×80)、P4(40×40)、P5(20×20),这三个是Neck的输入。
- 画Neck的FPN部分:从P5开始上采样到P4尺寸,与P4 concat,经过C2f;再上采样到P3尺寸,与P3 concat,经过C2f。
- 画Neck的PAN部分:从融合后的P3开始下采样到P4尺寸,与之前保留的P4融合结果concat,经过C2f;再下采样到P5尺寸,与P5 concat,经过C2f。
- 在最终的P3、P4、P5上挂三个Detect Head,标注stride 8/16/32,并把第2节提到的Head内部分支画全。
第三步和第四步里最需要小心的是concat的索引。在yaml的head部分,像[[-1, 6], 1, Concat, [1]]这样的写法,第二个数字6表示concat来源是backbone的第6层输出——也就是第1节表格里的C2f_3,即P4。如果你不看yaml里的数字编号,完全凭“感觉”连线,很容易把40×40的特征和80×80的特征连到一起,concat维度就错了。
3.4 用Netron反向验证结构图是否正确
画完图别急着发出去,有个特别有效的验证手段:把训练好的模型导出成ONNX,用Netron打开,逐个节点对照自己画的方块和shape。
yolo export model=best.pt format=onnxNetron打开后,你会看到每个节点的输入输出shape,和自己画的表一对就知道有没有错。有一点要提前说清楚:ONNX里DFL、transpose、reshape这类辅助节点很多,图会显得很乱,你只需要看主干上的Conv、C2f对应节点,不需要每个节点都看懂。这一段经历会在第4节里的“训练模型和导出模型对不上”再细聊。
4. 画过几十张结构图之后,我总结的高频错误:五个最容易翻车的地方
4.1 把C2f画成“只concat最后一个Bottleneck”
这是出镜率最高的一种错误,本质是拿C3模块的印象套C2f。一旦画错,你后面算通道数就跟着错。比如v8n第一个C2f,如果按C3的逻辑,concat后应该是2×32=64通道,但实际是3×32=96通道(分支a+输入b+一个Bottleneck输出b0),再经过cv2压缩回32。别小看差出来的32个通道,它会影响Neck和后面所有层的计算量评估。画C2f的建议是:先画cv1、split,再画Bottleneck链,最后把每条输出都引到同一个concat节点。
4.2 拿着l版本的图去讲n版本,通道全错
我在第1节已经给了n/s/m/l/x的depth_multiple和width_multiple对照,这里再次强调:不同规模的模型不是同一张图等比缩放,Bottleneck数量和通道数都变,单独拿一张网上找的“YOLOv8结构图”去推导任何具体版本的shape,基本都会翻车。还有一个相关的事:有人拿训练日志里的参数量反推结构,结果对不上,因为FLOPs和params会随实际输入分辨率变化。你拿640的shape推1280的模型,通道数一样但特征图尺寸不同,画出来的结构图如果是带尺寸的,就要明确标注输入分辨率。正确做法是始终以yaml加两个multiplier为准,现场算,或者用一个小脚本把每层输出打印出来对照。
4.3 把SPPF画成SPP,感受野结构完全不同
除了C2f,SPPF也经常被画错。老一点的YOLO版本用的SPP模块,内部是5、9、13三个不同尺寸的池化核并行池化,然后再concat;而YOLOv8用的SPPF是三个5×5池化串联,每池化一次都把中间结果保留,最后再把四份特征concat。两者在结构图上看起来都是“一堆池化+concat”,不细看很容易画混,但实际计算量和感受野结构差别很大。如果拿着SPP那张老图去推YOLOv8的计算量,得到的结果会明显偏高;反过来拿SPPF去理解需要多尺度并行池化的设计意图,也会觉得别扭。YOLOv8用的全是SPPF,这一点请务必画对。
4.4 训练模型和导出ONNX的结构对不上
这个问题几乎每个人都遇到过:训练时打印的模型结构和Netron里看到的ONNX图不一致,就开始怀疑自己画错了。其实训练用的结构和导出后的结构本来就不一样。训练时Detect头会保留DFL的完整计算路径,导出时则会针对推理做化简,还会插入大量transpose、reshape、split节点来匹配不同推理框架的要求。实践中我最多见的情况是:有人用torch.onnx.export默认配置导出的图,预处理和后处理节点特别多,以为自己网络结构画错了。其实先跑一下Ultralytics自带的yolo export命令,再在Netron里把opset相关选项调整一下,会清晰很多。所以我的建议是:画“论文用/教学用”结构图以源码yaml和forward代码为准,画“部署用”结构图以Netron里的实际节点为准,两套图不是一回事,不用强行对齐。
4.5 Concat的索引看错,连线画错层
在yaml的head部分,[[-1, 6], 1, Concat, [1]]里的6是backbone层的索引。不同小版本索引可能有差异,但规律一致。我在第3节已经演示过怎么读索引,这里再补一个容易踩的坑:第一次上采样后concat的是P4(40×40×128),第二次上采样后concat的是P3(80×80×64),而不要顺手就画成concat到第一个C2f的输出上。这两条线画错,整个Neck的融合逻辑就错了,而且光看shape可能发现不了问题,因为concat最终都被压缩回了预期通道数,shape层面看不出异常,只有回到yaml索引才能发现。
5. 结构图的最大价值:把它当成改进YOLOv8的作战地图
5.1 加小目标检测头,从哪个位置下手
很多人问“怎么加小目标检测头”,对着结构图就很好解释了。小目标通常在高分辨率特征图上更容易被检测,因此常见方案是再加一个stride=4的检测头,挂在更浅的特征上,比如把C2f_1(160×160×32)引出来,在Neck部分为它单独做一次上采样和融合,最后在Head部分新增一个输出支路。从结构图上看,改动就发生在“Backbone浅层出口”和“Head输入”两处,不会影响Backbone主干。不过要提醒一句:加头一定会带来额外的FLOPs和显存开销,而且并不是所有数据集都有足够多的小目标值得你加头,先统计一下数据里小目标占比再决定,别盲目加。
5.2 给Head加注意力机制,应该插在哪一层
注意力模块(SE、CBAM、CA等)在YOLOv8改进里很常见。从结构图上看,最稳妥的插入点是每个C2f输出之后、进入检测头之前。把它理解为“在送给检测头之前,先让网络重新标定一下哪些通道和空间位置更重要”。如果你把注意力硬塞进C2f内部,会打乱原本的密集连接和梯度路径,反而不如加在后面稳定。
5.3 换Backbone时,结构图怎么改最快
这几年流行换Backbone,比如用MobileNetV4或其他轻量骨干替代默认的C2f主干。从结构图角度,你只需要保证三点:新的Backbone能输出三个尺度的特征(stride=8/16/32)、三个尺度的特征shape要和你Neck入口对齐、通道数要匹配。结构图上就是整体替换第一段蓝色区域,绿色Neck和橙色Head保持不动。这也是为什么我一直强调画图要分颜色分区域——改模型时你一眼就能看出影响范围。
5.4 多路并发场景下,结构图怎么复用与评估
有读者做工厂缺陷检测,一个工位好几路摄像头并发跑YOLOv8。这种场景下模型结构本身没有变化,每路相机就是独立跑一份相同的结构图流程,但有两个点容易被低估:一是显存随并发路数线性叠加,像GTX 1660 Ti这种6GB卡跑v8n/s、batch size开小一点问题不大,跑l或x就要认真算显存;尤其是把模型部署到RK3588这类边缘设备时,多路并发很容易先撞显存/内存墙,而不是算力墙。二是真正的瓶颈往往不在网络推理,而在多路解码、预处理(letterbox)和后处理(NMS)的串联开销。建议把完整pipeline画成“摄像头输入→预处理→网络推理→后处理→输出”,你就能看清楚每路摄像头的时间花在哪,再决定是上硬件解码还是用多线程异步。
最后说一个我自己的小习惯。我的工作目录里永远放着一张SVG格式的YOLOv8结构图,每次要改网络或者排查问题,先把改动位置圈出来,再动代码。这张图不一定精致,但所有shape都是自己算过、跟Netron核对过的。如果你想真正把结构图用起来,建议也不要直接抄网图,按第3节的流程亲手画一张,画完你对整个网络的理解会上一个台阶。
本文还有配套的精品资源,点击获取