在Transformers中微调mBART-50学习新单词失败,求原因及解决办法
问题描述
尝试在Python的Transformers库中微调mBART-50(对应论文为mBART: Multilingual Denoising Pre-training for Neural Machine Translation,Hugging Face预训练模型为facebook/mbart-large-50),让模型学习将自定义法语单词billozarion翻译为英语单词plorization。代码大部分参考Hugging Face官方文档编写,但模型未学会该映射,测试输出仍为billozarion而非预期的plorization。运行环境为Ubuntu 20.04.5 LTS,搭配NVIDIA A100/T4 GPU及CUDA 12.0,conda环境配置为Python 3.9,安装transformers==4.28.1、chardet==5.1.0、sentencepiece==0.1.99、protobuf==3.20。
失败原因分析
- 仅执行前向传播,无参数更新:原代码仅调用
model(**model_inputs, labels=labels)完成前向传播,但未计算损失、执行反向传播或更新模型参数,模型权重完全没有变化,自然无法学习新映射。 - 分词器不统一:训练阶段使用
facebook/mbart-large-50的分词器,测试阶段却切换为facebook/mbart-large-50-many-to-many-mmt的分词器,两者的token映射规则可能存在差异,导致输入输出的token不匹配。 - 输入文本冗余空格:
src_text和tgt_text前后带有空格,会被分词器识别为额外的token干扰学习,导致模型无法聚焦目标单词的映射关系。 - 缺少训练核心组件:未配置优化器、学习率等训练必备组件,也没有梯度清零操作,无法完成参数更新的闭环。
解决办法
以下是修正后的完整代码,包含梯度更新流程、统一分词器、清理输入等关键调整:
from transformers import MBartForConditionalGeneration, MBart50TokenizerFast, AdamW # 加载模型和统一分词器 print('Model loading started') model = MBartForConditionalGeneration.from_pretrained("facebook/mbart-large-50") tokenizer = MBart50TokenizerFast.from_pretrained("facebook/mbart-large-50", src_lang="fr_XX", tgt_lang="en_XX") print('Model loading done') # 清理输入文本,去除冗余空格 src_text = "billozarion" tgt_text = "plorization" # 处理输入和标签 model_inputs = tokenizer(src_text, return_tensors="pt") with tokenizer.as_target_tokenizer(): labels = tokenizer(tgt_text, return_tensors="pt").input_ids # 配置优化器 optimizer = AdamW(model.parameters(), lr=5e-5) print('Fine-tuning started') # 调整训练轮次,单样本无需1000轮 for i in range(50): # 梯度清零 optimizer.zero_grad() # 前向传播并获取损失 outputs = model(**model_inputs, labels=labels) loss = outputs.loss # 反向传播 loss.backward() # 更新参数 optimizer.step() # 打印训练进度 if (i+1) % 10 == 0: print(f"Step {i+1}, Loss: {loss.item():.4f}") print('Fine-tuning ended') # 测试模型,使用同一个分词器 tokenizer.src_lang = "fr_XX" article_fr = src_text encoded_fr = tokenizer(article_fr, return_tensors="pt") generated_tokens = model.generate(**encoded_fr, forced_bos_token_id=tokenizer.lang_code_to_id["en_XX"]) translation = tokenizer.batch_decode(generated_tokens, skip_special_tokens=True) print("Translation result:", translation)
关键调整说明:
- 添加训练闭环:引入
AdamW优化器,每次训练步骤先清零梯度,再计算损失、执行反向传播,最后更新模型参数,完成完整的参数更新流程。 - 统一分词器:训练和测试阶段使用同一个
facebook/mbart-large-50分词器,避免token映射不一致问题。 - 清理输入文本:去除输入单词前后的空格,确保分词器仅处理目标单词本身。
- 调整训练轮次:单样本训练无需1000轮,50轮左右即可让模型学会简单映射,避免不必要的计算开销。
内容的提问来源于stack exchange,提问作者Franck Dernoncourt
相关产品推荐
相关产品推荐

