YOLOv7模型结构及使用环境

释放双眼,带上耳机,听听看~!
该文章介绍了YOLOv7模型的使用环境和结构,包括常规服务器、边缘服务器和云服务器的使用情况,以及模型结构中的CBS和ELAN模块。

本文正在参加 人工智能创作者扶持计划

本文中的框架图为作者本人绘制,如需转载或借鉴,注明链接即可!

1. YOLOv7使用环境

  • 常规服务器:

yolov7

yolov7-x:对yolov7使用了复合的模型缩放方法来扩大了整个模型的深度和宽度。

  • 边缘服务器:

yolov7-tiny:使用Leaky ReLU激活函数。

yolov7-tiny-silu:使用SiLU激活函数。

  • 云服务器:

yolov7-w6

yolov7-d6和yolov7-e6:对yolov7-w6使用了复合的模型缩放方法来扩大了整个模型的深度和宽度。

yolov7-e6e:对yolov7-e6用E-ELAN替代ELAN。

2. 模型结构

本模型结构以yolov7.yaml讲解为主,其他模型结构作为对比学习。我不会对下面的具体结构进行输出的说明,意为希望看到这些结构时,自己看着yaml和py文件推导一下,并不难的。

因此绘制yolov7.yaml模型结构,如下图:

YOLOv7模型结构及使用环境

yolov7.yaml模型结构

2.1 CBS模块

CBS=Conv+BN+SiLU

Conv即一个CBS模块,其中 [32, 3, 1] 表示[channel,kernel,stride]。根据公式推导,kernel=3,stride=1 不会改变输入的长宽,kernel=3,stride=2 输入的长宽变成一半。

SiLU激活函数:是Swish激活函数的变体,更好地处理梯度消失和非线性表达能力,与传统的ReLU函数相比,SiLU函数在保持计算速度的同时,能够提高模型的泛化性能和准确率。

silu(x)=x⋅sigmoid(x)silu(x)=x⋅sigmoid(x)

#在文件yolov7.yaml中

[-1, 1, Conv, [32, 3, 1]],  # 0
 [-1, 1, Conv, [64, 3, 2]],  # 1-P1/2      
 [-1, 1, Conv, [64, 3, 1]],
 [-1, 1, Conv, [128, 3, 2]],  # 3-P2/4

2.2 ELAN模块

经过ELAN模块最终进行简单的channel拼接,不会改变输入的长宽,只会改变深度。

ELAN模块通过控制最短和最长的梯度路径,深层网络可以有效地学习和收敛,并且具有更强的鲁棒性。

ELAN-1

#在文件yolov7.yaml中

