PyTorch Tensor 与 nn.Module
用 Tensor 表示数据,用 Module 管理层、参数、buffer 和前向。
学习目标
- 用一个参数和一个 buffer 做线性映射
- 普通列表为什么不适合存放待训练层?
- 说明:buffer 不训练不代表不重要;丢失预处理统计可能改变整个模型输出。
为什么需要这个概念
Tensor 保存数值与可选的梯度信息;nn.Module 组织计算、子模块、Parameter 和 buffer。Parameter 默认可训练,持久 buffer 保存随模型移动的状态。
学习前需要掌握
背景与问题
把权重放进普通 Python 列表并不能保证优化器发现它们。要让参数、设备移动和保存加载协同工作,模型需要遵守 PyTorch 的模块注册规则。
概念定义
Tensor 保存数值与可选的梯度信息;nn.Module 组织计算、子模块、Parameter 和 buffer。Parameter 默认可训练,持久 buffer 保存随模型移动的状态。
直观理解
Module 像一份可遍历的设备清单:参数列入优化名单,buffer 列入状态名单,普通属性则不会自动获得同样待遇。
核心原理
将 nn.Linear 等子模块赋给 self 的属性,会注册其参数;将 nn.Parameter 赋为属性也会注册。若要装多个层,应使用 ModuleList 或 Sequential,而非期待普通列表自动注册。forward 描述计算,通常通过 model(x) 调用以保留钩子等框架行为。
register_buffer 适合均值、位置表等非训练状态。持久 buffer 会进入 state_dict,并随 .to(device) 移动;普通 Tensor 属性默认不会。requires_grad=False 的参数仍是参数,只是暂停求梯度。
state_dict 保存注册的参数与持久 buffer,不保存 Python 类定义或完整预处理流程。恢复时仍需同一结构及一致配置;即使键名匹配,类别映射错位也会使输出含义出错。
数学表达
核心公式
Tensor 保存数值与可选的梯度信息;nn.Module 组织计算、子模块、Parameter 和 buffer。Parameter 默认可训练,持久 buffer 保存随模型移动的状态。
变量含义
X[N,in_features] 输入W[out_features,in_features] 参数
计算步骤
- 1计算 x×scale+offset。
- 2查看参数名字和 state_dict 名字。
代码对应位置
示例 1用一个参数和一个 buffer 做线性映射的最小验证:使用完整构造输入核对用一个参数和一个 buffer 做线性映射,输出只表示本例计算。
变量解释
| 变量 | 含义 |
|---|---|
X | [N,in_features] 输入 |
W | [out_features,in_features] 参数 |
完整数值示例
用一个参数和一个 buffer 做线性映射
已知条件
- 参数 scale=2
- buffer offset=1
- 输入为 3 和 4
计算步骤
- 计算 x×scale+offset。
- 查看参数名字和 state_dict 名字。
计算结果
输出为 7、9;优化器只看到 scale,保存状态包含 scale 与 offset。
处理前后对比
- buffer 不训练不代表不重要;丢失预处理统计可能改变整个模型输出。
案例推演与判断
这个模块只有一个可训练标量,offset 虽然参与前向,却不会出现在 parameters() 中。这样可以表达“固定中心化基准,但学习缩放”的语义。
如果把 offset 直接写成普通张量属性,本例在 CPU 上仍能运行,却可能在搬到 GPU 后出现设备不一致。模型能前向运行,并不足以证明状态管理正确。
计算与实现步骤
- 计算 x×scale+offset。
- 查看参数名字和 state_dict 名字。
代码实现
示例 1
用一个参数和一个 buffer 做线性映射的最小验证
example_01.py用途:使用完整构造输入核对用一个参数和一个 buffer 做线性映射,输出只表示本例计算。
import torch
from torch import nn
class Scale(nn.Module):
def __init__(self):
super().__init__()
self.scale = nn.Parameter(torch.tensor(2.))
self.register_buffer("offset", torch.tensor(1.))
def forward(self, x):
return x * self.scale + self.offset
model = Scale()
print(model(torch.tensor([3., 4.])).tolist())
print(list(dict(model.named_parameters())))
print(list(model.state_dict()))代码解析
解析始终位于完整代码下方,并按实际代码段逐项对应。
输入数据与任务
使用完整构造输入核对用一个参数和一个 buffer 做线性映射,输出只表示本例计算。
model- 组合预处理和估计器的模型对象。
Step 1 · 1–13 行
导入当前步骤需要的数值计算、预处理、模型或评价工具。依赖集中写在代码开头,便于复现。
import torch
from torch import nn
class Scale(nn.Module):
def __init__(self):
super().__init__()
self.scale = nn.Parameter(torch.tensor(2.))
self.register_buffer("offset", torch.tensor(1.))
def forward(self, x):
return x * self.scale + self.offset
model = Scale()
print(model(torch.tensor([3., 4.])).tolist())
print(list(dict(model.named_parameters())))
print(list(model.state_dict()))预期输出或运行结果
[7.0, 9.0] ['scale'] ['scale', 'offset']
常见错误 · 4 条
- 普通列表存层
- 直接 forward
- 只 eval 以为无梯度
- state_dict 当结构
实际应用
- 构建可保存的自定义网络
- 管理归一化统计与位置编码
常见错误
- 普通列表存层
- 直接 forward
- 只 eval 以为无梯度
- state_dict 当结构
常见问题
普通列表为什么不适合存放待训练层?
普通列表里的层不会通过列表容器自动注册,模块遍历、设备移动和优化器构建可能遗漏它们;应使用 ModuleList。
这个示例能说明什么边界?
buffer 不训练不代表不重要;丢失预处理统计可能改变整个模型输出。
推荐学习资料
PyTorch Tutorials
从张量、数据加载、自动微分和网络训练逐步进入视觉、NLP、性能与部署。
PyTorch Contributors · PyTorch
资料笔记
pytorch/examples
提供视觉、文本、强化学习和分布式训练等 PyTorch 参考示例。
PyTorch · GitHub
仓库信息
运行和研究常见 PyTorch 模型示例
主要语言:Python包含数据集或实验需要额外环境