李沐--动手学深度学习 ResNet

2024-08-27 23:20

本文主要是介绍李沐--动手学深度学习 ResNet,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.理论

2.残差块

import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2l#ResNet沿用了VGG完整的3*3卷积层设计.残差块的实现如下:
#此代码生成两种类型的网络:
#一种是当use_1x1conv=False时,应用ReLU非线性函数之前,将输入添加到输出。
#另一种是当use_1x1conv=True时,添加通过1*1卷积调整通道和分辨率。
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 = Noneself.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 += Xreturn F.relu(Y)#下面来查看输入和输出形状一致的情况。
b1k = Residual(3,3)
X = torch.rand(4,3,6,6)
Y = b1k(X)
print(Y.shape)
#也可以在增加输出通道数的同时,减半输出的高和宽
b1k = Residual(3,6,use_1x1conv=True,strides=2)
print(b1k(X).shape)

3.ResNet模型

import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2l#ResNet沿用了VGG完整的3*3卷积层设计.残差块的实现如下:
#此代码生成两种类型的网络:
#一种是当use_1x1conv=False时,应用ReLU非线性函数之前,将输入添加到输出。
#另一种是当use_1x1conv=True时,添加通过1*1卷积调整通道和分辨率。
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 = Noneself.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 += Xreturn F.relu(Y)'''
#下面来查看输入和输出形状一致的情况。
b1k = Residual(3,3)
X = torch.rand(4,3,6,6)
Y = b1k(X)
print(Y.shape)
#也可以在增加输出通道数的同时,减半输出的高和宽
b1k = Residual(3,6,use_1x1conv=True,strides=2)
print(b1k(X).shape)
'''#ResNet的前两层跟之前介绍的GoogLeNet中的一样,在输出通道数为64、步幅为2的7*7卷积层后,接步幅为2的3*3的最大汇聚层
#不同之处在于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))
#GoogLeNet在后面接了4个由Inception块组成的模块。
#ResNet则使用4个由残差块组成的模块,每个模块使用若干个同样输出通道数的残差块。
#第一个模块的通道数同输入通道数一致。 由于之前已经使用了步幅为2的最大汇聚层,所以无须减小高和宽。
#之后的每个模块在第一个残差块里将上一个模块的通道数翻倍,并将高和宽减半。
def resnet_block(input_channels,num_channels,num_residuals,first_block = False):b1k = []for i in range(num_residuals):if i == 0 and not first_block:b1k.append(Residual(input_channels,num_channels,use_1x1conv=True,strides=2))else:b1k.append(Residual(num_channels,num_channels))return b1k
#接着在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.AdaptiveAvgPool2d((1,1)),nn.Flatten(),nn.Linear(512,10))#在训练ResNet之前,让我们观察一下ResNet中不同模块的输入形状是如何变化的。
#在之前所有架构中,分辨率降低,通道数量增加,直到全局平均汇聚层聚集所有特征。
X = torch.rand(size=(1,1,224,224))
for layer in net:X = layer(X)print(layer.__class__.__name__,'output shape:\t',X.shape)

4.ResNet模型训练

