[修改记录]为yolov5-5.0增加解耦头

逛博客的时候发现了很多关于yolov5的改进建议,看中了有些博主提出的为yolov5增加解耦头的改进方法,便想着用到自己下载的yolov5版本中看看最后的情况。但是这种增加解耦头的方式很多评论区的人说使用了这个解耦头后训练的map涨点了,但是detect的结果并不好,且训练的稳定度不高,我不太知道具体的情况是啥样的,但想着去试一试吧,就对我下载的yolov5进行了修改。修改过程如下:

首先在common.py文件中新增加了一个类,类名叫做DecoupledHead。具体的代码如下所示:

#---------------自己添加的DecoupledHead函数--------------------------------
class DecoupledHead(nn.Module):def __init__(self, ch=256, nc=80, anchors=()):super(DecoupledHead, self).__init__()self.nc = nc #识别的种类self.nl = len(anchors)  #层数self.na = len(anchors[0]) // 2self.merge = Conv(ch, 256,1, 1)self.cls_convs1 = Conv(256, 256, 3, 1, 1)self.cls_convs2 = Conv(256, 256, 3, 1, 1)self.reg_convs1 = Conv(256, 256, 3, 1, 1)self.reg_convs2 = Conv(256, 256, 3, 1, 1)self.cls_preds = nn.Conv2d(256, self.nc * self.na, 1)self.reg_preds = nn.Conv2d(256, 4 * self.na, 1)self.obj_preds = nn.Conv2d(256, 1 * self.na, 1)def forward(self,x):x = self.merge(x)x1 = self.cls_convs1(x)x1 = self.cls_convs2(x1)x1 = self.cls_preds(x1)x2 = self.reg_convs1(x)x2 = self.reg_convs2(x2)x21 = self.reg_preds(x2)x22 = self.obj_preds(x2)out = torch.cat([x21, x22, x1], 1)return out#---------------------自己添加的DecoupledHead----------------------

然后再对yolo.py文件进行修改,修改的地方有以下两处:

1.对model类进行修改,可通过Ctrl+F的形式定位到这一部分,修改的主要部分代码如下:

# Build strides, anchorsm = self.model[-1]  # Detect()#if isinstance(m, Detect):if isinstance(m, Detect) or isinstance(m, Decoupled_Detect): #该句为自己添加的,替换上一句用于给网络添加解耦头用的s = 256  # 2x min stride#m.inplace = self.inplace  #该句为自己添加,用于给网络增加解耦头用,这句不可用,添加之后会报错,不知道是不是yolo版本的问题。m.stride = torch.tensor([s / x.shape[-2] for x in self.forward(torch.zeros(1, ch, s, s))])  # forwardcheck_anchor_order(m)  #must be in pixel-space (not grid-space) 该句为自己添加,用于给网络增加解耦头用m.anchors /= m.stride.view(-1, 1, 1)check_anchor_order(m)self.stride = m.stride#self._initialize_biases()  # only run once,添加解耦头时需要将这句注释掉# print('Strides: %s' % m.stride.tolist())#-----------------try 部分为自己添加,用于给网络增加解耦头用----------------try :self._initialize_biases() # only run oncelogger.info('initialize_biases done')except :logger.info('decoupled no biase')#-----------------try 部分为自己添加,用于给网络增加解耦头用--------------------# Init weights, biasesinitialize_weights(self)self.info()logger.info('')

2.修改parse_model里的以下部分,也可通过查找的方式找到,修改的部分后面带有注释,代码如下:

 if m in [Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, DWConv, MixConv2d, Focus, CrossConv, BottleneckCSP,C3, C3TR, GSConv, VoVGSCSP]:#GSConv、VoVGSCSP是自己添加的类名c1, c2 = ch[f], args[0]if c2 != no:  # if not outputc2 = make_divisible(c2 * gw, 8)args = [c1, c2, *args[1:]]if m in [BottleneckCSP, C3, C3TR, VoVGSCSP]: #VoVGSCSP是自己添加进去的类名,这里要不要加入GSConv类名还不知道args.insert(2, n)  # number of repeatsn = 1elif m is nn.BatchNorm2d:args = [ch[f]]elif m is Concat:c2 = sum([ch[x] for x in f])#elif m is Concat_bifpn:   #自己添加的,用于给网络增加解耦头用#c2 = max([ch[x] for x in f])   #自己添加的,用于给网络增加解耦头用elif m is Detect:args.append([ch[x] for x in f])if isinstance(args[1], int):  # number of anchorsargs[1] = [list(range(args[1] * 2))] * len(f)elif m is Decoupled_Detect:  #自己添加的,用于给网络增加解耦头args.append([ch[x] for x in f])    #自己添加的,用于给网络增加解耦头if isinstance(args[1], int):       #自己添加的,用于给网络增加解耦头args[1] = [list(range(args[1] * 2))] * len(f)     #自己添加的,用于给网络增加解耦头elif m is Contract:c2 = ch[f] * args[0] ** 2elif m is Expand:c2 = ch[f] // args[0] ** 2else:c2 = ch[f]

