【深度学习】pytorch——神经网络工具箱nn

笔记为自我总结整理的学习笔记,若有错误欢迎指出哟~

深度学习专栏链接:
http://t.csdnimg.cn/dscW7

pytorch——神经网络工具箱nn

  • 简介
  • nn.Module
    • nn.Module实现全连接层
    • nn.Module实现多层感知机
  • 常用神经网络层
    • 图像相关层
      • 卷积层(Conv)实现锐化过滤器
    • 常见激活函数
    • ModuleList和Sequential
    • 循环神经网络层(RNN)
  • 优化器
  • nn.functional VS nn.Module
  • nn.init实现参数初始化
  • nn.Module深入分析
    • nn.Module基类的构造函数
    • 访问模型中的子模块

简介

PyTorch神经网络工具箱nn是一个用于构建深度学习模型的核心模块。它提供了一组简单而灵活的API,可以轻松地定义、训练和评估各种类型的神经网络。

nn模块中包含了许多预定义的模块和方法,如线性层、卷积层、循环神经网络、损失函数等,可以直接调用这些模块来构建深度学习模型。以下是nn模块的主要功能:

  1. 定义神经网络模型:可以使用nn模块定义各种类型的神经网络。通过继承nn.Module类,可以创建一个自己的神经网络类,并在其中定义各个层的结构和参数。

  2. 易于使用的层:nn模块提供了各种类型的层,如线性层、卷积层、池化层、归一化层等。这些层已经默认实现了前向传播和反向传播的过程,可以直接使用。

  3. 非线性激活函数:nn模块提供了常见的激活函数,如ReLU、Sigmoid、Tanh等,可以在层之间添加非线性变换。

  4. 自动求导:nn模块基于PyTorch的自动求导机制,可以自动计算梯度并进行反向传播。这使得用户可以更加专注于模型的设计和实现,而不必手动计算梯度。

  5. 训练和优化:可以使用nn模块中的优化器(如SGD、Adam等)来训练模型,并使用预定义的损失函数(如交叉熵、均方误差等)来评估模型的性能。

  6. 序列化和保存:可以使用nn模块中的API将模型序列化为文件,并在需要时恢复模型。

PyTorch神经网络工具箱nn提供了一组简单而灵活的API,可以方便地定义、训练和评估各种类型的神经网络。同时也支持用户自定义的模型和层,使得用户可以根据自己的需求和应用场景创建更加复杂的深度学习模型。

nn.Module

nn.Module是PyTorch中所有神经网络模型的基类。所有用户自定义的神经网络模型都应该继承自nn.Module类,并实现其中的方法。

nn.Module提供了一些重要的属性和方法,使得用户可以方便地定义神经网络的结构和参数,并进行正向传播和反向传播的计算。

以下是nn.Module类的一些重要属性和方法:

  1. __init__(self):构造函数,用于初始化模型的结构和参数。在这个方法中,用户可以定义模型中的各个层,并指定它们的参数。

  2. forward(self, input):前向传播方法。在这个方法中,用户定义了模型的正向传播过程。通过调用各个层的前向传播方法,并对它们的输出进行组合和变换,最终生成模型的输出。

  3. parameters(self):返回模型中所有可学习的参数。这个方法返回一个迭代器,可以用于遍历模型中的所有参数,并进行优化和更新。

  4. to(self, device):将模型移动到指定的设备上,如CPU或GPU。通过这个方法,可以方便地将模型加载到合适的设备上进行计算。

  5. state_dict(self)load_state_dict(self, state_dict):这两个方法用于序列化和加载模型的状态。state_dict()方法返回一个包含模型所有状态的字典,可以将其保存到文件中。而load_state_dict()方法则从给定的字典中加载模型的状态。

  6. train()eval():这两个方法用于设置模型的训练模式和评估模式。在训练模式下,模型会保留一些特定的操作,如Dropout层,在评估模式下会关闭这些操作。

通过继承nn.Module类,并重写其中的方法,用户可以方便地定义自己的神经网络模型。同时,nn.Module还提供了一些实用的方法和功能,如参数管理、设备移动和状态保存等,使得模型的训练和部署变得更加简单和高效。

nn.Module实现全连接层

用nn.Module实现全连接层。全连接层,又名仿射层,输出 y \textbf{y} y和输入 x \textbf{x} x满足 y=Wx+b \textbf{y=Wx+b} y=Wx+b 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.wself.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对象中的所有参数,并打印了它们的名称和值。可以获取到wb两个参数。

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.layer1self.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

