尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

保姆级拆解:YOLOv5s的Backbone、Neck、Head到底在干什么?附代码逐行解读

保姆级拆解:YOLOv5s的Backbone、Neck、Head到底在干什么?附代码逐行解读 从零解剖YOLOv5三明治结构如何吃掉像素吐出检测框第一次打开YOLOv5的PyTorch实现时那些backbone、neck、head的模块名就像餐厅后厨的暗号——我们知道它们在协作生产目标检测这道菜但砧板上的肉块如何变成盘中餐本文将用手术刀级别的拆解配合可运行的代码片段带你穿透抽象术语直面数据流动的真相。我们以yolov5s为例看看这个三明治模型如何将原始图像层层加工最终输出带着坐标和类别的检测框。1. 后厨准备理解YOLOv5的流水线架构想象你走进一家汉堡店点单台输入接过你的订单后后厨分三个工区协作Backbone切菜工区把原始食材像素处理成标准化的食材块特征图Neck酱料调配台将不同粗细的食材混合调味多尺度特征融合Head组装流水线把处理好的食材压制成标准汉堡预测框生成# 模型结构直观映射对应models/yolov5s.yaml model Model( backboneBackbone(), # 特征提取车间 neckNeck(), # 特征调配中心 headHead() # 检测结果出厂线 )这个比喻对应到技术实现上模块技术职责相当于餐厅的Backbone降维/抽象图像特征食材预处理工区Neck混合不同抽象层次的特征酱料调配台Head输出坐标类别预测汉堡组装流水线2. 切菜工区Backbone如何榨取图像精华Backbone的本质是特征蒸馏器——把2240x2240像素以640x640输入为例压缩成20x20的特征图同时提炼出语义信息。其核心是三个关键操作2.1 卷积块的榨汁原理每个Conv模块像榨汁机一样执行榨取3x3卷积核滑动挤压局部特征标准化BN层统一果汁浓度特征分布调味SiLU激活决定保留哪些风味class Conv(nn.Module): def __init__(self, c1, c2, k3, s1): super().__init__() self.conv nn.Conv2d(c1, c2, k, s, paddingk//2, biasFalse) self.bn nn.BatchNorm2d(c2) self.act nn.SiLU() # 比ReLU更柔和的激活 def forward(self, x): return self.act(self.bn(self.conv(x))) # 榨汁→标准化→调味2.2 C3模块的流水线优化C3模块是Backbone的骨干其创新在于跨阶段部分连接CSP设计class C3(nn.Module): def __init__(self, c1, c2, n1): super().__init__() c_ c1 // 2 # 通道数减半 self.cv1 Conv(c1, c_, 1) # 分流路径 self.cv2 Conv(c1, c_, 1) self.m nn.Sequential(*(Bottleneck(c_, c_) for _ in range(n))) self.cv3 Conv(2 * c_, c2, 1) # 合并分支 def forward(self, x): y1 self.m(self.cv1(x)) # 主路径加工 y2 self.cv2(x) # 旁路直连 return self.cv3(torch.cat((y1, y2), 1)) # 特征拼接这种结构让梯度流动更顺畅就像餐厅设立备菜通道避免主厨台拥堵。2.3 SPPF的空间金字塔榨取SPPF空间金字塔池化快速版是Backbone的榨汁终极技用不同尺寸的池化核5x5,9x9,13x13并行处理捕获从局部到全局的多粒度特征class SPPF(nn.Module): def __init__(self, c1, c2): super().__init__() c_ c1 // 2 self.cv1 Conv(c1, c_, 1) self.pool nn.MaxPool2d(5, 1, 2) # 滑动窗口榨取 self.cv2 Conv(c_ * 4, c2, 1) def forward(self, x): x self.cv1(x) y1 x y2 self.pool(y1) y3 self.pool(y2) y4 self.pool(y3) return self.cv2(torch.cat((y1, y2, y3, y4), 1)) # 多尺度混合3. 酱料调配台Neck如何调制特征鸡尾酒Neck要解决的核心矛盾是大目标需要抽象特征小目标需要细节特征。YOLOv5采用PANet结构其工作流程像调制鸡尾酒自顶向下将深层语义特征像糖浆一样向下渗透自底向上将浅层细节特征像气泡水向上翻腾# PANet的特征融合示意简化版 def forward(self, x): p5 self.backbone(x) # 最抽象的特征 p4 self.upsample(p5) p4 # 糖浆下沉 p3 self.upsample(p4) p3 # 继续渗透 p3 self.downsample(p3) # 气泡上升 p4 self.downsample(p4) p4 # 混合搅拌 return [p3, p4, p5] # 三色鸡尾酒实际代码中这个调制过程通过精心设计的卷积块实现操作实现方式作用上采样nn.Upsample(scale_factor2)放大特征图尺寸下采样Conv(s2)缩小特征图尺寸特征相加torch.add()混合不同层次特征通道调整1x1卷积统一通道数便于融合4. 组装流水线Head如何包装检测结果Head的工作可以类比麦当劳的汉堡包装机分拣区分食材类别分类分支塑形调整汉堡尺寸回归分支质检淘汰不合格品NMS过滤4.1 锚框——标准包装盒YOLOv5预设了9种锚框anchor就像不同尺寸的汉堡盒# yolov5s的默认锚框配置px anchors [ [10,13, 16,30, 33,23], # P3/8 小目标 [30,61, 62,45, 59,119], # P4/16 中目标 [116,90, 156,198, 373,326] # P5/32 大目标 ]4.2 预测头的双通道输出每个检测头同时输出分类置信度80维向量COCO数据集类别数框坐标4维向量中心点宽高调整量class Detect(nn.Module): def __init__(self, nc80): super().__init__() self.m nn.ModuleList(nn.Conv2d(x, (5 nc) * 3, 1) for x in [256, 512, 1024]) def forward(self, x): return torch.cat([m(feature).view(feature.size(0), 3, 5 self.nc, -1) for m, feature in zip(self.m, x)], 2)4.3 后处理——质量抽检非极大值抑制NMS像质检员剔除重复检测def non_max_suppression(prediction, conf_thres0.25, iou_thres0.45): # 1. 过滤低置信度检测 mask prediction[..., 4] conf_thres prediction prediction[mask] # 2. 计算框间IoU boxes prediction[:, :4] scores prediction[:, 4] ious box_iou(boxes, boxes) # 3. 抑制重叠框 keep torch.ones(len(prediction)).bool() for i in range(len(prediction)-1): if keep[i]: overlap ious[i] iou_thres keep[overlap] False return prediction[keep]5. 完整流水线演示从图像到检测框让我们用代码串联整个处理流程# 实例化模型 model torch.hub.load(ultralytics/yolov5, yolov5s) # 前向传播演示 def detect(image): # 1. Backbone处理 x model.backbone(image) # 特征提取 # 2. Neck处理 features model.neck(x) # 特征融合 # 3. Head处理 preds model.head(features) # 原始预测 # 4. 后处理 results non_max_suppression(preds) return results这个过程中数据的形态变化如下阶段数据形状说明输入图像[1,3,640,640]批大小1RGB三通道640x640Backbone输出[1,1024,20,20]高维特征空间分辨率降低Neck输出[1,256,80,80]等多尺度特征图Head输出[1,25200,85]25200个预测框每个85维最终输出[n,6]n个检测框每行包含xyxy置信度类别理解这个数据流动过程后当看到YOLOv5的检测结果时你就能在脑海中重建像素是如何被层层加工成检测框的。这就像知道汉堡的制作工序后咬下的每一口都能尝出背后的工艺细节。
返回列表