PyTorch模型无训练效果求助:训练循环疑似存在异常
PyTorch训练模型未学习问题排查
问题现象
训练时损失曲线呈现重复模式,模型未发生有效学习——即使模型结构存在问题,损失也应出现正常波动,因此怀疑训练循环存在问题。
训练循环代码
import time import torch def train(model, train_dl, valid_dl, loss_fn, optimizer, scheduler, acc_fn, epochs=50): start = time.time() model.cuda() train_loss, valid_loss = [], [] train_acc, valid_acc = [], [] best_acc = 0.0 for epoch in range(epochs): print('Epoch {}/{}'.format(epoch, epochs - 1)) print('-' * 10) time_epoch_start = time.time() for phase in ['train', 'valid']: if phase == 'train': model.train() # 切换训练模式 dataloader = train_dl else: model.eval() # 切换评估模式 dataloader = valid_dl running_loss = 0.0 running_acc = 0.0 step = 0 for x, y, _ in dataloader: x = x.cuda() y = y.cuda() step += 1 if phase == 'train': optimizer.zero_grad() outputs = model(x) loss = loss_fn(outputs, y) loss.backward() optimizer.step() else: with torch.no_grad(): outputs = model(x) loss = loss_fn(outputs, y) # 统一训练/验证阶段的y输入类型 acc = acc_fn(outputs, y) # 提取标量值累积,避免张量占用额外内存 running_acc += acc.item() * dataloader.batch_size running_loss += loss.item() * dataloader.batch_size if step % 100 == 0: print('Current step: {} Loss: {:.4f} Acc: {:.4f} AllocMem (Mb): {:.2f}'.format( step, loss.item(), acc.item(), torch.cuda.memory_allocated()/1024/1024)) epoch_loss = running_loss / len(dataloader.dataset) epoch_acc = running_acc / len(dataloader.dataset) if phase == 'train': train_loss.append(epoch_loss) train_loss_print = epoch_loss train_acc.append(epoch_acc) train_acc_print = epoch_acc else: valid_loss.append(epoch_loss) valid_loss_print = epoch_loss valid_acc.append(epoch_acc) valid_acc_print = epoch_acc # 学习率调度器移至每个epoch结束后调用 if scheduler is not None: scheduler.step() time_epoch = time.time() - time_epoch_start print('Epoch {}/{} - TRAIN Loss: {:.4f} TRAIN Acc: {:.4f} - VAL. Loss: {:.4f} VAL. Acc: {:.4f} ({:.4f} seconds - {:.2f} Mb)'.format( epoch, epochs - 1, train_loss_print, train_acc_print, valid_loss_print, valid_acc_print, time_epoch, torch.cuda.memory_allocated()/1024/1024)) time_elapsed = time.time() - start print('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60)) return model, train_loss, valid_loss, train_acc, valid_acc
优化器与学习率调度器定义
opt = torch.optim.Adam(modelo.parameters(), lr=hp_lr, betas=(0.9, 0.999), eps=1e-08, weight_decay=0, amsgrad=False) lr_scheduler = torch.optim.lr_scheduler.StepLR(opt, step_size=10, gamma=0.1) modelo_trained, train_loss, valid_loss, train_acc, valid_acc = train(modelo, train_dl, valid_dl, loss_fn, opt, lr_scheduler, acc_metric, epochs=num_epochs)
核心问题与修复说明
- 学习率调度器调用时机错误:原代码在每个训练batch后调用
scheduler.step(),但StepLR设计为每个epoch更新一次学习率。频繁调用会导致学习率快速衰减至接近0,模型参数无法有效更新。修复后将调度器调用移到每个epoch的训练、验证阶段完成之后。 - 训练/验证阶段loss输入不一致:原验证阶段将
y转为long(),但训练阶段直接使用原始y,若y的 dtype 本身不是long,会导致loss计算逻辑矛盾,干扰模型学习。修复后统一使用原始y输入loss函数(若需统一类型,应在数据加载阶段处理)。 - 张量累积内存问题:原代码直接累积张量到
running_loss和running_acc,会占用额外GPU内存且可能引发计算异常。修复后使用.item()提取标量值进行累积。 - 模式切换规范:将
model.train(True/False)替换为更简洁规范的model.train()和model.eval()。
额外建议:
- 检查
acc_fn实现,确保正确处理模型输出(如分类任务中是否需要对logits取argmax后再计算准确率)。 - 确认
loss_fn的输入要求(如分类任务是否需要标签转为one-hot编码,模型输出是否为logits/概率分布)。
内容的提问来源于stack exchange,提问作者Laura Arakaki
相关产品推荐
相关产品推荐

