小数据集微调BERT MLM模型效果差及子词拆分问题求助
微调BEREL_2.0模型的问题排查与修正
问题1:训练损失过高(6.2156)
核心原因
- 数据量严重不足:你提供的训练样本仅10条左右,却强行设置
train_size=1_000,实际会重复采样数据,导致模型无法学到有效语义,损失居高不下。 - 训练参数配置错误:
metric_for_best_model='f1'不适用MLM任务,MLM的核心评估指标是损失(loss),该设置会导致Trainer无法识别有效指标,无法加载最优模型。- 对于小数据集,
batch_size=64过大,每个批次的样本多样性不足,模型训练不稳定。 - 学习率
2e-5可能过高,小数据微调易破坏预训练模型的已有知识。
修正步骤
调整数据使用策略:
- 去掉
train_test_split中的train_size=1_000,直接使用全部可用训练数据:downsampled_dataset = lm_datasets["train"].train_test_split( test_size=0.1, seed=42 ) - 若数据量仍不足,可做希伯来语文本增强:比如同义词替换、随机插入虚词、句子顺序打乱(需保证语义通顺)。
- 去掉
修正训练参数:
- 将
metric_for_best_model改为'eval_loss',并添加早停回调监控损失:training_args = TrainingArguments( output_dir=f"{model_name}-finetuned-sam-v1", overwrite_output_dir=True, evaluation_strategy=IntervalStrategy.STEPS, eval_steps=50, save_total_limit=5, learning_rate=5e-6, # 降低学习率 weight_decay=0.01, per_device_train_batch_size=8, # 减小batch size per_device_eval_batch_size=8, num_train_epochs=3, # 减少训练轮次 push_to_hub=True, fp16=True, logging_steps=logging_steps, metric_for_best_model='eval_loss', # 改用损失作为最优模型指标 load_best_model_at_end=True ) # 添加早停回调 trainer = Trainer( model=model, args=training_args, train_dataset=downsampled_dataset["train"], eval_dataset=downsampled_dataset["test"], data_collator=data_collator, tokenizer=tokenizer, callbacks=[EarlyStoppingCallback(early_stopping_patience=3)] # 3步无提升则停止 )
- 将
问题2:推理输出出现子词拆分(如##ת、##ה)
核心原因
你的group_texts函数中错误地将训练目标列命名为text,而非MLM任务要求的labels。DataCollatorForLanguageModeling需要labels列来处理掩码后的训练目标,错误的列名导致模型训练时的目标逻辑混乱,最终学会预测子词而非完整词汇。
修正步骤
修改group_texts函数中的目标列命名:
def group_texts(examples): # Concatenate all texts concatenated_examples = {k: sum(examples[k], []) for k in examples.keys()} # Compute length of concatenated texts total_length = len(concatenated_examples[list(examples.keys())[0]]) # We drop the last chunk if it's smaller than chunk_size total_length = (total_length // chunk_size) * chunk_size # Split by chunks of max_len result = { k: [t[i : i + chunk_size] for i in range(0, total_length, chunk_size)] for k, t in concatenated_examples.items() } # 修正:将目标列命名为labels,而非text result["labels"] = result["input_ids"].copy() return result
此外,推理时若仍有子词问题,可手动用tokenizer解码预测的token:
from transformers import AutoTokenizer, AutoModelForMaskedLM import torch tokenizer = AutoTokenizer.from_pretrained("johnlockejrr/BEREL_2.0-finetuned-sam-v1") model = AutoModelForMaskedLM.from_pretrained("johnlockejrr/BEREL_2.0-finetuned-sam-v1") text = "ואלין שמהת בני [MASK] דעלו למצרים עם יעקב גבר וביתה עלו" inputs = tokenizer(text, return_tensors="pt") mask_index = torch.where(inputs["input_ids"] == tokenizer.mask_token_id)[1] with torch.no_grad(): outputs = model(**inputs) logits = outputs.logits top_5_tokens = torch.topk(logits[0, mask_index], 5).indices[0].tolist() for token in top_5_tokens: # 手动解码,自动合并子词 filled_text = text.replace("[MASK]", tokenizer.decode(token)) print(f">>> {filled_text}")
内容的提问来源于stack exchange,提问作者bsteo
相关产品推荐
相关产品推荐

