- 🍨 本文为🔗365天深度学习训练营中的学习记录博客
- 🍖 原作者:K同学啊 | 接辅导、项目定制
- 🚀 文章来源:K同学的学习圈子
目录
文件位置:./models/common.py
该文件是实现YOLOv5中各个模块的地方。
-
如果我们需要修改某一模块(例如C3),那么就需要修改这个文件中对应模块的的定义。
本周任务:
将YOLOv5s网络模型中的C3模块按照下图方式修改,并跑通YOLOv5。
任务提示:仅需修改./models/common.yaml文件。
C3模块修改方案
yolov5s网络结构图:
C3解读:
这个模块是一种简化版的BottleneckCSP,因为除了Bottleneck部分只有3个卷积,可以减少参数,所以取名C3。而作者之所以用C3来带代替BottleneckCSP也是有原因的,作者原话:
C3() is an improved version of CSPBottleneck(). lt is simpler, faster and and lighter with similar
performance and better fuse characteristics.
C3模块具体的结构如下所示:
C3模块代码:
class C3(nn.Module):
# CSP Bottleneck with 3 convolutions
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
''' 在C3RT模块和yolo.py的parse_model函数中被调用
:params c1: 整个C3的输入channel
:params c2: 整个C3的输出channel
:params n: 有n个子模块[Bottleneck/CrossConv]
:params shortcut: bool值,子模块[Bottlenec/CrossConv]中是否有shortcut,默认True
:params g: 子模块[Bottlenec/CrossConv]中的3x3卷积类型,=1普通卷积,>1深度可分离卷积
:params e: expansion ratio,e*c2=中间其它所有层的卷积核个数=中间所有层的的输入输出channel
'''
super().__init__()
c_ = int(c2 * e) # hidden channels
self.cv1 = Conv(c1, c_, 1, 1)
self.cv2 = Conv(c1, c_, 1, 1)
self.cv3 = Conv(2 * c_, c2, 1) # optional act=FReLU(c2)
self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))
# 实验性 CrossConv
#self.m = nn.Sequential(*[CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n)])
def forward(self, x):
return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1))
参数:
c1:整个BottleneckCSP的输入channel
c2:整个BottleneckCSP的输出channel
n:有n个Bottleneck
shortcut:bool Bottleneck中是否有shortcut连接,默认为True
g:表示从输入通道到输出通道的阻塞连接数。Bottleneck中的3x3卷积类型: =1就是普通卷积 >1就是深度可分离卷积
e:expansion ratio c2xe=中间其他所有层的卷积核个数/中间所有层的输入输出channel数
torch.cat((y1,y2), dim=1):这里是指定第11个维度上进行合并,即再channel维度上合并
c_:bottleneckCSP结构的中间层的通道数,由膨胀率e决定
开始修改代码:
根据C3修改方案意图我们可以得知,我们需要将C3模块中concat后的卷积层去掉,现在开始修改:
class C3(nn.Module):
# CSP Bottleneck with 3 convolutions
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
''' 在C3RT模块和yolo.py的parse_model函数中被调用
:params c1: 整个C3的输入channel
:params c2: 整个C3的输出channel
:params n: 有n个子模块[Bottleneck/CrossConv]
:params shortcut: bool值,子模块[Bottlenec/CrossConv]中是否有shortcut,默认True
:params g: 子模块[Bottlenec/CrossConv]中的3x3卷积类型,=1普通卷积,>1深度可分离卷积
:params e: expansion ratio,e*c2=中间其它所有层的卷积核个数=中间所有层的的输入输出channel
'''
super().__init__()
c_ = int(c2 * e) # hidden channels
self.cv1 = Conv(c1, c_, 1, 1)
self.cv2 = Conv(c1, c_, 1, 1)
self.cv3 = Conv(2 * c_, c2, 1) # optional act=FReLU(c2)
self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))
# 实验性 CrossConv
#self.m = nn.Sequential(*[CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n)])
def forward(self, x):
return torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1)
运行代码:
命令:python train.py --img 900 --batch 24 --epoch 100 --data data/ab.yaml --cfg models/yolov5s.yaml --weights yolov5s.pt
总结:
本次任务中,我先通读全篇,这先让我对common.py文件有了大致的理解,然后通过对C3模块的修改,让我更加清晰地明白代码内函数的使用及参数的设置。