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

PyTorch复现Keras路透社多分类模型效果差异排查

路透社多分类任务PyTorch复现与Keras结果差异问题

我正在学习《Deep Learning with Python (Keras)》一书,为加深理解将书中示例改写为PyTorch代码,多数示例效果与Keras版本相当,但在第106页的路透社多分类任务中遇到问题。

书中Keras代码

keras_model = keras.Sequential([
    layers.Dense(64,activation='relu'),
    layers.Dense(64,activation='relu'),
    layers.Dense(46,activation='softmax'),
])

keras_model.compile(
    optimizer = 'rmsprop',
    loss = 'sparse_categorical_crossentropy',
    metrics = ['accuracy']
)

hist = keras_model.fit(
    partial_train_xs,
    partial_train_ys,
    epochs=20,
    batch_size=512,
    validation_data=[val_xs,val_ys]
)

我尝试复现的PyTorch代码

model = nn.Sequential(
          nn.Linear(10_000,64),
          nn.ReLU(),
          nn.Linear(64,64),
          nn.ReLU(),
          nn.Linear(64,46),
          nn.Softmax()
        )

def compute_val_loss(model,xs,ys):
    preds = model(xs)
    return(F.cross_entropy(preds,ys)).item()

def compute_accuracy(model,xs,ys):
    preds = model(xs)
    acc = (preds.argmax(dim=1) == ys).sum() / len(preds)
    return acc.item()

def train_loop(model,xs,ys,epochs=20,lr=1e-3,opt=torch.optim.RMSprop,
               batch_size=512,loss_func=F.cross_entropy):
    opt = opt(model.parameters(),lr=lr)
    losses = []
    for i in range(epochs):
        epoch_loss = []
        for b in range(0,len(xs),batch_size):
            xbatch = xs[b:b+batch_size]
            ybatch = ys[b:b+batch_size]            
            logits = model(xbatch)
            loss = loss_func(logits,ybatch)
            model.zero_grad()
            loss.backward()
            opt.step()
            epoch_loss.append(loss.item())
        losses.append([i,sum(epoch_loss)/len(epoch_loss)])
        print(loss.item())
    return losses

数据采用multihot编码处理词序列,例如词汇表为10k时,输入是10k维向量,出现单词对应索引位为1。

问题描述

PyTorch版本与Keras版本结果差异显著:

  • Keras版本20轮后训练损失极低,验证准确率约80%;
  • PyTorch版本训练损失从3.4缓慢降至3.1,Keras训练1轮后的损失(2.6)就已低于该值;
  • PyTorch准确率虽有提升但始终落后,且呈阶梯状(如图),即使训练150轮,验证准确率峰值仅约75%。

调整RMSProp参数无明显改善,请问是代码有误还是合理差异?

Torch训练/验证准确率


问题根源与修正方案

你的PyTorch代码存在两处关键错误,直接导致训练效率和效果远低于Keras版本:

1. Softmax层与CrossEntropyLoss的冲突

PyTorch的F.cross_entropy内置了LogSoftmax和NLLLoss的计算逻辑,但你在模型最后额外添加了nn.Softmax()层,会引发两个问题:

  • 数值稳定性问题:Softmax输出的概率值接近0或1时,取对数会出现梯度消失;
  • 损失计算逻辑错误:相当于对已经经过Softmax的结果再做一次LogSoftmax,完全偏离正确的损失计算路径。

修正:移除模型中的nn.Softmax()层,让最后一层Linear直接输出logits即可。

2. 优化器参数与训练流程未对齐Keras

  • Keras的RMSprop默认动量为0,而PyTorch的torch.optim.RMSprop默认动量为0.9,这会明显影响收敛速度,需手动设置momentum=0对齐;
  • 原训练循环未在每轮结束后计算验证集指标,无法监控泛化能力,也无法和Keras的训练日志对比;
  • 评估时未切换模型到eval()模式,也未关闭梯度计算,会浪费计算资源并可能影响结果。

修正后的PyTorch代码示例

import torch
import torch.nn as nn
import torch.nn.functional as F

# 移除Softmax层,直接输出logits
model = nn.Sequential(
    nn.Linear(10_000, 64),
    nn.ReLU(),
    nn.Linear(64, 64),
    nn.ReLU(),
    nn.Linear(64, 46)
)

def compute_val_loss(model, xs, ys):
    model.eval()  # 切换到评估模式
    with torch.no_grad():  # 关闭梯度计算,节省资源
        preds = model(xs)
        loss = F.cross_entropy(preds, ys).item()
    model.train()  # 切回训练模式
    return loss

def compute_accuracy(model, xs, ys):
    model.eval()
    with torch.no_grad():
        preds = model(xs)
        acc = (preds.argmax(dim=1) == ys).sum() / len(preds)
    model.train()
    return acc.item()

def train_loop(model, train_xs, train_ys, val_xs, val_ys, epochs=20, lr=1e-3, opt=torch.optim.RMSprop,
               batch_size=512, loss_func=F.cross_entropy):
    # 对齐Keras的RMSprop参数:momentum=0
    opt = opt(model.parameters(), lr=lr, momentum=0)
    train_losses = []
    val_losses = []
    val_accs = []
    
    for i in range(epochs):
        epoch_loss = []
        model.train()
        for b in range(0, len(train_xs), batch_size):
            xbatch = train_xs[b:b+batch_size]
            ybatch = train_ys[b:b+batch_size]            
            logits = model(xbatch)
            loss = loss_func(logits, ybatch)
            
            opt.zero_grad()  # 用优化器清梯度更规范
            loss.backward()
            opt.step()
            
            epoch_loss.append(loss.item())
        
        # 计算并记录本轮训练/验证指标
        avg_train_loss = sum(epoch_loss)/len(epoch_loss)
        train_losses.append(avg_train_loss)
        
        avg_val_loss = compute_val_loss(model, val_xs, val_ys)
        val_acc = compute_accuracy(model, val_xs, val_ys)
        val_losses.append(avg_val_loss)
        val_accs.append(val_acc)
        
        print(f"Epoch {i+1}: Train Loss = {avg_train_loss:.4f}, Val Loss = {avg_val_loss:.4f}, Val Acc = {val_acc:.4f}")
    
    return train_losses, val_losses, val_accs

额外建议

  • 确保输入数据类型对齐:Keras默认用float32,PyTorch需保证张量为torch.float32,若用GPU则模型和数据需同步移至GPU;
  • 权重初始化:Keras和PyTorch的全连接层默认初始化逻辑一致(Xavier/Glorot初始化),若需完全匹配可手动指定初始化方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 06:35:40