文章目录

  • 前言
  • 一、网络结构图
  • 二、各模块的实现
    • 1.BConv模块
    • 2.E-ELAN模块
    • 3.MPConv模块
    • 4.SPPCSPC模块
    • 5.CatConv模块
    • 6.RepConv模块
  • 三、整体实现
  • 总结

前言

前不久,正宗的YOLOV7横空出世,引来了很多人的关注,因为这次是官方作者的又一力作,自己也是抽时间看了看其中的结构。
代码链接如下:https://github.com/WongKinYiu/yolov7
论文链接如下:https://arxiv.org/abs/2207.02696


一、网络结构图

这里我参考的两张结构图分别为:
第一张图是微信公众号中发现的,但由于某些原因,发布不上来,下边是它的链接,大家可以根据链接点进去查看。
来自:https://mp.weixin.qq.com/s?__biz=MzU3ODk2Njc5Mg==&mid=2247496582&idx=1&sn=df6ca2fdebd524d2116c97c05c00424e&chksm=fd6ff7e1ca187ef77f4d110dd41c7d220f8bdcb22906f32558c897240bee0c94125272f9ac11&scene=21#wechat_redirect
第二张图如下:

来自:https://blog.csdn.net/u010899190/article/details/125883770
结合这两张图,完成了网络结构的初步复现。

二、各模块的实现

1.BConv模块

在YOLOV7的backbone最开始,首先是有若干个BConv模块组成,也就是Conv+BN+Silu(),结构图如下:

需要注意的是,这里面不同的颜色表示不同的卷积核大小和步长,实现代码如下:

