如何让预训练MarianMT模型不翻译或保留指定特殊字符?
解决MarianMT保留特殊标记的问题
核心问题说明
预训练MarianMT模型默认不会识别自定义特殊标记(比如<P>),add_special_tokens参数仅对模型原生定义的特殊token(如<pad>、<unk>)生效,对这类自定义标记完全不起作用,所以才会出现标记被翻译或删除的情况。要实现保留标记,得从输入预处理、tokenizer配置、生成约束这几个环节入手。
具体解决方案
1. 标记替换还原法(无需修改模型)
这是最直接的方案,先把特殊标记替换成模型不会翻译的占位符,翻译完成后再还原回去:
from transformers import MarianMTModel, MarianTokenizer # 加载示例模型与tokenizer model_name = "Helsinki-NLP/opus-mt-en-es" tokenizer = MarianTokenizer.from_pretrained(model_name) model = MarianMTModel.from_pretrained(model_name) # 定义自定义标记与占位符的映射 special_tag_map = {"<P>": "[FIXED_TAG_P]"} def preprocess_input(text): for tag, placeholder in special_tag_map.items(): text = text.replace(tag, placeholder) return text def postprocess_output(text): for tag, placeholder in special_tag_map.items(): text = text.replace(placeholder, tag) return text # 测试流程 input_text = "Hello <P> this is a test" processed_text = preprocess_input(input_text) inputs = tokenizer(processed_text, return_tensors="pt") outputs = model.generate(**inputs) translated_raw = tokenizer.decode(outputs[0], skip_special_tokens=True) final_result = postprocess_output(translated_raw) print(final_result)
2. 扩展Tokenizer词汇表(需适配模型)
把自定义标记加入tokenizer的词汇表,让模型将其视为独立token,避免被拆分或翻译:
# 将自定义标记添加到tokenizer tokenizer.add_tokens(list(special_tag_map.keys())) # 调整模型嵌入层尺寸以适配新词汇 model.resize_token_embeddings(len(tokenizer)) # 直接输入带特殊标记的文本推理 input_text = "Hello <P> this is a test" inputs = tokenizer(input_text, return_tensors="pt") outputs = model.generate(**inputs) translated_text = tokenizer.decode(outputs[0], skip_special_tokens=False) print(translated_text)
如果模型仍尝试翻译这些标记,建议用包含这类标记的平行语料做少量微调,强化模型对标记的认知,让它明白这些标记不需要翻译。
3. 生成时强制约束标记保留
通过prefix_allowed_tokens_fn函数约束模型生成逻辑,确保特殊标记完整保留:
def restrict_token_generation(batch_id, input_ids): current_text = tokenizer.decode(input_ids, skip_special_tokens=True) # 检查是否有未完成的特殊标记,强制生成剩余部分 for tag in special_tag_map.keys(): if tag[:-1] in current_text and not current_text.endswith(tag): remaining_part = tag[current_text.rfind(tag[:-1])+len(tag[:-1]):] allowed_token_ids = tokenizer.encode(remaining_part, add_special_tokens=False) return allowed_token_ids return None # 应用约束生成结果 outputs = model.generate(**inputs, prefix_allowed_tokens_fn=restrict_token_generation) translated_text = tokenizer.decode(outputs[0], skip_special_tokens=False) print(translated_text)
方案优先级建议
优先用标记替换还原法,无需修改模型结构,适配所有预训练MarianMT模型;如果要求必须保留原始标记格式,再尝试词汇表扩展+微调的方案;生成约束法可作为补充,用于特殊场景下的标记保护。
内容的提问来源于stack exchange,提问作者Maximiliano Ramirez
相关产品推荐
相关产品推荐

