pytorch-resnet34残差网络理解

pytorch-resnet34残差网络理解工欲善其事必先利其器,在使用该网络之前要先了解该网络的具体细节,我今天也是第一次查资料,然后加上自己的理解去写这篇学习成长文章。残差模块classResidualBlock(nn.Module):def__init__(self,inchannel,outchannel,stride=1,dowansample=None):super(ResidualBlock,self).__init__()self.left=nn.Sequential

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

工欲善其事必先利其器,在使用该网络之前要先了解该网络的具体细节,我今天也是第一次查资料,然后加上自己的理解去写这篇学习成长文章。

残差模块

class ResidualBlock(nn.Module):
    def __init__(self, inchannel, outchannel, stride=1, dowansample=None):
        super(ResidualBlock, self).__init__()
        self.left = nn.Sequential(
            nn.Conv2d(inchannel, outchannel, 3, stride, 1, bias=False),
            nn.BatchNorm2d(outchannel), 
            nn.ReLU(inplace=True),
            nn.Conv2d(outchannel, outchannel, 3, 1, 1, bias=False),
            nn.BatchNorm2d(outchannel)
        )
        self.dowansample=dowasample
    def forward(self, x):
        out = self.left(x)
        residual = x if self.dowansample is None else self.dowansample(x)
        out += residual
        return F.relu(out)

Jetbrains全家桶1年46,售后保障稳定

这是残差模块的代码,下面用一张图来具体介绍
在这里插入图片描述根据这张图和上面的代码,我们可以看出大概的一个过程,在前向传播函数中可以看到,数据传下来后会先通过两次卷积,也就是此案执行 self.left()函数,downsample是一个下采样函数,根据结果来判断是否执行想采样,残差模块的代码很简单,相信可以看明白。
主干网络模块
网络卷积图
在这里插入图片描述图片上的右边是resnet34残差网络的整体卷积过程,慢慢来逐个理解一下。
代码:

class ResNet34(nn.Module):
    def __init__(self, num_classes=1000):
        super(ResNet34, self).__init__()
        self.pre = nn.Sequential(
            nn.Conv2d(3, 64, 7, 2 ,3, bias=False), 
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(3, 1, 1) 
        )
        self.layer1 = self._make_layer(64, 128, 3)              ### 3 个 64 通道的残差单元,输出 128通道,共6层
        self.layer2 = self._make_layer(128, 256, 4, stride=2)   ### 4 个 128通道的残差单元,输出 256通道,共8层
        self.layer3 = self._make_layer(256, 512, 6, stride=2)   ### 6 个 256通道的残差单元,输出 512通道,共12层
        self.layer4 = self._make_layer(512, 512, 3, stride=2)   ### 3 个 512通道的残差单元,输出 512通道,共6层
        ### fc,1层
        self.fc = nn.Linear(512, num_classes)
    def _make_layer(self, inchannel, outchannel, block_num, stride=1):
        dowansample= nn.Sequential(
            nn.Conv2d(inchannel, outchannel, 1, stride, bias=False),
            nn.BatchNorm2d(outchannel)
        )
        layers = []
        layers.append(ResidualBlock(inchannel, outchannel, stride, dowansample))       ### 先来一个残差单元,主要是改变通道数
        for i in range(1, block_num+1): 
            layers.append(ResidualBlock(outchannel, outchannel))
        return nn.Sequential(*layers)
    def forward(self, x):
        ### 第1层
        x = self.pre(x)
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)
        ### 注意 resnet 最后的池化是把一个 feature map 变成一个特征,故池化野大小等于最后 x 的大小
        x = F.avg_pool2d(x, 2)      ### 这里用的 cifar10 数据集,此时的 x size 为 512x2x2,所以池化野为2
        x = x.view(x.size(0), -1)
        return self.fc(x)

