ResNet 残差网络 (乘法→加法的思想 - 残差连接是所有前沿模型的标配) + 代码实现 ——笔记2.16《动手学深度学习》

目录

前言

0. 乘法变加法的思想

1. 函数类

2. 残差块 (讲解+代码)

QA: 残差这个概念的体现?

3. ResNet模型 (代码+讲解)

补充:更多版本的ResNet

4. 训练模型

5. 小结

6. ResNet的两大卖点

6.1 加深模型可以退化为浅层模型

6.2 用加法解决梯度消失问题


前言

  • 课程全部代码(pytorch版)已上传到附件
  • 本章节为原书第7章(现代卷积),共分为7节,本篇是第6节:残差网络(ResNet)
  • 本节的代码位置为:chapter_convolutional-modern/resnet.ipynb
  • 本节的视频链接:29 残差网络 ResNet【动手学深度学习v2】_哔哩哔哩_bilibili


0. 乘法变加法的思想

  • 现在所有新的网络,不管是Bert还是Transformer,Residual connection(残差连接)算是标配了,得到了广泛应用
  • Residual connection 在一定程度上体现了“乘法变加法”的思想
    • 比如Transformer在多头注意力机制之后,会将输入与注意力层的输出相加
  • “让乘法变加法”
  • 使用 “让乘法变加法” 来训练的模型,包括ResNet, LSTM, CNN
  • 原先是用乘法进行线性变换:在深度神经网络中,每一层的输出是该层里的权重参数输入的元素逐个相乘,然后求和
  • 乘法容易导致梯度消失/爆炸(指数效应)
  • ResNet的核心:层数很多的时候,使用加法而不是乘法 (来传递信号)
  • LSTM:时序就是句子长度,例如把句子按照单词 (一个单词一个时序) 划分成一个一个的时序 (输入)
    • 原始的时序神经网络是对每一个时序做乘法,句子太长就会梯度消失/爆炸
    • LSTM将乘法变成加法
  • 加法出问题的概率远低于乘法(关于为什么,可参考本文6. ResNet的两大卖点

随着我们设计越来越深的网络,深刻理解“新添加的层如何提升神经网络的性能”变得至关重要。更重要的是设计网络的能力,在这种网络中,添加层会使网络更具表现力, 为了取得质的突破,我们需要一些数学基础知识。

1. 函数类

Non-nested function classes (非嵌套函数类)?;    Nested function classes (嵌套函数类)√

:label:fig_functionclasses

因此,只有当较复杂的函数类包含较小的函数类时,我们才能确保提高它们的性能。 对于深度神经网络,如果我们能将新添加的层训练成恒等映射(identity function)𝑓(𝐱)=𝐱,新模型和原模型将同样有效。 同时,由于新模型可能得出更优的解来拟合训练数据集,因此添加层似乎更容易降低训练误差。

针对这一问题,何恺明等人提出了残差网络(ResNet) :cite:He.Zhang.Ren.ea.2016。 它在2015年的ImageNet图像识别挑战赛夺魁,并深刻影响了后来的深度神经网络的设计。 残差网络的核心思想是:每个附加层都应该更容易地包含原始函数作为其元素之一。 于是,残差块(residual blocks)便诞生了,这个设计对如何建立深层神经网络产生了深远的影响。 凭借它,ResNet赢得了2015年ImageNet大规模视觉识别挑战赛。

2. 残差块 (讲解+代码)

让我们聚焦于神经网络局部:如图 :numref:fig_residual_block所示,假设我们的原始输入为𝑥,而希望学出的理想映射为𝑓(𝐱)(作为 :numref:fig_residual_block上方激活函数的输入)。 :numref:fig_residual_block左图虚线框中的部分需要直接拟合出该映射𝑓(𝐱),而右图虚线框中的部分则需要拟合出残差映射𝑓(𝐱)−𝐱。 残差映射在现实中往往更容易优化。

  • 拟合:就好比一个学生通过大量的练习题(数据)来摸索和总结出解题的方法和规律(拟合出的函数或模型),使用规律用输入得出正确的输出
  • 映射𝑓(𝐱):在这里可理解为模型本身,用输入x得出正确(预测)的输出𝑓(𝐱),就是一个映射

QA: 残差这个概念的体现?

  • 为什么是叫残差网络:
    • 粗浅理解:因为训练损失的时候是块的输出+块的输入x = f(x)这个映射(模型),因此块的输出 = f(x) - 块的输入x,f(x) - x就是残差啦
    • 深入理解:

      问题18: 残差这个概念体现在什么地方? 就是因为 f(x) = x + g(x), 所以g(x)可以视为f(x)的残差吗?

      李沐:因为x来自于上个块的输入,在底层(靠近数据),会先训练x(靠近底层),如图所示:

      把模型类比为 f(x) = x (layer1) + g(x) (layer2),两个要训练的层的叠加

      蓝色线:是一开始的模型 x (layer1),假设有152层,先训练前面18层,先学出个简单的模型

      红色线:训练的后期再不断加入残差让模型更复杂,即在 x (layer1) 基础上叠加 g(x) (layer2) ,比如训练完152层,红色线蓝色线的距离就是残差

以本节开头提到的恒等映射作为我们希望学出的理想映射𝑓(𝐱),我们只需将 :numref:fig_residual_block中右图虚线框内上方的加权运算(如仿射)的权重和偏置参数设成0,那么𝑓(𝐱)即为恒等映射。 实际中,当理想映射𝑓(𝐱)极接近于恒等映射时,残差映射也易于捕捉恒等映射的细微波动。 :numref:fig_residual_block右图是ResNet的基础架构--残差块(residual block)。 在残差块中,输入可通过跨层数据线路更快地向前传播

:label:fig_residual_block

ResNet沿用了VGG完整的3×3卷积层设计。 残差块里首先有2个有相同输出通道数的3×3卷积层。 每个卷积层后接一个批量规范化层和ReLU激活函数。 然后我们通过跨层数据通路,跳过这2个卷积运算,将输入直接加在最后的ReLU激活函数前。 这样的设计要求2个卷积层的输出与输入形状一样,从而使它们可以相加。 如果想改变通道数,就需要引入一个额外的1×1卷积层来将输入变换成需要的形状后再做相加运算。 残差块的实现如下:

In [1]:

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_1x1convzhi指要不要用1×1的卷积层use_1x1conv=False, strides=1):  # 如果想改变通道数,就用1×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:  # 如果用上了1×1卷积self.conv3 = nn.Conv2d(input_channels, num_channels,kernel_size=1, stride=strides)else:  # 不改变通道数的情况self.conv3 = Noneself.bn1 = nn.BatchNorm2d(num_channels)  # 残差块里的两个BNself.bn2 = nn.BatchNorm2d(num_channels)  # 都是2D卷积,输入输出的形状是(批量, 通道数, 高, 宽)
​def forward(self, X):Y = F.relu(self.bn1(self.conv1(X)))  # 对着下方架构图看就很好理解Y = self.bn2(self.conv2(Y))if self.conv3:  # 判断有没有1×1卷积改变通道数X = self.conv3(X)  # 如果有, 用1×1卷积改变一下输入X的通道数# ※ 这里是残差连接(Residual Connection)的核心体现 ※Y += X  # 不管通道有没有改变, 都得践行一下残差连接的思想: 输出的残差 + X = f(X) ※return F.relu(Y)  # 再做一下relu
 

