zoukankan      html  css  js  c++  java
  • 0609-搭建ResNet网络

    0609-搭建ResNet网络

    pytorch完整教程目录:https://www.cnblogs.com/nickchen121/p/14662511.html

    一、ResNet 网络概述

    Kaiming He 的深度残差网络(ResNet)相比较传统的深度深度神经网络,解决了训练极深网络的梯度消失问题。

    这里选取 ResNet34 讲解 ResNet 的网络结构,它的网络结构如下图所示:

    在上述的网络中,除了最开始的卷积池化和最后的池化全连接之外,网络中有很多结构相似的单元,这些重复单元的共同点就是有个跨层直连的 shortcut。ResNet 中将一个跨层直连的单元称为 Residual block,它的结构如下图所示:

    对于 Residual block,左边部分是普通的卷积网络结构,右边是直连,如果输入和输出的通道数不一致,或者它的步长不为 1,就需要有一个专门的单元将二者装换成一致的,让它们可以相加。

    并且从上图可以发现 Residual block 的大小也是有规律的,在最开始的 pool 之后又连续的几个一模一样的 Residual block 单元,这些单元的通道数一样,在这里我们把这几个拥有多个 Residual block 单元的结构称作 layer,注意这个 layer 和之前介绍的 layer 不同,这里的 layer 是几个层的集合。

    由于 Redisual block 和 layer 出现了很多次,我们可以把它们实现为一个子 Module 或函数。在这里我们把 Residual block 实现为一个子 Module,而让 layer 实现为一个函数。

    下面我们将尽量按照这三个规则去实现 ResNet 网络:

    • 对模型中的重复部分,实现为子 module 或用函数生成相应的 module
    • nn.Modulenn.Funcitonal 结合使用
    • 尽量使用 nn.Sequential

    二、利用 torch 实现 ResNet34 网络

    import torch as t
    from torch import nn
    from torch.nn import functional as F
    
    
    class ResidualBlock(nn.Module):
        """
        实现子 module:Residual Block
        """
    
        def __init__(self, inchannel, outchannel, stride=1, shortcut=None):
            super(ResidualBlock, self).__init__()
    
            # 由于 Residual Block 分为左右两部分,因此定义左右两边的 layer
            # 定义左边
            self.left = nn.Sequential(
                # Conv2d 参数:in_channel,out_channel,kernel_size,stride,padding
                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.right = shortcut
    
        def forward(self, x):
            out = self.left(x)
            residual = x if self.right is None else self.right(x)  # 检测右边直连的情况
            out += residual
            return F.relu(out)
    
    
    class ResNet(nn.Module):
        """
        实现主 module:ResNet34
        ResNet34 包含多个 layer,每个 layer 又包含多个 residual block
        用子 module 实现 residual block,用 _make_layer 函数实现 layer
        """
    
        def __init__(self, num_classes=1000):
            super(ResNet, 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, 2, 1),
            )
    
            # 重复的 layer 分别有 3,4,6,3 个 residual block
            self.layer1 = self._make_layer(64, 128, 3)
            self.layer2 = self._make_layer(128, 256, 4, stride=2)
            self.layer3 = self._make_layer(256, 512, 6, stride=2)
            self.layer4 = self._make_layer(512, 512, 3, stride=2)
    
            # 分类用的全连接
            self.fc = nn.Linear(512, num_classes)
    
        def _make_layer(self, inchannel, outchannel, block_num, stride=1):
            """
            构建 layer,包含多个 residual block
            """
            shortcut = nn.Sequential(
                nn.Conv2d(inchannel, outchannel, 1, stride, bias=False),
                nn.BatchNorm2d(outchannel))
    
            layers = []
            layers.append(ResidualBlock(inchannel, outchannel, stride, shortcut))
    
            for i in range(1, block_num):
                layers.append(ResidualBlock(outchannel, outchannel))
    
            return nn.Sequential(*layers)
    
        def forward(self, x):
            x = self.pre(x)
    
            x = self.layer1(x)
            x = self.layer2(x)
            x = self.layer3(x)
            x = self.layer4(x)
    
            x = F.avg_pool2d(x, 7)
            x = x.view(x.size(0), -1)
    
            return self.fc(x)
    
    res_net = ResNet()
    inp = t.autograd.Variable(t.randn(1, 3, 224, 224))
    output = res_net(inp)
    output.size()
    
    torch.Size([1, 1000])
    

    不到 50 行代码便实现了这样一个网络,看起来是那么不可思议,如果对此感兴趣的同学还可以取消尝试实现 Google 的 Inception 网络。

    三、torchvision 中的 resnet34网络调用

    前面我们讲过一个 hub 模块,里面存储了很多网络结构。不仅如此,和 torch 配套的图像工具包 torchvision 也实现了深度学习中的大多数经典的模型,其中就包括了 ResNet34,非常简单,可以通过以下两行代码调用这个网络:

    from torchvision import models
    res_net = models.resnet34()
    inp = t.autograd.Variable(t.randn(1, 3, 224, 224))
    output = res_net(inp)
    output.size()
    
    torch.Size([1, 1000])
    

    本例中的 ResNet34 的实现参考了 torchvision 中的实现并做了一定的调整,有兴趣的同学可以去阅读相对应的源码。

    四、第六章总结

    这一章详细的介绍了 torch 中的 nn 工具箱,但是你说详细吗?又不是那么详细,还有很多很多地方我们需要去补漏,如果想深入各个部分的同学们,可以去参考官方文档。

    当然,我更建议学一部分常用的基础,然后在实践中学习更加完善、更加系统的知识体系。因此,我们将在未来的实战项目中不断地巩固 nn 这个工具箱的使用。

    最后,随着 nn 的落幕,torch 的地基也算是落幕了,剩下的都是一些边边角角的知识点,但是还是借用古人的一句话:路漫漫其修远兮,任重而道远。

  • 相关阅读:
    MySQL 子查询
    mysql3
    mysql2
    mysql
    C语言理论知识
    冒泡排序
    猜数字游戏
    WPF清爽酷炫的界面Mahapps.metro
    如何在.net4.0中使用.net4.5的async/await
    在C#中使用官方驱动操作MongoDB
  • 原文地址:https://www.cnblogs.com/nickchen121/p/14704387.html
Copyright © 2011-2022 走看看