训练模型中损失(loss)异常分析

本文深入探讨模型训练中异常Loss值的原因与对策,包括数据预处理、学习率设置、除零错误、loss函数误用及代码陷阱,为Pytorch模型训练提供实用指南。
部署运行你感兴趣的模型镜像

前言

训练模型过程中随时都要注意目标函数值(loss)的大小变化。一个正常的模型loss应该随训练轮数(epoch)的增加而缓慢下降,然后趋于稳定。虽然在模型训练的初始阶段,loss有可能会出现大幅度震荡变化,但是只要数据量充分,模型正确,训练的轮数足够长,模型最终会达到收敛状态,接近最优值或者找到了某个局部最优值。在模型实际训练过程中,可能会得到一些异常loss值,如loss等于nan;loss值忽大忽小,不收敛等。下面根据自己使用Pythorh训练模型的经验,分析出一些具体原因和给出对应的解决办法。

一、输入数据

1. 数据的预处理

输入到模型的数据一般都是经过了预处理的,如用pandas先进行数据处理,尤其要注意空值,缺失值,异常值。

  • 缺失值:数值类型(NaN),对象类型(None, NaN),时间类型(NaT)
  • 空值:""
  • 异常值:不再正常区间范围的值

例如对缺失值可以进行判断df.isnull()或者df.isna();丢弃df.dropna();填充df.fillna()等操作。

输入到模型中的数据一般而言都是数值类型的值,一定要保证不能出现NaN, numpy中的nan是一种特殊的float,该值数值运算的结果是不正常的,所以可能会导致loss值等于nan。可以用numpy.any(numpy.isnan(x))检查一下input和target。

2. 数据的读写

例如使用Pandas读取.csv类型的数据得到的DataFrame会添加默认的index,再写回到磁盘会多一列。如果用其他读取方式再读入,可能会导致数据有问题,读取到NaN。

import pandas as pd

Output = pd.read_csv('./data/diabetes/Output.csv')
trainOutput, testOutput = Output[:6000], Output[6000:]
trainOutput.to_csv('./data/diabetes/trainOutput.csv')
testOutput.to_csv('./data/diabetes/testOutput.csv')

OutputData VS trainOutputData
OutputData VS trainOutputData

3. 数据的格式

Pythorch中的 torch.utils.data.Dataset 类是一个表示数据集的抽象类。自己数据集的类应该继承自 Dataset 并且重写__len__方法和__getitem__方法:

  • __len__ : len(dataset) 返回数据集的大小
  • __getitem__ :用以支持索引操作, dataset[idx]能够返回第idx个样本数据

然后使用torch.utils.data.DataLoader 这个迭代器(iterator)来遍历所有的特征。具体可以参见这里

在构造自己Dataset类时,需要注意返回的数据格式和类型,一般不会出现NaN的情况但是可能会导致数据float, int, long这几种类型的不兼容,注意转换。

二、学习率

基于梯度下降的优化方法,当学习率太高时会导致loss值不收敛,太低则下降缓慢。需要对学习率等超参数进行调参如使用网格搜索,随机搜索等。

三、除零错

对于回归问题,可能出现了除0 的计算,加一个很小的余项可能可以解决。类似于计算概率时进行的平滑修正,下面的代码片段中loss使用交叉混合熵(CossEntropy),计算3分类问题的AUC值,为了避免概率计算出现NaN而采取了相应的平滑处理。

from sklearn.metrics import roc_auc_score

model_ft, y_true, losslists = test_model(model_ft, criterion, optimizer)
n_class = 3
y_one_hot = np.eye(n_class)[y_true.reshape(-1)]
# solve divide zero errot
eps = 0.0000001
y_scores = losslists / (losslists.sum(axis=1, keepdims=True)+eps)
#print(y_scores)
#print(np.isnan(y_scores))
"""
metrics.roc_auc_score(y_one_hot, y_pred)
"""
print("auc: ")
roc_auc_score(y_one_hot, y_scores)

四、loss函数

loss函数代码编写不正确或者已经编写好的loss函数API使用不清楚

五、某些易错代码

Pytorch在进行自动微分的时候,默认梯度是会累加的,所以需要在每个epoch的每个batch中对梯度清零,否则可能会导致loss值不收敛。不要忘记添加如下代码

 optimizer.zero_grad()

 

 

您可能感兴趣的与本文相关的镜像

GPT-oss:20b

GPT-oss:20b

图文对话
Gpt-oss

GPT OSS 是OpenAI 推出的重量级开放模型,面向强推理、智能体任务以及多样化开发场景

### 关于模型训练Loss函数的定义、计算与优化 #### Loss函数的定义 在机器学习和深度学习领域,Loss函数被广泛应用于衡量模型预测结果与实际目标之间的差异。这种差异通常表示为误差或者距离,其目的是为了指导模型参数的更新,从而使模型能够更好地拟合数据[^1]。 #### Loss函数的计算方式 具体来说,损失函数可以通过多种方式进行定义,其中一种常见的形式是交叉熵损失函数。该函数适用于分类任务,尤其是当类别数量较多时更为有效。例如,在PyTorch框架下,`torch.nn.CrossEntropyLoss()`可以直接用于计算交叉熵损失。此外,负对数似然损失(Negative Log Likelihood, NLL)也是一种常用的损失函数,尤其适合多分类问题。NLL损失接受的是对数概率作为输入,这通常由模型的最后一层`log_softmax`提供[^2]。 以下是基于PyTorch的一个简单代码示例,展示如何定义并计算交叉熵损失: ```python import torch import torch.nn as nn # 假设我们有一个批量大小为3,类别数为5的任务 predictions = torch.randn(3, 5, requires_grad=True) # 模型输出 (未经softmax/log_softmax) labels = torch.tensor([1, 0, 4]) # 真实标签 # 使用交叉熵损失函数 criterion = nn.CrossEntropyLoss() loss_value = criterion(predictions, labels) print(f"Cross Entropy Loss: {loss_value.item()}") ``` #### Loss函数的优化方法 在模型训练过程中,可能会遇到一些挑战,比如Loss值震荡严重的情况。这种情况可能由以下几个因素引起,并可通过相应的方法加以改善: - **输入数据有误**:确保数据的质量和一致性。 - **Batch Size较小**:适当增加batch size有助于减少梯度估计的方差。 - **Loss函数设计不合理**:重新审视Loss函数的设计是否适配当前任务。 - **激活函数选用不当**:某些情况下,特定类型的激活函数可能导致数值不稳定或梯度消失等问题。 - **学习率过大**:降低学习率可以帮助稳定训练过程。 - **优化算法不合适**:尝试更换更先进的优化器,如Adam替代SGD。 - **正则化不足或过度**:合理设置L1/L2正则项强度以防止过拟合或欠拟合。 - **网络结构存在问题**:检查是否存在架构上的缺陷导致难以收敛[^4]。 另外,在大规模模型训练期间如果观察到Loss突然剧烈波动甚至激增,则需进一步排查是否有硬件错误或是软件层面的数据流异常引发此类现象[^5]。 ### 总结 综上所述,Loss函数不仅是一个重要的理论概念,也是实践操作中的核心组件之一。无论是从基础原理还是高级技巧角度出发,深入理解和灵活运用Loss函数都将极大地促进模型性能提升以及整个项目的成功推进。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值