2.11.ResNet

ResNet

动机:我们总是想加更多层,但加更多层并不总是能改进精度

在这里插入图片描述

可以看出F1到F6模型越来越大,但F6距离最优解却总变远了,反而效果不好,通俗的来说就是学偏了,实际上我们希望是这样的:
在这里插入图片描述

​ 更大的模型总是包含之前的小模型,则结果至少不会更差。

​ 这也是残差网络(ResNet)的核心思想:每个附加层都应该更容易地包含原始函数作为其元素之一。

1.残差块

​ 我们希望能串联一个层能改变函数类,让它变大:

在这里插入图片描述

​ 右侧是残差块,通过加入快速通道来得到 f ( x ) = x + g ( x ) f(x)=x+g(x) f(x)=x+g(x)的结构,如果 g ( x ) g(x) g(x)没有学到任何东西,就等价于恒等映射,可以直接跳过这个层,先去拟合小网络。显然如果使用了参拆快,那么 f ( x ) f(x) f(x)的范围肯定比 x x x大,且对输入的改变比较敏感。

ResNet块的具体细节

在这里插入图片描述

​ 可以使用1*1的卷积层来变换输出通道。箭头的位置可以随便选取,看具体效果吧

在这里插入图片描述

​ 效果都差不多

ResNet块可分为两类

  1. 高宽减半的ResNet块,即步幅为2,有1*1卷积层(步幅也设置为2)的,将输入高宽减半,输出通道自然增加,那么x需要通过1*1卷积层来变换输出通道
  2. 高宽不变的,即步幅为1,不需要使用1*1卷积层的ResNet块

2.ResNet架构

在这里插入图片描述

​ 如图所示为ResNet-18架构,类似VGG和GoogLeNet的总体架构,但替换成了ResNet块,基本架构也是这样的5阶段

  • 残差快使得很深的网络更加容易训练,甚至可以训练一千层的网络
  • 残差网络对随后的深度神经网络设计产生了深远影响

3.ResNet如何处理梯度消失


y = f ( x ) 梯度 ∂ y ∂ w w = w − D ∂ y ∂ w y= f(x)\\ 梯度\frac{\partial y}{\partial w}\\ w = w- D\frac{\partial y}{\partial w}\\ y=f(x)梯度wyw=wDwy
​ 不希望梯度变得很小,但如果又新嵌套很多层:
y ′ = g ( f ( x ) ) ∂ y ′ ∂ w = ∂ y ′ ∂ y ⋅ ∂ y ∂ w = ∂ g ( y ) ∂ y ⋅ ∂ y ∂ w y'=g(f(x))\\ \frac{\partial y'}{\partial w}=\frac{\partial y'}{\partial y}\cdot\frac{\partial y}{\partial w} =\frac{\partial g(y)}{\partial y}\cdot \frac{\partial y}{\partial w} y=g(f(x))wy=yywy=yg(y)wy
​ 如果新加的层拟合得很好,那么 ∂ g ( y ) ∂ y \frac{\partial g(y)}{\partial y} yg(y)就会很小,那么 ∂ y ′ ∂ w \frac{\partial y'}{\partial w} wy会很小,这时候我们只能增大学习率,但这样会导致顶部梯度爆炸,反之则底部梯度消失。

​ ResNet:
y ′ ′ = y + y ′ = f ( x ) + g ( f ( x ) ) ∂ y ′ ′ ∂ w = ∂ y ∂ w + ∂ y ′ ∂ w y'' = y+y' =f(x)+g(f(x))\\ \frac{\partial y''}{\partial w} =\frac{\partial y}{\partial w}+\frac{\partial y'}{\partial w} y′′=y+y=f(x)+g(f(x))wy′′=wy+wy
​ 将乘法变为了加法,这样大数加一个小数也是一个大数,这样在底部(靠近数据端的)在初始时也可以有较大的梯度(因为可以通过快速通道传递),会得到比较好的训练效果。

4.代码实现

import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2l


class Residual(nn.Module):  # @save
    def __init__(self, input_channels, num_channels,
                 use_1x1conv=False, strides=1):
        super().__init__()
        self.conv1 = nn.Conv2d(input_channels, num_channels,
                               kernel_size=3, padding=1, stride=strides)
        self.conv2 = nn.Conv2d(num_channels, num_channels,
                               kernel_size=3, padding=1)
        if use_1x1conv:
            self.conv3 = nn.Conv2d(input_channels, num_channels,
                                   kernel_size=1, stride=strides)
        else:
            self.conv3 = None
        self.bn1 = nn.BatchNorm2d(num_channels)
        self.bn2 = nn.BatchNorm2d(num_channels)
        self.relu = nn.ReLU(inplace=True)

    def forward(self, X):
        Y = F.relu(self.bn1(self.conv1(X)))
        Y = self.bn2(self.conv2(Y))
        if self.conv3:
            X = self.conv3(X)
        Y += X  # 相加后再ReLU
        return F.relu(Y)


blk = Residual(3, 3)
X = torch.rand(4, 3, 6, 6)
Y = blk(X)
print('输入和输出形状一致:', Y.shape)

blk = Residual(3, 6, use_1x1conv=True, strides=2)
print('使用步幅为2的1*1卷积层,输出通道翻倍,高宽减半:', blk(X).shape)

'''ResNet块'''
b1 = nn.Sequential(nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3),
                   nn.BatchNorm2d(64), nn.ReLU(),
                   nn.MaxPool2d(kernel_size=3, stride=2, padding=1))


