使用Huggingface Trainer微调GPT-J失败:模型未返回Loss求助
GPT-J微调报错:模型未返回loss的解决方法
问题背景
尝试用Huggingface Trainer微调GPT-J 6B模型时失败,报错提示模型未返回loss。参考BERT微调示例,但GPT-J作为因果语言模型和BERT有本质区别。使用Transformers 4.22.2版本,CPU和Paperspace GPU环境均出现相同错误,怀疑是从BERT示例照搬的配置(如compute_metrics、标签设置)存在问题,不清楚如何让模型生成loss并调整Trainer配置。
报错信息
File "xxx\ft_v3.py", line 66, in <module> File "xxx\venv\lib\site-packages\transformers\trainer.py", line 1521, in train return inner_training_loop( File "xxx\venv\lib\site-packages\transformers\trainer.py", line 1763, in _inner_training_loop tr_loss_step = self.training_step(model, inputs) File "xxx\venv\lib\site-packages\transformers\trainer.py", line 2499, in training_step loss = self.compute_loss(model, inputs) File "xxx\venv\lib\site-packages\transformers\trainer.py", line 2544, in compute_loss raise ValueError( ValueError: The model did not return a loss from the inputs, only the following keys: logits,past_key_values. For reference, the inputs it received are input_ids,attention_mask.
报错原因
- 因果语言模型的训练逻辑差异:GPT-J是自回归模型,需要将
input_ids作为标签传入模型才会自动计算交叉熵损失,原代码未添加标签列,导致模型无法生成loss。 - 错误的
label_names配置:原代码将input_ids和attention_mask设为标签,Trainer无法识别正确的标签字段。 - 不必要的评估函数干扰:训练阶段直接照搬BERT的
compute_metrics函数,因果语言模型的评估逻辑与BERT不同,且训练阶段无需该函数。
修正步骤
- 添加标签列:在tokenize时将
input_ids复制为labels,并将padding对应的标签设为-100(模型会忽略-100的标签,避免计算padding的损失)。 - 修正
label_names:将标签字段设为labels,删除错误的配置。 - 移除训练阶段的评估函数:先跑通训练流程,评估逻辑后续再补充。
完整修正代码
from transformers import Trainer, TrainingArguments, GPTJForCausalLM, AutoTokenizer from datasets import load_dataset import time import torch start = time.time() GPTJ_FINE_TUNED_FILE = "./fine_tuned_models/gpt-j-6B" print("Loading model") model = GPTJForCausalLM.from_pretrained("EleutherAI/gpt-j-6B", low_cpu_mem_usage=True) model.config.pad_token_id = model.config.eos_token_id print("Loading tokenizer") tokenizer = AutoTokenizer.from_pretrained("EleutherAI/gpt-j-6B") tokenizer.pad_token = tokenizer.eos_token print("Loading dataset") current_dataset = load_dataset("wikitext", 'wikitext-103-v1') current_dataset['train'] = current_dataset['train'].select(range(1200)) def tokenize_function(examples): # 处理文本,添加padding和截断 tokenized = tokenizer(examples["text"], padding="max_length", truncation=True, max_length=512) # 生成labels,将padding对应的token设为-100,避免计算损失 tokenized["labels"] = [ [-100 if token == tokenizer.pad_token_id else token for token in seq] for seq in tokenized["input_ids"] ] return tokenized print("Splitting and tokenizing dataset") tokenized_datasets = current_dataset.map(tokenize_function, batched=True) # 过滤空文本样本(可选) tokenized_datasets = tokenized_datasets.filter(lambda x: len(x["input_ids"]) > 0) small_train_dataset = tokenized_datasets["train"].select(range(100)) print("Preparing training arguments") training_args = TrainingArguments( output_dir=GPTJ_FINE_TUNED_FILE, report_to='all', logging_dir='./logs', per_device_train_batch_size=1, num_train_epochs=1, no_cuda=True, label_names=['labels'] # 明确标签字段为labels ) trainer = Trainer( model=model, args=training_args, train_dataset=small_train_dataset ) print("Starting training") trainer.train() print(f"Finished fine-tuning in {time.time() - start}")
补充说明
- GPU环境适配:去掉
no_cuda=True即可自动加载到CUDA设备,注意调整per_device_train_batch_size避免显存溢出,GPT-J 6B在单GPU上可配合梯度累积或8-bit量化(如bitsandbytes库)使用。 - 评估阶段补充:若需评估,需修改
compute_metrics函数,先过滤掉labels中的-100值,再计算准确率等指标。
内容的提问来源于stack exchange,提问作者Erik Hyrkas
相关产品推荐
相关产品推荐

