- PyTorch深度学习(六):PyTorch进阶与核心(中)
- 一、torch.nn——PyTorch神经网络的核心
- 1.torch.nn.Module——神经网络的基类
- 2.torch.nn的卷积层
- 3.torch.nn的池化层
- 4.torch.nn的非线性激活函数
- 5.torch.nn的正则化层
- 6.torch.nn的线性层
- 7.torch.nn的Dropout层
- 二、案例演示:搭建CIFAR10分类网络
- 1.网络结构
- 2.构建模型
- 3.torch.nn.Sequential——网络的容器
- 4.利用torch.nn.Sequential简化网络
- 5.parameters——模型的可迭代参数
- 6.利用tensorboard可视化网络
一、torch.nn——PyTorch神经网络的核心 1.torch.nn.Module——神经网络的基类
torch.nn.Module 是所有神经网络的基类,所有搭建神经网络的子类都需要继承 torch.nn.Module,该基类为所有神经网络提供基本的骨架
- 搭建一个神经网络时,我们可以构建一个类,这个类需要继承基类 torch.nn.Module:class Model(nn.Module);
- 接着,我们需要重写 __init__() 方法,在 __init__() 方法中我们需要调用 super(Model, self).__init__() 来继承来自基类 torch.nn.Module 中的所有属性;
- 其次,每个子类要重写 forward(x) 函数,该函数表示前向传播(加入 PyTorch 计算图)的过程
- 在构建神经网络时,使用 model_name = Model() 进行实例化,同时,在进行前向传播时直接调用 model_name(x) 即可,这是因为 torch.nn.Module 内置的 __call__ 方法中调用了 forward(x) 函数,因此,调用 model_name(x) 时就相当于调用了 forward(x) 函数,以此进行前向传播
import torch.nn as nn import torch.nn.functional as F class Model(nn.Module): # 一个神经网络类 def __init__(self): super(Model, self).__init__() # 继承基类所有属性 pass def forward(self, x): # 前向传播函数 pass
后面介绍的这些方法,都是一个类,都需要实例化后再调用来进行使用
2.torch.nn的卷积层nn.Conv1d(…) 一维卷积
torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode=‘zeros’, device=None, dtype=None)
二维卷积(图片)
nn.Conv3d(…) 三维卷积
卷积核内部的元素的选取符合一定的分布规律,PyTorch文档中有作出解释
in_channels (int) 输入图像的通道数
out_channels (int) 卷积后输出的通道数
kernel_size (int or tuple) 卷积核大小,如:1×1、3×3、5×5 卷积核,tuple 则可以定义不规则的卷积核
stride (int or tuple) 卷积核移动的步距,default=1
若输入的是 tuple,则 tuple[0] 表示垂直方向的步距;则 tuple[1] 表示水平方向的步距
padding (int, tuple or str, optional) 对输入图像四周填充 0 0 0 像素点的圈数,default=0 默认不填充,填充可使输入输出的宽高不变;
若输入的是 tuple,则 tuple[0] 表示使 H 增大的方向的填充;则 tuple[1] 表示使 W 增大的方向的填充
dilation (int or tuple, optional) 卷积核中两元素的距离大小,该参数用于构造 “空洞卷积”,正常情况下卷积核两元素的距离为 1 1 1,即 default=1;当 default>1 为空洞卷积,表示卷积核两元素的距离更大,default>1 就可以形成空洞
若输入的是 tuple,则 tuple[0] 表示元素在垂直方向上的距离;则 tuple[1] 表示元素在水平方向上的距离
groups (int, optional) “分组卷积” 需要设置的参数,default=1
例如: 基于 nn.Module 构建一个卷积模型,尝试对图像进行卷积 *** 作,通过 tensorboard 对比原图和卷积后的图像,观察它们有什么区别
# 导入相关库 import torch.nn as nn import torchvision from torchvision import transforms from torch.utils.tensorboard import SummaryWriter from torch.utils.data import DataLoader class Model(nn.Module): # 构建一个简单的卷积模型 def __init__(self): super(Model, self).__init__() self.conv1 = nn.Conv2d(3, 6, 3) # 输入通道数为3,输出通道数为6,卷积核大小为3×3 def forward(self, x): # 前向传播 return self.conv1(x) totensor = transforms.ToTensor() writer = SummaryWriter("logs") # 加载数据,并按batch_size=64打包,即(64, 3, 32, 32) test_set = torchvision.datasets.CIFAR10("./CIFAR10", train=False, transform=totensor, download=True) test_loader = DataLoader(dataset=test_set, batch_size=64, shuffle=False, num_workers=0, drop_last=False) convolution_model = Model() # 实例化卷积模型 step = 0 for data in test_loader: images, labels = data writer.add_images("test_loader", images, step) # 可视化原图像 output = convolution_model(images) # 调用卷积模型 # 由于卷积后的图像为(64, 6, 30, 30),通道数为6,无法直接可视化 # 但3→6的变化实际上是两个卷积核分别作用于图像的结果 # 因此前3个通道是一个卷积核作用的结果,而后3个通道则是另一个卷积核作用的结果 writer.add_images("After Convolution1", output[:, 0:3, :, :], step) # 一个卷积核的卷积结果 writer.add_images("After Convolution2", output[:, 3:6, :, :], step) # 另一个卷积核的卷积结果 step = step + 1
由于卷积后的图像为
(
64
,
6
,
30
,
30
)
(64,6,30,30)
(64,6,30,30),通道数为6,无法直接可视化;
但通道数由
3
⟹
6
3Longrightarrow6
3⟹6 的变化实际上是两个卷积核分别作用于图像的结果;
因此前
3
3
3 个通道是一个卷积核作用的结果,而后
3
3
3 个通道则是另一个卷积核作用的结果
因此我们可以分别使用 output[:, 0:3, :, :] 和 output[:, 3:6, :, :] 来分别展示两个卷积核的卷积结果
转换结果如图所示:
1️⃣最大池化(下采样):
nn.MaxPool1d(…) 一维最大池化
torch.nn.MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False) 二维最大池化
nn.MaxPool3d(…) 三维最大池化
kernel_size (int or tuple) 池化窗口的大小
若输入的是 tuple,则 tuple[0] 表示 H;则 tuple[1] 表示 W
stride (int or tuple) 池化窗口的步距,default=kernel_size
若输入的是 tuple,则 tuple[0] 表示垂直方向的步距;则 tuple[1] 表示水平方向的步距
padding (int or tuple) 对输入特征图四周填充 0 0 0 像素点的圈数,default=0 默认不填充
若输入的是 tuple,则 tuple[0] 表示使 H 增大的方向的填充;则 tuple[1] 表示使 W 增大的方向的填充
dilation (int or tuple) 池化窗口中两元素的距离大小,和 “空洞卷积” 类似,正常情况下池化窗口两元素的距离为 1 1 1,即 default=1;当 default>1 就构成了空洞窗口
若输入的是 tuple,则 tuple[0] 表示元素在垂直方向上的距离;则 tuple[1] 表示元素在水平方向上的距离
return_indices (bool, optional) 如果为 True,则返回最大值及其所在下标,default=False
ceil_mode (bool, optional) 当图像的 W 或 H 无法整除 kernel_size 时,说明池化窗口突出了(池化窗口无法填满),ceil_mode 就决定了剩余的这些无法填满池化窗口的元素是否保留
若 ceil_mode=True,则决定保留这些元素;若 ceil_mode=False 则决定不保留这些元素,default=False
2️⃣平均池化:
torch.nn.AvgPool1d(…) 一维平均池化
torch.nn.AvgPool2d(kernel_size, stride=None, padding=0, ceil_mode=False, count_include_pad=True, divisor_override=None) 二维平均池化
torch.nn.AvgPool3d(…) 三维平均池化
kernel_size (int or tuple) 池化窗口的大小
stride (int or tuple) 池化窗口的步距,default=kernel_size
padding (int or tuple) 对输入特征图四周填充像素点的圈数,default=0 默认不填充
ceil_mode (bool) 当图像的 W 或 H 无法整除 kernel_size 时,说明池化窗口突出了(池化窗口无法填满),ceil_mode 就决定了剩余的这些无法填满池化窗口的元素是否保留
若 ceil_mode=True,则决定保留这些元素;若 ceil_mode=False 则决定不保留这些元素,default=False
count_include_pad (bool) 计算平均值时是否包含 0 0 0 填充?count_include_pad=True 时包含 0 0 0 填充,default=True
divisor_override 计算平均值时的除数,如果指定,则平均池化的除数为该参数,否则为池化窗口面积
3️⃣最大池化的逆(上采样):
nn.MaxUnpool1d(…) 一维上采样
nn.MaxUnpool2d(…) 二维上采样
nn.MaxUnpool3d(…) 三维上采样
… …
例如: 基于 nn.Module 构建一个 卷积+池化 模型,尝试对图像进行 *** 作,通过 tensorboard 对比原图和输出图像,观察它们有什么区别
import torch.nn as nn import torchvision from torchvision import transforms from torch.utils.tensorboard import SummaryWriter from torch.utils.data import DataLoader class Model(nn.Module): # 卷积+池化网络 def __init__(self): super(Model, self).__init__() self.conv1 = nn.Conv2d(3, 6, 3) # 输入通道数为3,输出通道数为6,卷积核大小为3×3 self.maxpool1 = nn.MaxPool2d(3) # 窗口大小为3×3的池化层 def forward(self, x): # 前向传播 x = self.conv1(x) y = self.maxpool1(x) return y totensor = transforms.ToTensor() writer = SummaryWriter("logs") test_set = torchvision.datasets.CIFAR10("./CIFAR10", train=False, transform=totensor, download=True) test_loader = DataLoader(dataset=test_set, batch_size=64, shuffle=False, num_workers=0, drop_last=False) model = Model() step = 0 for data in test_loader: images, labels = data writer.add_images("test_loader", images, step) output = model(images) writer.add_images("After Convolution and MaxPooling 1", output[:, 0:3, :, :], step) writer.add_images("After Convolution and MaxPooling 2", output[:, 3:6, :, :], step) step = step + 1
可以看到,经过卷积+池化后的图像明显比只经过卷积的图像更模糊了,但仍然能够看到一些特征
4.torch.nn的非线性激活函数
5.torch.nn的正则化层torch.nn.Sigmoid(x) Sigmoid激活函数
torch.nn.Tanh() Tanh激活函数
torch.nn.ReLU(inplace=False) ReLU激活函数
inplace() 是否原地替换,inplace=True 表示原地替换,default=False
torch.nn.Softmax(dim=None) Softmax函数
dim (int) Softmax 将会沿着 dim 指定的维度进行计算,因此沿着 dim 的每个切片的总和为 1 1 1
torch.nn.BatchNorm2d(num_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True, device=None, dtype=None)
正则化
论文地址:Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift
num_features (int) 通道数的数量,即输入 ( N , C , H , W ) (N,C,H,W) (N,C,H,W) 中的 C C C
eps (float) 正则化公式中为保证数值稳定性而加在分母上加的 ϵ epsilon ϵ 则,Default= 1 × 1 0 − 5 tt 1×10^{-5} 1×10−5
momentum 用于 running_mean 和 running_var 计算的值,default=0.1
affine (bool) 若 affine=True,该模块具有可学习的仿射参数,Default=True
track_running_stats (bool) 若 track_running_stats=True,该模块跟踪运行平均值 running_mean 和方差 running_var,若 track_running_stats=False,该模块不跟踪此类统计,并初始化统计缓冲区 running_mean 和running_var 为 None,当这些缓冲区为 None 时,训练和测试两种模式中该模块总是使用批处理统计信息,default=True
正则化层的类较多,这里不再作详细的说明,详情查阅 PyTorch 官网文档或相关论文
6.torch.nn的线性层7.torch.nn的Dropout层object = torch.nn.Linear(in_features, out_features, bias=True, device=None, dtype=None)
神经网络中的一层,即单层感知机
in_features (int) 输入特征数量
out_features (int) 输出特征数量
bias(bool) 是否学习偏差,若 bias=True,则该层具有偏差 b ( l ) b^{(l)} b(l),若 bias=False 则不具有偏差,default=True
具有的属性:
object.weight 该层的权重,初值的选取符合一定的分布
object.bias 该层的偏差,初值的选取符合一定的分布
二、案例演示:搭建CIFAR10分类网络 1.网络结构torch.nn.Dropout(p=0.5, inplace=False)
在训练过程中(训练模式),根据伯努利分布,将输入张量中的某些元素以概率 p 随机失活(归零),是一种防止过拟合的手段
p (float) 一个元素失活的概率,default=0.5
inplace (bool) 是否原地替换,inplace=True 表示原地替换,default=False
注意:现在已不使用 5 × 5 5×5 5×5 的卷积核了,而是使用两个 3 × 3 3×3 3×3 的卷积核来代替一个 5 × 5 5×5 5×5 的卷积核,从而减少参数量,或者使用两个 1 × 1 1×1 1×1 的卷积核和一个 3 × 3 3×3 3×3 的卷积核,此处仅当练习使用
2.构建模型import torch import torch.nn as nn import torchvision from torchvision import transforms from torch.utils.tensorboard import SummaryWriter from torch.utils.data import DataLoader class Model(nn.Module): def __init__(self): super(Model, self).__init__() self.conv1 = nn.Conv2d(3, 32, 5, padding=2) # 由于输入输出通道数不变,因此需要设置padding self.maxpool1 = nn.MaxPool2d(2) # 最大池化 self.conv2 = nn.Conv2d(32, 32, 5, padding=2) # 由于输入输出通道数不变,因此需要设置padding self.maxpool2 = nn.MaxPool2d(2) # 最大池化 self.conv3 = nn.Conv2d(32, 64, 5, padding=2) # 由于输入输出通道数不变,因此需要设置padding self.maxpool3 = nn.MaxPool2d(2) # 最大池化 self.flatten = nn.Flatten() # 压扁到一维 self.linear1 = nn.Linear(1024, 64) # 全连接层 self.relu1 = nn.ReLU() self.linear2 = nn.Linear(64, 10) self.softmax1 = nn.Softmax() def forward(self, x): # 前向传播 x = self.conv1(x) x = self.maxpool1(x) x = self.conv2(x) x = self.maxpool2(x) x = self.conv3(x) x = self.maxpool3(x) x = self.flatten(x) x = self.linear1(x) # 神经网络第一层 x = self.relu(x) # 调用ReLU激活函数 x = self.linear2(x) # 神经网络第二层 y = self.softmax(x) # 调用Softmax激活函数 return y model = Model() # 实例化模型 print(model) # 打印模型结构3.torch.nn.Sequential——网络的容器
torch.nn.Sequential 是一个网络的容器,在构造网络时,可以按网络的传递顺序来将 torch.nn 各层添加到容器中,Sequential 的forward() 方法接受任何输入并将其转发给 Sequential 容器内的第一个模块,然后,它将随后每个模块的输出按顺序 “链接” 到输入,最后返回最后一个模块的输出
容器可以将多个层存放在一起,增强代码复用性与高效性
4.利用torch.nn.Sequential简化网络torch.nn.Sequential(*args)
构造一个容器,可将若干个 torch.nn 对象添加到容器中
*args 若干个顺序 torch.nn 对象
此外,容器 Sequential 还可以嵌套 Sequential 容器,灵活运用可以使编码更高效
import torch import torch.nn as nn import torchvision from torchvision import transforms from torch.utils.tensorboard import SummaryWriter from torch.utils.data import DataLoader class Model(nn.Module): def __init__(self): super(Model, self).__init__() self.model1 = nn.Sequential( nn.Conv2d(3, 32, 5, padding=2), nn.MaxPool2d(2), nn.Conv2d(32, 32, 5, padding=2), nn.MaxPool2d(2), nn.Conv2d(32, 64, 5, padding=2), nn.MaxPool2d(2), nn.Flatten(), nn.Linear(1024, 64), nn.ReLU(), nn.Linear(64, 10), nn.Softmax(), ) def forward(self, x): y = self.model1(x) return y model = Model() # 实例化模型 print(model) # 打印模型结构5.parameters——模型的可迭代参数
6.利用tensorboard可视化网络model.parameters
在 model = Model() 实例化模型后,通过该属性可以显示模型的所有可迭代参数
例如: 显示上述网络的可迭代参数
model.parameters()
在 model = Model() 实例化模型后,通过该函数可以获取包含模型的所有可迭代参数的对象
该函数的返回值对象可用于传入优化器,来实现参数的迭代更新
例如: 获取可迭代参数对象
add_graph(model, input_to_model=None, verbose=False, use_strict_trace=True)
向 tensorboard 日志中添加一个网络可视化图
model 实例化后的 PyTorch 模型
input_to_model (torch.Tensor or list of torch.Tensor) 要输入模型的张量或张量元组,可以是 ( N , C , H , W ) (N,C,H,W) (N,C,H,W)
verbose (bool) 是否在控制台打印图像结构,若 verbose=True,则打印在控制台,default=False
writer = SummaryWriter("logs") model = Model() input = torch.ones((64, 3, 32, 32)) writer.add_graph(model, input)
参考资料:
[1]PyTorch深度学习快速入门教程(绝对通俗易懂!)【小土堆】
[2]PyTorch官网文档
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)