NLP核心技术解析:大模型与分词工具的协同工作原理
一、核心关系概述
分词工具(如 Jieba、SentencePiece)与 AI 大模型(如 GPT、BERT)的关系可总结为:
- 分词工具是 AI 大模型的“前处理引擎”,为大模型提供数据预处理支持
- 大模型是任务的“智能大脑”,它利用分词结果可以进行更高级的语言理解和生成任务
二、分词工具的核心作用
- 文本标准化处理
- 中文分词示例:
"深度学习" → ["深度", "学习"] - 解决英文子词问题:
"unhappiness" → ["un", "happiness"]
- 中文分词示例:
- 降低计算复杂度
- 长文本分割为词/子词单元,减少模型计算量
- 跨语言适配
- 针对不同语言特性设计(如中文需分词,英文需处理子词)
三、未登录词(OOV)问题
3.1 问题本质分析
分词工具(如 Jieba)分出的词汇后续由 Tokenizer(如 BERT)转换为词汇表中的索引时,若词汇表中不包含某些词,则会出现 OOV(Out-of-Vocabulary)问题,这会导致:
- 稀有词/专业术语被拆解为
<UNK>(未知标记) - 语义信息丢失(如 “量子计算” →
[UNK]) - 模型性能下降
3.2 解决方案
3.2.1 预对齐词汇表(最优解)
原理:强制分词工具只输出 Tokenizer 词汇表中存在的词汇
1 | |
3.2.2 子词回退策略
原理:利用 Tokenizer 的子词分解能力处理未登录词
1 | |
3.2.3 词汇表扩展(适合专业领域)
步骤:
收集领域专有词汇(如医疗术语)
添加到分词工具用户词典
1
jieba.load_userdict("medical_terms.txt") # 每行格式: `术语 词频 词性`微调 Tokenizer(需重新训练模型)
1
2
3new_tokens = ["COVID-19", "mRNA疫苗"]
tokenizer.add_tokens(new_tokens) # 扩展词汇表
model.resize_token_embeddings(len(tokenizer)) # 调整模型嵌入层
3.3 技术选型建议
| 场景 | 推荐方案 | 优点 | 缺点 |
|---|---|---|---|
| 通用领域 | 子词回退策略 | 无需额外资源 | 可能拆解专业术语 |
| 专业领域(如医疗/法律) | 词汇表扩展+预对齐 | 保持术语完整性 | 需要领域词典和模型微调 |
| 多语言混合文本 | 使用 SentencePiece 分词 | 统一处理多种语言 | 需替换原有分词工具 |
3.4 关键验证方法
覆盖率测试
1
2
3
4
5
6
7
8
9def check_coverage(texts):
vocab = set(tokenizer.get_vocab().keys())
oov_rate = 0
for text in texts:
words = jieba.lcut(text)
oov_rate += sum(1 for w in words if w not in vocab) / len(words)
print(f"OOV率: {oov_rate/len(texts):.2%}")
check_coverage(["量子物理", "临床试验"]) # 示例输出: OOV率: 15.00%可视化调试
1
2
3
4
5from transformers import pipeline
nlp = pipeline("ner", model="bert-base-chinese")
text = "患者有COVID-19症状"
print(nlp(text)) # 检查专业术语是否被正确识别
3.5 总结
通过 词汇表预对齐 + 子词回退 + 领域适配扩展 的组合策略,可确保:
✅ 分词结果 100% 被 Tokenizer 接受
✅ 专业术语完整性保留
✅ 避免 <UNK> 导致的语义损失
最终效果取决于分词工具与 Tokenizer 的协同设计,建议在预处理阶段加入 OOV 检测模块 进行质量监控。
四、分词工具与 Tokenizer 的区别
| 特性 | jieba(传统分词工具) | 大模型 Tokenizer(如 BERT/GPT) |
|---|---|---|
| 设计目标 | 针对特定语言(如中文)的词汇级分割 | 将文本转换为模型可处理的子词/字符级 ID |
| 输出单元 | 词语(如[“深度学习”, “是”, “未来”]) | 子词(如[“深”, “度”, “学习”, “是”, “未”, “来”]) |
| 语言适应性 | 需针对不同语言训练专用模型 | 通过统一算法(如 BPE/WordPiece)支持多语言 |
| 典型应用场景 | 搜索引擎、文本分析等传统 NLP 任务 | 大模型的输入预处理 |
问题:为什么大模型仍需自研 Tokenizer?
- 子词平衡:Tokenizer 通过算法(如 BPE)解决 OOV(未登录词)问题,而
jieba无法动态生成子词。 - 多语言统一:大模型需处理混合语言文本(如中英混杂),
jieba仅支持中文。 - 端到端训练:Tokenizer 的分词方式与模型架构强相关(如 BERT 的 WordPiece 需与预训练一致)。
五、NLP 中的特殊标记
在自然语言处理(NLP)任务中,特殊标记(Special Tokens)用于处理文本输入和输出的特定需求。以下是常见的特殊标记及其作用:
5.1 特殊标记解释
[CLS](Classification Token)- 作用:用于分类任务的特殊标记。
- 位置:通常添加到输入文本的开头。
- 用途:
- 在 BERT 等模型中,
[CLS]标记的最终隐藏状态(即模型输出的对应向量)通常用作整个输入序列的聚合表示,用于分类任务(如情感分析、文本分类)。 - 例如,在句子分类任务中,模型会根据
[CLS]标记的向量输出分类结果。
- 在 BERT 等模型中,
[SEP](Separator Token)- 作用:用于分隔不同句子或文本段的特殊标记。
- 位置:
- 在单句任务中,通常添加到句子末尾。
- 在双句任务(如句子对分类、问答任务)中,用于分隔两个句子。
- 用途:
- 帮助模型区分不同的句子或文本段。
- 例如,在问答任务中,
[SEP]标记用于分隔问题和上下文。
[MASK](Mask Token)- 作用:用于掩码语言模型(Masked Language Model, MLM)任务。
- 位置:替换输入文本中的某些词(通常随机选择)。
- 用途:
- 在 BERT 等模型的预训练过程中,
[MASK]标记用于掩盖部分输入词,模型需要预测被掩盖的词。 - 例如,输入
"I love [MASK] learning.",模型需要预测[MASK]位置的实际词(如"deep")。
- 在 BERT 等模型的预训练过程中,
[PAD](Padding Token)- 作用:用于填充输入序列,使其达到固定长度。
- 位置:添加到输入序列的末尾。
- 用途:
- 在批处理(Batching)过程中,不同序列的长度可能不同,
[PAD]标记用于将短序列填充到相同长度。 - 模型通常会忽略
[PAD]标记的计算(通过注意力掩码实现)。
- 在批处理(Batching)过程中,不同序列的长度可能不同,
[UNK](Unknown Token)- 作用:用于表示词汇表中未包含的词(即未知词)。
- 位置:替换输入文本中的未知词。
- 用途:
- 当输入文本中的词不在模型的词汇表中时,模型会将其替换为
[UNK]标记。 - 例如,如果词汇表中没有
"ChatGPT",输入"I use ChatGPT."可能会被转换为"I use [UNK]."。
- 当输入文本中的词不在模型的词汇表中时,模型会将其替换为
5.2 示例
以下是一个包含特殊标记的输入示例(以 BERT 为例):
1 | |
六、大模型输入的核心组成部分
在自然语言处理(NLP)和大模型(如 BERT、GPT 等)中,input_ids、attention_mask 和 token_type_ids 是模型输入的核心组成部分,用于将原始文本转换为模型可处理的数值化格式。以下是它们的详细解释和实际示例:
6.1 名词解释
input_ids(文本的数值化表示)作用:将分词后的文本(Tokens)转换为模型词汇表中对应的整数 ID。
生成方式:
- 分词器(Tokenizer)先将文本拆分为词/子词(如
"深度学习"→["深", "度", "学", "习"])。 - 然后查询词汇表,将每个 Token 映射为对应的 ID(如
"深"→3918)。
- 分词器(Tokenizer)先将文本拆分为词/子词(如
示例:
1
2
3
4
5from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-chinese")
text = "深度学习很重要"
inputs = tokenizer(text)
print(inputs["input_ids"]) # 输出如:[101, 3918, 2428, 2110, 739, 2523, 7028, 6206, 102]101和102是 BERT 的[CLS]和[SEP]特殊标记的 ID。
attention_mask(注意力掩码)作用:标识哪些 Token 是有效输入,哪些是填充(Padding)部分。
1:真实 Token(模型需处理)。0:填充 Token(模型忽略)。
为什么需要:批量训练时,不同文本长度不同,需填充到相同长度。
示例:
1
print(inputs["attention_mask"]) # 输出如:[1, 1, 1, 1, 1, 1, 1](无填充)如果填充到长度 10:
1
2padded_inputs = tokenizer(text, padding="max_length", max_length=10)
print(padded_inputs["attention_mask"]) # 输出如:[1, 1, 1, 1, 1, 1, 1, 0, 0, 0]
token_type_ids(或segment_ids,句子分段标识):作用:区分输入中的不同句子(如问答任务中的问题和上下文)。
0:第一个句子。1:第二个句子。
适用场景:BERT 等模型处理句子对任务(如文本相似度、问答)。
示例:
1
2
3text_pair = ("深度学习是什么?", "它是AI的一个分支")
inputs = tokenizer(*text_pair)
print(inputs["token_type_ids"]) # 输出如:[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]
6.2 输入示例
1 | |
6.3 关键总结
input_ids:文本的数字身份证,决定模型“看到”什么内容。attention_mask:告诉模型“哪些部分需要关注”,优化计算效率。token_type_ids:为模型标注“句子边界”,解决上下文依赖问题。
这些输入张量共同构成了大模型理解文本的基础,类似于人类阅读时需要的“文字+上下文+注意力焦点”。