如何阻止Tokenizer进一步拆分单词?及合并带##子词的高效方法
问题描述
使用Hugging Face Transformers的AutoTokenizer调用obi/deid_bert_i2b2模型分词时,即使设置do_basic_tokenize=False,部分单词仍会被拆分。执行代码如下:
from transformers import AutoTokenizer text = "Patient John Doe visited the hospital on 01/05/2023 with complaints of chest pain." tokenizer = AutoTokenizer.from_pretrained("obi/deid_bert_i2b2", tokenizer_args={"do_basic_tokenize": False}) tokens = tokenizer.tokenize(text, truncation=True, padding=True, return_tensors="pt") model = AutoModelForTokenClassification.from_pretrained("obi/deid_bert_i2b2") tokens
得到的分词结果:
['Pat', '##ient', 'John', 'Do', '##e', 'visited', 'the', 'hospital', 'on', '01', '/', '05', '/', '202', '##3', 'with', 'complaints', 'of', 'chest', 'pain', '.']
疑问:
- 这种拆分是模型的固有特性吗?
- 能否通过配置阻止单词被拆分?
- 是否存在高效的方法或工具可将带
##的子词与前后词合并?
解决方案与解释
1. 拆分是模型的固有特性吗?
是的,这种拆分是BERT类模型基于WordPiece分词算法的固有特性。obi/deid_bert_i2b2属于BERT衍生模型,预训练阶段就用WordPiece分词构建词汇表,若词汇表中未收录Patient、Doe这类完整单词,分词时就会自动拆分为子词。
do_basic_tokenize=False仅关闭了基础分词(比如空格切分、标点分离这类初步处理),但不会跳过WordPiece的子词拆分逻辑——这是BERT类分词器的核心步骤,和基础分词是独立的两个阶段。
2. 能否通过配置阻止单词被拆分?
很难完全阻止,因为WordPiece的拆分逻辑和模型预训练用的词汇表强绑定:如果单词不在词汇表中,就一定会被拆分为子词。不过可以尝试两种方式:
- 添加自定义词汇到分词器:把需要保留完整的单词(比如
Patient、Doe)添加到分词器的词汇表中,再调整模型的词嵌入层。但这种方式可能影响模型推理效果,因为模型预训练时未见过这些完整单词的嵌入。
示例代码:tokenizer.add_tokens(["Patient", "Doe"]) model.resize_token_embeddings(len(tokenizer)) - 更换非子词类分词器:换用基于空格分词的模型(如部分规则分词器),但这意味着无法继续使用
obi/deid_bert_i2b2。
3. 高效合并带##的子词
有两种高效方式:
手动遍历合并
直接遍历分词结果,手动拼接子词,逻辑清晰且无额外依赖:
def merge_subwords(tokens): merged = [] current_word = "" for token in tokens: if token.startswith("##"): current_word += token[2:] else: if current_word: merged.append(current_word) current_word = "" merged.append(token) if current_word: merged.append(current_word) return merged # 调用示例 merged_tokens = merge_subwords(tokens) # 输出:['Patient', 'John', 'Doe', 'visited', 'the', 'hospital', 'on', '01', '/', '05', '/', '2023', 'with', 'complaints', 'of', 'chest', 'pain', '.']
使用Tokenizer内置方法
Hugging Face的Tokenizer自带convert_tokens_to_string方法,可自动处理子词合并:
merged_text = tokenizer.convert_tokens_to_string(tokens) # 输出:"Patient John Doe visited the hospital on 01 / 05 / 2023 with complaints of chest pain."
该方法会自动合并##子词,但会给标点、符号添加空格,若需要严格还原原始格式,可在合并后做微调处理。
内容的提问来源于stack exchange,提问作者learner
相关产品推荐
相关产品推荐

