Module & parameter
Module
Module是所有神经网络的基类,所有的模型必须继承与Module类
1. Module类的基本结构
Module类是PyTorch中最重要的类,它提供了一种方式来创建和管理包含可训练参数的神经网络层。主要特点:
- 包含可训练参数(Parameter)和持久缓冲区(Buffer)
- 可以包含其他Module作为子模块
- 支持GPU加速和分布式训练
Module类使用8个有序字典(OrderedDict)来管理不同类型的属性和功能:
- _parameters: 存储所有的可训练参数(Parameter对象),这些参数会在反向传播中自动计算梯度
- _buffers: 存储模型的固定缓冲区,比如BatchNorm层中的running_mean,这些不参与梯度计算
- _modules: 存储所有的子模块(子层),允许模型具有层次化的结构
- _non_persistent_buffers_set: 存储非持久化缓冲区的集合,这些缓冲区在模型保存时不会被保存
- _backward_hooks: 存储反向传播钩子函数,用于自定义梯度计算过程
- _forward_hooks: 存储前向传播钩子函数,用于监控和修改前向传播过程
- _forward_pre_hooks: 存储前向传播前的钩子函数,在forward函数调用前执行
- _state_dict_hooks: 存储状态字典钩子函数,用于自定义状态字典的保存和加载行为
这些有序字典的使用确保了:
- 参数和缓冲区的有序性和可追踪性
- 模型结构的层次化管理
- 灵活的钩子机制以支持自定义行为
- 高效的状态保存和加载机制
2. 类的继承
创建自定义神经网络模型时,需要继承nn.Module类:
import torch.nn as nn
class MyModel(nn.Module):
def __init__(self):
super(MyModel, self).__init__()
# 初始化层和参数
def forward(self, x):
# 定义前向传播
return x
3. 重要方法
- init(): 初始化模型,定义层和参数
- forward(): 定义前向传播过程
- parameters(): 返回模型的所有参数
- state_dict(): 返回模型的状态字典
- eval(): 设置为评估模式
- train(): 设置为训练模式
4. 具体案例:简单的神经网络
下面是一个包含两个隐藏层的简单神经网络示例:
import torch
import torch.nn as nn
class SimpleNet(nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super(SimpleNet, self).__init__()
# 定义网络层
self.layer1 = nn.Linear(input_size, hidden_size)
self.relu = nn.ReLU()
self.layer2 = nn.Linear(hidden_size, hidden_size)
self.output = nn.Linear(hidden_size, output_size)
def forward(self, x):
# 定义前向传播
x = self.layer1(x)
x = self.relu(x)
x = self.layer2(x)
x = self.relu(x)
x = self.output(x)
return x
# 创建模型实例
model = SimpleNet(input_size=10, hidden_size=20, output_size=2)
# 打印模型结构
print(model)
# 获取模型参数
for name, param in model.named_parameters():
print(f"Layer: {name} | Size: {param.size()}")
运行结果:
详细解释这段代码的调用流程:
- 实例化过程
- 当执行 model = SimpleNet(input_size=10, hidden_size=20, output_size=2) 时:
- 调用__init__方法
- 通过super()初始化父类nn.Module
- 创建三个线性层(layer1, layer2, output)和ReLU激活函数
- 前向传播的触发机制
- 当我们使用model(input)形式调用时,实际上发生了这些步骤:
- PyTorch会先调用模型的__call__方法(这是从nn.Module继承的)
- __call__会进行一些准备工作(比如检查训练模式)
- 然后自动调用我们定义的forward方法
- 数据在forward中的流动过程:
- 输入数据x首先传入layer1进行线性变换(10维→20维)
- 经过ReLU激活函数处理
- 进入layer2进行第二次线性变换(20维→20维)
- 再次经过ReLU激活函数
- 最后通过output层(20维→2维)得到最终输出
这种设计模式使得模型的使用非常简洁,用户只需要关注forward中的逻辑实现,而不需要关心底层的调用机制。
5.构建网络的步骤
到这里一个模型的搭建就很清晰了,构建自己的网络只需要三步:
-
写一个类继承于Module
-
init函数中把需要的网络层创建好
-
forward函数中把模型如何搭建的规则写好
Parameter
parameter,即参数,它是Module中非常重要的一个对象,继承与Tensor,但是与常规的Tensor不一样,这个参数表示模型的权重和偏置,是可以通过反向传播算法去不断更新的。Module中对于参数是采用_parameters 进行管理的,并且提供相应的api可以对module内所有参数进行调用与读取。
1. Parameter对象的基本概念
Parameter是PyTorch中专门用于存储和管理可训练参数的类,它具有以下特点:
- 继承自torch.Tensor,具有张量的所有特性
- 默认requires_grad=True,表示该参数需要计算梯度
- 会自动被添加到模型的参数列表中,便于统一管理
2. Parameter的创建和使用
有两种方式创建Parameter:
- 直接使用nn.Parameter()创建
- 通过nn.Module中的register_parameter()方法注册
import torch
import torch.nn as nn
class CustomLayer(nn.Module):
def __init__(self, in_features, out_features):
super(CustomLayer, self).__init__()
# 方式1:直接创建Parameter
self.weight = nn.Parameter(torch.randn(in_features, out_features))
self.bias = nn.Parameter(torch.zeros(out_features))
# 方式2:使用register_parameter注册
self.register_parameter('custom_param',
nn.Parameter(torch.ones(out_features)))
def forward(self, x):
return torch.mm(x, self.weight) + self.bias + self.custom_param
# 创建实例
layer = CustomLayer(3, 2)
# 查看所有参数
for name, param in layer.named_parameters():
print(f"Parameter name: {name}")
print(f"Parameter shape: {param.shape}")
print(f"Requires grad: {param.requires_grad}")
print("---")
3. Parameter的特性和管理
- 自动梯度计算: Parameter默认会跟踪梯度,用于反向传播
- 参数管理: 可以通过模型的parameters()或named_parameters()方法访问
- 状态保存: 会被自动包含在模型的state_dict中
- 设备迁移: 使用model.to(device)时会自动转移到指定设备
4. Parameter与普通Tensor的区别
以下是Parameter和普通Tensor的主要区别:
特性 | Parameter | Tensor |
---|---|---|
梯度计算 | 默认需要梯度 | 默认不需要梯度 |
模型参数管理 | 自动加入参数组 | 不会被模型追踪 |
保存和加载 | 自动包含在state_dict中 | 需要手动处理 |
5. 实践建议
- 需要训练和更新的参数应该使用Parameter
- 模型中的权重和偏置通常都是Parameter
- 固定的常量或临时变量使用普通Tensor即可
- 使用parameters()方法进行优化器参数设置
这是一个使用parameters()方法设置优化器参数的例子:
import torch
import torch.nn as nn
import torch.optim as optim
# 定义模型
model = SimpleNet(input_size=10, hidden_size=20, output_size=2)
# 创建优化器,将模型的所有参数传入
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 或者也可以指定特定参数的学习率
optimizer = optim.SGD([
{'params': model.layer1.parameters(), 'lr': 0.01},
{'params': model.layer2.parameters(), 'lr': 0.001}
], lr=0.001)
通过model.parameters()方法,优化器可以自动获取并管理模型中所有需要更新的参数。