NLP 交互中,jieba 和 Transformers(如 Hugging Face 的 transformers 库)分别承担不同层级的任务,常协同使用以构建中文 NLP 流水线:
-
jieba:轻量级、基于规则与统计的中文分词工具,适用于快速、低延迟的预处理,如切词、关键词提取、词性标注(需配合
jieba.posseg)、TF-IDF 特征生成等。其优势在于无需 GPU、模型小、可自定义词典,但不理解语义,无法处理歧义消解或上下文依赖问题。 -
Transformers:提供预训练语言模型(如
bert-base-chinese、RoBERTa-wwm-ext,ChatGLM,Qwen等),支持上下文感知的深度语义理解,适用于文本分类、命名实体识别(NER)、问答、摘要、对话生成等任务。它通常要求将中文文本先分词(tokenize),而中文 Tokenizer(如BertTokenizer)内部已集成 WordPiece 分词逻辑——一般无需、也不推荐先用 jieba 再送入 Transformers 模型,因为:- BERT 类模型的 tokenizer 是端到端训练的,直接输入原始中文字符串即可;
- 强行用 jieba 切词再拼接,可能破坏 subword 对齐,导致 OOV 或掩码异常;
- 例外场景:在构建特定下游任务的特征工程(如将 jieba 分词结果作为附加特征输入多模态模型)、或为小模型(如 TextCNN/LSTM)准备输入时,可结合 jieba 提升词汇粒度控制。
✅ 典型协作流程示例(非端到端模型):
import jieba
from sklearn.feature_extraction.text import TfidfVectorizer
# 1. jieba 分词 + 去停用词
def cut_and_clean(text):
return " ".join([w for w in jieba.cut(text) if w.strip() and w not in stopwords])
corpus = ["我爱自然语言处理技术", "NLP是人工智能的重要分支"]
processed = [cut_and_clean(t) for t in corpus]
# 2. TF-IDF 向量化(供传统模型或轻量级下游使用)
vectorizer = TfidfVectorizer(max_features=1000)
X = vectorizer.fit_transform(processed)
# 3. 若需 Transformer 模型推理(如情感分析):
from transformers import pipeline
classifier = pipeline("sentiment-analysis",
model="uer/roberta-finetuned-jd-binary-chinese",
tokenizer="uer/roberta-finetuned-jd-binary-chinese")
result = classifier("这个手机太卡了") # 直接输入原始字符串,自动 tokenize
⚠️ 注意事项:
- 中文 BERT 的
tokenizer.encode()输入是原始字符串(非 jieba 结果); - 如需细粒度控制(如强制保留专有名词),可用
jieba.load_userdict()+jieba.cut_for_search()辅助构造 prompt 或增强数据; - 在 RAG 或检索阶段,可用 jieba 提升关键词召回率,再用 transformer 重排序(re-rank)。
将 jieba 分词结果与 Hugging Face 的BertTokenizer(如BertTokenizer.from_pretrained("bert-base-chinese"))输出对齐,用于可解释性分析(如 LIME、Integrated Gradients、注意力可视化或 token-level 归因),是一个常见但具挑战性的任务。核心难点在于:jieba 是基于词(word-level)的分词,而 BERT Tokenizer 是 subword-level(WordPiece),二者切分粒度、边界和语义单元不一致。
✅ 可行策略(兼顾准确性与实用性):
1. 前向映射 + 启发式对齐(推荐用于可解释性)
思路:以 BERT tokenizer 的 tokens(subword)为基准,将 jieba 分出的“词”映射到其覆盖的 token indices 区间。
步骤:
- 对原始文本
text,用 jieba 获取词序列jieba_words = list(jieba.cut(text)); - 用
tokenizer.encode(text, add_special_tokens=True)得到 input_ids 和 tokens(含[CLS],[SEP]); - 利用
tokenizer.convert_ids_to_tokens(input_ids)得到 tokens; - 关键:通过 字符级位置回溯 实现对齐:
- tokenizer 提供
tokenize()+convert_tokens_to_string()不可靠,应使用tokenizer.backend_tokenizer(需tokenizers库)的encode()并启用return_offsets_mapping=True(仅限transformers>=4.20且 tokenizer 支持,如BertTokenizerFast):
- tokenizer 提供
from transformers import BertTokenizerFast
tokenizer = BertTokenizerFast.from_pretrained("bert-base-chinese")
text = "南京市长江大桥"
# ✅ 获取每个 subword token 在原文中的字符偏移 (start, end)
encoding = tokenizer(text, return_offsets_mapping=True, truncation=True, padding=False)
tokens = encoding.tokens
offsets = encoding.offset_mapping # e.g., [(0,0), (0,2), (2,4), (4,7), (7,9), (0,0)]
# jieba 分词及起止位置(需手动计算字符偏移)
import jieba
jieba_words = list(jieba.cut(text))
jieba_spans = []
start = 0
for w in jieba_words:
end = start + len(w)
jieba_spans.append((start, end, w))
start = end
# 🌟 对齐:对每个 jieba 词 (s,e,w),找出所有 offsets[i] 满足 s <= offsets[i][0] and offsets[i][1] <= e
word_to_token_indices = {}
for s, e, w in jieba_spans:
aligned_idxs = [
i for i, (ts, te) in enumerate(offsets)
if ts >= s and te <= e and (ts, te) != (0, 0) # 过滤 [CLS]/[SEP]
]
word_to_token_indices[w] = aligned_idxs
print(word_to_token_indices)
# 输出示例:{'南京': [1], '市长': [2], '江大桥': [3, 4]} —— 注意 '江大桥' 被拆为两个 subword
📌 优势:精确到字符偏移,鲁棒性强;支持后续归因到 jieba 词粒度(如聚合 token attribution)。
2. 后处理对齐(无 offset 时的备选)
若 tokenizer 不支持 offset_mapping(如旧版 BertTokenizer),可用启发式方法:
- 先用
tokenizer.tokenize(text)得到 subwords; - 逐个拼接 subwords(用
tokenizer.convert_tokens_to_string([t])或直接字符串连接),并维护累计字符长度; - 与 jieba 词按字符串匹配(注意空格/标点干扰,需清洗);
- ⚠️ 易受全角/半角、空格、标点影响,精度较低,仅作粗略参考。
3. 可解释性应用示例
对齐后,可做:
- 词级显著性聚合:将 Integrated Gradients 对每个 token 的归因分数,按 jieba 词分组求和,生成词重要性热力图;
- 注意力头分析:统计某 jieba 词对应 tokens 在各层注意力中被关注的平均权重;
- LIME 替换实验:以 jieba 词为不可分割单元进行 masking(而非 subword),提升人类可读性。
⚠️ 注意事项:
- BERT 的
[CLS]/[SEP]和特殊符号(如[UNK])需排除; - jieba 未登录词(如新词、英文混排)可能无法完全覆盖 subword 边界,需容忍部分错位;
- 繁体/简体、异体字、拼音缩写等场景需统一预处理(如
opencc转换)。


306

被折叠的 条评论
为什么被折叠?



