当前位置: 首页 > news >正文

7.6 残差网络

随着我们设计越来越深网络深刻理解 添加如何提升神经网络性能变得至关重要。更重要设计网络能力在这种网络添加使网络更具有表达为了取得突破需要一些数学基础

7.6.1 函数

假设有一类特定神经网络架构F包括学习率其他参数设置对于所有f属于F存在一些参数这些参数可以通过合适数据集上进行训练获得现在假设f我们真正想找到函数如果f属于F那么可以轻而易举通过网络得到通常不会那么幸运我们尝试找到一个函数f这是F最佳选择例如给定一个具有X特性y标签数据集我们可以尝试通过解决以下优化问题找到

F = argminL(X,y,f)

怎样得到更接近真正f函数唯一合理可能是我们需要设计一个更强架构F换句话说我们预计fF接近然而如果F则无法保证新的体系接近事实f 可能更糟如图7-7所示对于嵌套函数较为复杂函数并不总函数f靠拢7x7左侧虽然F3F

接近f函数但是F6离得更远了对于7-7右侧嵌套函数F1 <= F6, 我们可以避免上述问题

7-7 对于嵌套函数 较为复杂函数不能保证更接近函数f这种现象嵌套函数会发生

因此只有较复杂函数包含较小函数我们才能确保提高他们性能对于深度神经网络如果我们 能将新添加训练成恒等函数f(x) = x模型源模型同样有效,同时由于模型可能更优拟合训练数据集因此添加层四户更容易见效训练误差

针对这个问题提出了残差网络ResNet2015ImageNet 图像识别挑战赛夺魁并深刻影响了后来深度神经网络设计残差网络核心思想每个附加层都应该容易包含原始函数作为元素之一残差块便诞生这个设计对于如何建立深度神经网络影响ResNet赢得了2015ImageNet大规模视觉识别挑战赛

7.6.2 残差块

聚焦于神经网络局部如图7-8所示假设原始输入x希望学习理想映射f(x) 7-8作图虚线部分需要直接拟合映射f(x)右图虚线部分需要拟合残差映射f(x)我们只需要7-8虚线上方运算权重偏置参数设置0那么f(x)恒等函数世纪钟理想映射f(x) 基础架构--残差块残差块输入通过跨层数据通路更快向前传播

激活函数f(x) 权重 激活函数 权重层

激活函数 f(x) f(x) 权重 激活函数 权重层

7-8 一个正常一个残差块

ResNet沿用了VGG完整3x3卷积层设计残差块首先2相同输出通道数3x3卷积层每个卷积层一个批量规范化ReLU激活函数我们通过数据通道跳过2卷积运算输入直接最后ReLU激活函数这样设计要求2卷积层输出输入形状相同从而使得他们可以相加如果想要改变通道数需要引入一个额外1x1卷积层输入变换所需要形状后运算残差块实现如下

import pytorch

from torch import nn

from torch.nn import functional as F

from d2l import torch as d2l

class Residual(nn.Module):

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)

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

return F.relu(Y)

r如图7-9所示执行此代码生成两种类型网络一种use_1x1conv=False应用ReLU线性函数之前输入添加到输出另一种use_1x1conv = True通过添加1x1卷积层调整通道分辨率

RELU

批量规范化

3x3卷积层

ReLU

批量规范化

3x3卷积层

x

RELU

批量规范化

3x3卷积层

RELU

批量规范化

3x3卷积层

1x1卷积层

下面我们查看输入和输出形状一致情况

blk = Residual(3,3)

X=torch.rand(4,3,6,6)

Y = blk(X)

  1. shape
  2. torch.size[4,3,6,6]
  3. 我们也可以增加输出通道数同时减半输出高度宽度
  4. blk=Residual(3,6,use_1x1conv=True,strides=2)
  5. blk(X).shape
  6. torch.size([4,6,3,3])
  7. 7.6.3 ResNet模型

ResNet两层之前介绍GoogleNet一样输出通道数64步骤27x7卷积步骤23x3最大汇聚层不同之处在于ResNet每个卷积层增加批量规范化

b1 = nn.Sequential(nn.Conv2d(1,64,kernel_size=7,stride=2,apdding=3),

nn.BatchNorm2d(64), nn.ReLU(),

nn.MaxPool2d(kernel_size=3, stride=2, padding=1))

