任何网站都可以做谷歌推广的吗,强化网站建设,一起做网站欧洲站,中国旺旺(00151) 股吧笔记为自我总结整理的学习笔记#xff0c;若有错误欢迎指出哟~ 深度学习专栏链接#xff1a; http://t.csdnimg.cn/dscW7 pytorch——神经网络工具箱nn 简介nn.Modulenn.Module实现全连接层nn.Module实现多层感知机 常用神经网络层图像相关层卷积层#xff08;Conv#xff… 笔记为自我总结整理的学习笔记若有错误欢迎指出哟~ 深度学习专栏链接 http://t.csdnimg.cn/dscW7 pytorch——神经网络工具箱nn 简介nn.Modulenn.Module实现全连接层nn.Module实现多层感知机 常用神经网络层图像相关层卷积层Conv实现锐化过滤器 常见激活函数ModuleList和Sequential循环神经网络层(RNN) 优化器nn.functional VS nn.Modulenn.init实现参数初始化nn.Module深入分析nn.Module基类的构造函数访问模型中的子模块 简介
PyTorch神经网络工具箱nn是一个用于构建深度学习模型的核心模块。它提供了一组简单而灵活的API可以轻松地定义、训练和评估各种类型的神经网络。
nn模块中包含了许多预定义的模块和方法如线性层、卷积层、循环神经网络、损失函数等可以直接调用这些模块来构建深度学习模型。以下是nn模块的主要功能 定义神经网络模型可以使用nn模块定义各种类型的神经网络。通过继承nn.Module类可以创建一个自己的神经网络类并在其中定义各个层的结构和参数。 易于使用的层nn模块提供了各种类型的层如线性层、卷积层、池化层、归一化层等。这些层已经默认实现了前向传播和反向传播的过程可以直接使用。 非线性激活函数nn模块提供了常见的激活函数如ReLU、Sigmoid、Tanh等可以在层之间添加非线性变换。 自动求导nn模块基于PyTorch的自动求导机制可以自动计算梯度并进行反向传播。这使得用户可以更加专注于模型的设计和实现而不必手动计算梯度。 训练和优化可以使用nn模块中的优化器如SGD、Adam等来训练模型并使用预定义的损失函数如交叉熵、均方误差等来评估模型的性能。 序列化和保存可以使用nn模块中的API将模型序列化为文件并在需要时恢复模型。
PyTorch神经网络工具箱nn提供了一组简单而灵活的API可以方便地定义、训练和评估各种类型的神经网络。同时也支持用户自定义的模型和层使得用户可以根据自己的需求和应用场景创建更加复杂的深度学习模型。
nn.Module
nn.Module是PyTorch中所有神经网络模型的基类。所有用户自定义的神经网络模型都应该继承自nn.Module类并实现其中的方法。
nn.Module提供了一些重要的属性和方法使得用户可以方便地定义神经网络的结构和参数并进行正向传播和反向传播的计算。
以下是nn.Module类的一些重要属性和方法 __init__(self)构造函数用于初始化模型的结构和参数。在这个方法中用户可以定义模型中的各个层并指定它们的参数。 forward(self, input)前向传播方法。在这个方法中用户定义了模型的正向传播过程。通过调用各个层的前向传播方法并对它们的输出进行组合和变换最终生成模型的输出。 parameters(self)返回模型中所有可学习的参数。这个方法返回一个迭代器可以用于遍历模型中的所有参数并进行优化和更新。 to(self, device)将模型移动到指定的设备上如CPU或GPU。通过这个方法可以方便地将模型加载到合适的设备上进行计算。 state_dict(self)和load_state_dict(self, state_dict)这两个方法用于序列化和加载模型的状态。state_dict()方法返回一个包含模型所有状态的字典可以将其保存到文件中。而load_state_dict()方法则从给定的字典中加载模型的状态。 train()和eval()这两个方法用于设置模型的训练模式和评估模式。在训练模式下模型会保留一些特定的操作如Dropout层在评估模式下会关闭这些操作。
通过继承nn.Module类并重写其中的方法用户可以方便地定义自己的神经网络模型。同时nn.Module还提供了一些实用的方法和功能如参数管理、设备移动和状态保存等使得模型的训练和部署变得更加简单和高效。
nn.Module实现全连接层
用nn.Module实现全连接层。全连接层又名仿射层输出 y \textbf{y} y和输入 x \textbf{x} x满足 yWxb \textbf{yWxb} yWxb W \textbf{W} W和 b \textbf{b} b是可学习的参数。
import torch as t
from torch import nnclass Linear(nn.Module): # 继承nn.Moduledef __init__(self, in_features, out_features):super(Linear, self).__init__() # 等价于nn.Module.__init__(self)self.w nn.Parameter(t.randn(in_features, out_features))self.b nn.Parameter(t.randn(out_features))def forward(self, x):x x.mm(self.w) # x.(self.w)return x self.b.expand_as(x)layer Linear(4,3)
input t.randn(2,4)
output layer(input)
print(output)for name, parameter in layer.named_parameters():print(name, parameter) # w and b
代码解释 这段代码定义了一个自定义的线性层Linear它继承自nn.Module类并重写了其中的__init__和forward方法。该层的输入维度为in_features输出维度为out_features。
class Linear(nn.Module): def __init__(self, in_features, out_features):super(Linear, self).__init__() self.w nn.Parameter(t.randn(in_features, out_features))self.b nn.Parameter(t.randn(out_features))def forward(self, x):x x.mm(self.w) return x self.b.expand_as(x)在__init__方法中首先调用父类的构造函数来初始化模型然后定义了两个参数self.w和self.b它们分别对应于该层的权重矩阵和偏置向量并将它们标记为可学习的参数。
在forward方法中首先将输入张量x与权重矩阵self.w相乘然后加上偏置向量self.b最终得到该层的输出。
接下来代码创建了一个Linear对象layer并传入了输入的维度4和输出的维度3。然后定义了一个随机输入张量input其形状为(2, 4)。
layer Linear(4,3)
input t.randn(2,4)最后将输入张量传入layer对象的forward方法中得到输出张量output。
output layer(input)通过print(output)语句打印输出张量output的值可以查看模型对给定输入的计算结果。
print(output)此外代码还使用named_parameters方法遍历了layer对象中的所有参数并打印了它们的名称和值。可以获取到w和b两个参数。
for name, parameter in layer.named_parameters():print(name, parameter)nn.Module实现多层感知机 import torch as t
from torch import nnclass Linear(nn.Module): # 继承nn.Moduledef __init__(self, in_features, out_features):super(Linear, self).__init__() # 等价于nn.Module.__init__(self)self.w nn.Parameter(t.randn(in_features, out_features))self.b nn.Parameter(t.randn(out_features))def forward(self, x):x x.mm(self.w) # x.(self.w)return x self.b.expand_as(x)class Perceptron(nn.Module):def __init__(self, in_features, hidden_features, out_features):nn.Module.__init__(self)self.layer1 Linear(in_features, hidden_features) # 此处的Linear是自定义的全连接层self.layer2 Linear(hidden_features, out_features)def forward(self,x):x self.layer1(x)x t.sigmoid(x)return self.layer2(x)perceptron Perceptron(3,4,1)
for name, param in perceptron.named_parameters():print(name, param.size())代码解释
首先定义了一个名为Linear的类它继承自nn.Module。这个类代表了一个线性层包含权重参数w和偏置参数b。
class Linear(nn.Module):def __init__(self, in_features, out_features):super(Linear, self).__init__()self.w nn.Parameter(t.randn(in_features, out_features))self.b nn.Parameter(t.randn(out_features))def forward(self, x):x x.mm(self.w)return x self.b.expand_as(x)然后定义了一个名为Perceptron的类它也继承自nn.Module。这个类代表了一个多层感知机模型由两个线性层组成。
class Perceptron(nn.Module):def __init__(self, in_features, hidden_features, out_features):nn.Module.__init__(self)self.layer1 Linear(in_features, hidden_features)self.layer2 Linear(hidden_features, out_features)def forward(self, x):x self.layer1(x)x t.sigmoid(x)return self.layer2(x)在初始化方法中创建了两个Linear对象self.layer1和self.layer2作为感知机的两个层。在前向传播方法中输入数据首先通过self.layer1进行计算然后经过sigmoid激活函数最终通过self.layer2得到输出。
最后创建了一个Perceptron对象perceptron并打印出其中的参数名称和大小。
perceptron Perceptron(3, 4, 1)
for name, param in perceptron.named_parameters():print(name, param.size())这段代码展示了如何使用自定义的线性层构建一个多层感知机模型并打印出其中的参数信息。通过这个例子我们可以理解如何使用PyTorch构建神经网络模型并对其进行调试和优化。
module中parameter的命名规范
对于类似self.param_name nn.Parameter(t.randn(3, 4))命名为param_name对于子Module中的parameter会其名字之前加上当前Module的名字。如对于self.sub_module SubModel()SubModel中有个parameter的名字叫做param_name那么二者拼接而成的parameter name 就是sub_module.param_name。
常用神经网络层
在神经网络中有许多常用的层用于构建各种不同类型的模型。以下是几个常见的神经网络层及其用途 全连接层Fully Connected Layer全连接层是最基本的层之一也称为线性层或密集层。它将输入的每个元素与权重相乘并通过添加偏差项得到输出。全连接层通常用于提取特征和进行分类。 卷积层Convolutional Layer卷积层是专门用于处理图像和空间数据的层。它使用卷积运算对输入数据进行滤波以提取局部的空间特征。卷积层通常用于图像识别、目标检测和语音处理等任务。 池化层Pooling Layer池化层主要用于减少特征图的空间尺寸并保留最重要的特征。常见的池化操作包括最大池化和平均池化它们分别选择每个区域中的最大值或平均值作为输出。 递归层Recurrent Layer递归层用于处理序列数据如自然语言处理和时间序列预测。它们具有记忆机制可以在每个时间步骤上传递信息。常见的递归层包括循环神经网络RNN和长短期记忆网络LSTM。 嵌入层Embedding Layer嵌入层用于将离散型的符号或类别数据编码为连续型的低维向量表示。它在自然语言处理中广泛应用将单词或字符映射到连续的向量空间中。 规范化层Normalization Layer规范化层用于在神经网络中对输入数据进行标准化处理以提高模型的稳定性和收敛速度。常见的规范化操作包括批量归一化Batch Normalization和层归一化Layer Normalization。 激活函数层Activation Layer激活函数层对神经网络的输出应用非线性变换以引入非线性能力。常见的激活函数包括ReLURectified Linear Unit、Sigmoid和Tanh等。
这只是一小部分常用的神经网络层实际应用中还有许多其他类型的层如注意力层、残差连接等。根据任务和问题的不同选择合适的层组合可以有效地构建出强大的神经网络模型。
图像相关层
图像相关层主要包括卷积层Conv、池化层Pool等这些层在实际使用中可分为一维(1D)、二维(2D)、三维3D池化方式又分为平均池化AvgPool、最大值池化MaxPool、自适应池化AdaptiveAvgPool等。而卷积层除了常用的前向卷积之外还有逆卷积TransposeConv。
卷积层Conv实现锐化过滤器
# 导入所需的库
from PIL import Image
from torchvision.transforms import ToTensor, ToPILImage
import torch as t
import torch.nn as nn# 创建将图像转换为张量的转换器
to_tensor ToTensor()# 创建将张量转换为图像的转换器
to_pil ToPILImage()# 打开图像文件
lena Image.open(C:/图片路径/1.png)# 将彩色图像转换为灰度图像并将其通道数从3变为1。并将图像转换为张量并添加一维作为batch_size
input to_tensor(lena.convert(L)).unsqueeze(0) # 定义锐化卷积核
kernel t.ones(3, 3)/-9.
kernel[1][1] 1
conv nn.Conv2d(1, 1, (3, 3), 1, biasFalse)
conv.weight.data kernel.view(1, 1, 3, 3)# 对输入进行卷积操作
out conv(input)# 将输出张量转换为图像并显示出来
to_pil(out.data.squeeze(0))这段代码的功能是实现一个锐化过滤器对输入图像进行锐化处理。具体步骤如下 创建将图像转换为张量的转换器to_tensor ToTensor()和将张量转换为图像的转换器to_pil ToPILImage()。 打开图像文件lena Image.open(图片路径)。 input to_tensor(lena.convert(L)).unsqueeze(0)将彩色图像转换为灰度图像并将其通道数从3变为1。并将图像转换为张量并添加一维作为batch_size即将它转换为输入大小为(1, channels, height, width)的模型输入。 kernel t.ones(3, 3)/-9.; kernel[1][1] 1 定义锐化卷积核这个卷积核是一个3x3的矩阵中心点为1其它位置为-1/9即偏移量为-1/9。 conv nn.Conv2d(1, 1, (3, 3), 1, biasFalse)创建一个卷积层conv该卷积层的输入通道数为1输出通道数为1卷积核大小为(3, 3)步长为1偏置为False。 conv.weight.data kernel.view(1, 1, 3, 3)将之前创建的卷积核kernel转换为相同形状的张量并将其赋给卷积层的权重。 out conv(input)对输入进行卷积操作使用创建好的卷积核对输入进行卷积操作得到一个输出大小为(1, 1, height, width)的张量。 to_pil(out.data.squeeze(0))将输出张量转换为图像并显示出来。由于输入时添加了一维batch_size因此需要先通过squeeze()去除这一维。
常见激活函数
函数图像sigmoidtanhReLUleaky ReLU
下面是一个PyTorch实现常见激活函数的例子
import torch
import torch.nn as nn# 定义输入张量x
x torch.randn(1, 10)# Sigmoid激活函数
sigmoid nn.Sigmoid()
activated_x sigmoid(x)
print(Sigmoid激活后的输出, activated_x)# Tanh双曲正切激活函数
tanh nn.Tanh()
activated_x tanh(x)
print(Tanh激活后的输出, activated_x)# ReLU激活函数
relu nn.ReLU()
activated_x relu(x)
print(ReLU激活后的输出, activated_x)# LeakyReLU激活函数
leaky_relu nn.LeakyReLU(negative_slope0.01)
activated_x leaky_relu(x)
print(LeakyReLU激活后的输出, activated_x)# Softmax激活函数
softmax nn.Softmax(dim1)
activated_x softmax(x)
print(Softmax激活后的输出, activated_x)在这个例子中我们首先定义了一个大小为(1, 10)的输入张量x然后分别使用PyTorch中的ReLU、Sigmoid、Tanh、LeakyReLU和Softmax激活函数对其进行处理并输出处理后的结果。
请注意每个激活函数都是通过创建一个相应的PyTorch模型来实现的。例如ReLU激活函数是通过创建一个nn.ReLU的实例来实现的。在使用时我们只需要将输入张量传递给模型即可。
输出结果如下
Sigmoid激活后的输出 tensor([[0.6914, 0.3946, 0.2316, 0.3845, 0.6496, 0.7061, 0.3284, 0.4206, 0.8200, 0.6755]])
Tanh激活后的输出 tensor([[ 0.6678, -0.4035, -0.8334, -0.4386, 0.5492, 0.7046, -0.6141, -0.3099, 0.9080, 0.6250]])
ReLU激活后的输出 tensor([[0.8068, 0.0000, 0.0000, 0.0000, 0.6172, 0.8765, 0.0000, 0.0000, 1.5163, 0.7332]])
LeakyReLU激活后的输出 tensor([[ 0.8068, -0.0043, -0.0120, -0.0047, 0.6172, 0.8765, -0.0072, -0.0032, 1.5163, 0.7332]])
Softmax激活后的输出 tensor([[0.1407, 0.0409, 0.0189, 0.0392, 0.1164, 0.1508, 0.0307, 0.0456, 0.2860, 0.1307]])ReLU函数有个inplace参数如果设为True它会把输出直接覆盖到输入中这样可以节省内存/显存。之所以可以覆盖是因为在计算ReLU的反向传播时只需根据输出就能够推算出反向传播的梯度。但是只有少数的autograd操作支持inplace操作如tensor.sigmoid_()除非你明确地知道自己在做什么否则一般不要使用inplace操作。
# ReLU激活函数
relu nn.ReLU(inplaceTrue)
activated_x relu(x)
print(ReLU激活后的输出, activated_x)ModuleList和Sequential
ModuleList和Sequential是PyTorch中用于构建神经网络模型的两个重要类。
ModuleList是一个容器类它可以包含多个子模块如层、激活函数等并将它们作为一个整体来处理。通过使用ModuleList可以方便地管理和组织多个子模块。
下面是一个使用ModuleList构建模型的示例
import torch
import torch.nn as nnclass MyModel(nn.Module):def __init__(self):super(MyModel, self).__init__()self.layers nn.ModuleList([nn.Linear(10, 20),nn.ReLU(),nn.Linear(20, 30),nn.Tanh()])def forward(self, x):for layer in self.layers:x layer(x)return x在这个示例中MyModel类定义了一个包含四个子模块的模型。在模型的构造函数中创建了一个ModuleList对象并将四个子模块添加到其中。在模型的forward方法中通过遍历ModuleList中的子模块并将输入逐层传递给它们以得到最终的输出。
相比于直接使用列表或元组来存储子模块使用ModuleList的一个优点是它会自动地注册子模块使得子模块的参数可以被模型的其他部分识别和更新。
Sequential是另一个用于构建模型的类它提供了一种更加简洁的方式来定义连续的层序列。使用Sequential可以以序列的形式将多个层如线性层、激活函数等串联起来形成一个完整的神经网络模型。
以下是一个使用Sequential构建模型的示例
import torch
import torch.nn as nnmodel nn.Sequential(nn.Linear(10, 20),nn.ReLU(),nn.Linear(20, 30),nn.Tanh()
)在这个示例中直接使用Sequential类来构造模型并将每个层作为参数传递给Sequential的构造函数。这样每个层都会按照顺序依次被添加到模型中。
使用Sequential的一个优点是它提供了一种更加简洁和直观的方式来定义模型结构。然而由于Sequential只适用于顺序连接的模型因此无法灵活地处理一些复杂的网络结构如跳跃连接或多路连接等。
ModuleList和Sequential都是用于构建神经网络模型的重要工具。ModuleList适用于管理和组织多个子模块而Sequential适用于简洁地定义顺序连接的模型。选择使用哪个类取决于具体的需求和模型结构。
循环神经网络层(RNN)
循环神经网络层RNN是一种用于处理序列数据的神经网络层。与传统的前馈神经网络不同RNN将一个序列中的每个元素作为输入并通过记忆状态来传递信息从而在序列中实现信息的持续传递。
在RNN中当前时刻的输出不仅取决于当前时刻的输入还取决于之前所有时刻的输入和记忆状态。具体地RNN的计算可以表示为 h t f ( W ∗ x t U ∗ h t − 1 ) h_t f(W * x_t U * h_{t-1}) htf(W∗xtU∗ht−1) 其中h_t表示当前时刻的记忆状态x_t表示当前时刻的输入W和U是权重矩阵。
RNN的基本结构如下所示 RNN的优点是可以处理任意长度的序列数据并且具有较强的记忆能力可以学习到序列中的长期依赖关系。然而由于RNN在计算过程中需要多次重复使用相同的权重矩阵导致梯度消失或爆炸的问题影响了其训练效果。为了解决这个问题后来出现了一些改进的RNN结构如LSTM和GRU等。
以下是使用PyTorch实现一个简单的RNN模型的示例
import torch
import torch.nn as nnclass MyRNN(nn.Module):def __init__(self, input_size, hidden_size, output_size):super(MyRNN, self).__init__()self.hidden_size hidden_sizeself.rnn nn.RNN(input_size, hidden_size, batch_firstTrue)self.fc nn.Linear(hidden_size, output_size)def forward(self, x):h0 torch.zeros(1, x.size(0), self.hidden_size) # 初始化记忆状态out, hn self.rnn(x, h0)out self.fc(out[:, -1, :]) # 取最后一个时刻的输出作为模型输出return out在这个示例中我们创建了一个名为MyRNN的RNN模型类并在其中使用nn.RNN类来定义RNN层。在模型的forward方法中我们首先通过torch.zeros函数初始化记忆状态并将输入张量和记忆状态传递给RNN层进行计算。然后我们通过取最后一个时刻的输出并使用一个全连接层来将其映射到输出空间中得到最终的模型输出。
优化器
在PyTorch中可以使用torch.optim模块来实现优化器的基本使用方法、对模型的不同部分设置不同的学习率以及调整学习率。下面我们分别介绍这些内容。
优化器的基本使用方法
首先需要创建一个优化器对象以便于优化模型的参数。假设我们已经定义好了一个模型对象model可以按照以下方式创建一个优化器对象
import torch.optim as optimoptimizer optim.Adam(model.parameters(), lr0.01)在这个示例中我们使用Adam优化算法来更新模型参数。我们将模型对象model的所有可训练参数即权重和偏置传递给优化器的构造函数并设置初始学习率为0.01。
接下来在训练循环中可以按照以下方式进行参数更新
optimizer.zero_grad() # 清零梯度
loss.backward() # 反向传播计算梯度
optimizer.step() # 更新参数在这个示例中我们首先调用zero_grad()函数清零所有参数的梯度然后调用backward()函数计算损失函数关于模型参数的梯度最后调用step()函数更新参数。
对模型的不同部分设置不同的学习率
对模型的不同部分设置不同的学习率以便更好地调整模型参数。在PyTorch中可以通过以下方式实现
optimizer optim.Adam([{params: model.conv1.parameters()},{params: model.conv2.parameters(), lr: 0.01},{params: model.fc.parameters(), lr: 0.001}], lr0.0001)在这个示例中将模型的三个部分conv1、conv2和fc分别放在不同的字典中并为每个字典设置不同的学习率。最后我们将所有字典传递给优化器的构造函数并设置初始学习率为0.0001。
调整学习率
有时候在训练过程中需要调整学习率以便更好地优化模型参数。在PyTorch中可以按照以下方式调整学习率
# 减小学习率到原来的1/10
for param_group in optimizer.param_groups:param_group[lr] / 10.0在这个示例中我们首先遍历所有参数组然后将每个参数组的学习率除以10.0从而减小学习率到原来的1/10。注意optimizer.param_groups是一个列表其中每个元素都是一个字典包含了与该参数组相关的所有信息例如学习率、权重衰减系数等。
nn.functional VS nn.Module
nn.functional和nn.Module都是PyTorch深度学习库中非常重要的模块。它们都有助于定义神经网络模型但它们的使用方式和目的略有不同。
nn.functional
nn.functional是PyTorch中一个包含各种非线性函数、池化函数、卷积函数等的模块。这些函数都被实现为纯函数pure function即它们的输出只取决于输入而不依赖于任何外部状态。因此它们通常用于构建没有参数的简单层或者复杂的自定义损失函数。
下面是一个使用nn.functional实现的简单的全连接层
import torch.nn as nn
import torch.nn.functional as Fclass MyNet(nn.Module):def __init__(self):super(MyNet, self).__init__()self.fc1 nn.Linear(784, 256)self.fc2 nn.Linear(256, 10)def forward(self, x):x F.relu(self.fc1(x))x self.fc2(x)return x在这个示例中使用了nn.Linear来创建两个全连接层然后在forward方法中使用了F.relu函数作为激活函数。
nn.Module
nn.Module是PyTorch中的一个基类所有的神经网络模型都应该继承它。nn.Module提供了一些有用的方法例如parameters()、named_parameters()和modules()等可以方便地访问模型中的参数和子模块。在继承nn.Module类后我们需要实现__init__和forward方法来定义模型结构和前向传播过程。
下面是一个使用nn.Module实现的简单的全连接层
import torch.nn as nnclass MyNet(nn.Module):def __init__(self):super(MyNet, self).__init__()self.fc1 nn.Linear(784, 256)self.fc2 nn.Linear(256, 10)def forward(self, x):x nn.functional.relu(self.fc1(x))x self.fc2(x)return x在这个示例中使用了nn.Linear来创建两个全连接层并在__init__方法中将它们定义为模型的属性。然后在forward方法中使用了nn.functional.relu函数作为激活函数。
总的来说nn.Module用于构建更复杂、带有参数的神经网络模型而nn.functional则用于构建简单的不含参数的层或者自定义损失函数。当构建神经网络时nn.Module往往是首选因为它提供了更多的灵活性和可扩展性。
nn.init实现参数初始化
nn.init是PyTorch深度学习库中一个用于初始化神经网络权重的模块。在训练神经网络时通常需要对权重进行初始化以提高模型的收敛速度和泛化能力。
nn.init提供了多种初始化方法包括常见的正态分布初始化、均匀分布初始化和Xavier初始化等。下面以Xavier初始化为例进行讲解。
Xavier初始化
Xavier初始化是一种常用的权重初始化方法旨在使输入信号和输出信号的方差相等。这可以帮助加速模型的收敛并提高模型的性能。Xavier初始化的具体公式如下 W ∼ U [ − 6 n i n n o u t , 6 n i n n o u t ] W \sim U[-\frac{\sqrt{6}}{\sqrt{n_{in}n_{out}}}, \frac{\sqrt{6}}{\sqrt{n_{in}n_{out}}}] W∼U[−ninnout 6 ,ninnout 6 ]
其中 U [ a , b ] U[a, b] U[a,b]表示从区间 [ a , b ] [a, b] [a,b]的均匀分布中随机采样 n i n n_{in} nin和 n o u t n_{out} nout分别表示权重的输入和输出维度。
使用nn.init进行Xavier初始化
使用nn.init进行Xavier初始化非常简单只需要将需要初始化的参数传递给相应的初始化函数即可。例如以下代码演示了如何使用nn.init进行Xavier初始化
import torch.nn as nn
import torch.nn.init as initclass MyNet(nn.Module):def __init__(self):super(MyNet, self).__init__()self.fc1 nn.Linear(784, 256)self.fc2 nn.Linear(256, 10)# 对权重进行Xavier初始化init.xavier_uniform_(self.fc1.weight)init.xavier_uniform_(self.fc2.weight)def forward(self, x):x nn.functional.relu(self.fc1(x))x self.fc2(x)return x在这个示例中使用nn.Linear创建了两个全连接层并在__init__方法中将它们定义为模型的属性。然后使用init.xavier_uniform_函数对权重进行Xavier初始化。
总的来说使用nn.init进行权重初始化可以帮助模型更快地收敛并提高模型的性能。但需要注意的是权重初始化并不是万能的有时候还需要调整学习率、正则化等超参数来优化模型。
nn.Module深入分析
nn.Module基类的构造函数
def __init__(self):self._parameters OrderedDict()self._modules OrderedDict()self._buffers OrderedDict()self._backward_hooks OrderedDict()self._forward_hooks OrderedDict()self.training Truenn.Module基类的构造函数__init__是所有PyTorch神经网络模型的基础构建块之一。其主要作用是初始化模型的各个属性并创建一个空的有序字典来存储模型的参数、子模块、缓存、正向/反向传播钩子等。
下面对__init__函数中定义的各个属性进行解释 self._parameters有序字典用于存储模型的可学习参数例如权重和偏置。在模型中定义的nn.Parameter类型的变量会自动添加到该字典中。 self._modules有序字典用于存储模型的子模块。在模型中定义的nn.Module类型的变量会自动添加到该字典中。 self._buffers有序字典用于存储模型的缓存。例如一些中间结果、滑动平均值等可以保存在这里。 self._backward_hooks有序字典用于存储模型的反向传播钩子即在反向传播过程中执行的函数。 self._forward_hooks有序字典用于存储模型的正向传播钩子即在正向传播过程中执行的函数。 self.training布尔变量用于指示模型的训练状态。在训练过程中该变量为True在测试过程中该变量为False。
总的来说nn.Module基类的构造函数初始化了神经网络模型中的各个属性并创建了一个有序字典来存储模型的参数、子模块、缓存、正向/反向传播钩子等。这些属性和有序字典提供了方便的机制来访问和管理模型的组件并可以方便地进行序列化和反序列化。
示例代码
import torch.nn as nnclass MyNet(nn.Module):def __init__(self):super(MyNet, self).__init__()self.fc1 nn.Linear(784, 256)self.fc2 nn.Linear(256, 10)def forward(self, x):x nn.functional.relu(self.fc1(x))x self.fc2(x)return x# 创建模型实例
model MyNet()# 打印 Module 属性
print(Parameters:)
for name, param in model.named_parameters():print(name, param.size())print(\nModules:)
for name, module in model.named_modules():print(name, module)print(\nBuffers:)
for name, buffer in model.named_buffers():print(name, buffer.size())print(\nForward hooks:)
for hook in model._forward_hooks.values():print(hook)print(\nBackward hooks:)
for hook in model._backward_hooks.values():print(hook)在这个示例中我们创建了一个继承自nn.Module基类的神经网络模型并在其中定义了两个全连接层。然后我们通过访问实例对象的属性和有序字典打印了模型的Parameter、Module、Buffer以及正向/反向传播钩子等属性。输出结果如下
Parameters:
fc1.weight torch.Size([256, 784])
fc1.bias torch.Size([256])
fc2.weight torch.Size([10, 256])
fc2.bias torch.Size([10])Modules:MyNet((fc1): Linear(in_features784, out_features256, biasTrue)(fc2): Linear(in_features256, out_features10, biasTrue)
)
fc1 Linear(in_features784, out_features256, biasTrue)
fc2 Linear(in_features256, out_features10, biasTrue)Buffers:Forward hooks:Backward hooks:从输出结果中可以看出
Parameters属性打印了模型的可学习参数即两个全连接层的权重和偏置。Modules属性打印了模型的子模块包括整个模型本身和其两个全连接层。Buffers属性为空因为在模型中没有定义任何缓存。Forward hooks属性为空因为在模型中没有定义任何正向传播钩子。Backward hooks属性为空因为在模型中没有定义任何反向传播钩子。
访问模型中的子模块
import torch
import torch.nn as nnclass SubNet(nn.Module):def __init__(self):super(SubNet, self).__init__()self.conv nn.Conv2d(3, 16, kernel_size3, padding1)self.pool nn.MaxPool2d(kernel_size2, stride2)def forward(self, x):x self.conv(x)x self.pool(x)return xclass MyNet(nn.Module):def __init__(self):super(MyNet, self).__init__()self.subnet1 SubNet()self.subnet2 SubNet()self.fc nn.Linear(16 * 8 * 8, 10)def forward(self, x):x1 self.subnet1(x)x2 self.subnet2(x)x torch.cat((x1, x2), dim1)x x.view(-1, 16 * 8 * 8)x self.fc(x)return x# 创建模型实例
model MyNet()# 查看直接子模块
print(Children:)
for name, module in model.named_children():print(name, module)# 查看所有子模块包括当前模块
print(\nModules:)
for name, module in model.named_modules():print(name, module)# 查看命名直接子模块
print(\nNamed Children:)
for name, module in model.named_children():print(name, module)# 查看命名所有子模块包括当前模块
print(\nNamed Modules:)
for name, module in model.named_modules():print(name, module)在这个示例中我们定义了一个SubNet子模块和一个MyNet模型其中MyNet包含了两个SubNet子模块和一个全连接层。我们使用named_children和named_modules函数查看了直接子模块、所有子模块以及它们的命名版本。
输出结果如下
Children:
subnet1 SubNet((conv): Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))(pool): MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse)
)
subnet2 SubNet((conv): Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))(pool): MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse)
)Modules:MyNet((subnet1): SubNet((conv): Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))(pool): MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse))(subnet1.conv): Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))(subnet1.pool): MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse)(subnet2): SubNet((conv): Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))(pool): MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse))(subnet2.conv): Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))(subnet2.pool): MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse)(fc): Linear(in_features1024, out_features10, biasTrue)
)
subnet1 SubNet((conv): Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))(pool): MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse)
)
subnet1.conv Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))
subnet1.pool MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse)
subnet2 SubNet((conv): Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))(pool): MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse)
)
subnet2.conv Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))
subnet2.pool MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse)
fc Linear(in_features1024, out_features10, biasTrue)Named Children:
subnet1 SubNet((conv): Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))(pool): MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse)
)
subnet2 SubNet((conv): Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))(pool): MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse)
)Named Modules:MyNet MyNet((subnet1): SubNet((conv): Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))(pool): MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse))(subnet1.conv): Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))(subnet1.pool): MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse)(subnet2): SubNet((conv): Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))(pool): MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse))(subnet2.conv): Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))(subnet2.pool): MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse)(fc): Linear(in_features1024, out_features10, biasTrue)
)
subnet1 SubNet((conv): Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))(pool): MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse)
)
subnet1.conv Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))
subnet1.pool MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse)
subnet2 SubNet((conv): Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))(pool): MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse)
)
subnet2.conv Conv2d(3, 16, kernel_size(3, 3), stride(1, 1), padding(1, 1))
subnet2.pool MaxPool2d(kernel_size2, stride2, padding0, dilation1, ceil_modeFalse)
fc Linear(in_features1024, out_features10, biasTrue)从输出结果可以看出
使用named_children函数可以返回直接子模块并可以通过返回的元组中的第一个元素访问子模块的名称第二个元素访问子模块本身。使用named_modules函数可以返回所有子模块包括当前模块同样可以通过返回的元组中的第一个元素访问模块的名称第二个元素访问模块本身。named_children和named_modules函数都有一个命名版本分别为named_childen和named_modules。这两个函数返回的元组中第一个元素是子模块的名称第二个元素是子模块本身。
这些函数提供了一种方便的方式来管理、访问和控制复杂的神经网络模型中的子模块。