结合上图和代码,可以在初始化函数中看到self.pre()函数,这个函数主要是数据输进来时先通过一个7×7的卷积核来改变数据,也就是上图中 7×7, conv, 64 ,/2 这一行,初始化函数中还有一个self.layer1() , self.layer2() , self.layer3(),self.layer4()这几个函数,这几个分别对应上图的 3×3,conv,64。 3×3,conv,128。 3×3,conv,256 。 3×3,conv,512。
再看他们的函数定义的内容:

    def _make_layer(self, inchannel, outchannel, block_num, stride=1):
        downsample= nn.Sequential(
            nn.Conv2d(inchannel, outchannel, 1, stride, bias=False),
            nn.BatchNorm2d(outchannel)
        )
        layers = []
        layers.append(ResidualBlock(inchannel, outchannel, stride, downsample))
        for i in range(1, block_num+1):
            layers.append(ResidualBlock(outchannel, outchannel))
        return nn.Sequential(*layers)

先是一个downsample,里面是一个卷积,然后是一个数组,数组中先放一个残差模块,并且有dawnsample参数,这是在改变两个模块之间的通道数,比如上边3×3,conv,64。 3×3,conv,128。之间,在通道数转变的时候才执行。继续往下看,是一个for循环,循环里面还是向数组中放入残差模块,不同的是这次没有downsample参数了,通过这几行代码产生了上图中3个3×3,conv,64 4个 3×3,conv,128。一次类推,应该可以看明白,self.layer1() , self.layer2() , self.layer3(),self.layer4()这几个函数就是产生了上图竖着的那几十个卷积,接下来就是前向传播了,前向传播很简单,需要明白的是下采样downsample是在两个卷积时通道数不同的时候才执行,如64通过转变成128通道时。这一块也是最经典的地方,加深卷积后,先判断是否有变化,如果有变化,我就把变化加上,然后继续执行下边的卷积,如果没有变化,我就不加,还是继续执行下边的卷积,这样理论上就可以一直往下添加卷积层了。
以上就是我的理解,目前对一些实战中各个卷积层输入输出通道数的选择和卷积核的选择还是有一点疑惑和不解的,需要继续学习。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/215577.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Matlab仿真PID控制(带M文件、simulink截图和参数分析)

    Matlab仿真PID控制(带M文件、simulink截图和参数分析)在直接数字域设计中,我们常常需要用到PID算法,而PID算法投入单片机使用时,往往需要硬件的支持,在调试时非常麻烦。本文通过Matlab仿真的手段实现PID,方便了开发者对系统的设计和实时调试。

    2022年6月6日
    208
  • Silverlight传值「建议收藏」

    Silverlight传值「建议收藏」Silverlight页面之间传值的。主要是使用独立存储的IsolatedStorageSettings对象,首先需要创建对象privateIsolatedStorageSettingsappSettings=IsolatedStorageSettings.Applic

    2022年10月18日
    0
  • 使用ComponentOne C1WebGrid控件「建议收藏」

    使用ComponentOne C1WebGrid控件「建议收藏」作者:SinoryComponentOne.Studio.Enterprise.2006中的(C1StudioAspNET2_T106)是著名的C1开发的针对ASP.NET2.0的一套控件库.为ASP.NET开发人员提供了功能丰富的Web开发组件。包括个表格,报表,图表,数据,用户界面和电子商务组件等支持.C1WebGrid是其中最基本的控件之一.下面介绍它的具体应用方法:添加引用:<…

    2022年10月6日
    0
  • 如何从tushare获取股票历史数据写入自己的MySQL数据库[通俗易懂]

    如何从tushare获取股票历史数据写入自己的MySQL数据库[通俗易懂]如何从tushare获取股票历史数据写入自己的MySQL数据库点击https://tushare.pro/register?reg=414428,免费注册后,即可获取tushare的token,就可以下载金融数据了。1.tushare推荐方法如果你需要读取全部股票的历史数据,tushare给的建议是按“天”获取。因为tushareapi限制一次获取最高5000条记录,而A股市场目前有3000多只股票,提取一次数据不会超过api的限制记录数。代码如下:importtus

    2022年6月24日
    77
  • 运维架构

    运维架构运维架构1、运维团队配置运维团队分为:应用运维、系统运维、运维开发、监控运维、DBA团队和安全团队团队分工:应用运维:负责支持线上业务,各自会负责对应的业务线,主要职能是保证线上业务稳定性和同开发共

    2022年7月1日
    20
  • 简单鼠标跟随代码[通俗易懂]

    简单鼠标跟随代码[通俗易懂]效果图:htmlcode:csscode:jscode

    2022年7月2日
    24

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号