同一套 GPT,两条完整路线:训练更新与逐 Token 生成
沿 Hi 你! 串起 GPT 的完整计算:位置向量、LN 与 QKV、两次残差、MLP、全词表 logits、交叉熵和 AdamW,再看固定参数怎样逐 Token 生成与增量解码。用三张双语图解、两份分步动画区分参数、激活、梯度与生成上下文。
沿 Hi 你! 串起 GPT 的完整计算:位置向量、LN 与 QKV、两次残差、MLP、全词表 logits、交叉熵和 AdamW,再看固定参数怎样逐 Token 生成与增量解码。用三张双语图解、两份分步动画区分参数、激活、梯度与生成上下文。
前三篇把 loss 到每个参数的二十六步全推了一遍,但那是打开黑盒逐步走。这一篇把黑盒合回去:交叉熵的八步压成一行、BatchNorm 的十步压成一行,用的是同一个方法 —— 数一数变量在前向里出现几次,反向就有几项。压完撤掉 backward() 训 20 万步,val loss 2.1105,而 PyTorch 训的是 2.1106。
最后五步,没有分叉点,前三步是上一篇的复制粘贴。真正新的是后两步:view 的反向为什么就是它自己的逆操作(判据只有一条 —— 数的个数变没变),以及 dC[Xb] += demb 这行看着完全正确的代码为什么是错的。跑完这五步,4137 个参数的梯度全部手算出来。
上一篇停在 logits —— 那是网络的边界,八步里一个参数都没碰到。这一篇往里走十三步,参数第一次出现。而 BatchNorm 那九步之所以是全集最绕的一段,原因和 softmax 是同一个:归一化的分子必须先被拿去造分母。顺带遇到第一个「系数不是 1」的求和反向,以及一个只差 3% 的错 —— 它的 maxdiff 小到像浮点误差。
上一篇把张量求导的判据推完了,这一篇把它用满八次 —— 从 loss 一路倒推回 logits。真正带得走的不是那八个式子,是一套给自己判卷的方法、三条操作规则,以及一个「梯度必须恰好是 0」的性质:它反过来能当调试手段用。
第三篇给过多元链式法则那个 Σ,第十三篇用它推过线性层 —— 但那是一个特例。这一篇把它变成通用方法:加法从全微分来,四种形态只是同一张雅可比里非零项的分布不同,而「该 sum 还是该广播、沿哪一维」由两组下标怎么差直接读出来。
梯度的形状永远和被求导的对象一样,两条规则就能推出线性层的反传公式。而 C[X] 的雅可比只含 0 和 1 —— 嵌入表梯度的稀疏与累加,两个性质都写在那一张表里。
用一百行 Python 写出自动求导:Value 类建计算图,_backward 闭包存局部规则,拓扑排序做全局调度。以及 += 为什么就是多路径求和那个 Σ。
输出层从 1 个变成 2 个之后,反向传播多出来一步。这一步不是新规则,是多元链式法则本来就有的。
一个 2→2→1 的网络,三轮训练里每一个数字是怎么算出来的。以及两个只有真的跑起来才看得见的现象。