常用神经网络层

在神经网络中,有许多常用的层用于构建各种不同类型的模型。以下是几个常见的神经网络层及其用途:

  1. 全连接层(Fully Connected Layer):全连接层是最基本的层之一,也称为线性层或密集层。它将输入的每个元素与权重相乘,并通过添加偏差项得到输出。全连接层通常用于提取特征和进行分类。

  2. 卷积层(Convolutional Layer):卷积层是专门用于处理图像和空间数据的层。它使用卷积运算对输入数据进行滤波,以提取局部的空间特征。卷积层通常用于图像识别、目标检测和语音处理等任务。

  3. 池化层(Pooling Layer):池化层主要用于减少特征图的空间尺寸,并保留最重要的特征。常见的池化操作包括最大池化和平均池化,它们分别选择每个区域中的最大值或平均值作为输出。

  4. 递归层(Recurrent Layer):递归层用于处理序列数据,如自然语言处理和时间序列预测。它们具有记忆机制,可以在每个时间步骤上传递信息。常见的递归层包括循环神经网络(RNN)和长短期记忆网络(LSTM)。

  5. 嵌入层(Embedding Layer):嵌入层用于将离散型的符号或类别数据编码为连续型的低维向量表示。它在自然语言处理中广泛应用,将单词或字符映射到连续的向量空间中。

  6. 规范化层(Normalization Layer):规范化层用于在神经网络中对输入数据进行标准化处理,以提高模型的稳定性和收敛速度。常见的规范化操作包括批量归一化(Batch Normalization)和层归一化(Layer Normalization)。

  7. 激活函数层(Activation Layer):激活函数层对神经网络的输出应用非线性变换,以引入非线性能力。常见的激活函数包括ReLU(Rectified 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, bias=False)
conv.weight.data = kernel.view(1, 1, 3, 3)# 对输入进行卷积操作
out = conv(input)# 将输出张量转换为图像,并显示出来
to_pil(out.data.squeeze(0))

在这里插入图片描述
在这里插入图片描述

这段代码的功能是实现一个锐化过滤器,对输入图像进行锐化处理。具体步骤如下:

  1. 创建将图像转换为张量的转换器to_tensor = ToTensor()和将张量转换为图像的转换器to_pil = ToPILImage()

  2. 打开图像文件lena = Image.open('图片路径')

  3. input = to_tensor(lena.convert('L')).unsqueeze(0),将彩色图像转换为灰度图像,并将其通道数从3变为1。并将图像转换为张量,并添加一维作为batch_size,即将它转换为输入大小为(1, channels, height, width)的模型输入。

  4. kernel = t.ones(3, 3)/-9.; kernel[1][1] = 1
    定义锐化卷积核:这个卷积核是一个3x3的矩阵,中心点为1,其它位置为-1/9,即偏移量为-1/9。

  5. conv = nn.Conv2d(1, 1, (3, 3), 1, bias=False),创建一个卷积层conv,该卷积层的输入通道数为1,输出通道数为1,卷积核大小为(3, 3),步长为1,偏置为False。

  6. conv.weight.data = kernel.view(1, 1, 3, 3),将之前创建的卷积核kernel转换为相同形状的张量,并将其赋给卷积层的权重。

  7. out = conv(input):对输入进行卷积操作,使用创建好的卷积核对输入进行卷积操作,得到一个输出大小为(1, 1, height, width)的张量。

  8. to_pil(out.data.squeeze(0)),将输出张量转换为图像,并显示出来。由于输入时添加了一维batch_size,因此需要先通过squeeze()去除这一维。

常见激活函数

函数图像
sigmoid在这里插入图片描述
tanh在这里插入图片描述
ReLU在这里插入图片描述
leaky 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_slope=0.01)
activated_x = leaky_relu(x)
print("LeakyReLU激活后的输出:", activated_x)# Softmax激活函数
softmax = nn.Softmax(dim=1)
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(inplace=True)
activated_x = relu(x)
print("ReLU激活后的输出:", activated_x)

ModuleList和Sequential

ModuleListSequential是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只适用于顺序连接的模型,因此无法灵活地处理一些复杂的网络结构,如跳跃连接或多路连接等。