GoogleNet在后面接了4Inception组成模块ResNet使用4残差组成模块每个模块使用若干输出通道数相同残差块第一个模块通道数输入通道数一致由于之前已经使用了步骤2最大汇聚层因此无须减少高度宽度之后每个模块第一个残差块上一个模块通道数翻倍高度宽度减半

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

def resnet_block(input_channels, num_channels, num_residuals, first_block=False):

bllk=[]

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

return blk

接着ResNet加入所有残差块这里每个模块使用2残差块

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

最后GoogleNet一样ResNet加入全局平均汇聚层以及全连接输出

net = nn.Sequential(b1,b2,b3,b4,b5,

nn.AdaptivePool2d(1,1),

nn.Flatten(),nn.Linear(512,10))

每个模块4卷积层加上第一个7x7卷积层最后一个全连接层18

因此这种模型通常被称为ResNet-18. 通过配置不同通道数模块里面残差块可以得到不同ResNet模型例如更深152ResNet-152虽然ResNet主题架构GooGLeNet类似但是ResNet架构简单修改更方便ResNet广泛使用7-10展示完整ResNet-18架构

训练ResNet之前我们观察一个ResNet不同模块输入形状如何变化在之前所有架构分辨率降低通道数增加直到全局平均汇聚层聚合所有特征

X=torch.rand(size=(1,1,224,224))

for layer in net:

X = layer(X)

Sequential output shape: torch.Size(1,64,56,56)

Sequential output shape: torch.Size(1,64,56,56)

AdaptiveAvgPool2d output shape

Flatten output shape

Linear output shape

7.6.4 训练模型

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

lr, num_epochs, batch_size=0.05, 10. 256

train_iter, test_iter=d2l.load_data_fashion_mnist(batch_szie, resize=96)

d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

小结

学习嵌套函数训练神经网络理想情况在深度神经网络中, 学习另一层作为恒等函数较为容易

残差映射可以更容易学习同一函数例如使权重参数接近

利用残差可以训练一个有效深度神经网络输入可以通过残余连接更快向前传播

残差网络ResNet 其后深度神经网络设计产生深远影响

http://www.dtcms.com/a/348355.html

相关文章:

  • Palantir Foundry 领先其他数据平台5到10年:一位使用者的深入观察
  • vscode配置remote-ssh进行容器内开发
  • BQTLOCK 勒索软件即服务出现,拥有复杂的规避策略
  • MRO and mixin in Python Django
  • GD32VW553-IOT 测评和vscode开发环境搭建
  • Flutter性能优化完全指南:构建流畅应用的实用策略
  • 多奥将梯控系统、无线网桥及工业交换机的核心功能与参数整合为结构化表格,并补充应用价值分析
  • rust语言 (1.88) egui (0.32.1) 学习笔记(逐行注释)(十八) 使用表格
  • 时间复杂度
  • 多核多线程应用程序开发可见性和乱序如何处理
  • ESNP LAB 笔记:配置MPLS(Part2)
  • Java Stream API详解
  • iptables 防火墙核心知识梳理(附实操指南)
  • VS2022的MFC中关联使用控制台并用printf输出调试信息
  • GPT 模型详解:从原理到应用
  • 构建AI智能体:十二、给词语绘制地图:Embedding如何构建机器的认知空间
  • 大白话解析:多证明验证(Merkle Multi-Proof)​
  • 【Python】CSV批量转Excel工具 (Tkinter版)
  • 【Docker基础】Docker-compose多容器协作案例示例:从LNMP到分布式应用集群
  • 复杂姿态误报率↓78%!陌讯多模态算法在跌倒检测的医疗落地
  • 恶劣天气下漏检率↓79%!陌讯多模态时序融合算法在道路事故识别的实战优化
  • 第16届蓝桥杯C++中高级选拔赛(STEMA)2025年1月12日真题
  • 大模型面试题剖析:模型微调和蒸馏核心技术拆解与考点梳理
  • 爆肝三周,我终于上线了自己的第一个小程序
  • 01-鸿蒙系统概览与发展历程
  • 鸿蒙中Frame分析
  • 线段树相关算法题(1)
  • mybatis过渡到mybatis-plus过程中需要注意的地方
  • 自由学习记录(87)
  • 《飞算Java开发实战:从入门安装到项目部署》