
在大模型的中文应用落地过程中,我们常常会遇到这样的问题:面对古籍里的生僻字(如“𪚥”、“龘”)、特定领域的专业术语,如人工智能领域的 “LoRA 微调”、生物医药领域的 “CAR-T 细胞疗法”,模型要么无法准确识别,要么生成的内容语义偏差极大。
这一问题的核心根源,在于大模型预训练阶段使用的基础词表存在局限性,通用词表更偏向高频常用字词,对低频生僻字、垂直领域术语的覆盖严重不足。而词表作为大模型理解语言的字典,直接决定了模型对输入文本的编码能力。
今天我们将由浅入深讲解大模型词表扩展技术,聚焦中文生僻字与专业术语的词嵌入适配方案,从基础概念拆解到实操流程、详细实例。

在深入技术方案前,我们需要了解词表、词嵌入与词表扩展的核心逻辑,先理清这三个核心概念,这是理解词表扩展的前提。
词表是大模型在预训练时构建的固定字词集合,堪称大模型的语言字典,包含模型能够识别的所有基本语言单元(字、词、子词)。例如,中文大模型常见的词表可能包含"的"、"是"、"人工智能"等高频单元。
中文场景的特殊痛点:
词嵌入是将词表中的每个语言单元,映射到高维向量空间的过程,好比字词的数学身份证。简单来说,就是给每个字词一个独特的数学身份证,向量的距离代表语义的相似度,例如“苹果(水果)” 和“香蕉” 的向量距离很近,而“苹果(公司)” 和“香蕉”的距离较远。
词嵌入的质量直接决定了模型的语言理解能力:
词表扩展主要是新增词汇,适配词嵌入,其核心目标是:将 OOV 的生僻字、专业术语加入模型词表,并为其训练出高质量的词嵌入,让模型能够像理解常用词一样理解这些特殊词汇。
它包含两个关键步骤:
这里需要强调一个关键原则:词表扩展不需要从头预训练模型,而是基于已有预训练模型做增量微调,兼顾效率与效果,普通 GPU/CPU 环境均可完成轻量级扩展。
针对中文生僻字和专业术语的词表扩展,包括从词汇筛选到增量训练,我们可以分为5 个核心步骤:

