Module 0 · Foundations Lesson 02 2026-07-20

Embedding

token id 只是个数字,模型怎么知道它是什么意思?—— 这一课回答你自己提的 Q5。

TopicEmbedding(词嵌入)
Objectives搞懂 token id → 有意义的向量;修正 Token 课的两个误区
PrerequisitesToken ✅
Outcome能解释"意义"存在哪里,以及 transformer 真正吃的是什么
Warningembedding 只是入口,还没"理解上下文"(那是 attention 的活)

① Why — 为什么需要 embedding?

tokenizer 给了你一串整数:[1917, 995, ...]。但整数不能直接喂神经网络,两个原因:

我们需要一种表示:语义相近的 token → 数值上也相近。这就是 embedding 要解决的问题。

② How — 机制(这里补上你的两个误区)

想象一张巨大的查找表 E,本质就是个矩阵。token id = 行号,取出对应的一整行向量:

Embedding 矩阵 E  ·  形状 [vocab_size × d_model] d_model 列(例如 768 个数) 行 0 0.12 -0.98 ... 0.44 行 1 -0.31 0.07 ... -0.55 ... 行 1917 0.88 0.02 ... -0.19 ← "world" 的向量 ... 行 vocab-1 ... id=1917 共 vocab_size 行(词表多大就多少行)
token id 的唯一作用:当行号,去表里取出一整行向量。它是座位号,不是内容。
✅ 修正误区 B: transformer 吃的是取出来的那一行向量,不是整数 1917。整数只负责"去第几行取"。
✅ 修正误区 A(你的"矩阵"直觉没错,只是站错了位置): 一句话 N 个 token → 取出 N 个向量 → 叠起来就是一个 [N × d_model] 矩阵。这个"矩阵"发生在 embedding 层,不是 tokenizer;tokenizer 只吐整数序列。

③ 意义从哪来?(回答你的 Q5)

E 里的数字一开始是随机的,不是人填的,而是在训练中学出来的:

训练时模型不断读海量文本、预测下一个词;预测错了就微调这些数字。经过千亿次调整,出现在相似上下文里的 token,它们的向量会被拉到相似的位置

所以"意义"不在整数 1917 里,而在它那行向量在高维空间里的"位置"里。 cat 和 dog 总出现在相似句子中 → 向量靠得近;world 和 banana → 离得远。

向量空间直觉(示意,实际是几百维) cat dog 语义相近 → 靠得近 banana world 语义无关 → 离得远 king queen 方向也有含义
不只是"近=相似";空间里的方向也能编码关系。

vector("king") − vector("man") + vector("woman") ≈ vector("queen")

"性别"是一个方向,"王室身份"是另一个方向 —— 早期 word2vec 的经典直觉,帮你建感觉。

⚠️ 一个诚实的边界: 上面"一个词一个固定向量"是静态老观念。现代 LLM 里 embedding 只是起点 —— "bank"(银行/河岸)拿到的初始向量一样,真正区分要靠后面的 attention 根据上下文调整。这是下一模块的内容,今天记住"embedding 是入口"就够了。

💬 深入问答(来自讨论)

Q:编号是几,本身有意义吗?like=123like=7 有区别吗?

没区别。 模型拿到整数后第一件事就是把它当行号去 embedding 表取向量,从此再也不碰这个整数——它不会对 123 做任何加减乘。整数的"数值大小"在取完向量那一刻就被彻底丢掉,只有"取的是哪一行"有意义。所以换门牌号不影响座位上那个向量该学成什么样。编号分配是任意的,没有优劣。

⚠️ 但要加一个前提:必须"一致"

"任意"的限定词是——任意,但前后必须一致(一个固定的置换)。把 like 从 123 改成 7,就必须同时把它的向量从第 123 行搬到第 7 行,且 tokenizer 以后永远给 like 吐 7。

tokenizer 和 embedding 表是一对绑定的搭档。不能对训练好的模型随便交换 id,除非把 embedding 表的行也按同样方式重排。编号自由,但"编号 ↔ 向量行"的对应一旦定了就锁死。

🔧 一个容易混的区分

"tokenizer 做的事"其实是两个不同问题,优劣情况相反:

