02 分词、嵌入与语言模型
课程锚点:Lecture01 Slides22–39;Lecture02 Slides4–10、12;week3 Code/tokenization.py。代码中有些 text()/link()/@inspect 来自教学展示环境,不等于一个可直接独立运行的普通脚本。
2.1 为什么要分词
神经网络需要可计算的数值输入;自然语言的可变长字符串先编码为有限词表中的 ID。字符级词表在 Unicode 上很大且很多字符罕见;byte 词表只有256种基础值但序列长;整词级词表巨大、有未知词、难共享词形信息。子词方法在词表大小与序列长度之间折中。
一个汉字常占多个 UTF-8 byte,一个词可能多个 token,空格和标点也可能占 token。len(text)、UTF-8 byte 数和 token 数是三种长度。词表大通常缩短序列,但 embedding 与 LM head 参数增加,softmax 也更贵。
Byte-level BPE 若包含全部256基础字节,可表示任意有效 UTF-8 文本,不意味着每个单独 token 都能独立解码成完整 Unicode 字符。decode 通常先拼接 token 对应 bytes,再做 UTF-8 解码。
2.2 BPE 训练与编码分开讲
训练:初始化基础符号序列与词表→统计相邻 pair 频次→选择最高频 pair→用新符号替换其非重叠出现→记录 merge 及顺序→重复到预算。它是统计启发式,不是神经网络梯度训练。
例,语料只有 ababab,初始 [a,b,a,b,a,b]。pair ab 3 次、ba 2 次,合并 ab→X 后得到 [X,X,X];相邻 XX 的统计出现 2 次,但左到右非重叠替换只会替换1次,得 [Y,X]。频次统计可重叠,替换不能把同一位置使用两次。 tie-breaking 需固定,否则训练结果可能不同。
编码新文本时,使用已经学习的 merge ranks;不能在每个输入上重新选最高频 pair。解码时查 ID→bytes 并拼接,通常不必反向逐个拆 merge。真实 tokenizer 还可能有 normalization、regex pre-tokenization、special token 匹配,不能把教学版 BPE 当成所有生产 tokenizer 的完整实现。
为什么空格敏感?预切分规则和词表可能把前导空格与单词合并;同一个可见单词出现在句首和句中可能用不同 ID。对数字和拼写任务,token 边界会改变模型需要处理的基本单位,这也是 LLM 不等同于逐字符程序的原因。
2.3 Embedding 与分布式表示
词表大小 V,隐藏宽度 D,embedding 表 E:[V,D]。ID 序列 [B,T] 通过行查表得到 [B,T,D]。等价地可用 one-hot 向量乘 E,但查表省内存与计算。ID=10不表示语义是ID=5的两倍。
静态词向量:同一个 token 查出同一初始向量;contextual hidden state:经过网络后,bank 在“河岸”和“银行”上下文中的表示不同。位置和上下文的差异不是 tokenizer 每次重新训练出了词向量。
CBOW:用周围上下文预测中心词。Skip-gram:用中心词预测窗口内上下文。
完整 softmax 对每个训练对需访问整个词表。负采样把一个正例和若干噪声词组成二分类任务:
增大真实共现向量的内积,减小噪声内积。它与 NCE 相关,但word2vec negative sampling 和严格 NCE 目标不完全相同;不能直接说负采样等于算出了原 softmax 的精确概率。常见噪声分布与词频的3/4次幂有关,这是具体方法选择而非唯一可用分布。
向量类比(king-man+woman≈queen)是某些嵌入中的经验结构,不是对任意词和语义必然成立的代数定律;投影到二维也可能扭曲距离。
2.4 从 n-gram 到神经语言模型
联合概率的链式分解:
n-gram 近似只保留前 n-1 项上下文,易受稀疏和有限窗口限制。神经模型通过可学习表示共享统计规律;RNN/LSTM 以状态递归压缩历史,但训练序列依赖强、长距离梯度/信息保存困难;attention 让当前位置直接按内容访问其他位置,Transformer 又使已知序列上的位置计算可以并行。代价包括标准 attention 的 T²分数规模。
三类经典架构:encoder-only(如 BERT)双向理解,常用 masked-token 目标;decoder-only(如 GPT)因果 next-token;encoder-decoder(如原始翻译 Transformer、T5)编码输入再自回归解码输出。mask、训练目标和用途要一起说,而不是只按模型名字分类。
2.5 Prompt 到 output 的完整链条
messages(system/user/assistant 等)→chat template(角色、边界、生成提示等)→tokenizer→input IDs与mask→embedding→N个block→最终norm→LM head→logits→解码策略→追加新token→重复→decode文本。
System prompt 是模型输入的一部分,不是修改权重的操作;inference-time preference 不自动成为永久知识。指令微调让模型学会理解角色和任务格式,但不能仅凭插入一个角色字符串就保证模型遵循优先级。
LM head 将 [B,T,D] 投影到 [B,T,V]。输入 embedding 和输出投影可共享参数(weight tying),也可以不共享。算参数量时共享只算一次。某位置的 logits 用于预测下一个 token,不是重构当前位置ID。
2.6 PPL 从似然推出来
M是参与评价的有效目标token总数。对概率乘积取M次根再取倒数,得到几何平均意义的困惑度。若每个位置都在 K 个 token 上均匀预测,PPL=K;若每个正确项概率趋于1,PPL趋于1。
若用 log2 计算交叉熵,PPL要用 2^H,不能混用底数。汇总不同长度batch时,要先加总所有NLL与有效token数;不能直接平均各batch的PPL,也不能不加权平均各batch loss。
比较PPL必须固定语料、tokenizer、上下文切片、mask与评估协议;不同tokenizer每个token携带的信息量不同。低PPL说明这个概率建模指标更好,不自动意味着数学推理更强、人更偏好或事实更可靠。