问题记录7:Pytorch训练网络模型过程中Loss为负值的问题及其解决方案

1. 问题描述

在复现论文的过程中,遇到了训练模型Loss一直为负的情况。

程序主要通过深度学习实现一个分类任务。编程与debug过程全部在windows10系统,Pycharm2018v1.4的IDE下完成,主要框架为pytorch 1.2.0。复现过程中采用了交叉熵损失函数计算Loss。训练过程中输出信息如下:

输出部分的代码段:

    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        output = model(data)
        loss = F.nll_loss(output, target.squeeze())
        loss.backward()
        optimizer.step()
        if batch_idx % log_interval == 0:
            print("Train Epoch: {} [{}/{} ({:0f}%)]\tLoss:{:.6f}".format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                100.*batch_idx/len(train_loader), loss.item()
            ))
            print("output:", output)

2. 解决过程与方案

在检查确认训练代码无误之后,通过查找资料和逐步排查,寻找到了两个出错原因。

针对交叉熵损失函数:

Loss = -[ylog\hat{y}+(1-y)log(1-\hat{y})))]

一般情况下,分类任务的输出y采用One-hot Encoding,即每个值非0即1,对应公式中的y或(1-y)一定是1,而log\hat{y}一定要是负值才能保证Loss大于零。所以初步判断实验数据和模型输出是错误的根源。

原因一  输入数据未归一化

数据没有归一化会造成取对数的过程中数据跨度超过了[0,1]这个范围,那么自然会造成log\hat{y}为正,从而Loss小于零。解决办法就是对数据进行归一化。于是构造了一个归一化函数,从而解决问题。代码如下

def data_in_one(inputdata):
    min = np.nanmin(inputdata)
    max = np.nanmax(inputdata)
    outputdata = (inputdata-min)/(max-min)
    return outputdata

原因二 torch.nn.functional.nll_loss()使用条件不满足

执行方案一,并不能解决我的问题。于是开始寻找交叉熵函数本身的问题,于是查询了torch.nn.functional.nll_loss()函数上。不同于nn.CrossEntropyLoss(),nn.functional.nll_loss()并没有对预测数据\hat{y}进行对数运算,这样一来,就需要再网络模型的输出中补充上对数运算。

我的原本网络输出层是:

self.softmax = nn.Softmax(dim=1)

改为:

self.softmax = nn.LogSoftmax(dim=1)

即可解决问题。或者将nn.functional.nll_loss()换成模型中的nn.CrossEntropyLoss(),不过这样需要修改的代码较多,我采用了前者作为解决方案,解决了问题。

3. 总结

针对解决方案一,我认为应该是主要针对回归问题而言的,因为回归问题中的模型输出具有很大的不确定性,需要归一化处理。而分类问题中,大多数输出都是转化成独热码形式,按理说不应该出现范围溢出的情况。

所以遇到此类问题,回归任务主要检查方案一中的问题;分类问题主要检查方案二中的问题,基本就能解决。

  • 28
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
PyTorch训练模型时,可以使用TensorBoard或Matplotlib来绘制损失曲线和准确率曲线。 ## 使用TensorBoard绘制曲线 TensorBoard是一个用于可视化机器学习实验结果的工具,可以用来展示训练过程的损失曲线和准确率曲线。以下是一个简单的示例代码,展示如何在PyTorch使用TensorBoard来记录和可视化训练过程的损失和准确率: ```python from torch.utils.tensorboard import SummaryWriter # 创建一个SummaryWriter对象,参数log_dir指定TensorBoard日志的存储路径 writer = SummaryWriter(log_dir='logs') for epoch in range(num_epochs): # ... # 记录训练损失和准确率 writer.add_scalar('Train/Loss', train_loss, global_step=epoch) writer.add_scalar('Train/Accuracy', train_acc, global_step=epoch) # 记录验证损失和准确率 writer.add_scalar('Val/Loss', val_loss, global_step=epoch) writer.add_scalar('Val/Accuracy', val_acc, global_step=epoch) # 关闭SummaryWriter对象 writer.close() ``` 在上面的示例代码,首先需要创建一个`SummaryWriter`对象,并指定TensorBoard日志的存储路径。然后在每个epoch结束时,使用`add_scalar`方法记录训练损失、训练准确率、验证损失和验证准确率。最后,在训练过程结束时,需要调用`close`方法关闭`SummaryWriter`对象。 ## 使用Matplotlib绘制曲线 除了使用TensorBoard,还可以使用Matplotlib来绘制损失曲线和准确率曲线。以下是一个简单的示例代码,展示如何在PyTorch使用Matplotlib来绘制损失曲线和准确率曲线: ```python import matplotlib.pyplot as plt train_losses = [] train_accs = [] val_losses = [] val_accs = [] for epoch in range(num_epochs): # ... # 记录训练损失和准确率 train_losses.append(train_loss) train_accs.append(train_acc) # 记录验证损失和准确率 val_losses.append(val_loss) val_accs.append(val_acc) # 绘制训练和验证损失曲线 plt.plot(train_losses, label='Train Loss') plt.plot(val_losses, label='Val Loss') plt.legend() plt.xlabel('Epoch') plt.ylabel('Loss') plt.show() # 绘制训练和验证准确率曲线 plt.plot(train_accs, label='Train Acc') plt.plot(val_accs, label='Val Acc') plt.legend() plt.xlabel('Epoch') plt.ylabel('Accuracy') plt.show() ``` 在上面的示例代码,首先定义了四个空列表来存储训练和验证过程的损失和准确率。在每个epoch结束时,将训练和验证的损失和准确率记录到对应的列表。最后,使用Matplotlib库绘制训练和验证损失曲线、训练和验证准确率曲线。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值