ModuleListSequential都是用于构建神经网络模型的重要工具。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}) ht=f(Wxt+Uht1)
其中,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_first=True)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模块来实现优化器的基本使用方法、对模型的不同部分设置不同的学习率以及调整学习率。下面我们分别介绍这些内容。

  1. 优化器的基本使用方法

首先,需要创建一个优化器对象以便于优化模型的参数。假设我们已经定义好了一个模型对象model,可以按照以下方式创建一个优化器对象:

import torch.optim as optimoptimizer = optim.Adam(model.parameters(), lr=0.01)

在这个示例中,我们使用Adam优化算法来更新模型参数。我们将模型对象model的所有可训练参数(即权重和偏置)传递给优化器的构造函数,并设置初始学习率为0.01

接下来,在训练循环中,可以按照以下方式进行参数更新:

optimizer.zero_grad() # 清零梯度
loss.backward() # 反向传播,计算梯度
optimizer.step() # 更新参数

在这个示例中,我们首先调用zero_grad()函数清零所有参数的梯度,然后调用backward()函数计算损失函数关于模型参数的梯度,最后调用step()函数更新参数。

  1. 对模型的不同部分设置不同的学习率

对模型的不同部分设置不同的学习率,以便更好地调整模型参数。在PyTorch中,可以通过以下方式实现:

optimizer = optim.Adam([{'params': model.conv1.parameters()},{'params': model.conv2.parameters(), 'lr': 0.01},{'params': model.fc.parameters(), 'lr': 0.001}], lr=0.0001)

在这个示例中,将模型的三个部分(conv1、conv2和fc)分别放在不同的字典中,并为每个字典设置不同的学习率。最后,我们将所有字典传递给优化器的构造函数,并设置初始学习率为0.0001

  1. 调整学习率

有时候,在训练过程中需要调整学习率,以便更好地优化模型参数。在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深度学习库中非常重要的模块。它们都有助于定义神经网络模型,但它们的使用方式和目的略有不同。

  1. 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函数作为激活函数。

  1. 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初始化为例进行讲解。

  1. 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}}}] WU[nin+nout 6 ,nin+nout 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分别表示权重的输入和输出维度。

  1. 使用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 = True

nn.Module基类的构造函数__init__是所有PyTorch神经网络模型的基础构建块之一。其主要作用是初始化模型的各个属性,并创建一个空的有序字典来存储模型的参数、子模块、缓存、正向/反向传播钩子等。

下面对__init__函数中定义的各个属性进行解释:

  1. self._parameters:有序字典,用于存储模型的可学习参数(例如权重和偏置)。在模型中定义的nn.Parameter类型的变量会自动添加到该字典中。

  2. self._modules:有序字典,用于存储模型的子模块。在模型中定义的nn.Module类型的变量会自动添加到该字典中。

  3. self._buffers:有序字典,用于存储模型的缓存。例如,一些中间结果、滑动平均值等可以保存在这里。

  4. self._backward_hooks:有序字典,用于存储模型的反向传播钩子,即在反向传播过程中执行的函数。

  5. self._forward_hooks:有序字典,用于存储模型的正向传播钩子,即在正向传播过程中执行的函数。

  6. 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基类的神经网络模型,并在其中定义了两个全连接层。然后,我们通过访问实例对象的属性和有序字典,打印了模型的ParameterModuleBuffer以及正向/反向传播钩子等属性。输出结果如下:

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_features=784, out_features=256, bias=True)(fc2): Linear(in_features=256, out_features=10, bias=True)
)
fc1 Linear(in_features=784, out_features=256, bias=True)
fc2 Linear(in_features=256, out_features=10, bias=True)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_size=3, padding=1)self.pool = nn.MaxPool2d(kernel_size=2, stride=2)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), dim=1)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_childrennamed_modules函数查看了直接子模块、所有子模块以及它们的命名版本。

输出结果如下:

Children:
subnet1 SubNet((conv): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
subnet2 SubNet((conv): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)Modules:MyNet((subnet1): SubNet((conv): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False))(subnet1.conv): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(subnet1.pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(subnet2): SubNet((conv): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False))(subnet2.conv): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(subnet2.pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(fc): Linear(in_features=1024, out_features=10, bias=True)
)
subnet1 SubNet((conv): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
subnet1.conv Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
subnet1.pool MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
subnet2 SubNet((conv): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
subnet2.conv Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
subnet2.pool MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
fc Linear(in_features=1024, out_features=10, bias=True)Named Children:
subnet1 SubNet((conv): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
subnet2 SubNet((conv): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)Named Modules:MyNet MyNet((subnet1): SubNet((conv): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False))(subnet1.conv): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(subnet1.pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(subnet2): SubNet((conv): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False))(subnet2.conv): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(subnet2.pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(fc): Linear(in_features=1024, out_features=10, bias=True)
)
subnet1 SubNet((conv): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
subnet1.conv Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
subnet1.pool MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
subnet2 SubNet((conv): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
subnet2.conv Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
subnet2.pool MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
fc Linear(in_features=1024, out_features=10, bias=True)

从输出结果可以看出:

  • 使用named_children函数可以返回直接子模块,并可以通过返回的元组中的第一个元素访问子模块的名称,第二个元素访问子模块本身。
  • 使用named_modules函数可以返回所有子模块(包括当前模块),同样可以通过返回的元组中的第一个元素访问模块的名称,第二个元素访问模块本身。
  • named_childrennamed_modules函数都有一个命名版本,分别为named_childennamed_modules。这两个函数返回的元组中,第一个元素是子模块的名称,第二个元素是子模块本身。

这些函数提供了一种方便的方式来管理、访问和控制复杂的神经网络模型中的子模块。

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

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

相关文章

高压放大器能够在哪里使用呢

高压放大器是一种重要的电子设备,可以在许多不同的领域和应用中使用。下面西安安泰将详细介绍高压放大器的应用。 医学影像:高压放大器在医学影像领域具有广泛的应用。医学影像设备(如X射线机、CT扫描仪等)需要高压来产生足够的能…

VUE3 TypeError: defineConfig is not a function

VUE3 TypeError: defineConfig is not a function 1. 问题2. 原因3. 解决 1. 问题 在运行npm run serve时,出现报错: 2. 原因 原因:由于用vue-cli直接创建了vue 3的项目,而里面的生态并非都是最新版,vue.config.js…

摄影师的必备神器:这三款炙手可热的人像修图工具了解一下!

不会吧,现在还有人不修图就直接上传照片吧?作为新时代的精致男孩女孩,修复工具是一定必不可少的,随着手机拍照的流行,许多后期的图片修复工具也是很强大的,有的甚至可以帮助我们一键搞定修图,无…

11 传输层协议

1、传输层里比较重要的两个协议,一个是 TCP,一个是UDP 对于不从事底层开发的人员来讲,或者对于开发应用的人来讲,最常用的就是这两个协议。 2、TCP 和 UDP 有哪些区别? 1.TCP 是面向连接的,UDP 是面向无…

微服务之Eureka

文章目录 一、Eureka介绍1.Eureka的作用2.总结 二.搭建Eureka服务端步骤1.导入maven依赖2.编写启动类,添加EnableEurekaServer注解3.添加application.yml文件,编写下面的配置: 三.注册Eureka客户端服务提供者(user-service&#x…

java高级之单元测试、反射

1、Junit测试工具 Test定义测试方法 1.被BeforeClass标记的方法,执行在所有方法之前 2.被AfterCalss标记的方法,执行在所有方法之后 3.被Before标记的方法,执行在每一个Test方法之前 4.被After标记的方法,执行在每一个Test方法之后 public …

Apache Doris 开源最顶级基于MPP架构的高性能实时分析数据库

背景介绍 Apache Doris是一个基于MPP架构的易于使用,高性能和实时的分析数据库,以其极高的速度和易用性而闻名。海量数据下返回查询结果仅需亚秒级响应时间,不仅可以支持高并发点查询场景,还可以支持高通量复杂分析场景。 这些都…

数据库系统概念系列 - 数据库系统的历史

从商业计算机的出现开始,数据处理就一直推动着计算机的发展。事实上,数据处理自动化早于计算机的出现。Herman Hollerith 发明的穿孔卡片,早在20世纪初就用来记录美国的人口普查数据,并且用机械系统来处理这些卡片和列出结果。穿孔…

麒麟KYLINIOS软件仓库搭建02-软件仓库添加新的软件包

原文链接:麒麟KYLINIOS软件仓库搭建02-软件仓库添加新的软件包 hello,大家好啊,今天给大家带来麒麟桌面操作系统软件仓库搭建的文章02-软件仓库添加新的软件包,本篇文章主要给大家介绍了如何在麒麟桌面操作系统2203-x86版本上&…

【1++的Linux】之线程(二)

👍作者主页:进击的1 🤩 专栏链接:【1的Linux】 文章目录 一,对上一篇内容的补充二,Linux线程互斥1. 互斥的引出2. 互斥量3. 剖析锁的原理 一,对上一篇内容的补充 线程创建: pthread…

nginx--install

1. ubuntu 1.1 下载并解压依赖 每个包去各自官网下载 stable 版就行。 tar xzvf nginx-1.24.0.tar.gz tar xzvf openssl-3.1.4.tar.gz tar xzvf pcre2-10.42.tar.gz tar xzvf zlib-1.3.tar.gz1.2 配置及安装 参数含义详见 nginx 官网 cd nginx-1.24.0./configure --pre…

随时随地时时刻刻使用GPT类应用

疑问 很多人说GPT的广泛使用可能会使人们失业,会对一些互联网公司的存活造成挑战,那么这个说法是真的吗? 这个说法并不完全准确。虽然GPT等AI技术的广泛应用可能会对某些行业和职业产生影响,但并不意味着它会导致人们失业或互联网…

Zookeeper3.7.1分布式安装部署

上传安装文件到linux系统上面 解压安装文件到安装目录 [zhangflink9wmwtivvjuibcd2e package]$ tar -zxvf apache-zookeeper-3.7.1-bin.tar.gz -C /opt/software/3. 修改解压文件名 [zhangflink9wmwtivvjuibcd2e software]$ mv apache-zookeeper-3.7.1-bin/ zookeeper-3.7…

2021年电工杯数学建模B题光伏建筑一体化板块指数发展趋势分析及预测求解全过程论文及程序

2021年电工杯数学建模 B题 光伏建筑一体化板块指数发展趋势分析及预测 原题再现: 国家《第十四个五年规划和 2035 年远景目标纲要》中提出,将 2030 年实现“碳达峰”与 2060 年实现“碳中和”作为我国应对全球气候变暖的一个重要远景目标。光伏建筑一体…

力扣最热一百题——盛水最多的容器

终于又来了。我的算法记录的文章已经很久没有更新了。为什么呢? 这段时间都在更新有关python的文章,有对python感兴趣的朋友可以在主页找到。 但是这也并不是主要的原因 在10月5号我发布了我的第一篇博客,大家也可以看见我的每一篇算法博客…

Canal同步Mysql数据到ES以及Springboot项目查询ES数据

1、环境准备 服务器:Centos7 Jdk版本:1.8 Mysql版本:5.7.44 Canal版本:1.17 Es版本:7.12.1 kibana版本:7.12.1 软件包下载地址:链接:https://pan.baidu.com/s/1jRpCJP0-hr9aI…

Elasticsearch:在 ES|QL 中使用 DISSECT 和 GROK 进行数据处理

目录 DISSECT 还是 GROK? 或者两者兼而有之? 使用 DISSECT 处理数据 Dissect pattern 术语 例子 DISSECT 关键修饰符 右填充修饰符 (->) 附加修饰符 () 添加顺序修饰符( 和 /n) 命名的跳过键(&#xff1f…

LLM之Prompt(一):5个Prompt高效方法在文心一言3.5的测试对比

在Effective Prompt: 编写高质量Prompt的14个有效方法文中我们了解了14个编写Prompt的方法(非常感谢原作者),那么这些Prompt在具体大模型中的效果如何呢?本文以百度文心一言3.5版本大模型在其中5个方法上做个测试对比。 第1条&am…

MySQL复习总结(二):进阶篇(索引)

文章目录 一、存储引擎1.1 MySQL体系结构1.2 存储引擎介绍1.3 存储引擎特点1.4 存储引擎选择 二、索引2.1 基本介绍2.2 索引结构2.3 索引分类2.4 索引语法2.5 SQL性能分析2.6 索引使用2.6.1 最左前缀法则2.6.2 范围查询2.6.3 索引失效情况2.6.4 SQL提示2.6.5 覆盖索引2.6.6 前缀…

linux中if条件判断,case...esac,function学习

第一、 if [ 判断式 ] ; then fi 注意:中括号和判断式之间的空格,否则会报错,上案例 第二个图的12行,中括号和条件判断如果没有空格,则会提示缺号‘】’,如第二个图最上面的提示。所以使用中括号的格式…