- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊 | 接辅导、项目定制
- 🚀 文章来源:K同学的学习圈子
这部分挑选了几个比较重要的模块,其他可以查看我之前的文章https://blog.csdn.net/geo436872/article/details/134990833
YOLOv8中主要模块:
import math
import numpy as np
import torch
import torch.nn as nn
__all__ = (
"Conv",
"Conv2",
"LightConv",
"DWConv",
"DWConvTranspose2d",
"ConvTranspose",
"Focus",
"GhostConv",
"ChannelAttention",
"SpatialAttention",
"CBAM",
"Concat",
"RepConv",
)
Conv: 使用普通卷积操作的模块。
Conv2: 使用2D卷积操作的模块。
LightConv: 使用轻量级卷积操作的模块。
DWConv: Depth-wise卷积操作的模块。
DWConvTranspose2d: 反卷积操作的深度卷积模块。
ConvTranspose: 反卷积操作的普通卷积模块。
Focus: YOLOv4中的焦点机制模块,用于提升小物体检测精度。
GhostConv: 使用Ghost卷积操作的模块。
ChannelAttention: 通道注意力模块,用于增强卷积操作的通道特征重要性。
SpatialAttention: 空间注意力模块,用于增强卷积操作的空间特征重要性。
CBAM: 基于通道和空间注意力的CBAM模块,用于增强卷积操作的特征重要性。
Concat: 将多个特征图连接在一起的模块。
RepConv: 重复卷积操作的模块。
一、autopad
def autopad(k, p=None, d=1): # kernel, padding, dilation
"""Pad to 'same' shape outputs."""
if d > 1:
k = d * (k - 1) + 1 if isinstance(k, int) else [d * (x - 1) + 1 for x in k] # actual kernel-size
if p is None:
p = k // 2 if isinstance(k, int) else [x // 2 for x in k] # auto-pad
return p
autopad函数是用来进行自动填充(padding)的。它接受参数k(卷积核大小)、p(填充大小,默认为None)和d(扩张率,默认为1)。
函数首先判断扩张率d是否大于1,如果是的话,计算实际的卷积核大小k。如果k为整数,则实际的卷积核大小为d * (k - 1) + 1;如果k是一个列表,则分别计算每个元素的实际卷积核大小。
接下来,如果填充大小p为None,则根据卷积核大小k计算自动填充大小。如果k是整数,则自动填充大小为k // 2;如果k是一个列表,则分别计算每个元素的自动填充大小。
最后,函数返回填充大小p。
二、Conv
class Conv(nn.Module):
"""Standard convolution with args(ch_in, ch_out, kernel, stride, padding, groups, dilation, activation)."""
default_act = nn.SiLU() # default activation
def __init__(self, c1, c2, k=1, s=1, p=None, g=1, d=1, act=True):
"""Initialize Conv layer with given arguments including activation."""
super().__init__()
self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p, d), groups=g, dilation=d, bias=False)
self.bn = nn.BatchNorm2d(c2)
self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()
def forward(self, x):
"""Apply convolution, batch normalization and activation to input tensor."""
return self.act(self.bn(self.conv(x)))
def forward_fuse(self, x):
"""Perform transposed convolution of 2D data."""
return self.act(self.conv(x))
这是一个标准的卷积操作的类Conv,它继承自nn.Module。该类接受参数ch_in(输入通道数)、ch_out(输出通道数)、kernel(卷积核大小)、stride(步长)、padding(填充)、groups(分组卷积数)、dilation(扩张率)和activation(是否使用激活函数)。
在初始化方法__init__中,该类定义了一个2D卷积层conv,使用给定的参数进行配置。同时,还定义了一个批量归一化层bn来规范化输出特征图,并通过default_act属性定义了默认的激活函数nn.SiLU()。如果act为True,则使用默认激活函数;如果act是nn.Module类型的实例,则使用该实例作为激活函数;否则,使用nn.Identity()作为激活函数。
在前向传播方法forward中,该类对输入特征图应用了卷积操作、批量归一化和激活函数,然后返回处理后的输出。
三、Focus
class Focus(nn.Module):
"""Focus wh information into c-space."""
def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):
"""Initializes Focus object with user defined channel, convolution, padding, group and activation values."""
super().__init__()
self.conv = Conv(c1 * 4, c2, k, s, p, g, act=act)
# self.contract = Contract(gain=2)
def forward(self, x):
"""
Applies convolution to concatenated tensor and returns the output.
Input shape is (b,c,w,h) and output shape is (b,4c,w/2,h/2).
"""
return self.conv(torch.cat((x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]), 1))
# return self.conv(self.contract(x))
这段代码定义了一个名为Focus的类,用于将宽高信息聚焦到通道维度上。
在__init__方法中,这个模块接受一些参数,包括输入通道数c1,输出通道数c2,卷积核大小k,步长s,填充p,分组数g和是否应用激活函数act。然后,它创建一个卷积层对象self.conv,该层的输入通道数是输入通道数c1乘以4,输出通道数是c2。
在forward方法中,模块的实际操作是将输入的特征图x进行分块,并通过torch.cat函数在通道维度上进行拼接。然后,将拼接后的特征图输入到之前创建的卷积层self.conv中进行卷积操作。最后,返回卷积操作后得到的特征图作为模块的输出。
四、C2f
此模块在block.py中。
class C2f(nn.Module):
"""Faster Implementation of CSP Bottleneck with 2 convolutions."""
def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5):
"""Initialize CSP bottleneck layer with two convolutions with arguments ch_in, ch_out, number, shortcut, groups,
expansion.
"""
super().__init__()
self.c = int(c2 * e) # hidden channels
self.cv1 = Conv(c1, 2 * self.c, 1, 1)
self.cv2 = Conv((2 + n) * self.c, c2, 1) # optional act=FReLU(c2)
self.m = nn.ModuleList(Bottleneck(self.c, self.c, shortcut, g, k=((3, 3), (3, 3)), e=1.0) for _ in range(n))
def forward(self, x):
"""Forward pass through C2f layer."""
y = list(self.cv1(x).chunk(2, 1))
y.extend(m(y[-1]) for m in self.m)
return self.cv2(torch.cat(y, 1))
def forward_split(self, x):
"""Forward pass using split() instead of chunk()."""
y = list(self.cv1(x).split((self.c, self.c), 1))
y.extend(m(y[-1]) for m in self.m)
return self.cv2(torch.cat(y, 1))
这段代码实现了名为C2f的PyTorch模块,是CSP Bottleneck的一种快速实现。它由两个卷积层组成,并包含一些参数用于定制模块的行为。
在初始化方法中,参数c1表示输入的通道数,c2表示输出的通道数,n表示重复的次数,shortcut表示是否使用shortcut连接,g表示分组数,e表示扩展因子。根据输出通道数c2和扩展因子e计算得到隐藏通道数self.c。接着定义了两个卷积层cv1和cv2,cv1将输入通道数c1变换为2*self.c个通道,cv2将(2+n)*self.c个通道变换为c2个通道。最后,通过nn.ModuleList创建了一个包含n个Bottleneck模块的列表m。
在前向传播方法forward中,首先通过cv1对输入x进行卷积操作,并使用chunk函数将结果分成两部分。然后,将第一部分作为输入,通过n个Bottleneck模块进行重复操作,并将每个模块的输出结果添加到列表y中。最后,将y中的结果沿着通道维度拼接起来,并通过cv2进行最终的卷积操作,得到最终的输出。
与forward方法类似,前向传播方法forward_split也是对输入进行卷积操作,并使用split函数将结果按照self.c进行切分。然后,通过n个Bottleneck模块进行重复操作,并将每个模块的输出结果添加到列表y中。最后,将y中的结果沿着通道维度拼接起来,并通过cv2进行最终的卷积操作,得到最终的输出。
C2f模块的作用是在CSP Bottleneck中起到加强特征表达能力的作用,并提高网络的计算效率。通过堆叠多个Bottleneck模块和合适的连接方式,可以构建更强大、更高效的神经网络模型来应对各种图像处理任务。