class Bconv(nn.Module):def __init__(self,ch_in,ch_out,k,s):''':param ch_in: 输入通道数:param ch_out: 输出通道数:param k: 卷积核尺寸:param s: 步长:return:'''super(Bconv, self).__init__()self.conv=nn.Conv2d(ch_in,ch_out,k,s,padding=k//2)self.bn=nn.BatchNorm2d(ch_out)self.act=nn.SiLU()def forward(self,x):''':param x: 输入:return:'''return self.act(self.bn(self.conv(x)))

2.E-ELAN模块

这个模块的长宽不变,输出通道数变为输入的2倍,需要注意的是,在backbone的最后一层E-ELAN中,输出通道数为1024,而非2048(官方代码中也是1024),结构图如下:

代码如下:

class E_ELAN(nn.Module):def __init__(self,ch_in,ch_out,flg=False):''':param ch_in: 输入通道:param ch_out: 这里给的是中间层的输出通道:param flg: 判断是否为backbone的最后一层,因为这里的输出通道数有所改变'''super(E_ELAN, self).__init__()# 卷积类型一self.conv1=Bconv(ch_in,ch_out,k=1,s=1)# 卷积类型二self.conv2=Bconv(ch_out,ch_out,k=3,s=1)#cat之后的卷积if flg:self.conv3=Bconv(2*ch_in,ch_in,k=1,s=1)else:self.conv3=Bconv(2*ch_in,2*ch_in,k=1,s=1)def forward(self,x):''':param x: 输入:return:'''#分支一输出output1=self.conv1(x)#分支二输出output2_1=self.conv1(x)output2_2=self.conv2(output2_1)output2_3=self.conv2(output2_2)output2_4=self.conv2(output2_3)output2_5=self.conv2(output2_4)output_cat=torch.cat((output1, output2_1, output2_3, output2_5), dim=1)return self.conv3(output_cat)

3.MPConv模块

这个模块没什么需要注意的,结构图如下:

代码如下:

class MPConv(nn.Module):def __init__(self,ch_in,ch_out):''':param ch_in: 输如通道:param ch_out: 这里给的是中间层的输出通道'''super(MPConv, self).__init__()#分支一self.conv1=nn.Sequential(nn.MaxPool2d(2,2),Bconv(ch_in,ch_out,1,1),)#分支二self.conv2=nn.Sequential(Bconv(ch_in,ch_out,1,1),Bconv(ch_out,ch_out,3,2),)def forward(self,x):#分支一输出output1=self.conv1(x)#分支二输出output2=self.conv2(x)return torch.cat((output1,output2),dim=1)

4.SPPCSPC模块

这里是在传统的SPP结构上又进行了一些改变,改变后的结构图如下:

代码如下:

class SppCSPC(nn.Module):def __init__(self,ch_in,ch_out):''':param ch_in: 输入通道:param ch_out: 输出通道'''super(SppCSPC, self).__init__()#分支一self.conv1=nn.Sequential(Bconv(ch_in,ch_out,1,1),Bconv(ch_out,ch_out,3,1),Bconv(ch_out,ch_out,1,1))#分支二(SPP)self.mp1=nn.MaxPool2d(5,1,5//2) #卷积核为5的池化self.mp2=nn.MaxPool2d(9,1,9//2) #卷积核为9的池化self.mp3=nn.MaxPool2d(13,1,13//2) #卷积核为13的池化#concat之后的卷积self.conv1_2=nn.Sequential(Bconv(4*ch_out,ch_out,1,1),Bconv(ch_out,ch_out,3,1))#分支三self.conv3=Bconv(ch_in,ch_out,1,1)#此模块最后一层卷积self.conv4=Bconv(2*ch_out,ch_out,1,1)def forward(self,x):#分支一输出output1=self.conv1(x)#分支二池化层的各个输出mp_output1=self.mp1(output1)mp_output2=self.mp2(output1)mp_output3=self.mp3(output1)#合并以上并进行卷积result1=self.conv1_2(torch.cat((output1,mp_output1,mp_output2,mp_output3),dim=1))#分支三result2=self.conv3(x)return self.conv4(torch.cat((result1,result2),dim=1))

5.CatConv模块

命名就直接使用参考文章里的那种命名了哈,这个结构和上边提到的E-ELAN结构类似,只不过concat的部分不同,结构图如下:

代码如下:

class CatConv(nn.Module):def __init__(self,ch_in,ch_out):''':param ch_in: 输入通道:param ch_out: 输出通道'''super(CatConv, self).__init__()c_=ch_out//2 # hidden_channels#分之一self.conv1=Bconv(ch_in,ch_out,1,1)#分支二self.conv2=Bconv(ch_in,ch_out,1,1)self.conv3=Bconv(ch_out,c_,3,1)self.conv4=Bconv(c_,c_,3,1)self.conv5=Bconv(c_,c_,3,1)self.conv6=Bconv(c_,c_,3,1)def forward(self,x):conv1=self.conv1(x)conv2=self.conv2(x)conv3=self.conv3(conv2)conv4=self.conv4(conv3)conv5=self.conv5(conv4)conv6=self.conv6(conv5)return torch.cat((conv1,conv2,conv3,conv4,conv5,conv6),dim=1)

6.RepConv模块

这里需要注意的是,训练阶段,当输入和输出的通道数相同时,除了一个33的卷积和一个11的卷积之外,还会在加一个BN层,输出为三者相加。部署阶段,仅有一个3*3的卷积来替换。结构图如下:

这里的代码仅实现了训练部分代码如下:

class RepConv(nn.Module):def __init__(self,ch_in,ch_out,s=1):''':param ch_in: 输入通道:param ch_out: 输出通道:param s:卷积核的步长'''super(RepConv, self).__init__()self.ch_out=ch_outself.conv1=nn.Sequential(nn.Conv2d(ch_in,ch_out,3,1,padding=3//2),nn.BatchNorm2d(ch_out))self.conv2=nn.Sequential(nn.Conv2d(ch_in,ch_out,1,1,padding=0),nn.BatchNorm2d(ch_out))if ch_in==ch_out and s==1:self.bn=nn.BatchNorm2d(self.ch_out)else:self.bn=Nonedef forward(self,x):output1=self.conv1(x)output2=self.conv2(x)if self.bn==None:output3=0else:output3=self.bn(x)return output1+output2+output3

三、整体实现

在RepConv之后,加了个1*1的卷积层,用于升降维,如下:

class YoloV7(nn.Module):def __init__(self,ch_in=3,cl=85):''':param ch_in: 输入通道数:param cl: 类别数'''super(YoloV7, self).__init__()#backboneself.bconv1=nn.Sequential(Bconv(ch_in,32,3,1),Bconv(32,64,3,2),Bconv(64,64,3,1),Bconv(64,128,3,2))self.e_elan1=nn.Sequential(E_ELAN(128,64),)self.mpconv1=MPConv(256,128)self.e_elan2=E_ELAN(256,128)self.mpconv2=MPConv(512,256)self.e_elan3=E_ELAN(512,256)self.mpconv3=MPConv(1024,512)self.e_elan4=E_ELAN(1024,512,flg=True)#headself.sppcsp=SppCSPC(1024,512)self.bconv2=nn.Sequential(Bconv(512,256,1,1),nn.Upsample(None, 2, "nearest")  # 上采样)self.bconv3=Bconv(1024,256,1,1)self.catconv1=CatConv(512,256)self.bconv4=Bconv(1024,256,1,1)self.bconv5=nn.Sequential(Bconv(256,128,1,1),nn.Upsample(None,2,"nearest") #上采样)self.bconv6=Bconv(512,128,1,1)self.catconv2=CatConv(256,128)self.bconv7=Bconv(512,128,1,1)self.rep1=RepConv(128,256)self.head1=nn.Conv2d(256,cl,1)self.mpconv4=MPConv(128,128)self.catconv3=CatConv(512,256)self.bconv8=Bconv(1024,256,1,1)self.rep2=RepConv(256,512)self.head2=nn.Conv2d(512,cl,1)self.mpconv5=MPConv(256,256)self.catconv4=CatConv(1024,512)self.bconv9=Bconv(2048,512,1,1)self.rep3=RepConv(512,1024)self.head3=nn.Conv2d(1024,cl,1)def forward(self,x):''':param x: 输入:return:'''output1_0=self.bconv1(x)output1_1=self.e_elan1(output1_0)output1_2=self.mpconv1(output1_1)result1=self.e_elan2(output1_2)print(result1.shape)output2_0=self.mpconv2(result1)result2=self.e_elan3(output2_0)print(result2.shape)output3_0=self.mpconv3(result2)result3=self.e_elan4(output3_0)print(result3.shape)#headspp_output=self.sppcsp(result3)bconv2_output=self.bconv2(spp_output)bconv3_output=torch.cat((self.bconv3(result2),bconv2_output),dim=1)catconv1_output=self.catconv1(bconv3_output)bconv4_output=self.bconv4(catconv1_output)bconv5_output=self.bconv5(bconv4_output)bconv6_output=torch.cat((self.bconv6(result1),bconv5_output),dim=1)catconv2_output=self.catconv2(bconv6_output)bconv7_output=self.bconv7(catconv2_output)rep1_output=self.rep1(bconv7_output)head1=self.head1(rep1_output)print(head1.shape)mpconv4_output=torch.cat((self.mpconv4(bconv7_output),bconv4_output),dim=1)catconv3_output=self.catconv3(mpconv4_output)bconv8_output=self.bconv8(catconv3_output)rep2_output=self.rep2(bconv8_output)head2=self.head2(rep2_output)print(head2.shape)mpconv5_output=torch.cat((self.mpconv5(bconv8_output),spp_output),dim=1)catconv4_output=self.catconv4(mpconv5_output)bconv9_output=self.bconv9(catconv4_output)rep3_output=self.rep3(bconv9_output)head3=self.head3(rep3_output)print(head3.shape)return head1,head2,head3if __name__ == '__main__':x=torch.Tensor(1,3,640,640)model=YoloV7(3)result=model(x)

输出维度如下:


总结

以上,就是就是本篇的全部内容,如有错误,欢迎评论取指正,或加入QQ群:995760755交流。

pytorch构建YOLOV7网络结构相关推荐

  1. 睿智的目标检测61——Pytorch搭建YoloV7目标检测平台

    睿智的目标检测61--Pytorch搭建YoloV7目标检测平台 学习前言 源码下载 YoloV7改进的部分(不完全) YoloV7实现思路 一.整体结构解析 二.网络结构解析 1.主干网络Backb ...

  2. 【深度学习】保姆级教程,用PyTorch构建第一个神经网络

    PyTorch是一个基于python的科学计算包,主要针对两类人群: 作为NumPy的替代品,可以利用GPU的性能进行计算 作为一个高灵活性.速度快的深度学习平台 在PyTorch中搭建神经网络并使用 ...

  3. 使用PyTorch构建卷积GAN源码(详细步骤讲解+注释版) 02人脸图片生成 上

    阅读提示:本篇文章的代码为在普通GAN代码上实现人脸图片生成的修改,文章内容仅包含修改内容,全部代码讲解需结合下面的文章阅读. 相关资料链接为:使用PyTorch构建GAN生成对抗 本次训练代码使用了 ...

  4. 使用PyTorch构建神经网络(详细步骤讲解+注释版) 01-建立分类器类

    文章目录 1 数据准备 2 数据预览 3 简单神经网络创建 3.1 设计网络结构 3.2 损失函数相关设置 3.3 向网络传递信息 3.4 定义训练函数train 4 函数汇总 1 数据准备 神经网络 ...

  5. Pytorch构建网络细节总结

    Pytorch构建网络细节总结 optimizer.step() 和 scheduler.step() 的区别 定义: 区别: .to(device)与.cuda()的区别 .to(device) 可 ...

  6. 基于pytorch使用实现CNN 如何使用pytorch构建CNN卷积神经网络

    基于pytorch使用实现CNN 如何使用pytorch构建CNN卷积神经网络 所用工具 文件结构: 数据: 代码: 结果: 改进思路 拓展 本文是一个基于pytorch使用CNN在生物信息学上进行位 ...

  7. 第18课:项目实战——利用 PyTorch 构建 RNN 模型

    上一篇,我们主要介绍了基本的 RNN 模型和 LSTM.本文将通过一个实战项目带大家使用 PyTorch 搭建 RNN 模型. 本项目将构建一个 RNN 模型,来对 MNIST 手写数据集进行分类.可 ...

  8. [Python图像识别] 四十八.Pytorch构建Faster-RCNN模型实现小麦目标检测

    该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门.OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子.图像增强技术.图像分割等,后期结合深度学习研究图像识别 ...

  9. RNN知识+LSTM知识+encoder-decoder+ctc+基于pytorch的crnn网络结构

    一.基础知识: 下图是一个循环神经网络实现语言模型的示例,可以看出其是基于当前的输入与过去的输入序列,预测序列的下一个字符. 序列特点就是某一步的输出不仅依赖于这一步的输入,还依赖于其他步的输入或输出 ...

最新文章

  1. python 函数调用 不允许关键字参数_你所不知道的Python|函数参数的演进之路
  2. 【共振峰跟踪】通过平均不同分辨率的方法跟踪共振峰,基于时频lpc的频谱图的MATLAB仿真
  3. 区块链基础知识系列第5课 Hyperledger fabric1.0网络中transaction产生以及流转过程
  4. 首批国家应用数学中心名单公布,哪些高校获批?
  5. python文件替换一行_python自动化替换文件中每一行中的特有字符串
  6. 程序员的进阶课-架构师之路(1)-数据结构与算法简介
  7. shiro包_Shiro--从一个简单的 Realm 开始权限认证
  8. 2017.2.10自测(noip2002)
  9. jquery easyui Tab 引入页面的问题
  10. Docker在Windows上运行NetCore系列(一)使用命令控制台运行.NetCore控制台应用
  11. AI “闯入”北极圈
  12. android退出图标按钮,android-setCloseButtonIcon(位图可绘制)不适用于...
  13. Android 开源框架Universal-Image-Loader完全解析(二)--- 图片缓存策略详解
  14. 078 numpy模块
  15. Unreal Engine 4 手绘风滤镜(Paint Filter)即 桑原滤镜(Kuwahara Filter)教程(下)
  16. li指令 汇编_汇编指令简介
  17. docker容器怎么设置开机启动
  18. 一款好用的WEB版报表工具、报表设计器
  19. 三天速成前端——CSS
  20. 计算机二级c语言模拟上机,计算机二级C语言上机模拟题

热门文章

  1. Linux系统下word转pdf,xls转pdf,ppt转pdf
  2. halcon工件圆孔检测
  3. 前端面试高频手写题目
  4. 高并发带来的问题极其解决方法
  5. EIDE助手插件 快速定位
  6. matlab单边带调幅系统的建模仿真(笔记)
  7. 简单教你计算图片数据集的均值和方差
  8. 输入地址,获取邮编的工具类
  9. OpenCV图像处理——拉普拉斯金字塔
  10. 计算机房辐射 安全距离,机房辐射范围和预防辐射?