切成哪些碎片(词表设计)有优劣 —— 好词表更高效(更少 token、生僻词/多语言更好)。BPE 统计在优化这个。
每个碎片编成几号(id 分配)无优劣 —— 纯任意,通常按合并顺序/频率排,但换一套也一样。
一句话收口: 正因为整数编号任意、无意义,才必须有 embedding 这一层 —— 它把"任意的门牌号"翻译成"训练学出来的、有意义的向量"。

Q:训练会让一个 token 的 index 从 1 跑到 10234 吗?embedding 的映射是训练出来的吗?

不会,index 永远不迁移。 关键在于区分两种完全不同的"训练"

① Tokenizer 训练(BPE) 决定「切成哪些碎片」+「每个碎片编几号」= 那张词表(token↔id 映射)。建模型之前单独跑一次,之后冻结,再不变。
② 模型训练(梯度下降) 只改 embedding 表里每行向量的数值。id 映射当作常量不动,只有向量在变

所以 like=123 由 ① 定死;② 阶段 index 绝不迁移,改的只是"第 123 行那串数字"。

🏠 门牌号在开训前就钉死了;训练只重新装修每个房间里的家具(向量),不搬门牌。

Q:tokenization 是"积重难返"的吗?如果后来改了切分(like+dlik+ed),之前的 embedding 要全重跑吗?

对一个已训练好的模型:tokenizer 锁死,改切分 ≈ 重训。 整个模型(不只 embedding,还有 attention/FFN)都是假设着这套切分训出来的;改了切分,喂进去的 id 序列全变,而表里各行学的还是旧含义 → 输出垃圾。

但"积重难返"只对半:没人会中途改主意。 tokenizer 是开训前一次性选好、然后冻结的,不存在"训练到一半改切分"。发现更好的方案 → 下一代新模型用新 tokenizer 从头训(如 GPT-2/3 与 GPT-4 用不同 tokenizer,是各自独立训练的模型)。所以不是被早期选择永远困住,而是"每个新模型可重选;一旦进入训练就锁死"。

新增 token(加新词)较轻 —— embedding 表加几行、初始化、微调即可,老的不动。
改动已有切分边界很重 —— 老 id 含义与分布全变 ≈ 重训。

补充:不只是 embedding 要重跑,整个模型都依赖那套 token 分布;embedding 只是"最直接绑定"的一层。学术上有"换 tokenizer 不从头训"的技巧(旧词表向量映射到新词表当初始化再微调,如 vocabulary transfer / WECHSEL),能省掉完整预训练,但仍需可观微调

收口: tokenizer 对"当前模型"是动不了的地基;对"下一个模型"完全可换。理解成"每个模型一次性、锁死的地基决策"就对了。

Q:这里说的"重训"大致怎么做?从原始语料开始,还是"蒸馏"?

"重训"是个光谱,从最贵到最省三档:

① 从头预训练 权重随机初始化 → 在海量原始文本上做 next-token prediction。换 tokenizer 通常是新一代模型的一揽子改动之一,反正从头训。标准做法,代价最大。
② 词表迁移 + 继续训练 复用旧模型深层权重(attention/FFN 不扔),只把 embedding 表按"旧词↔新词"映射重新初始化(WECHSEL / vocabulary transfer),再继续训练一段。省钱中间档,但仍需可观训练。
③ 蒸馏(distillation) 让"学生"模型模仿"老师"的输出概率分布,主要用于压缩(大模型学成小模型)或迁移能力。

蒸馏不是修 tokenizer 的自然解法: 它在 token 概率分布层面对齐,若师生用不同 tokenizer,两边输出词表对不上号(老师第 1917 号 ≠ 学生第 1917 号)。跨 tokenizer 蒸馏有研究但很 tricky,非常规。

收口: 换 tokenizer 的"重训"本质是回到原始语料做预训练(或"词表迁移+继续训"这种暖启动);蒸馏解决的是另一个问题(压缩),还会被"两边词表对不上"绊住。细节见 Module 4 — Training。

✅ 快速检查(用自己的话答)

  1. 座位号这个比喻,重新解释:token id 和 embedding 向量分别对应比喻里的什么?
  2. embedding 表里的数字是人手工设定的,还是别的方式来的?一句话说清。
  3. 判断对错并说理由:"两个 token 的 id 数值很接近,它们的 embedding 向量也一定很接近。"

答完 3 题,再按格式给我一份 Lesson Summary(My Understanding / Key Mental Models / Remaining Questions / Misconceptions Fixed)。批改后进入 Vector 向量空间直觉(很短),然后上 Transformer。