赞
踩
最近比较火的可变形卷积(Deformable Convolutional Networks(DCN))被称为目标检测改进网络结构的中涨点神器,确实在yolov8中加入DCN3可以涨3到4个点,尤其是它对小目标检测效果较好。下面是对DCNv2添加记录一下
首先我们要在nn/models/文件夹下block.py文件中加入以下代码
- class DCNv2(nn.Module):
- def __init__(self, in_channels, out_channels, kernel_size, stride=1,
- padding=1, dilation=1, groups=1, deformable_groups=1):
- super(DCNv2, self).__init__()
-
- self.in_channels = in_channels
- self.out_channels = out_channels
- self.kernel_size = (kernel_size, kernel_size)
- self.stride = (stride, stride)
- self.padding = (padding, padding)
- self.dilation = (dilation, dilation)
- self.groups = groups
- self.deformable_groups = deformable_groups
-
- self.weight = nn.Parameter(
- torch.empty(out_channels, in_channels, *self.kernel_size)
- )
- self.bias = nn.Parameter(torch.empty(out_channels))
-
- out_channels_offset_mask = (self.deformable_groups * 3 *
- self.kernel_size[0] * self.kernel_size[1])
- self.conv_offset_mask = nn.Conv2d(
- self.in_channels,
- out_channels_offset_mask,
- kernel_size=self.kernel_size,
- stride=self.stride,
- padding=self.padding,
- bias=True,
- )
- self.bn = nn.BatchNorm2d(out_channels)
- self.act = Conv.default_act
- self.reset_parameters()
-
- def forward(self, x):
- offset_mask = self.conv_offset_mask(x)
- o1, o2, mask = torch.chunk(offset_mask, 3, dim=1)
- offset = torch.cat((o1, o2), dim=1)
- mask = torch.sigmoid(mask)
- x = torch.ops.torchvision.deform_conv2d(
- x,
- self.weight,
- offset,
- mask,
- self.bias,
- self.stride[0], self.stride[1],
- self.padding[0], self.padding[1],
- self.dilation[0], self.dilation[1],
- self.groups,
- self.deformable_groups,
- True
- )
- x = self.bn(x)
- x = self.act(x)
- return x
-
- def reset_parameters(self):
- n = self.in_channels
- for k in self.kernel_size:
- n *= k
- std = 1. / math.sqrt(n)
- self.weight.data.uniform_(-std, std)
- self.bias.data.zero_()
- self.conv_offset_mask.weight.data.zero_()
- self.conv_offset_mask.bias.data.zero_()
-
-
- class Bottleneck_DCN(nn.Module):
- # Standard bottleneck with DCN
- def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 3), e=0.5): # ch_in, ch_out, shortcut, groups, kernels, expand
- super().__init__()
- c_ = int(c2 * e) # hidden channels
- if k[0] == 3:
- self.cv1 = DCNv2(c1, c_, k[0], 1)
- else:
- self.cv1 = Conv(c1, c_, k[0], 1)
- if k[1] == 3:
- self.cv2 = DCNv2(c_, c2, k[1], 1, groups=g)
- else:
- self.cv2 = Conv(c_, c2, k[1], 1, g=g)
- 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))
-
-
- class C2f_DCN(nn.Module):
- # CSP Bottleneck with 2 convolutions
- def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5): # 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_DCN(self.c, self.c, shortcut, g, k=(3, 3), e=1.0) for _ in range(n))
-
- def forward(self, x):
- 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))
然后在tasks.py文件
这三处()里都加上C2f_DCN,接着在modules文件夹下的__init__.py
来declare一下,否则会导入失败,至此已经差不多就ok了,现在只需要在yaml中你想要更改的网络结构的地方改一下就行,然后就可以训练了,如果不确定可以在训练的时候看一下print的网络结构即可。
下面是DCNv3的代码,操作跟上述有些不同,需要去GitHub上下载ops_dcnv3模块,然后进行编译,具体怎么弄可以私信我,如果我有时间的话,因为DCNv3配置起来还是比较麻烦的
- class DCNV3_YoLo(nn.Module):
- def __init__(self, inc, ouc, k=1, s=1, p=None, g=1, d=1, act=True):
- super().__init__()
-
- self.conv = Conv(inc, ouc, k=1)
- self.dcnv3 = DCNv3(ouc, kernel_size=k, stride=s, group=g, dilation=d)
- self.bn = nn.BatchNorm2d(ouc)
- self.act = Conv.default_act
-
- def forward(self, x):
- x = self.conv(x)
- x = x.permute(0, 2, 3, 1)
- x = self.dcnv3(x)
- x = x.permute(0, 3, 1, 2)
- x = self.act(self.bn(x))
- return x
-
- class Bottleneck_DCNV3(nn.Module):
- # Standard bottleneck
- def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 3), e=0.5): # ch_in, ch_out, shortcut, groups, kernels, expand
- super().__init__()
- c_ = int(c2 * e) # hidden channels
- self.cv1 = Conv(c1, c_, k[0], 1)
- self.cv2 = DCNV3_YoLo(c_, c2, k[1], 1, g=g)
- 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))
-
- class DCNV3(nn.Module):
- # CSP Bottleneck with 2 convolutions
- def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5): # 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_DCNV3(self.c, self.c, shortcut, g, k=(3, 3), e=1.0) for _ in range(n))
-
- def forward(self, x):
- 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):
- 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))
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。