输入 X
↓
算子 f₁(X; θ₁)
↓
中间表示 H
↓
算子 f₂(H; θ₂)
↓
输出 Y
模型可以很复杂,但每一步仍然只是 Tensor → Tensor。
| 维度 | 含义 |
|---|---|
| batch:同时处理的样本数 | |
| 额外结构维:位置、对象或序列 | |
| 输入特征维度 | |
| 输出特征维度 |
| 位置 | 输入向量 | 共享参数 | 输出向量 |
|---|---|---|---|
| (0,0) | X[0,0,:] | W [D,E] 同一个 Parameter | Y[0,0,:] |
| (0,1) | X[0,1,:] | Y[0,1,:] | |
| (0,2) | X[0,2,:] | Y[0,2,:] | |
| (1,0) | X[1,0,:] | Y[1,0,:] |
输入随位置变化;
xw = x @ w # [B, H, E]
b = ... # [E]
y = xw + b # [B, H, E]
PyTorch 让同一个
x = torch.randn(
2, 3, 4,
dtype=torch.float32,
device="cpu",
)
shape:数据如何组织dtype:每个元素如何表示device:计算在哪里执行requires_grad:是否需要追踪梯度后续所有模型组件,输入、输出和参数最终都是 Tensor。
# 矩阵乘:收缩相邻维度
y = x @ w
# 对应元素相乘:shape 相同或可广播
z = x * scale
# 批量矩阵乘
o = torch.bmm(q, k)
读代码时先问:输入和输出的 shape 是什么?各个维度如何变化?
比较两个 Tensor 的 shape 时:
1,可以沿该维重复使用1 [B, H, E]
+ [E]
-------------
[B, H, E]
[B,H,E] + [E]令
x[0] = [[ 1, 2, 3], [ 4, 5, 6]]
x[1] = [[ 7, 8, 9], [10, 11, 12]]
b = [10, 20, 30] # [E]
对齐: [2, 2, 3] + [1, 1, 3]
b 沿 B、H 维重复使用后:
y[0] = [[11, 22, 33], [14, 25, 36]]
y[1] = [[17, 28, 39], [20, 31, 42]]
同一个向量
[B,H,E] * [H,1]仍令
scale = [[ 10], [100]] # [H, 1]
对齐: [2, 2, 3] * [1, 2, 1]
展开: [2, 2, 3] * [2, 2, 3]
y[0] = [[ 10, 20, 30], [ 400, 500, 600]]
y[1] = [[ 70, 80, 90], [1000, 1100, 1200]]
10 作用于每个 batch 的第 0 行,100 作用于第 1 行,并沿
| 运算 | 对齐过程 | 结果 |
|---|---|---|
[B,H,E] + [E] |
[B,H,E] + [1,1,E] |
[B,H,E] |
[B,H,E] * [H,1] |
[B,H,E] * [1,H,1] |
[B,H,E] |
[B,H,E] + [D] |
报错 |
先从右向左补齐维度,再逐维检查“相等或为 1”。
B, H, D, E = 2, 3, 4, 5
x = torch.randn(B, H, D)
w = torch.randn(D, E)
y = torch.einsum("bhd,de->bhe", x, w)
assert y.shape == (B, H, E)
b、h、e 被保留,d 只在输入中出现,因此沿 d 求和。
w = nn.Parameter(torch.empty(D, E))
b = nn.Parameter(torch.zeros(E))
普通 Tensor 变成 Parameter 后:
model.parameters() 中model.to(device) 移动state_dict(),从而保存和加载nn.Module 写一个真实可用的模块class FeatureTransform(nn.Module):
def __init__(self, in_dim, out_dim):
super().__init__()
self.weight = nn.Parameter(
torch.empty(in_dim, out_dim)
)
self.bias = nn.Parameter(torch.zeros(out_dim))
nn.init.xavier_uniform_(self.weight)
def forward(self, x):
return x @ self.weight + self.bias
__init__ |
forward |
|---|---|
| 创建参数 | 接收输入 |
| 创建子模块 | 组合 Tensor 运算 |
| 注册状态 | 返回输出 |
一个 PyTorch 模型,本质上是由多个 nn.Module 递归组合而成。
model(x) 触发 forwardlayer = FeatureTransform(4, 5)
x = torch.randn(2, 3, 4)
y = layer(x) # 推荐
# y = layer.forward(x) # 不推荐
print(y.shape) # torch.Size([2, 3, 5])
layer(x) 会经过 nn.Module.__call__,在内部调用 forward(),同时保留 hooks、Autograd 等框架能力。
nn.Linear 采用另一种权重布局| 实现 | 权重形状 | 前向公式 |
|---|---|---|
本课/A0 ManualLinear |
[D, E] |
X @ W |
PyTorch nn.Linear |
[E, D] |
X @ weight.T + bias |
linear = nn.Linear(D, E)
y1 = linear(x)
y2 = x @ linear.weight.T + linear.bias
assert torch.allclose(y1, y2)
数学操作一致,区别只是参数的存储布局。
layer = nn.Linear(20, 30)
x = torch.randn(2, 8, 20)
y = layer(x)
print(y.shape) # [2, 8, 30]
前面的 batch、序列、空间或对象维都被保留。
class TinyMLP(nn.Module):
def __init__(self, dim, hidden_dim):
super().__init__()
self.up = nn.Linear(dim, hidden_dim)
self.act = nn.ReLU()
self.down = nn.Linear(hidden_dim, dim)
def forward(self, x):
h = self.up(x)
h = self.act(h)
return self.down(h)
TinyMLP 自身是 Module,内部又包含三个子 Module。
| 代码 | 表达能力 |
|---|---|
linear2(linear1(x)) |
仍然是线性变换 |
linear2(relu(linear1(x))) |
能够表达非线性关系 |
后面的 FFN、GELU、SwiGLU 都是在扩展这条思路。
class ResidualBlock(nn.Module):
def __init__(self, dim):
super().__init__()
self.mlp = TinyMLP(dim, 4 * dim)
def forward(self, x):
return x + self.mlp(x)
┌──→ TinyMLP ──┐
X ────┤ ├──→ Y
└──────────────┘
模型不一定是一条直线,但仍然是由 Tensor 运算构成的有向无环图。
nn.Module 让代码更接近真实模型model = ResidualBlock(dim=128)
print(model)
print(dict(model.named_parameters()).keys())
model = model.to("cuda")
torch.save(model.state_dict(), "model.pt")
nn.Module 统一管理:
参数注册 · 子模块 · 设备迁移 · 状态保存 · 前向调用
| 课堂中的工程写法 | A0 中的手写写法 |
|---|---|
class Layer(nn.Module) |
class ManualLinear |
forward() 定义计算 |
forward() 显式保存输入 |
| Autograd 自动反向 | backward(g) 手工计算 |
先学会开“自动挡”,再通过 A0 拆开它,理解框架替我们完成了什么。
模型 = 对输入张量进行计算的参数化程序
nn.Module = 状态 + 子模块 + forward
forward = 输入 Tensor → 输出 Tensor
下一课:给定一个标量 Loss,梯度如何沿这张计算图反向传播?
[Sources] https://docs.pytorch.org/docs/stable/generated/torch.nn.Module.html
[Sources] https://docs.pytorch.org/docs/stable/generated/torch.nn.Module.html https://docs.pytorch.org/docs/stable/generated/torch.nn.parameter.Parameter.html
[Sources] https://docs.pytorch.org/docs/stable/generated/torch.nn.Module.html
[Sources] https://njudeepengine.github.io/LLM-Blog/2025/06/10/A0-onboarding/