如 :numref:fig_resnet_block所示,此代码生成两种类型的网络: 一种是当use_1x1conv=False时,应用ReLU非线性函数之前,将输入添加到输出。 另一种是当use_1x1conv=True时,添加通过1×1卷积调整通道和分辨率。

:label:fig_resnet_block

下面我们来查看[输入和输出形状一致]的情况。

In [2]:

blk = Residual(3,3)  # 输入和输出形状一致=3的残差块
X = torch.rand(4, 3, 6, 6)  # (批量, 通道数, 高, 宽)
Y = blk(X)  # 输出的f(x)
Y.shape
Out[2]:
torch.Size([4, 3, 6, 6])

我们也可以在[增加输出通道数的同时,减半输出的高和宽]。

In [3]:

blk = Residual(3,6, use_1x1conv=True, strides=2)  # strides=2 会让高宽减半
blk(X).shape
Out[3]:
torch.Size([4, 6, 3, 3])

3. ResNet模型 (代码+讲解)

ResNet的前两层跟之前介绍的GoogLeNet中的一样: 在输出通道数为64、步幅为2的7×7卷积层后,接步幅为2的3×3的最大汇聚层。 不同之处在于ResNet每个卷积层后增加了批量规范化层。

In [4]:

b1 = nn.Sequential(nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3),  # 输入通道维1是因为咱使用的nn.BatchNorm2d(64), nn.ReLU(), # stride=2 高宽减半      # Fashion-MNIST数据集是单通道的nn.MaxPool2d(kernel_size=3, stride=2, padding=1))  # 高宽再减半
 

