文章目录
- 一、面试官到底在考什么?(考点拆解)
- 二、核心原理:为什么不能随便“加词”?
- 三、标准答案与实操解析
- 1. 什么是“词表扩展”?
- 2. 常见方法(由浅入深)
- 3. 注意事项(这是区分初级和高级的关键)
- 四、易错点与深水区(面试官的“陷阱”)
- 五、模拟面试现场
- 总结(一句话记忆)
你好!咱们直接切入正题。这道题在现在的面试中(尤其是涉及垂直领域微调、多语言适配的岗位)出现频率极高,因为它不仅考察你对Tokenizer 原理的理解,更考察你是否有工程落地经验和避坑意识。
很多候选人只会背“加几个词就行”,但真正做过的人知道,改词表等于动模型的根基,处理不好模型直接“失语”或崩溃。
下面我按“考点拆解 -> 核心原理 -> 标准答案(含实操) -> 易错点/深水区 -> 模拟面试”的逻辑给你深度解析。
一、面试官到底在考什么?(考点拆解)
当面试官问“词表扩展”时,他其实想确认你三件事:
- 原理深度:你是否理解 Token ID 与 Embedding 层的映射关系?是否知道修改词表后,模型权重矩阵发生了什么变化?
- 工程能力:你会用
transformers还是手写脚本?你是直接替换词表文件,还是走了标准的resize_token_embeddings流程? - 风险意识:扩展后是否需要重训?只训新向量够不够?会不会破坏原有语义空间?
二、核心原理:为什么不能随便“加词”?
在回答之前,脑子里要有这张图:
- Tokenizer:字典,负责把文字转成 ID(比如 “苹果” -> 1024)。
- Embedding Layer:查找表(Lookup Table),形状是
[Vocab_Size, Hidden_Dim]。ID 1024 对应这一行向量。
词表扩展的本质:
- 字典变大:Tokenizer 能识别更多新词(如生僻字、医疗术语)。
- 矩阵扩容:模型的 Embedding 层和 Output (LM Head) 层必须从
[V_old, D]扩容到[V_new, D]。 - 初始化关键:新增的那部分行向量(新词的 Embedding)怎么初始化?随机?平均?这是影响收敛速度的核心。
三、标准答案与实操解析
1. 什么是“词表扩展”?
“简单来说,就是给大模型‘增补字典’。预训练模型的词表通常是通用的,遇到垂直领域(如医疗、法律)的生僻词、专业术语,或者特定语言的字符时,会被切分成很多细碎的子词(Subwords),导致序列变长、语义割裂。
词表扩展就是把这些高频的专业词或生僻字,作为一个完整的 Token 加入词表,并相应地扩大模型的 Embedding 矩阵,让模型能‘一口吃掉’这些概念,而不是‘嚼碎了再咽’。”
2. 常见方法(由浅入深)
这里要展示你知道不同的场景用不同的招:
方法 A:基于 Hugging Faceresize_token_embeddings(最常用、最标准)
适用场景:绝大多数微调任务,增加几百到几千个新词。
操作逻辑:
- 用
tokenizer.add_tokens(new_tokens)添加新词,返回新增数量。 - 调用
model.resize_token_embeddings(len(tokenizer))。 - 关键点:HF 底层会自动将新增加的 Embedding 向量初始化为均值为 0、方差为预设值的高斯分布(或者有时复用已有向量的平均,取决于具体实现配置,但默认通常是随机初始化)。
- 用
代码示例(面试时能口述出这个很加分):
fromtransformersimportAutoTokenizer,AutoModelForCausalLM tokenizer=AutoTokenizer.from_pretrained("base_model")model=AutoModelForCausalLM.from_pretrained("base_model")# 1. 准备新词列表 (例如医疗术语)new_tokens=["靶向药","免疫疗法","CAR-T"]num_added=tokenizer.add_tokens(new_tokens)ifnum_added>0:# 2. 扩容模型嵌入层model.resize_token_embeddings(len(tokenizer))# 3. (进阶) 此时新向量是随机的,通常需要针对新词表进行一段“预热训练”
方法 B:特殊符号占位符替换(Hack 法,不推荐但需知道)
- 适用场景:无法修改模型结构,或者紧急修复某个特定词。
- 逻辑:利用原词表中极少使用的特殊符号(如
<unused0>)映射到新词。训练时强制模型学习该 ID 代表新含义。 - 缺点:浪费原词表空间,语义不直观,难以维护。
方法 C:完全重训 Tokenizer + 从头映射(高成本,用于大改版)
- 适用场景:跨语言迁移(如从纯英文模型改成中英混排),或原词表对目标语言支持极差(如中文被切成单字)。
- 逻辑:在新语料上重新训练 BPE/Unigram 词表 -> 构建新旧词表映射 -> 尝试将旧 Embedding 投影到新空间(很难完美)-> 大量重训。
- 注意:这通常等同于重新预训练,成本极高。
3. 注意事项(这是区分初级和高级的关键)
面试时一定要强调以下几点,这是血泪经验:
必须同步扩容 LM Head:
- 很多新人只改了 Embedding 层,忘了输出层(LM Head /
lm_head)。如果输出层没扩容,模型生成时遇到新词 ID 会直接报错或映射错误。resize_token_embeddings通常会自动处理这两层,但如果是自定义模型架构,务必检查。
- 很多新人只改了 Embedding 层,忘了输出层(LM Head /
新向量的初始化策略:
- 随机初始化是默认做法,但会导致训练初期新词梯度不稳定。
- 高阶技巧:如果新词是由旧词组成的(例如 “人工智能” 原本被切分为 “人工” + “智能”),可以将新词的 Embedding 初始化为旧词向量的平均值。这能让新词在训练开始前就拥有合理的语义位置,显著加快收敛。
训练策略(两阶段法):
- 不要直接全量微调!
- Phase 1:冻结大部分主干参数,只训练 Embedding 层和 LM Head(或者加上少量 Layer),让新词向量先“融入”语义空间。
- Phase 2:解锁全部参数进行正常 SFT(监督微调)。
- 原因:新向量是随机的,如果直接参与深层计算,巨大的噪声会破坏预训练好的权重分布。
分词优先级的变化:
- 加入新词后,Tokenizer 的贪心匹配逻辑会变。要确保新加的长词不会被错误的短词优先匹配掉(通常
add_tokens会自动处理优先级,但需验证)。
- 加入新词后,Tokenizer 的贪心匹配逻辑会变。要确保新加的长词不会被错误的短词优先匹配掉(通常
量化兼容性:
- 如果模型是 4-bit/8-bit 量化的(如 bitsandbytes),直接
resize可能会报错或失效。通常需要先卸载量化,扩容后再重新量化,或者使用支持动态扩容的量化后端。
- 如果模型是 4-bit/8-bit 量化的(如 bitsandbytes),直接
四、易错点与深水区(面试官的“陷阱”)
Q: 词表扩展后,原来的性能会下降吗?
- 易错回答:不会,只是加了新词。
- 专业回答:有可能。
- 优化器状态污染:如果使用 AdamW,新加入的参数会影响全局的梯度统计量(momentum/variance),可能导致旧知识遗忘加速。
- 语义空间挤压:如果扩充太大(比如从 32k 扩到 100k),而隐藏层维度不变,单个向量代表的语义密度可能变化,需要足够的训练数据来“校准”。
- 解决:控制学习率,对新旧参数使用不同的学习率(新词用大一点,旧词用小一点)。
Q: 为什么有时候加了词,模型还是输出乱码?
- 原因:
- 只加了词表,没改模型权重(最常见)。
- 训练数据不足:新词在微调数据里出现次数太少,向量没学好。
- 解码错误:生成的 Token ID 超出了原词表范围,但解码器还在用旧词表解,或者新词对应的字节序列非法。
五、模拟面试现场
面试官: “我们想在医疗场景下用 LLaMA-3,但它对很多药品名切分得很碎。你怎么做词表扩展?要注意什么?”
候选人(你):
“这个问题很典型。我会分三步走:第一步,数据驱动的选词。
我不会拍脑袋加词。我会先拿一批医疗语料,用原生的 LLaMA-3 Tokenizer 跑一遍,统计那些被切分成 3 个以上 token 且高频出现的专有名词(比如具体的化学药名)。同时,结合医学词典,筛选出约 2000-5000 个核心术语作为候选集。第二步,标准扩容与初始化。
利用transformers库,先tokenizer.add_tokens()把这些词加进去。然后关键一步,调用model.resize_token_embeddings()。
这里有个细节,默认是新向量随机初始化。为了稳一点,我会写个小脚本,对于像‘阿司匹林肠溶片’这种由已知字组成的词,尝试用其子词向量的均值来初始化新向量,而不是纯随机。这样模型一开始就能大概猜到这词的意思。第三步,差异化训练策略。
扩容后,我绝对不会直接全量微调。
我会先做一个Embedding Warm-up:冻结 Transformer 的主体层,只开放 Embedding 层和 LM Head,用医疗语料跑几个 epoch,让新词向量快速收敛到合理的语义空间。
然后再解冻所有层,用正常的学习率进行 SFT。
另外,因为引入了新参数,我会稍微调低一点整体学习率,防止破坏基座模型原有的通用能力。最后还要注意一点,如果我们要部署量化版本,必须在扩容完成、训练好之后,再进行量化,不能在量化状态下直接改词表大小,否则容易出兼容性问题。”
总结(一句话记忆)
词表扩展不是简单的“加字典”,而是**“字典扩容 + 矩阵重塑 + 向量初始化 + 分层热身训练”**的系统工程。
这套回答既展示了你对 HF 工具的熟练度,又体现了对深度学习原理(初始化、优化器、语义空间)的深刻理解,绝对是资深程序员的水平。