[-1, 1, Conv, [64, 1, 1]],
[-2, 1, Conv, [64, 1, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[[-1, -3, -5, -6], 1, Concat, [1]],
[-1, 1, Conv, [256, 1, 1]],  # 11

YOLOv7模型结构及使用环境

ELAN-1模块

ELAN-2

#在文件yolov7.yaml中

[-1, 1, Conv, [256, 1, 1]],
[-2, 1, Conv, [256, 1, 1]],
[-1, 1, Conv, [128, 3, 1]],
[-1, 1, Conv, [128, 3, 1]],
[-1, 1, Conv, [128, 3, 1]],
[-1, 1, Conv, [128, 3, 1]],
[[-1, -2, -3, -4, -5, -6], 1, Concat, [1]],
[-1, 1, Conv, [256, 1, 1]], # 63

YOLOv7模型结构及使用环境

ELAN-2模块

E-ELAN

yolov7的创新点之一,原文中就对应的是《3.1. Extended efficient layer》 这一小节

在大规模的ELAN模块中,如果无限叠加更多的计算块,则可能破坏这种稳定状态,并且参数利用率将降低。E-ELAN模块使用了expand、shuffle、merge cardinality来实现在不破坏原有梯度路径的情况下不断增强网络学习能力的能力。

E-ELAN结构:

YOLOv7模型结构及使用环境

上图E-ELAN结构与图(d)E-ELAN的结构完全等价:实际上,图(d)E-ELAN使用了分组卷积,降低了参数量。我们E-ELAN的创新点就在于使用了分组卷积,与group=1(即不分组)相比,降低了参数量。

(3×3,2c,2c,c) 表示 k=3,channel_in=2c,channel_out=2c,group=2

YOLOv7模型结构及使用环境

分组卷积的等价性:分组卷积等价于对每一组进行常规卷积,最后将输出拼接。

YOLOv7模型结构及使用环境

#在文件yolov7-e6e.yaml中

[-1, 1, Conv, [64, 1, 1]],
[-2, 1, Conv, [64, 1, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[[-1, -3, -5, -7, -8], 1, Concat, [1]],
[-1, 1, Conv, [160, 1, 1]],  # 12
[-11, 1, Conv, [64, 1, 1]],
[-12, 1, Conv, [64, 1, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[[-1, -3, -5, -7, -8], 1, Concat, [1]],
[-1, 1, Conv, [160, 1, 1]],  # 22
[[-1, -11], 1, Shortcut, [1]],  # 23 Shortcut就是元素位置相加

E-ELAN结构如下:

YOLOv7模型结构及使用环境

注:最后两个CBS相加是元素位置相加,yaml中写作Shortcut

X-ELAN

yolov7的创新点之一,原文中就对应的是《3.2 Model scaling》 这一小节

模型中只有yolov7x使用了模型缩放这个创新点的内容,体现在X-ELAN模块中(我自己称为X-ELAN)。

yolov7x的X-ELAN模块和yolov7的ELAN模块对比:

1.扩大的模型的深度。多了一条由两个卷积构成的支路。

2.扩大的模型的宽度。输入channel;concat输出channel;最终输出channel都是ELAN模块的1.25倍。

YOLOv7模型结构及使用环境

左:yolov7的ELAN模块 右:yolov7x的X-ELAN模块

#在文件yolov7x.yaml中

[-1, 1, Conv, [160, 3, 2]],  # 3-P2/4  
[-1, 1, Conv, [64, 1, 1]],
[-2, 1, Conv, [64, 1, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[-1, 1, Conv, [64, 3, 1]],
[[-1, -3, -5, -7, -8], 1, Concat, [1]],
[-1, 1, Conv, [320, 1, 1]],  # 13

X-ELAN结构:

YOLOv7模型结构及使用环境

2.3 MP模块

MP模块有两个分支,作用是下采样:

第一个分支经过最大池化,然后是1×1的卷积层改变深度。

第二个分支是1×1的卷积层改变深度,然后再经过3×3的卷积层、步长为2的卷积块,也是下采样的目的。

最后将第一个分支和第二条分支的结果拼接在一起。

#在文件yolov7.yaml中

[-1, 1, MP, []], #2×2的最大池化
[-1, 1, Conv, [128, 1, 1]],
[-3, 1, Conv, [128, 1, 1]],
[-1, 1, Conv, [128, 3, 2]],
[[-1, -3], 1, Concat, [1]],  # 16-P3/8  

YOLOv7模型结构及使用环境

MP模块

注:head的MP模块除了上一层,还有来自其他层的连接。

2.4 SPPCSPC模块

最大池化的数值越大,获得的感受野越大,感受野大会得到一些大目标特征、感受野小会得到一些小目标特征。通过最大池化来获得不同的感受野,使不同分辨率的图像在模型中都得到特征的提取。

Conv(c1, c_, 1, 1)指的是(in_chaanel,out_channel,kernel,stride)

#common.py文件中

class SPPCSPC(nn.Module):
    # CSP https://github.com/WongKinYiu/CrossStagePartialNetworks
    def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5, k=(5, 9, 13)):
        super(SPPCSPC, self).__init__()
        c_ = int(2 * c2 * e)  # hidden channels
        self.cv1 = Conv(c1, c_, 1, 1)
        self.cv2 = Conv(c1, c_, 1, 1)
        self.cv3 = Conv(c_, c_, 3, 1)
        self.cv4 = Conv(c_, c_, 1, 1)
        self.m = nn.ModuleList([nn.MaxPool2d(kernel_size=x, stride=1, padding=x // 2) for x in k])
        self.cv5 = Conv(4 * c_, c_, 1, 1)
        self.cv6 = Conv(c_, c_, 3, 1)
        self.cv7 = Conv(2 * c_, c2, 1, 1)

    def forward(self, x):
        x1 = self.cv4(self.cv3(self.cv1(x)))
        #torch的size: (n,c,h,w)  torch.cat(input,dim) dim=1按照c进行拼接
        y1 = self.cv6(self.cv5(torch.cat([x1] + [m(x1) for m in self.m], 1)))
        y2 = self.cv2(x)
        return self.cv7(torch.cat((y1, y2), dim=1))

YOLOv7模型结构及使用环境

SPPCSPC模块

2.5 RepConv模块

yolov7的创新点之一,原文中就对应的是《4.1 re-parameterized convolution》 这一小节

多分支结构

多分支结构可以提高表征能力,例如Inception、ResNet都使用的是多分支结构。RepVGG在3*3的卷积基础上弄了一个1*1的分支和一个identity分支。

YOLOv7模型结构及使用环境

(A)ResNet结构 (B)RepVGG训练时的结构 (C)RepVGG推理时的结构

但是多分支会带来内存的增加,因为分支处必须要保留内存。为了使网络具有高性能,又要有高效推理速度,RepVGG提出训练时尽量用多分支结构来提升网络性能,而推理时,将其变为单路结构,这样,显存占用少,推理速度又快。

结构重参化

  • 3×3的Conv2d融合BN:

通常 x→Cond2d→BN→y 的过程如下:

kernel=3,padding=1,stride=1

YOLOv7模型结构及使用环境

我们将公式拆解开:

YOLOv7模型结构及使用环境

YOLOv7模型结构及使用环境

我们发现,分解原式,可以先将卷积核元素kkγ1σ12+ϵfrac{gamma_1}{sqrt{sigma^2_1+epsilon}}相乘,这样就实现了Conv2d与BN层的融合,得到了新的卷积核,再进行卷积,且省去了再将输出与BN层计算的过程:

YOLOv7模型结构及使用环境

  • 1×1的Conv2d融合BN:将1×1的kernel周围补0变成3×3的kernel,其余的与3×3的Conv2d融合BN相同操作。

  • 输入与BN融合:制作中间为1周围为0的3×3的kernel,其余的与3×3的Conv2d融合BN相同操作。

YOLOv7模型结构及使用环境

将Conv+BN进行等价映射

经过结构重参化后:

1.参数量得到了降低。

2.相加后输出为3×3,也会提高运算效率。

yolov7中的RepConv

在yolov7.yaml中只用了最普通的RepConv卷积(b)。

#在文件yolov7.yaml中。

[75, 1, RepConv, [256, 3, 1]],
[88, 1, RepConv, [512, 3, 1]],
[101, 1, RepConv, [1024, 3, 1]],

注:当有残差结构或者有拼接结构时,不应该使用RepConv,如(d)、(f)。

YOLOv7模型结构及使用环境

在common.py文件。

#部署和训练的时候分支不同

if deploy:
    self.rbr_reparam = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=True)

else:
    self.rbr_identity = (nn.BatchNorm2d(num_features=c1) if c2 == c1 and s == 1 else None)

    self.rbr_dense = nn.Sequential(
        nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False),
        nn.BatchNorm2d(num_features=c2),
    )

    self.rbr_1x1 = nn.Sequential(
        nn.Conv2d( c1, c2, 1, s, padding_11, groups=g, bias=False),
        nn.BatchNorm2d(num_features=c2),
    )

2.6 Detect模型

Detect在训练时和推理时得到的输出还是不同的:

1.训练只需要得到偏移量即可,推理则要将偏移量经过计算转换成(x,y,w,h)。

if not torch.onnx.is_in_onnx_export():
    y[..., 0:2] = (y[..., 0:2] * 2. - 0.5 + self.grid[i]) * self.stride[i]  # xy
    y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i]  # wh

2.推理还需要将合起来(20×20×3+40×40×3+80×80×3=252000,85)

out = (torch.cat(z, 1), x)

YOLOv7模型结构及使用环境

3. 创新点总结

1.E-ELAN模块:3.1 Extended efficient layer aggregation networks

2.X-ELAN模块:3.2 Model scaling for concatenation-based models

3.REP模块:4.1 Planned re-parameterized convolution

4.深度监督(Deep supervision):添加辅助头。不仅是检测头loss计算,检测头的前一部分,即辅助头,也会进行loss计算。

5.标签分配(label assignmet):软标签。yolov5用的是硬标签,yolov7用的是软标签。 分配器:OTA算法。

# train.py中的第300行:软标签损失计算
compute_loss_ota = ComputeLossOTA(model)  # init loss class

6.训练过程添加的trick:BN层的融合;移动平均算法(EMA)。

4. 参考资料

本文有参考到

视频:RepVGG

视频:YOLOv7

论文:YOLOv7

论文:RepVGG

本网站的内容主要来自互联网上的各种资源,仅供参考和信息分享之用,不代表本网站拥有相关版权或知识产权。如您认为内容侵犯您的权益,请联系我们,我们将尽快采取行动,包括删除或更正。
AI教程

层归一化:解决批量归一化无法解决的问题

2023-12-16 5:14:14

AI教程

GPT-4的编程能力测试:小猫问题和新月问题

2023-12-16 7:44:14

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索