GoogLeNet在后面接了4个由Inception块组成的模块。 ResNet则使用4个由残差块组成的模块,每个模块使用若干个同样输出通道数的残差块。 第一个模块的通道数同输入通道数一致。 由于之前已经使用了步幅为2的最大汇聚层,所以无须减小高和宽。 之后的每个模块在第一个残差块里将上一个模块的通道数翻倍,并将高和宽减半。

下面我们来实现这个模块。注意,我们对第一个模块做了特别处理。

In [5]:

def resnet_block(input_channels, num_channels, num_residuals,first_block=False):blk = []  # 存放块for i in range(num_residuals):  # num_residuals:块的数量if i == 0 and not first_block:blk.append(Residual(input_channels, num_channels,use_1x1conv=True, strides=2))  # 看架构图,第1个块一般是高宽减半, 通道翻倍else:  # 看架构图,第1个块之后的块一般不改变高宽和通道数blk.append(Residual(num_channels, num_channels))return blk  # 返回这些块用于nn.Sequential定义网络
 

接着在ResNet加入所有残差块,这里每个模块(stage/残差块组)使用2个残差块。

In [6]:

# 每个模块都是两个残差块的组合(stage/残差块组)
b2 = nn.Sequential(*resnet_block(64, 64, 2, first_block=True))  # num_residuals=2时
b3 = nn.Sequential(*resnet_block(64, 128, 2))  # 一次循环时:i = 0;第二次循环时:i = 1,就循环两次
b4 = nn.Sequential(*resnet_block(128, 256, 2))  # 通道数不断加倍
b5 = nn.Sequential(*resnet_block(256, 512, 2))
# “*”指的是把block从list形式展开,展成nn.Sequential的可用传参
 

最后,与GoogLeNet一样,在ResNet中加入全局平均汇聚层,以及全连接层输出。

In [7]:

net = nn.Sequential(b1, b2, b3, b4, b5,nn.AdaptiveAvgPool2d((1,1)),nn.Flatten(), nn.Linear(512, 10))  # nn.Flatten()展平
 

每个模块有4个卷积层(不包括恒等映射的1×1卷积层)。 加上第一个7×7卷积层和最后一个全连接层,共有18层。 因此,这种模型通常被称为ResNet-18。 通过配置不同的通道数和模块里的残差块数可以得到不同的ResNet模型,例如更深的含152层的ResNet-152。 虽然ResNet的主体架构跟GoogLeNet类似,但ResNet架构更简单,修改也更方便。这些因素都导致了ResNet迅速被广泛使用。 :numref:fig_resnet18描述了完整的ResNet-18。

:label:fig_resnet18

补充:更多版本的ResNet

  • 横坐标是计算速度,纵坐标是准确率
  • 圆点的面积大小,指的是内存占用的相对大小(圆点越大,越占内存)
  • ResNet经过多年改进,有了超多版本,一般使用预训练的resnet50就够啦

  • 可以看到resnet的效果非常好,而且有很多版本,比如resnet18,常用的是resnet50

在训练ResNet之前,让我们[观察一下ResNet中不同模块的输入形状是如何变化的]。 在之前所有架构中,分辨率降低,通道数量增加,直到全局平均汇聚层聚集所有特征。

In [8]:

X = torch.rand(size=(1, 1, 224, 224))
for layer in net:X = layer(X)print(layer.__class__.__name__,'output shape:\t', X.shape)
Sequential output shape:	 torch.Size([1, 64, 56, 56])
Sequential output shape:	 torch.Size([1, 64, 56, 56])
Sequential output shape:	 torch.Size([1, 128, 28, 28])
Sequential output shape:	 torch.Size([1, 256, 14, 14])
Sequential output shape:	 torch.Size([1, 512, 7, 7])
AdaptiveAvgPool2d output shape:	 torch.Size([1, 512, 1, 1])
Flatten output shape:	 torch.Size([1, 512])
Linear output shape:	 torch.Size([1, 10])

4. 训练模型

同之前一样,我们在Fashion-MNIST数据集上训练ResNet。

In [9]:

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())
 