def resnet_block(input_channels, num_channels, num_residuals,
                 first_block=False):
    # num_residuals表示这里面有多少个resnet块
    # first_block用于特判第一个,之前在第一阶段b1块时就已经减少了很多,所以第一个残差块不减半
    blk = []
    for i in range(num_residuals):
        if i == 0 and not first_block:
            blk.append(Residual(input_channels, num_channels,
                                use_1x1conv=True, strides=2))
        else:
            blk.append(Residual(num_channels, num_channels))
    return blk


b2 = nn.Sequential(*resnet_block(64, 64, 2, first_block=True))
b3 = nn.Sequential(*resnet_block(64, 128, 2))
b4 = nn.Sequential(*resnet_block(128, 256, 2))
b5 = nn.Sequential(*resnet_block(256, 512, 2))
net = nn.Sequential(b1, b2, b3, b4, b5,
                    nn.AdaptiveAvgPool2d((1,1)),
                    nn.Flatten(), nn.Linear(512, 10))


X = torch.rand(size=(1, 1, 224, 224))
for layer in net:
    X = layer(X)
    print(layer.__class__.__name__,'output shape:\t', X.shape)


lr, num_epochs, batch_size = 0.05, 10, 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=96)
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())
  • 30
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Keras是一种用于构建神经网络深度学习框架。keras.applications.resnet50是Keras中预训练的ResNet50模型。ResNet50是一个深度卷积神经网络,用于图像分类任务。 要使用keras.applications.resnet50,您需要安装Keras并导入它。然后,您可以使用以下代码创建ResNet50模型: ``` from keras.applications.resnet50 import ResNet50 model = ResNet50(weights='imagenet') ``` 在这里,weights参数指定使用预训练的权重,这些权重在ImageNet数据集上进行了训练。您还可以通过设置include_top参数为False来创建不包含顶部(全连接层)的模型。这在使用迁移学习时非常有用,因为您可以将自己的顶部模型添加到预训练模型中。 例如,以下代码将创建一个ResNet50模型,该模型不包含顶部,并且可以用于特征提取: ``` from keras.applications.resnet50 import ResNet50 from keras.layers import Input input_tensor = Input(shape=(224, 224, 3)) base_model = ResNet50(weights='imagenet', include_top=False, input_tensor=input_tensor) ``` 在这里,我们使用了Keras中的Input层来指定输入张量的形状,这与ResNet50模型期望的形状相同。然后我们通过设置include_top为False来创建模型,这将删除顶部的全连接层。最后,我们使用输入张量和模型权重创建模型的实例。 ### 回答2: keras.applications.resnet50是一个预训练的卷积神经网络模型,基于50层的残差网络(ResNet)架构,用于图像分类任务。ResNet的残差结构可以有效地缓解深度神经网络在训练过程中出现的梯度消失问题,使得模型更加容易训练,同时提高了模型的准确率。 keras.applications.resnet50模型包含了ImageNet图像分类任务的权重参数,拥有1000个类别预测能力,可以直接在各种图像数据集上进行Fine-tuning训练以适应不同的应用场景。同时,该模型还可被用于特征提取,即在已有的特征向量上添加新的分类器(如SVM,KNN等)进行分类任务。 除了keras.applications.resnet50之外,Keras还提供了许多其他的预训练卷积神经网络模型,如VGG16、VGG19、InceptionV3等,这些模型都可以直接使用,并能在不同的图像相关任务上获得较好的表现,因此被广泛应用于图像分类、目标检测、图像分割、人脸识别等诸多领域。 ### 回答3: keras是一个开源的深度学习框架,它提供了一系列的应用程序接口(API),使得开发者可以使用它们来构建深层神经网络模型。其中之一就是keras.applications.resnet50。 ResNet(残差网络)是2015年ILSVRC比赛的冠军网络,提出了残差学习的概念。它解决了过深的网络导致的梯度消失问题。ResNet通过引入“残差块”来拟合跨层所遇到的差异,这种方法在减少参数的同时,能够提高网络的拟合性,并且可以比较好地乘以传播梯度。 keras.applications.resnet50就是基于ResNet的50层网络进行预训练的模型。它预训练了在Imagenet数据集上的权重,使得我们能够使用这个经过训练的模型来进行特征提取或者对未知图像进行分类。 使用keras.applications.resnet50模型,我们可以很方便地进行图像分类或者特征提取。只需要将图片输入模型,输出就是一个1000维的向量,对应1000个Imagenet数据集中的类别。如果我们只需要提取特征而不需要分类,我们可以将模型的最后一层拆下来(也就是去掉最后的全连接层),输出的向量大小变为2048维,我们可以用这些特征向量来进行简单的聚类等操作。 总之,keras.applications.resnet50是一个非常强大的深度学习模型,提供了预训练权重,并且可以用于图像分类和特征提取,是许多人在图像任务中的不二选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值