You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GPT2模型训练出现Loss Nan问题求助(附实现代码)

GPT2微调问答任务时Loss出现NaN的问题排查

问题概述

我正在做GPT2的微调用于问答任务,因为数据集规模较大,用了Dataloader做批处理,但训练时Loss直接变成NaN。以下是我的批处理创建流程及代码:

class FeedbackEssentials(Dataset):
    def __init__(self, qa_pairs, tokenizer, max_length):
        self.qa_pairs = qa_pairs
        self.tokenizer = tokenizer
        self.max_length = max_length

    def __len__(self):
        return len(self.qa_pairs)

    def __getitem__(self, idx):
        question = self.qa_pairs[idx][0]
        text = f"{question} {self.tokenizer.eos_token}"
        input_ids = self.tokenizer.encode(text, add_special_tokens=True, max_length=self.max_length, padding='max_length', truncation=True)
        attention_mask = [1] * len(input_ids)  # Assuming all tokens should be attended to

        return {
            'input_ids': torch.tensor(input_ids),
            'attention_mask': torch.tensor(attention_mask)
        }


def text_manipulation(train_dataset):
    column1_values = train_dataset['Total Marks'].values
    column2_values = train_dataset['Coding'].values
    listOfLists = [[pair[0], pair[1]] for pair in zip(column1_values, column2_values)]

    text = ""
    for feedback in listOfLists:
        text += f"{feedback[0]} {feedback[1]} {tokenizer.eos_token}"
    return text

training_dataset = text_manipulation(dataset)
max_length_training = max(len(tokenizer.encode(qa_pair[0],add_special_tokens=True)) for qa_pair in training_dataset)
dataset_training = FeedbackEssentials(training_dataset, tokenizer, max_length_training)

数据加载器及优化器设置:

batch_size = 4
dataloader = DataLoader(dataset_training, batch_size=batch_size, shuffle=True)

optimizer = torch.optim.AdamW(model.parameters(), lr=5e-5)
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=1, gamma=0.9)

问题排查及修复方案

1. 数据集构造核心错误

你的text_manipulation函数返回的是拼接后的大字符串,但FeedbackEssentials需要的是QA对列表。这导致后续training_dataset是字符串,遍历它时qa_pair是单个字符,__getitem__里取qa_pairs[idx][0]就是单个字符,完全不符合QA对的格式,输入数据混乱直接导致Loss NaN。

修复text_manipulation,直接返回QA对列表:

def text_manipulation(train_dataset):
    column1_values = train_dataset['Total Marks'].values
    column2_values = train_dataset['Coding'].values
    # 直接返回QA对列表,不要拼接成字符串
    return [[pair[0], pair[1]] for pair in zip(column1_values, column2_values)]

2. Max Length计算错误

之前因为training_dataset是字符串,计算max_length_training时遍历的是单个字符,得到的max_length是1,导致所有输入被截断成1个token,模型根本无法学习。修复后重新计算:

training_dataset = text_manipulation(dataset)
# 计算每个QA对(问题+答案)的最大token长度
max_length_training = max(
    len(tokenizer.encode(f"{qa[0]} {qa[1]}", add_special_tokens=True)) 
    for qa in training_dataset
)
dataset_training = FeedbackEssentials(training_dataset, tokenizer, max_length_training)

3. 缺少训练所需的Labels

GPT2是自回归语言模型,训练时需要labels(和input_ids对应,模型会自动处理移位逻辑)。当前代码没有返回labels,模型计算loss时会出错。修改__getitem__:

def __getitem__(self, idx):
    question, answer = self.qa_pairs[idx]
    # 拼接问题+答案,作为模型的输入和目标
    text = f"{question} {answer} {self.tokenizer.eos_token}"
    encoding = self.tokenizer(
        text,
        max_length=self.max_length,
        padding='max_length',
        truncation=True,
        return_tensors='pt'
    )
    input_ids = encoding['input_ids'].squeeze()
    attention_mask = encoding['attention_mask'].squeeze()
    # labels和input_ids一致,将padding位置设为-100,计算loss时会忽略这些位置
    labels = input_ids.clone()
    labels[attention_mask == 0] = -100

    return {
        'input_ids': input_ids,
        'attention_mask': attention_mask,
        'labels': labels
    }

4. Attention Mask错误

之前的attention_mask把padding部分也设为1,这会让模型关注无效的padding token,导致计算异常。现在直接使用tokenizer返回的attention_mask即可,它会自动把padding位置设为0。

5. 其他辅助修复点

  • 梯度裁剪:训练时添加梯度裁剪,防止梯度爆炸导致NaN:
    torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
    
  • 降低学习率:当前5e-5可能过高,尝试降到1e-5
  • 检查数据:确认Total Marks和Coding列有没有异常值(比如空值、非文本内容)

内容的提问来源于stack exchange,提问作者Irfan Yaqub

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 16:57:36