paddle复现pytorch踩坑(七):softmax_with_cross_entropy的用法

博客围绕飞桨和PyTorch的交叉熵损失函数展开。介绍了fluid.layers.softmax_with_cross_entropy的作用,复现问题时发现loss为nan,原因是API对应错误。分析了不同API的差异,还进行了问题拓展,对比了不同方法计算loss的结果,最终建议paddle计算使用softmax_with_cross_entropy。

fluid.layers.softmax_with_cross_entropy

  • 作用:OP实现了softmax交叉熵损失函数。该函数会将softmax操作、交叉熵损失函数的计算过程进行合并,从而提供了数值上更稳定的梯度值。
  • 链接:pp飞桨API说明

复现问题

  • 报错:loss为nan
  • 解决:API对应错误
  • pytorch采用:F.cross_entropy
  • 原拟采用:fluid.layers.cross_entropy
  • 更改:fluid.layers.softmax_with_cross_entropy

问题分析

  • F.cross_entropy时,相当于执行以下代码
soft_out = F.softmax(out)
log_soft_out = torch.log(soft_out)
loss = F.nll_loss(log_soft_out, y)
  • paddle API里cross_entropy不包含softmax,故采用softmax_with_cross_entropy
  • 实际复现的代码
# pytorch code
loss_cls = F.cross_entropy(cls[active, :], labels[active], reduction='none', ignore_index=IGN_FLAG)
    
# paddlepaddle code
index_active = fluid.layers.nonzero(active)
loss_cls = fluid.layers.softmax_with_cross_entropy(
                    fluid.layers.gather(cls, index_active), fluid.layers.reshape(fluid.layers.gather(labels, index_active), [-1, 1]), ignore_index=IGN_FLAG)

问题拓展

理论上讲 fluid.layers.softmax_with_cross_entropy 效果应等同于 fluid.layers.softmax + fluid.layers.cross_entropy。实际测试的时候二者loss的计算后取均值结果不一样,且对比pytorch的方法计算结果不同,下面进行对比:

  • F.cross_entropy
    Min = 0.7678133
    Mean = 10.989796
    Max = 320.526

  • fluid.layers.softmax + fluid.layers.cross_entropy
    Min = 0.7678134
    Mean = 9.627525e+17
    Max = 1e+20

  • fluid.layers.softmax_with_cross_entropy
    Min = 0.7678134
    Mean = 9.82002
    Max = 64.6236
    总结:排查了一下,不是其他API计算错误,是三者的差异,实际paddle计算还是应使用softmax_with_cross_entropy。

--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[8], line 23 20 loss_fn = paddle.nn.CrossEntropyLoss() 22 ##模型的训练 ---> 23 train_dataset = paddle.io.TensorDataset(paddle.to_tensor(train_X), paddle.to_tensor(train_y)) 24 train_loader = paddle.io.DataLoader(train_dataset, batch_size=128, shuffle=True) 26 # 训练过程记录 TypeError: TensorDataset.__init__() takes 2 positional arguments but 3 were given##模型设计 class BikeClassifier(paddle.nn.Layer): def __init__(self, input_size): super().__init__() self.fc1 = paddle.nn.Linear(input_size, 128) self.relu1 = paddle.nn.ReLU() self.fc2 = paddle.nn.Linear(128, 64) self.relu2 = paddle.nn.ReLU() self.fc3 = paddle.nn.Linear(64, 3) # 三分类输出 self.softmax = paddle.nn.Softmax() def forward(self, x): x = self.relu1(self.fc1(x)) x = self.relu2(self.fc2(x)) return self.softmax(self.fc3(x)) # 模型初始化 model = BikeClassifier(input_size=X.shape[1]) optimizer = paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters()) loss_fn = paddle.nn.CrossEntropyLoss() ##模型的训练 train_dataset = paddle.io.TensorDataset(paddle.to_tensor(train_X), paddle.to_tensor(train_y)) train_loader = paddle.io.DataLoader(train_dataset, batch_size=128, shuffle=True) # 训练过程记录 train_losses = [] train_accs = [] val_accs = [] for epoch in range(150): model.train() total_loss = 0 correct = 0 for batch_x, batch_y in train_loader: outputs = model(batch_x) loss = loss_fn(outputs, batch_y) loss.backward() optimizer.step() optimizer.clear_grad() total_loss += loss.numpy() correct += (outputs.argmax(1) == batch_y).sum().numpy() # 验证集评估 model.eval() with paddle.no_grad(): val_outputs = model(paddle.to_tensor(test_X)) val_acc = (val_outputs.argmax(1) == paddle.to_tensor(test_y)).numpy().mean() epoch_loss = total_loss / len(train_loader) epoch_acc = correct / len(train_X) train_losses.append(epoch_loss) train_accs.append(epoch_acc) val_accs.append(val_acc)
最新发布
10-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值