整体说明
nn.Parameter是torch.Tensor的一个子类,其定义方式如下:1
2
3class Parameter(torch.Tensor, metaclass=_ParameterMeta):
"""..."""
def __init__ ...nn.Parameter是最常用的模型参数类,其他许多高级封装的层(如nn.Linear和nn.Conv2d等)都包含着nn.Parameter对象作为参数
torch.Tensor和nn.Parameter的却别
- 两者主要区别是是否自动注册为模型参数,具体逻辑见下文:
特性 nn.Parametertorch.Tensor是否自动注册为模型参数 是 否 是否默认启用梯度计算 是 ( requires_grad=True)否 ( requires_grad=False)是否被优化器自动更新 是 否(需手动添加到优化器) 适用场景 可训练参数(如权重、偏置) 中间结果或固定值 - 在构建神经网络时,通常使用
nn.Parameter来定义可训练参数,而torch.Tensor更适合存储不需要训练的数据
是否自动注册为模型参数
nn.Parameter:- 当
nn.Parameter被赋值给nn.Module的属性时,它会自动注册为模型的可训练参数 - 可以通过
model.parameters()访问这些参数,优化器会自动更新它们 - 示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import torch.nn as nn
class MyModel(nn.Module):
def __init__(self):
super(MyModel, self).__init__()
self.weight = nn.Parameter(torch.randn(2, 2)) # 自动注册为模型参数
def forward(self, x):
return x @ self.weight
model = MyModel()
for param in model.parameters():
print(param) # 可以访问到 self.weight
# Parameter containing:
# tensor([[-0.1866, 0.6549],
# [-0.2559, -0.4768]], requires_grad=True)
- 当
torch.Tensor:- 直接使用
torch.Tensor初始化的张量不会被自动注册为模型参数 - 无法通过
model.parameters()访问,优化器也不会更新它 - 示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import torch.nn as nn
class MyModel(nn.Module):
def __init__(self):
super(MyModel, self).__init__()
self.weight = torch.randn(2, 2) # 只是一个普通的张量,不会注册为参数
def forward(self, x):
return x @ self.weight
model = MyModel()
for param in model.parameters():
print(param) # 不会输出 self.weight
# 无任何输出
- 直接使用
是否支持自动梯度计算
nn.Parameter:nn.Parameter是torch.Tensor的子类,默认启用梯度计算(requires_grad=True)- 在反向传播时,PyTorch 会自动计算其梯度
torch.Tensor:- 默认情况下,
torch.Tensor的requires_grad=False,不会计算梯度 - 如果需要计算梯度,必须手动设置
requires_grad=True - 示例:
1
self.weight = torch.randn(2, 2, requires_grad=True) # 手动启用梯度计算
- 默认情况下,
优化器是否能更新
nn.Parameter:- 优化器可以通过
model.parameters()获取nn.Parameter并更新其值
- 优化器可以通过
torch.Tensor:- 普通的
torch.Tensor不会被优化器识别,除非手动将其添加到优化器的参数列表中 - 示例:
1
optimizer = torch.optim.SGD([self.weight], lr=0.01) # 手动添加到优化器
- 普通的
使用场景
nn.Parameter:- 适用于定义模型的可训练参数(如权重、偏置等)
- 是构建神经网络时的标准做法
torch.Tensor:- 适用于存储不需要训练的中间结果或固定值(如常量张量)
- 如果需要训练,必须手动设置
requires_grad=True并注册到优化器
示例对比
- 对比代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27import torch
import torch.nn as nn
# 使用 nn.Parameter
class ModelWithParameter(nn.Module):
def __init__(self):
super(ModelWithParameter, self).__init__()
self.weight = nn.Parameter(torch.randn(2, 2)) # 自动注册为参数
def forward(self, x):
return x @ self.weight
# 使用 torch.Tensor
class ModelWithTensor(nn.Module):
def __init__(self):
super(ModelWithTensor, self).__init__()
self.weight = torch.randn(2, 2, requires_grad=True) # 需要手动设置 requires_grad
def forward(self, x):
return x @ self.weight
# 比较
model1 = ModelWithParameter()
print(list(model1.parameters())) # 输出: [Parameter containing...]
model2 = ModelWithTensor()
print(list(model2.parameters())) # 输出: []
nn.Linear和nn.Parameter的关系
nn.Parameter是torch.Tensor的子类,用于表示模型中的可训练参数,当它被赋值给nn.Module的属性时,会自动注册为模型参数,参与反向传播和优化nn.Linear内部包含两个nn.Parameter,分别用于存储权重和偏置1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18class Linear(Module):
"""...comments..."""
__constants__ = ['in_features', 'out_features']
in_features: int
out_features: int
weight: Tensor
def __init__(self, in_features: int, out_features: int, bias: bool = True,
device=None, dtype=None) -> None:
factory_kwargs = {'device': device, 'dtype': dtype}
super(Linear, self).__init__()
self.in_features = in_features
self.out_features = out_features
self.weight = Parameter(torch.empty((out_features, in_features), **factory_kwargs)) # Parameter定义
if bias:
self.bias = Parameter(torch.empty(out_features, **factory_kwargs)) # Parameter定义
else:
self.register_parameter('bias', None)
self.reset_parameters()对上面代码的其他解读:
__constants__ = ['in_features', 'out_features']:__constants__是 PyTorch 的一个特殊属性,用于声明哪些属性是常量。这些常量在 TorchScript(PyTorch 的 JIT 编译器)中会被优化,并且不会保存在模型的state_dict中in_features: int: 是一个类型注解,声明in_features是一个整数类型的类属性。它表示输入特征的数量,即输入向量的维度,这个注解的主要作用是提高代码的可读性和类型检查(例如,使用静态类型检查工具如mypy)out_features: int: 同样是一个类型注解,声明out_features是一个整数类型的类属性。它表示输出特征的数量,即输出向量的维度,这个注解的主要作用是提高代码的可读性和类型检查weight: Tensor: 是一个类型注解,声明weight是一个Tensor类型的类属性。weight是线性层的权重矩阵,形状为(out_features, in_features)。它会在__init__方法中被初始化为一个可学习的参数(通过torch.nn.Parameter封装)
torch模型参数都是nn.Parameter类吗?
在PyTorch中,模型参数通常是
nn.Parameter类的实例,但并非所有模型中的可学习参数都必须是nn.Parameter模型中不是
nn.Parameter类的一些特例和说明:Buffer(缓冲区) :有些模型需要存储一些状态,但这些状态不是可学习的参数。这些状态可以通过
register_buffer方法注册为缓冲区,而不是nn.Parameter。缓冲区不会被优化器更新,但会随模型一起保存和加载1
self.register_buffer('running_mean', torch.zeros(num_features))
非可学习参数 :有些参数虽然是模型的一部分,但不需要通过反向传播进行更新。这些参数可以是普通的
torch.Tensor,而不是nn.Parameter自定义参数 :在某些情况下,开发者可能会手动管理参数,而不是使用
nn.Parameter。例如,直接使用torch.Tensor并在需要时手动更新动态生成的临时变量 :在某些复杂的模型中,可能会有动态生成的参数或临时变量,这些可能不是
nn.Parameter注:子模块中间接包含了
nn.Parameter对象 :子模块(如nn.Linear、nn.Conv2d等)中包含的nn.Parameter对象参数会自动被识别并注册为模型参数,开发者可以通过parameters()方法访问这些参数。