import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2l#ResNet沿用了VGG完整的3*3卷积层设计.残差块的实现如下:
#此代码生成两种类型的网络:
#一种是当use_1x1conv=False时,应用ReLU非线性函数之前,将输入添加到输出。
#另一种是当use_1x1conv=True时,添加通过1*1卷积调整通道和分辨率。
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 = Noneself.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 += Xreturn F.relu(Y)'''
#下面来查看输入和输出形状一致的情况。
b1k = Residual(3,3)
X = torch.rand(4,3,6,6)
Y = b1k(X)
print(Y.shape)
#也可以在增加输出通道数的同时,减半输出的高和宽
b1k = Residual(3,6,use_1x1conv=True,strides=2)
print(b1k(X).shape)
'''#ResNet的前两层跟之前介绍的GoogLeNet中的一样,在输出通道数为64、步幅为2的7*7卷积层后,接步幅为2的3*3的最大汇聚层
#不同之处在于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))
#GoogLeNet在后面接了4个由Inception块组成的模块。
#ResNet则使用4个由残差块组成的模块,每个模块使用若干个同样输出通道数的残差块。
#第一个模块的通道数同输入通道数一致。 由于之前已经使用了步幅为2的最大汇聚层,所以无须减小高和宽。
#之后的每个模块在第一个残差块里将上一个模块的通道数翻倍,并将高和宽减半。
def resnet_block(input_channels,num_channels,num_residuals,first_block = False):b1k = []for i in range(num_residuals):if i == 0 and not first_block:b1k.append(Residual(input_channels,num_channels,use_1x1conv=True,strides=2))else:b1k.append(Residual(num_channels,num_channels))return b1k
#接着在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.AdaptiveAvgPool2d((1,1)),nn.Flatten(),nn.Linear(512,10))'''
#在训练ResNet之前,让我们观察一下ResNet中不同模块的输入形状是如何变化的。
#在之前所有架构中,分辨率降低,通道数量增加,直到全局平均汇聚层聚集所有特征。
X = torch.rand(size=(1,1,224,224))
for layer in net:X = layer(X)print(layer.__class__.__name__,'output shape:\t',X.shape)
'''#在Fashion-MNIST数据集上训练ResNet。
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())
d2l.plt.show()

这篇关于李沐--动手学深度学习 ResNet的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1113070

相关文章

Python 中的异步与同步深度解析(实践记录)

《Python中的异步与同步深度解析(实践记录)》在Python编程世界里,异步和同步的概念是理解程序执行流程和性能优化的关键,这篇文章将带你深入了解它们的差异,以及阻塞和非阻塞的特性,同时通过实际... 目录python中的异步与同步:深度解析与实践异步与同步的定义异步同步阻塞与非阻塞的概念阻塞非阻塞同步

Redis中高并发读写性能的深度解析与优化

《Redis中高并发读写性能的深度解析与优化》Redis作为一款高性能的内存数据库,广泛应用于缓存、消息队列、实时统计等场景,本文将深入探讨Redis的读写并发能力,感兴趣的小伙伴可以了解下... 目录引言一、Redis 并发能力概述1.1 Redis 的读写性能1.2 影响 Redis 并发能力的因素二、

最新Spring Security实战教程之表单登录定制到处理逻辑的深度改造(最新推荐)

《最新SpringSecurity实战教程之表单登录定制到处理逻辑的深度改造(最新推荐)》本章节介绍了如何通过SpringSecurity实现从配置自定义登录页面、表单登录处理逻辑的配置,并简单模拟... 目录前言改造准备开始登录页改造自定义用户名密码登陆成功失败跳转问题自定义登出前后端分离适配方案结语前言

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx

Redis 内存淘汰策略深度解析(最新推荐)

《Redis内存淘汰策略深度解析(最新推荐)》本文详细探讨了Redis的内存淘汰策略、实现原理、适用场景及最佳实践,介绍了八种内存淘汰策略,包括noeviction、LRU、LFU、TTL、Rand... 目录一、 内存淘汰策略概述二、内存淘汰策略详解2.1 ​noeviction(不淘汰)​2.2 ​LR

Python与DeepSeek的深度融合实战

《Python与DeepSeek的深度融合实战》Python作为最受欢迎的编程语言之一,以其简洁易读的语法、丰富的库和广泛的应用场景,成为了无数开发者的首选,而DeepSeek,作为人工智能领域的新星... 目录一、python与DeepSeek的结合优势二、模型训练1. 数据准备2. 模型架构与参数设置3

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操

五大特性引领创新! 深度操作系统 deepin 25 Preview预览版发布

《五大特性引领创新!深度操作系统deepin25Preview预览版发布》今日,深度操作系统正式推出deepin25Preview版本,该版本集成了五大核心特性:磐石系统、全新DDE、Tr... 深度操作系统今日发布了 deepin 25 Preview,新版本囊括五大特性:磐石系统、全新 DDE、Tree