何恺明编年史之深度残差网络ResNet


前言

图像分类是计算机视觉任务的基石,在目标监测、图像分割等任务中需要使用骨干网咯,将浅层的视觉特征映射到深层的语义特征,以发现高层数据的分布式特征表示。在ILSVRC2015分类任务竞赛中,由何恺明提出的深度残差网络ResNet首次超越人类水平,斩获竞赛第一名的同时并拿到2016年CVPR最佳论文。

一、提出ResNet原因

网络是不是越深越好?直到把计算机的性能榨干为止。而在实验中可以发现,随着网络加深,训练集的错误率反而更高,这种现象被称作为“网络退化”。从下图中可以看出,无论是训练集还是验证集,56层的网络比20层的网络都更差,这是因为在运用链式法则反向传播时,梯度或消失、或爆炸。

在这里插入图片描述

二、深度残差模块

1.数学理论基础

复杂问题简单解决,公式 F ( x ) + x F(x)+x F(x)+x在不添加可学习参数的前提下提升了网络性能。极端情况下,权重层(weight layer)已经收敛不再更新任何参数,“网络退化”说明 F ( x ) F(x) F(x)通道向着变坏的方向迭代,而添加的恒等映射(Identity)仅复制上一层的输出特征,一定程度上阻碍了更坏的情况发生。有点类似物理学中的楞次定律,若权重层的网络是不断进化的,恒等映射则同样阻碍更好的情况发生。 y l = h ( x l ) + F ( x l , W l ) x l + 1 = f ( y l ) \begin{gathered} \mathbf{y}_{l}=h\left(\mathbf{x}_{l}\right)+\mathcal{F}\left(\mathbf{x}_{l}, \mathcal{W}_{l}\right) \\ \mathbf{x}_{l+1}=f\left(\mathbf{y}_{l}\right) \end{gathered} yl=h(xl)+F(xl,Wl)xl+1=f(yl)
在这里插入图片描述

2.深度网络结构

只要保证 F ( x ) F(x) F(x) x x x相加时的张量维度保持一致,就可以构造出残差模块block,以卷积神经网络为例,[kernel, stride, padding]=[1×1,1,0]和[3×3,1,1]均不会改变张量维度,可以根据图像尺寸大小适当调整卷积核算子,何恺明在论文中给出了几种经典的构造方式,如:resnet50和resnet101。
在这里插入图片描述

三、Pytorch代码实现

论文代码复现tips:Block模块应保证输入和输出的张量维度一致,即C=256、512、1024、2048,卷积核的运算亦不会改变特征图的尺寸。flatten展开前使用AdaptiveAvgPool2d将特征图尺寸降为[1, 4096, 1, 1],接fc层就不用考虑维度变换问题。以下代码为resnet50:

import torch
import torch.nn as nn

class Block(nn.Module):
    def __init__(self, in_channels, out_channels):
        super(Block, self).__init__()
        self.conv1 = nn.Conv2d(out_channels, in_channels, 1, 1, 0)
        self.bn1 = nn.BatchNorm2d(in_channels)
        self.conv2 = nn.Conv2d(in_channels, in_channels,  3, 1, 1)
        self.bn2 = nn.BatchNorm2d(in_channels)
        self.conv3 = nn.Conv2d(in_channels, out_channels, 1, 1, 0)
        self.bn3 = nn.BatchNorm2d(out_channels)
        self.relu = nn.ReLU()
        
    def forward(self, input):
        x = input
        f_x = self.bn1(self.conv1(x))
        f_x = self.bn2(self.conv2(f_x))
        f_x = self.bn3(self.conv3(f_x))
        out = self.relu(x + f_x)		#精华
        return out

class Resnet(nn.Module):
    def __init__(self, n_classes=1000, input_channels=3):
        super(Resnet, self).__init__()
        self.conv0 = nn.Conv2d(input_channels, 64, kernel_size=7, stride=2, padding=3)
        self.bn0 = nn.BatchNorm2d(64)
        self.relu0 = nn.ReLU()
        self.conv1 = nn.Conv2d(64, 256, 1, 1, 0)
        self.bn1 = nn.BatchNorm2d(256)
        self.relu1 = nn.ReLU()
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
        
        self.layer1 = self._make_layer(64, 256, 3)
        self.layer2 = self._make_layer(128, 512, 4)
        self.layer3 = self._make_layer(256, 1024, 6)
        self.layer4 = self._make_layer(512, 2048, 3)
        
        self.avgpool = nn.AdaptiveAvgPool2d(output_size=1)
        self.flatten = nn.Flatten(start_dim=1, end_dim=-1)
        self.fc = nn.Linear(4096, n_classes)
        
    def _make_layer(self, in_channels, out_channels, num):
        layers = []
        for _ in range(0, num):
            layers.append(Block(in_channels, out_channels))
        layers.append(nn.Sequential(
            nn.Conv2d(out_channels, out_channels*2, 1, 1, 0),
            nn.BatchNorm2d(out_channels*2),
            nn.MaxPool2d(2, 2, 0)))
        return nn.Sequential(*layers)
        
    def forward(self, input):
        x = self.relu0(self.bn0(self.conv0(input)))
        x = self.relu1(self.bn1(self.conv1(x)))
        x = self.maxpool(x)
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)
        x = self.avgpool(x)
        x = self.flatten(x)
        x = self.fc(x)
        return x
    
def main():
    ins = torch.randn(1, 3, 224, 224)
    model = Resnet()
    out = model(ins)
    print('out shape:', out.shape)
    
if __name__ == '__main__':
    main()
"""
out shape: torch.Size([1, 1000])
"""

四、总结

开源框架(Pytorch、PaddlePaddle)都具有Resnet模型的库函数,开发者可以直接调用函数名来训练模型,对于不同场景的任务需求甚至都有预训练好的参数文件。作者在复现代码的过程中,并非一成不变地搬运code,只是保证在每个阶段的输出维度保持一致,对于图像分类任务的精度表现,有待进一步实践验证,越来越想揭开MobileNetShffuleNet的面纱。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值