这一课完成什么
把一个汉字编号变成一组可以学习的数字。第 4 课编号只告诉我们字表中的位置;现在为每个位置准备一行浮点数,供后面的计算使用。这张表在代码里叫 Embedding,中文常译作“嵌入”。
把一个编号,换成一整行数字
字向量就是字表中可学习的一行数字。它起初是随机的,在训练中逐渐变化;不要把某一格直接命名为“春天程度”。
用文字逐步读这张图
- 输入编号:春 → 1;编号不是含义
- 可学习的表:每字对应一行;每行有 C 个数字
- 查找第 1 行:[0.2, −0.1, 0.4];教学数值
- 同字再出现:仍然查第 1 行;得到相同字向量
- 进入后续计算:结合位置与前文;得到不同上下文
- 反向更新:用到的数字参与学习;表不再保持初始值
两个“春”的字向量相同,最终表示也相同吗?
不一定。加上不同位置、汇总不同前文以后,表示就会不同。
查表,而不是给编号赋予大小含义
假设字表有 6 个字,每个字用 4 个数表示,那么表的尺寸是 [6,4],共有 24 个可学习参数。输入编号 [1,2,1],就取第 1、2、1 行,输出三行、每行四项。
embedding = torch.nn.Embedding(6, 4)
ids = torch.tensor([1, 2, 1])
vectors = embedding(ids)在同一次模型状态下,两个编号 1 会取到完全相同的行。下一课加上位置表示后,同一个字处于不同位置的最终输入才会不同。
数字最初意味着什么
开始时这些数随机初始化,没有已经学会的古诗含义。训练通过第 7 课的误差反传更新它们。一个字在许多相似上下文中出现,可能被学到与这些上下文有关的规律;但不能把第一维直接称为“山水”,第二维称为“思乡”。向量坐标通常没有这种人工指定的解释。
./poet lesson 8先看三行数值,确认第一行和第三行相同。再把中间编号也改成 1,三行都会相同。改变表示宽度会改变每行可用的数字数量,也增加模型参数,后面注意力头的尺寸要同步兼容。
在正式模型里找到它
PoetryGPT 中 characters 是汉字表,positions 是位置表。汉字表尺寸为“正式字表大小 × 表示宽度”。输入编号 [B,T] 查表后成为 [B,T,C],正好接上第 5 课的数字形状。
self.characters = nn.Embedding(config.vocab_size, config.width)
hidden = self.characters(tokens)这个项目让输出层与输入字表共用参数:self.output.weight = self.characters.weight。这样每个字的一行数字既参与输入表示,也参与最终候选字打分,减少参数数量。共用的是同一份参数,不是训练前复制一次后各自更新。统计参数时不要把它重复算两次。
验收与排错
- 能从字表大小和表示宽度算出这张表的参数数量。
- 能解释
[B,T]到[B,T,C]的变化。 - 编号从 0 起,最大编号必须小于字表大小。
- 若增加新字,只改字表文件会使模型尺寸或含义不匹配;需要配套重建并训练。
小练习与答案
字表 6000 个字,宽度 128,这张表有多少参数?换成宽度 256 呢?
查看答案
分别是 768,000 和 1,536,000。宽度翻倍使这张表参数翻倍,但整个 GPT 中还有宽度乘宽度的矩阵,因此总模型参数和计算开销不会都只翻倍。可以在第 26 课比较完整模型的参数统计。