yolov8学习笔记
cbs:
c指conv,卷积层,当 stride=1 且 padding=k//2(如YOLOv8中常用配置)时,空间尺寸保持不变,当 stride=2 时,空间尺寸减半(如YOLOv8的下采样层)。卷积层的核心作用是提取局部特征,其空间尺寸可能保持不变或缩小,但不会主动增大。
b指bn,归一化,对每个批次的数据在通道维度上进行标准化意思是规范化,更规范,防止梯度爆炸(深度神经网络训练过程中,反向传播的梯度值变得异常大,导致参数更新幅度过大,模型无法收敛)公式为:

- μ 和 σ2 是当前批次在通道维度上的均值和方差。
- γ 和 β 是可学习参数,用于恢复数据分布。
BN的作用是缓解内部协变量偏移,加速训练收敛,但不保证数值范围在[0,1]
s指激活函数,为网络引入非线性特性,帮助模型学习复杂的特征映射关系。yolov8中的默认激活函数:SiLU(Swish),

YOLOv8的骨干网络(Backbone)和特征金字塔(Neck)中的C2f模块默认使用SiLU。如果不使用激活函数,则每一层的输入直接是上一层的输出,这样就是最原始的感知机。引入激活函数,在每一层的数据传递会引入非线性变换,这样神经网络会引入众多非线性模型。
yolov8各层作用:
1. Conv 层(标准卷积层)
通俗解释:
像流水线上的基础加工站,对输入的图像特征进行基础加工(提取边缘/纹理等),包含卷积、归一化和激活函数三步操作。类似用不同滤镜扫描照片提取特征。
专业解释:
实现特征的空间维度变换和通道维度变换。通过卷积核权重学习局部特征,BatchNorm 加速收敛并提升泛化能力,SiLU 激活函数引入非线性。公式:Output = SiLU( BatchNorm( Conv(Input) )
源码:
class Conv(nn.Module):
def __init__(self, c1, c2, k=3, s=1): # 输入通道, 输出通道, 卷积核, 步长
super().__init__()
self.conv = nn.Conv2d(c1, c2, k, s, padding=k//2, bias=False)
self.bn = nn.BatchNorm2d(c2)
self.act = nn.SiLU() # 激活函数
def forward(self, x):
return self.act(self.bn(self.conv(x)))
示例:
输入 224x224x3 的图片,经过 Conv(3, 64, k=7, s=2) 后输出 112x112x64 的特征图。
各组件解析:
-
self.conv:PyTorch 的 2D 卷积层-
nn.Conv2d(c1, c2, k, s):创建卷积核 -
c1:输入通道数(如RGB图像为3) -
c2:输出通道数(特征图数量) -
k:卷积核尺寸(默认3×3) -
s:步长(默认1) -
padding=k//2:填充保证尺寸不变(如k=3时填充1) -
bias=False:禁用偏置(因BatchNorm已有偏移参数)
-
-
self.bn:批标准化层-
nn.BatchNorm2d(c2):对每个通道独立标准化 -
作用:加速收敛,减少内部协变量偏移
-
公式:$y = \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} \times \gamma + \beta$
-
-
self.act:激活函数-
nn.SiLU():Sigmoid Linear Unit -
公式:$SiLU(x) = x \cdot \sigma(x)$
-
特点:平滑非饱和激活,优于ReLU
-
2. C2f 层(梯度分流瓶颈层)
通俗解释:
像分叉-合并的流水线:
-
将输入特征拆成两份(如原料分两路)
-
主路直接传输(保留原始特征)
-
支路通过多个Bottleneck加工(深度加工)
-
最后合并两路结果,获得更丰富的特征
专业解释:
CSPNet 的改进版,通过特征分流缓解梯度消失:
-
输入特征拆分为两部分(
split(1, dim=1)) -
主路保留浅层特征(Identity)
-
支路经
n个 Bottleneck 模块提取深层特征 -
拼接后融合(增强特征复用)
源码:
class C2f(nn.Module):
def __init__(self, c1, c2, n=1): # 输入/输出通道, Bottleneck数量
super().__init__()
self.c = c2 // 2 # 拆分通道数
self.cv1 = Conv(c1, 2 * self.c, 1) # 拆分前的1x1卷积
self.cv2 = Conv((2 + n) * self.c, c2, 1) # 合并后的1x1卷积
self.m = nn.ModuleList(Bottleneck(self.c, self.c) for _ in range(n))
def forward(self, x):
y = list(self.cv1(x).chunk(2, 1) # 拆分为两部分 [A, B]
y.extend(m(y[-1]) for m in self.m) # B通过n个Bottleneck
return self.cv2(torch.cat(y, 1)) # 拼接[A, B, Bottleneck输出]
执行流程:
-
特征拆分:
-
self.cv1(x):1×1卷积将通道扩展为2c -
.chunk(2, 1):沿通道维度拆分为两个c通道张量[A, B]
-
-
Bottleneck处理:
-
B分支通过n个串联的Bottleneck
-
每个Bottleneck处理前一个的输出
-
结果保存到列表y中
-
-
特征融合:
-
torch.cat(y, 1):拼接所有特征(原始A + 原始B + n个Bottleneck输出) -
self.cv2:1×1卷积调整通道数到c2
-
维度变化示例:
输入:56×56×128 (c1=128)
-
cv1:56×56×256 (2c, c=c2//2=64)
-
拆分:两个56×56×64张量
-
3个Bottleneck:生成3个56×56×64张量
-
拼接:56×56×(64×5)=56×56×320
-
cv2:56×56×128 (c2=128)
3. SPPF 层(空间金字塔快速池化)
通俗解释:
用三种不同尺寸的筛子同时筛选特征:
-
对同一特征图分别做 5x5/9x9/13x13 的池化
-
将不同尺度的池化结果与原图拼接
-
融合后获得多尺度特征(适应不同大小物体)
专业解释:
SPP 的加速版,通过重复使用池化层减少计算量:
-
单次最大池化(kernel=5, padding=2)等效于多尺度池化
-
级联三次池化输出:
[原始特征, 池化1次, 池化2次, 池化3次] -
融合多尺度信息提升感受野
源码:
class SPPF(nn.Module):
def __init__(self, c1, c2, k=5): # 输入/输出通道, 池化核
super().__init__()
self.cv1 = Conv(c1, c1//2, 1) # 通道压缩
self.cv2 = Conv(c1*2, c2, 1) # 通道恢复
self.pool = nn.MaxPool2d(k, stride=1, padding=k//2)
def forward(self, x):
x = self.cv1(x)
y1 = self.pool(x)
y2 = self.pool(y1)
y3 = self.pool(y2)
return self.cv2(torch.cat([x, y1, y2, y3], 1))
关键点解析:
-
池化层重用:
-
单池化层重复使用3次(而非SPP的3个独立池化层)
-
计算量减少约50%,速度提升
-
-
多尺度融合:
-
原始特征:感受野1×1
-
1次池化:感受野5×5
-
2次池化:感受野9×9
-
3次池化:感受野13×13
-
-
通道控制:
-
cv1:压缩通道减少计算量 -
cv2:恢复通道整合特征
-
4.Bottleneck 模块解析
源码:
class Bottleneck(nn.Module):
def __init__(self, c1, c2, shortcut=True, g=1, e=0.5):
super().__init__()
c_ = int(c2 * e) # 中间层通道数
self.cv1 = Conv(c1, c_, 1, 1) # 1×1卷积压缩
self.cv2 = Conv(c_, c2, 3, 1, g=g) # 3×3卷积
self.add = shortcut and c1 == c2 # 是否使用残差连接
def forward(self, x):
return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))
核心设计:
-
通道压缩:1×1卷积减少通道数($c_2 \times e$)
-
特征提取:3×3卷积处理压缩后的特征
-
残差连接:当输入输出通道相同时,添加跳跃连接
输入 x (n×c1×h×w)
│
↓
[1×1卷积] → 降维到 c_ 通道
│
↓
[3×3卷积] → 恢复 c2 通道
│
├──────────────┐ (当 add=True 且 c1=c2)
↓ ↓
[元素级加法] → 输出
更多推荐


所有评论(0)