5. 小结

  • 残差块使得很深的网络更加容易训练;
    • 甚至可以训练一千层的网络;
  • 残差网络的 Residual connection(残差连接)对随后的深层神经网络设计产生了深远影响,无论是卷积类网络还是全连接类网络;
  • 学习嵌套函数(nested function)是训练神经网络的理想情况。在深层神经网络中,学习另一层作为恒等映射(identity function)较容易(尽管这是一个极端情况)。
  • 残差网络(ResNet)对随后的深层神经网络设计产生了深远影响。

6. ResNet的两大卖点

6.1 加深模型可以退化为浅层模型

  1.  使得深层网络(x (layer1) + g(x) (layer2))在性能不好的时候能够退化为浅层网络(x (layer1))
  2. 模型加深,性能至少不会下降

6.2 用加法解决梯度消失问题

梯度大小的角度来解释,residual connection 使得靠近数据的层的权重 w 也能够获得比较大的梯度;因此,不管网络有多深,下面的层都是可以拿到足够大的梯度,使得网络能够比较高效地更新

  1. 乘法导致梯度消失:训练很深的神经网络时,由于(反向传播)计算梯度时的链式法则中的乘法,导致容易在靠近输入的层出现梯度消失的问题: 
    1. 由于这个计算过程中包含了多个乘法运算,如果在传播过程中每一项的梯度值都 小于 1,那么随着层数的增加,这些小于 1 的数不断相乘,就会导致梯度越来越小,靠近输入层的梯度可能会趋近于零,这就是梯度消失问题。
  2. 使用加法的残差连接:(不会导致梯度消失
    1. 残差连接的结构
    2. 加法不会导致梯度消失的原因
      1. 从而缓解了梯度消失问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/59965.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iphone怎么删除重复的照片的新策略

Phone用户常常面临存储空间不足的问题,其中一个主要原因是相册中的重复照片。这些重复项不仅占用了大量的存储空间,还会影响设备的整体性能。本文将向您展示iphone怎么删除重复的照片的方法,包括一些利用工具来自动化这个过程的创新方法。 识…

软件缺陷等级评定综述

1. 前言 正确评估软件缺陷等级,在项目的生命周期中有着重要的作用: 指导缺陷修复的优先级和资源分配 在软件开发和维护过程中,资源(包括人力、时间和资金)是有限的。通过明确缺陷的危险等级,可以帮助团队合…

【Pikachu】Cross-Site Scripting跨站脚本攻击实战

只管把目标定在高峰,人家要笑就让他去笑! 1.XSS(跨站脚本)概述 XSS(跨站脚本)概述 Cross-Site Scripting 简称为“CSS”,为避免与前端叠成样式表的缩写"CSS"冲突,故又称…

【SpringBoot】 黑马大事件笔记-day2

目录 用户部分 实体类属性的参数校验 更新用户密码 文章部分 规定josn日期输出格式 分组校验 上期回顾:【SpringBoot】 黑马大事件笔记-day1 用户部分 实体类属性的参数校验 对应的接口文档: 基本信息 请求路径:/user/update 请求方式&#…

大数据面试题--kafka夺命连环问

1、kafka消息发送的流程? 在消息发送过程中涉及到两个线程:一个是 main 线程和一个 sender 线程。在 main 线程中创建了一个双端队列 RecordAccumulator。main 线程将消息发送给双端队列,sender 线程不断从双端队列 RecordAccumulator 中拉取…

QT信号和槽与自定义的信号和槽

QT信号和槽与自定义的信号和槽 1.概述 这篇文章介绍下QT信号和槽的入门知识,通过一个案例介绍如何创建信号和槽,并调用他们。 2.信号和槽使用 下面通过点击按钮关闭窗口的案例介绍如何使用信号和槽。 创建按钮 在widget.cpp文件中创建按钮代码如下 …

unity显示获取 年月日周几【日期】

unity显示获取 年月日周几【日期】 public void ShowDate(Text txt){//txt.text DateTime now DateTime.Now; // 获取当前时间int year now.Year; // 获取年份int month now.Month; // 获取月份(1-12)int day now.Day; // 获取天数(1-31&…

emr上使用sparkrunner运行beam数据流水线

参考资料 https://time.geekbang.org/column/intro/167?tabcatalog Apache Beam和其他开源项目不太一样,它并不是一个数据处理平台,本身也无法对数据进行处理。Beam所提供的是一个统一的编程模型思想,而我们可以通过这个统一出来的接口来编…

AUTOSAR CP SocketAdaptor(SoAd)规范导读

《AUTOSAR_SWS_SocketAdaptor》规范的主要内容包括: 简介和功能概述:说明了 AUTOSAR 基本软件模块 Socket Adaptor(SoAd)的功能、API 和配置。数据传输的 TCP/IP 概念在计算和电信环境中已成为标准,应用程序的寻址等…

代码随想录-栈和队列-用栈实现队列

问题描述 题目描述中有说不存在空栈的pop和peek,所以无需判断这个 解析 重点在于思路,代码白给。 要用栈实现队列,肯定是两个栈才可以。一个做入队操作,一个做出队操作。 首先入队简单,往栈里加就完事了。 出队复…

【设计模式】结构型模式(四):组合模式、享元模式

《设计模式之结构型模式》系列,共包含以下文章: 结构型模式(一):适配器模式、装饰器模式结构型模式(二):代理模式结构型模式(三):桥接模式、外观…

轻型民用无人驾驶航空器安全操控------理论考试多旋翼部分笔记

官网:民用无人驾驶航空器综合管理平台 (caac.gov.cn) 说明:一是法规部分;二是多旋翼部分 本笔记全部来源于轻型民用无人驾驶航空器安全操控视频讲解平台 目录 官网:民用无人驾驶航空器综合管理平台 (caac.gov.cn) 一、轻型民用无人…

【leetcode练习·二叉树】用「分解问题」思维解题 I

本文参考labuladong算法笔记[【强化练习】用「分解问题」思维解题 I | labuladong 的算法笔记] 105. 从前序与中序遍历序列构造二叉树 | 力扣 | LeetCode | 给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵…

深入解析四种核心网络设备:集线器、桥接器、路由器和交换机

计算机网络系列课程《网络核心设备》 在现代网络技术中,集线器、桥接器、路由器和交换机扮演着至关重要的角色。本文,将深入探讨这四种设备的功能、工作原理及其在网络架构中的重要性。 集线器:基础网络连接设备 集线器(Hub&…

宏景eHR uploadLogo.do 任意文件上传致RCE漏洞复现

0x01 产品简介 宏景eHR人力资源管理软件是一款专为复杂单组织或多组织客户设计的人力资源管理软件,融合了最新的互联网技术和先进的人力资源管理理念和实践。宏景eHR软件支持B/S架构,特别适合集团化管理和跨地域使用。它提供了全面的人力资源管理功能,包括人员、组织机构、…

ssm基于JAVA的网上订餐管理系统+vue

系统包含:源码论文 所用技术:SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习,获取源码看文章最下面 需要定制看文章最下面 目 录 目 录 I 摘 要 III ABSTRACT IV 1 绪论 1 1.1 课题背景 1 1.2 研究现状 1 1.3 研究内容…

NVR设备ONVIF接入平台EasyCVR私有化部署视频平台如何安装欧拉OpenEuler 20.3 MySQL

在当今数字化时代,安防视频监控系统已成为保障公共安全和个人财产安全的重要工具。NVR设备ONVIF接入平台EasyCVR作为一款功能强大的智能视频监控管理平台,它不仅提供了视频远程监控、录像、存储与回放等基础功能,还涵盖了视频转码、视频快照、…

测试网空投进行中 — 全面了解 DePIN 赛道潜力项目 ICN Protocol 及其不可错过的早期红利

随着云计算技术的飞速发展,越来越多的企业和个人对云服务的需求变得多样化且复杂化。然而,传统的中心化云服务平台(如AWS、微软Azure等)往往存在着高成本、数据隐私保护不足以及灵活性差等问题。 为了解决这些挑战,Imp…

CulturalBench :一个旨在评估大型语言模型在全球不同文化背景下知识掌握情况的基准测试数据集

2024-10-04,为了提升大型语言模型在不同文化背景下的实用性,华盛顿大学、艾伦人工智能研究所等机构联合创建了CulturalBench。这个数据集包含1,227个由人类编写和验证的问题,覆盖了包括被边缘化地区在内的45个全球区域。CulturalBench的推出&…

CAD VBA 图元颜色跟随图层

效果如下: 一、所有图元颜色为bylayer Sub 图元颜色跟随图层() Dim item As AcadEntityFor Each item In ThisDrawing.ModelSpace item.color acByLayer Next ThisDrawing.Regen acActiveViewport End Sub二、与图层颜色相同(不是bylayer):…