介绍
torch.nn.Parameter 是 可训练参数的封装类,继承自 torch.Tensor,是构建自定义可训练模型参数的核心工具——它本质是一种特殊的张量,会被自动注册到模型的参数列表中,参与反向传播和优化更新
特点
- 特殊的张量,默认开启
requires_grad=True(可求梯度); - 当把它赋值给
nn.Module的属性时,会被自动注册到模型的parameters()/named_parameters()列表中; - 优化器(如
Adam/SGD)能识别并更新这些参数,普通张量则不会。
简单来说:普通张量是“数据”,torch.nn.Parameter 是“模型可训练的权重/偏置”。
语法
torch.nn.Parameter(data=None, requires_grad=True)
核心参数
| 参数 | 作用 | 说明 |
|---|---|---|
data |
初始化参数的张量(必填) | 通常用 torch.randn()/torch.zeros() 等初始化,数据类型建议为 float32 |
requires_grad |
是否开启梯度计算(默认 True) | 设为 False 时,该参数不会被优化器更新(变为“冻结参数”) |
例子
先通过极简的自定义模型示例,理解 nn.Parameter 的核心用法:
import torch
import torch.nn as nn
# 示例1:定义一个含可训练参数的简单模型
class MyModel(nn.Module):
def __init__(self):
super().__init__()
# 定义可训练参数:权重 w(2×3 矩阵)、偏置 b(3维向量)
self.w = nn.Parameter(torch.randn(2, 3)) # 默认 requires_grad=True
self.b = nn.Parameter(torch.zeros(3)) # 全零初始化的偏置
# 定义普通张量(不会被注册为模型参数)
self.not_a_param = torch.randn(2, 3) # 无 requires_grad,也不注册
# 初始化模型
model = MyModel()
# 查看模型的可训练参数(仅 nn.Parameter 会被列出)
print("模型可训练参数:")
for name, param in model.named_parameters():
print(f"名称:{name},形状:{param.shape},是否可求梯度:{param.requires_grad}")
# 输出:
# 名称:w,形状:torch.Size([2, 3]),是否可求梯度:True
# 名称:b,形状:torch.Size([3]),是否可求梯度:True
# 普通张量不会出现在参数列表中
print("\n普通张量是否在参数列表中?", "not_a_param" in [n for n, _ in model.named_parameters()])
# 输出:False
特性
自动注册到模型参数列表
只有赋值给 nn.Module 实例属性的 nn.Parameter 才会被注册,直接创建的 nn.Parameter 只是普通张量:
# 直接创建的 nn.Parameter 不会被注册
isolated_param = nn.Parameter(torch.ones(1))
print("孤立参数是否属于模型?", isolated_param in model.parameters()) # False
支持梯度计算与优化更新
nn.Parameter 是反向传播的核心载体,优化器会自动更新其值:
# 模拟:前向计算 → 计算损失 → 反向传播 → 优化器更新参数
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
# 前向计算
x = torch.randn(4, 2) # 输入:4个样本,2维特征
output = x @ model.w + model.b # 线性计算
# 计算损失(模拟)
loss = output.sum()
# 反向传播
loss.backward()
# 查看梯度
print("\n参数w的梯度:\n", model.w.grad)
print("参数b的梯度:\n", model.b.grad)
# 优化器更新参数
optimizer.step()
# 清空梯度(必须步骤)
optimizer.zero_grad()
print("\n更新后参数w的前两个值:\n", model.w[:2, :2]) # 数值已更新
与普通张量的核心区别
| 特性 | torch.nn.Parameter |
普通 torch.Tensor |
|---|---|---|
| 自动注册到模型参数 | ✅(赋值给 Module 属性时) | ❌ |
默认 requires_grad |
✅(True) | ❌(False) |
| 被优化器更新 | ✅ | ❌(除非手动设 requires_grad=True 且加入优化器) |
实战场景:自定义层/模型
nn.Parameter 最常用的场景是自定义层(nn.Module),比如实现一个简单的线性层(替代 nn.Linear):
# 自定义线性层
class MyLinear(nn.Module):
def __init__(self, in_features, out_features):
super().__init__()
# 初始化权重:遵循 PyTorch 官方初始化策略(Kaiming 正态分布)
self.weight = nn.Parameter(torch.randn(out_features, in_features) * 0.01)
# 初始化偏置:全零
self.bias = nn.Parameter(torch.zeros(out_features))
def forward(self, x):
# 前向计算:y = x @ weight.T + bias
return x @ self.weight.T + self.bias
# 使用自定义线性层
linear_layer = MyLinear(in_features=5, out_features=3)
x = torch.randn(4, 5) # 4个样本,5维特征
output = linear_layer(x)
print("自定义线性层输出形状:", output.shape) # torch.Size([4, 3])
# 查看层的参数
print("\n自定义层参数:")
for name, param in linear_layer.named_parameters():
print(f"{name}: {param.shape}")
# 输出:
# weight: torch.Size([3, 5])
# bias: torch.Size([3])
常见易错点
忘记继承 nn.Module
如果自定义类不继承 nn.Module,nn.Parameter 不会被自动注册:
# 错误示例:不继承 nn.Module
class BadModel:
def __init__(self):
self.w = nn.Parameter(torch.randn(2,3))
bad_model = BadModel()
# 无法调用 parameters() 方法
# print(list(bad_model.parameters())) # 报错:'BadModel' object has no attribute 'parameters'
参数初始化不当
直接用 torch.randn() 初始化大维度参数时,数值过大会导致训练不稳定,建议遵循 PyTorch 官方初始化策略:
# 推荐:Kaiming 初始化(适用于线性层/卷积层)
self.weight = nn.Parameter(torch.nn.init.kaiming_normal_(torch.empty(out_features, in_features)))
# 或简单缩放
self.weight = nn.Parameter(torch.randn(out_features, in_features) * 0.01)
冻结参数(设 requires_grad=False)
如果想冻结部分参数(不更新),可手动设置 requires_grad=False:
# 冻结偏置参数
linear_layer.bias.requires_grad = False
# 优化器仅更新未冻结的参数
optimizer = torch.optim.SGD(
[p for p in linear_layer.parameters() if p.requires_grad],
lr=0.1
)
总结
torch.nn.Parameter是封装可训练参数的特殊张量,赋值给nn.Module实例属性时会自动注册到模型参数列表,默认开启梯度计算。- 核心区别:普通张量不会被模型注册、不会被优化器更新;
torch.nn.Parameter是模型的“可训练权重/偏置”。 - 实战用法:自定义层/模型时,用
torch.nn.Parameter定义权重、偏置等可训练参数,配合torch.nn.Module实现自动注册和梯度更新。