从 out=P@V 分出 dV 与 dP 两条梯度支路
🎯 先猜一猜
p.shape=[2,8,8]、v.shape=[2,8,16]、dout.shape=[2,8,16]。
dv 与 dp 的 shape 分别是什么?
先补的知识
- 前向中 q/k/v.shape=[B,N,d],scores/p.shape=[B,N,N],out/dout.shape=[B,N,d]。
- 矩阵乘法反向会使用转置:out=P@V,所以 dV=P^T@dout,dP=dout@V^T。
- transpose(-2,-1) 只交换最后两个矩阵维,保留 batch 维。
- ctx.saved_tensors 按 forward 保存顺序取回 q、k、v、p;它们的 dtype/device 与前向一致。
图解原理
out 的每个值同时依赖注意力概率 P 和内容 V。上游梯度 dout 到达矩阵乘法后分成两路:一路告诉 V 应怎样变化,另一路告诉 P 应怎样变化;之后 P 的梯度还要继续穿过 Softmax。
| 计算 | 左输入 | 右输入 | 结果 |
|---|---|---|---|
dV=Pᵀ@dout | [B,N,N] | [B,N,d] | [B,N,d] |
dP=dout@Vᵀ | [B,N,d] | [B,d,N] | [B,N,N] |
语法热身:手算批量矩阵乘法的两条反向支路
weights = torch.randn(3, 4, 5)
values = torch.randn(3, 5, 2)
grad_output = torch.randn(3, 4, 2)
grad_values = weights.transpose(-2, -1) @ grad_output
grad_weights = grad_output @ values.transpose(-2, -1)
print(grad_values.shape, grad_weights.shape)把独立例子迁移回 Notebook
weights / values / grad_output对应p / v / dout。grad_values对应dv,shape 跟 v 一致。grad_weights对应dp,shape 跟 p 一致。- 例子故意使用非方形矩阵,帮助你从维度而不是死记位置判断转置。
巩固一下
dP 为什么使用 dout @ v.transpose(-2,-1)?
学完这一段,试着做
用一个小动作确认自己理解了;最后再进入官方题目。