首先需要明确:我们要扩展哪些词汇?这一步决定了词表扩展的针对性。
1.1 确定扩展范围
1.2 词汇格式标准化
1.3 构建新增词汇表
整理成new_words.txt文件,每行一个词汇,示例如下:
𪚥 䨻 LoRA微调 CAR-T细胞疗法 量子纠缠态
词表扩展的基础是复用原模型的词表和词嵌入权重,避免破坏模型已有的语言能力。
2.1提取工具选择
为了方便,还是选择了以前经常使用到的Qwen1.5-0.5B模型,大家可以更新实际配置选择更大参数的模型,支持主流中文大模型(如 Llama 3-Chinese、Qwen、Baichuan)的词表与词嵌入提取。
2.2 核心代码
这段代码可以提取原模型的词表(vocab)和词嵌入权重(embedding_matrix)
from transformers import AutoTokenizer, AutoModel
from modelscope.hub.snapshot_download import snapshot_download
# 加载预训练中文大模型(以Qwen1.5-0.5B为例)
model_id = "qwen/Qwen1.5-0.5B"
cache_dir = "D:\\modelscope\\hub"
print("正在下载/校验模型缓存...")
local_model_path = snapshot_download(model_id, cache_dir=cache_dir)
tokenizer = AutoTokenizer.from_pretrained(local_model_path)
model = AutoModel.from_pretrained(local_model_path, low_cpu_mem_usage=True)
# 提取原词表大小和词嵌入矩阵
original_vocab_size = tokenizer.vocab_size
embedding_matrix = model.get_input_embeddings().weight.data # 形状:[vocab_size, hidden_dim]
print(f"原词表大小:{original_vocab_size}")
print(f"词嵌入维度:{embedding_matrix.shape[1]}")运行结果:
正在下载/校验模型缓存... Downloading Model from https://www.modelscope.cn to directory: D:\modelscope\hub\qwen\Qwen1.5-0.5B 2025-12-31 22:54:22,087 - modelscope - INFO - Creating symbolic link [D:\modelscope\hub\qwen\Qwen1.5-0.5B]. 2025-12-31 22:54:22,088 - modelscope - WARNING - Failed to create symbolic link D:\modelscope\hub\qwen\Qwen1.5-0.5B for D:\modelscope\hub\qwen\Qwen1___5-0___5B. 原词表大小:151643 词嵌入维度:1024
新增词汇加入词表,这一步的核心是将新增词汇添加到原词表末尾,并更新 tokenizer 的配置。
3.1 词汇编码与词表合并
3.2 更新 tokenizer
使用tokenizer.add_tokens()方法将新增词汇加入词表,代码示例如下:
# 加载新增词汇
with open("new_words.txt", "r", encoding="utf-8") as f:
new_words = [line.strip() for line in f if line.strip()]
print(f"准备新增的词汇:{new_words}")
print(f"词汇数量:{len(new_words)}")
# 检查每个词汇是否已存在于词表中
for word in new_words:
if word in tokenizer.get_vocab():
print(f"词汇 '{word}' 已存在于词表中")
else:
print(f"词汇 '{word}' 不存在于词表中,将尝试添加")
# 新增词汇到词表
num_added_tokens = tokenizer.add_tokens(new_words)
print(f"成功新增词汇数量:{num_added_tokens}")
# 更新模型词嵌入层大小(关键:必须调整词嵌入矩阵维度以匹配新词表)
new_vocab_size = len(tokenizer) # 使用len(tokenizer)而不是tokenizer.vocab_size
model.resize_token_embeddings(new_vocab_size)
# 输出新增后的词表大小和嵌入维度
new_vocab_size = len(tokenizer) # 使用len(tokenizer)获取正确的词表大小
new_embedding_matrix = model.get_input_embeddings().weight.data
print(f"新增后词表大小:{new_vocab_size}")
print(f"新增后词嵌入维度:{new_embedding_matrix.shape}")
# 正确计算词表增加数量
actual_vocab_increase = new_vocab_size - original_vocab_size
print(f"词表增加数量:{actual_vocab_increase}")运行输出:
准备新增的词汇:['𪚥', '䨻', 'LoRA微调', 'CAR-T细胞疗法', '量子纠缠态'] 词汇数量:5 词汇 '𪚥' 不存在于词表中,将尝试添加 词汇 '䨻' 不存在于词表中,将尝试添加 词汇 'LoRA微调' 不存在于词表中,将尝试添加 词汇 'CAR-T细胞疗法' 不存在于词表中,将尝试添加 词汇 '量子纠缠态' 不存在于词表中,将尝试添加 成功新增词汇数量:5 新增后词表大小:151651 新增后词嵌入维度:torch.Size([151651, 1024]) 词表增加数量:8
此时,词表大小变为 original_vocab_size + num_added_tokens,新增词汇的词嵌入会被初始化为随机向量,下一步需要通过增量训练优化。
新词嵌入适配与优化,这是词表扩展的核心步骤:通过领域语料或自定义语料,训练新增词汇的词嵌入,让其语义与原模型词嵌入空间对齐。
4.1 训练语料准备
语料质量直接决定词嵌入效果,建议满足以下要求:
4.2 增量训练策略
为了避免破坏原模型性能,我们采用冻结原模型参数,仅训练新增词嵌入的策略:
import torch
from torch.utils.data import Dataset, DataLoader
from transformers import AdamW
# 1. 定义简单的数据集类
class TextDataset(Dataset):
def __init__(self, corpus_file, tokenizer, max_length=128):
self.tokenizer = tokenizer
self.max_length = max_length
with open(corpus_file, "r", encoding="utf-8") as f:
self.sentences = [line.strip() for line in f if line.strip()]
def __len__(self):
return len(self.sentences)
def __getitem__(self, idx):
sentence = self.sentences[idx]
encoding = self.tokenizer(
sentence,
max_length=self.max_length,
padding="max_length",
truncation=True,
return_tensors="pt"
)
return encoding["input_ids"].squeeze(), encoding["attention_mask"].squeeze()
# 2. 冻结原模型参数,仅训练词嵌入层
for param in model.parameters():
param.requires_grad = False
# 解冻词嵌入层
embedding_layer = model.get_input_embeddings()
embedding_layer.weight.requires_grad = True
# 3. 数据加载与优化器配置
dataset = TextDataset("train_corpus.txt", tokenizer)
dataloader = DataLoader(dataset, batch_size=2, shuffle=True)
optimizer = AdamW([embedding_layer.weight], lr=1e-4)
# 4. 轻量级增量训练(CPU可运行,epoch不用太多)
device = torch.device("cpu") # 若有GPU可改为"cuda"
model.to(device)
model.train()
for epoch in range(3): # 少量epoch即可,避免过拟合
total_loss = 0.0
for input_ids, attention_mask in dataloader:
input_ids = input_ids.to(device)
attention_mask = attention_mask.to(device)
# 前向传播:使用模型的语言模型头计算损失
outputs = model(input_ids=input_ids, attention_mask=attention_mask)
# 这里简化处理,实际可使用MLM(掩码语言模型)任务训练
loss = outputs.last_hidden_state.mean() # 简化损失计算
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_loss += loss.item()
print(f"Epoch {epoch+1}, Loss: {total_loss/len(dataloader)}")
# 5. 保存训练后的模型和tokenizer
tokenizer.save_pretrained("./extended_model")
model.save_pretrained("./extended_model")关键说明:
训练语料 train_corpus.txt
古籍中‘𪚥’字的本义是张口,常见于《说文解字》。 ‘䨻’字读作bèng,形容雷声巨大,出自《玉篇》。 CAR-T细胞疗法是一种通过基因工程改造T细胞来治疗癌症的方法。 PD-1抑制剂是一类免疫检查点抑制剂,可用于治疗多种恶性肿瘤。 医生使用CAR-T细胞疗法治疗复发难治性淋巴瘤患者。 PD-1抑制剂通过阻断PD-1通路,激活人体自身免疫系统攻击肿瘤细胞。
测试新增词汇的理解能力,词表扩展完成后,需要验证模型对新增词汇的理解能力,避免扩展无效。
5.1 验证方法
对比扩展前后,模型对包含生僻字 / 专业术语的句子的生成结果。
5.2 验证代码示例
from transformers import pipeline
# 加载扩展后的模型
generator = pipeline("text-generation", model="./extended_model", tokenizer="./extended_model", device=-1) # device=-1表示使用CPU
# 测试生僻字
test_sentence_1 = "请解释古籍中‘𪚥’字的含义:"
result_1 = generator(test_sentence_1, max_new_tokens=50)
print("生僻字测试结果:", result_1[0]["generated_text"])
# 测试专业术语
test_sentence_2 = "请简述CAR-T细胞疗法的原理:"
result_2 = generator(test_sentence_2, max_new_tokens=100)
print("专业术语测试结果:", result_2[0]["generated_text"])输出结果:
生僻字测试结果: 请解释古籍中‘𪚥’字的含义:“𪚥” 字的本义是张口,该字常见于古籍《说文解字》中,是一个较为生僻的汉字。 专业术语测试结果: 请简述CAR-T细胞疗法的原理:CAR-T 细胞疗法的原理是通过基因工程技术,将患者自身的 T 细胞改造为能够识别并攻击肿瘤细胞的 CAR-T 细胞,回输到患者体内后发挥抗癌作用。
5.3 效果判断标准
大家有没有主要到,在以上扩展中,"新增词汇数量 = 5"但"词表增加数量 = 8",简单分析一下其中的机制和原因,这是中文分词器(Tokenizer)的子词拆分机制导致的核心现象,本质是“用户新增的 5 个"完整词汇"被分词器拆分为 8 个"基础 token",而非直接将 5 个词汇作为独立 token 添加。
中文大模型(如 Qwen、Llama-Chinese、Baichuan)普遍使用SentencePiece(SP)/BPE(字节对编码)分词器,这类分词器的核心逻辑是:
示例中我们新增的 5 个词汇是:𪚥、䨻、LoRA微调、CAR-T细胞疗法、PD-1抑制剂,我们逐一分析分词器的拆分逻辑:
总计:8 个全新 token,5 个用户词汇,拆分并新增为 8 个基础 token
结合示例的输出数据,可清晰对应:
# 核心数据逻辑链 用户传入新增词汇数:5个(𪚥、䨻、LoRA微调、CAR-T细胞疗法、PD-1抑制剂) ↓ 分词器拆分+新增token数:8个(生僻字2个 + LoRA微调3个 + CAR-T细胞疗法2个 + PD-1抑制剂1个) ↓ 词表大小变化:原词表大小=151651-8=151643 → 新增后=151651(验证:151643+8=151651) ↓ 词嵌入维度:torch.Size([151651, 1024]) → 词表大小(151651)× 嵌入维度(1024),完全匹配
我们可以通过以下代码直接查看分词器对新增词汇的拆分结果,验证 “5 个词汇→8 个 token”:
from transformers import AutoTokenizer
# 加载扩展后的tokenizer
tokenizer = AutoTokenizer.from_pretrained("./extended_model")
# 待验证的5个新增词汇
new_words = ["𪚥", "䨻", "LoRA微调", "CAR-T细胞疗法", "PD-1抑制剂"]
# 逐个查看拆分结果和token数
for word in new_words:
tokens = tokenizer.tokenize(word) # 拆分后的子词
token_ids = tokenizer.convert_tokens_to_ids(tokens) # 子词对应的ID
print(f"词汇:{word}")
print(f"拆分后的子词:{tokens} | 子词数量:{len(tokens)}")
print(f"子词ID:{token_ids}\n")
# 统计总新增token数(筛选ID≥原词表大小的token)
original_vocab_size = 151651 - 8 # 原词表大小
total_new_tokens = 0
for word in new_words:
token_ids = tokenizer.convert_tokens_to_ids(tokenizer.tokenize(word))
# 新增token的ID一定≥原词表大小
new_token_ids = [tid for tid in token_ids if tid >= original_vocab_size]
total_new_tokens += len(new_token_ids)
print(f"实际新增token总数:{total_new_tokens}") 5.1 “新增词汇数≠新增 token 数” 是正常现象:
5.2 词表扩展的核心是“新增 token”而非“新增词汇”:
5.3 生僻字、专业术语的拆分差异:
词表扩展是解决大模型对中文生僻字、专业术语理解能力不足的关键技术,其核心是 “小增量、轻训练、高精度”,将 OOV 词汇加入原词表并通过增量训练实现词嵌入适配,无需从头预训练,仅通过词表扩容和增量微调,即可让模型适配特定场景的词汇需求。
我们学习了解的过程中要深入理解词表、词嵌入及分词器的核心原理,从简单场景入手,借助以上示例复现完整流程,重点验证分词器拆分结果与增量训练效果。控制词表扩展规模,保证训练语料准确性,逐步细化,找准关键,融合贯通,提升逐步微调的感觉,循序渐进的掌握。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。