另外,还需要在yolo.py文件中增加一个类,类名为:Decoupled_Detect,里面被注释掉的有一个check_version函数,我在编写的时候这个函数报错了,好像是因为没有给这个函数定义,我寻思着应该是我用的是5.0版本的原因,然后看了下它的主要作用是判断torch的版本是否大于了1.10,于是我结合我的torch版本给它注释掉了,只是一个小尝试,最后的结果是代码可运行,但注释掉了会不会对后续的识别精度等产生深远的影响还未知。代码如下:

#-----------------------自己添加的Decoupled_Detcet-----------------------
class Decoupled_Detect(nn.Module):stride = None  #strides computed during buildonnx_dynamic = False  #ONNX export parameterexport = False  # export modedef __init__(self, nc=80, anchors=(), ch=(), inplace=True):  # detection layersuper(Decoupled_Detect, self).__init__()self.nc = nc  #分类的数量self.no = nc + 5self.nl = len(anchors)self.na = len(anchors[0]) // 2self.grid = [torch.zeros(1)] * self.nlself.anchor_grid = [torch.zeros(1)] * self.nlself.register_buffer('anchors', torch.tensor(anchors).float().view(self.nl, -1, 2)) #shape(nl,na,2)self.m = nn.ModuleList(DecoupledHead(x, nc, anchors) for x in ch)self.inplace = inplace  # ues in-place ops (e.g. slice assignment)def forward(self, x):z = []for i in range(self.nl):x[i] = self.m[i](x[i])bs, _, ny, nx = x[i].shape #x(bs,255,20,20) to x(bs,3,20,20,85)x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous()if not self.training:if self.onnx_dynamic or self.grid[i].shape[2:4] != x[i].shape[2:4]:self.grid[i],self.anchor_grid[i] = self._make_grid(nx, ny, i)y = x[i].sigmoid()if self.inplace:y[..., 0:2] = (y[..., 0:2] * 2 + self.grid[i]) * self.stride[i] #xyy[..., 2:4] = (y[...,2:4] * 2) ** 2 * self.anchor_grid[i] #whelse:xy, wh, conf = y.split((2, 2, self.nc + 1), 4) #y.tensor_split((2, 4, 5), 4)  #torch 1.8.0xy = (xy * 2 + self.grid[i]) * self.stride[i]  #xywh = (wh * 2) ** 2 * self.anchor_grid[i]y = torch.cat((xy, wh, conf), 4)z.append(y.view(bs, -1, self.no))return x if self.training else (torch.cat(z, 1),) if self.export else (torch.cat(z, 1), x)def _make_grid(self, nx=20, ny=20, i=0):d = self.anchors[i].devicet = self.anchros[i].dtypeshape = 1, self.na, ny, nx, 2  #grid shapey, x = torch.arange(ny, device=d, dtype=t), torch.arange(nx, device=d, dtype=t)#if check_version(torch.__version__, '1.10.0'):#yv, xv = torch.meshgrid(y, x, indexing='ij')#else:yv, xv = torch.meshgrid(y, x) #这里只是一个小尝试,用于解决没有check_versiongrid = torch.stack((xv, yv), 2).expand(shape) - 0.5  #add grid offset, i.e. y = 2.0 * x - 0.5anchor_grid = (self.anchors[i] * self.stride[i]).view((1, self.na, 1, 1, 2)).expand(shape)return grid, anchor_grid#------------------------自己添加的Decoupled_Detcet函数,用于给网络添加解耦头用--------------------------------

最后一步就是修改模型的yaml文件了


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部