pytorch构建YOLOV7网络结构
文章目录
- 前言
- 一、网络结构图
- 二、各模块的实现
- 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网络结构相关推荐
- 睿智的目标检测61——Pytorch搭建YoloV7目标检测平台
睿智的目标检测61--Pytorch搭建YoloV7目标检测平台 学习前言 源码下载 YoloV7改进的部分(不完全) YoloV7实现思路 一.整体结构解析 二.网络结构解析 1.主干网络Backb ...
- 【深度学习】保姆级教程,用PyTorch构建第一个神经网络
PyTorch是一个基于python的科学计算包,主要针对两类人群: 作为NumPy的替代品,可以利用GPU的性能进行计算 作为一个高灵活性.速度快的深度学习平台 在PyTorch中搭建神经网络并使用 ...
- 使用PyTorch构建卷积GAN源码(详细步骤讲解+注释版) 02人脸图片生成 上
阅读提示:本篇文章的代码为在普通GAN代码上实现人脸图片生成的修改,文章内容仅包含修改内容,全部代码讲解需结合下面的文章阅读. 相关资料链接为:使用PyTorch构建GAN生成对抗 本次训练代码使用了 ...
- 使用PyTorch构建神经网络(详细步骤讲解+注释版) 01-建立分类器类
文章目录 1 数据准备 2 数据预览 3 简单神经网络创建 3.1 设计网络结构 3.2 损失函数相关设置 3.3 向网络传递信息 3.4 定义训练函数train 4 函数汇总 1 数据准备 神经网络 ...
- Pytorch构建网络细节总结
Pytorch构建网络细节总结 optimizer.step() 和 scheduler.step() 的区别 定义: 区别: .to(device)与.cuda()的区别 .to(device) 可 ...
- 基于pytorch使用实现CNN 如何使用pytorch构建CNN卷积神经网络
基于pytorch使用实现CNN 如何使用pytorch构建CNN卷积神经网络 所用工具 文件结构: 数据: 代码: 结果: 改进思路 拓展 本文是一个基于pytorch使用CNN在生物信息学上进行位 ...
- 第18课:项目实战——利用 PyTorch 构建 RNN 模型
上一篇,我们主要介绍了基本的 RNN 模型和 LSTM.本文将通过一个实战项目带大家使用 PyTorch 搭建 RNN 模型. 本项目将构建一个 RNN 模型,来对 MNIST 手写数据集进行分类.可 ...
- [Python图像识别] 四十八.Pytorch构建Faster-RCNN模型实现小麦目标检测
该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门.OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子.图像增强技术.图像分割等,后期结合深度学习研究图像识别 ...
- RNN知识+LSTM知识+encoder-decoder+ctc+基于pytorch的crnn网络结构
一.基础知识: 下图是一个循环神经网络实现语言模型的示例,可以看出其是基于当前的输入与过去的输入序列,预测序列的下一个字符. 序列特点就是某一步的输出不仅依赖于这一步的输入,还依赖于其他步的输入或输出 ...
最新文章
- python 函数调用 不允许关键字参数_你所不知道的Python|函数参数的演进之路
- 【共振峰跟踪】通过平均不同分辨率的方法跟踪共振峰,基于时频lpc的频谱图的MATLAB仿真
- 区块链基础知识系列第5课 Hyperledger fabric1.0网络中transaction产生以及流转过程
- 首批国家应用数学中心名单公布,哪些高校获批?
- python文件替换一行_python自动化替换文件中每一行中的特有字符串
- 程序员的进阶课-架构师之路(1)-数据结构与算法简介
- shiro包_Shiro--从一个简单的 Realm 开始权限认证
- 2017.2.10自测(noip2002)
- jquery easyui Tab 引入页面的问题
- Docker在Windows上运行NetCore系列(一)使用命令控制台运行.NetCore控制台应用
- AI “闯入”北极圈
- android退出图标按钮,android-setCloseButtonIcon(位图可绘制)不适用于...
- Android 开源框架Universal-Image-Loader完全解析(二)--- 图片缓存策略详解
- 078 numpy模块
- Unreal Engine 4 手绘风滤镜(Paint Filter)即 桑原滤镜(Kuwahara Filter)教程(下)
- li指令 汇编_汇编指令简介
- docker容器怎么设置开机启动
- 一款好用的WEB版报表工具、报表设计器
- 三天速成前端——CSS
- 计算机二级c语言模拟上机,计算机二级C语言上机模拟题