训练过程中遇到的问题及解决方案

在图像分类任务中, 训练数据不足会带来什么问题, 如何缓解数据量不足带来的问题?

(百面: 1.07.1)
带来的问题: 过拟合
处理方法

  • 基于模型的方法: 采用降低过拟合风险的措施,包括简化模型(如将非线性简化成线性), 添加约束项以缩小假设空间(如L1和L2正则化), 集成学习, Dropout超参数等.
  • 基于数据的方法, 主要通过数据扩充(Data Augmentation), 即根据一些先验知识, 在保持特定信息的前提下, 对原始数据进行适合变换以达到扩充数据集的效果.

在图像分类任务中,在保持图像类别不变的前提下,可以对训练集中的每幅图像进行以下变换:

  • 观察角度:一定程度内的随机旋转、平移、缩放、裁剪、填充、左右翻转等
  • 噪声扰动:椒盐噪声、高斯白噪声
  • 颜色变换:在RGB颜色空间上进行主成分分析
  • 其他:亮度、清晰度、对比度、锐度

其他扩充数据方法:特征提取, 在图像的特征空间内进行变换:数据扩充or上采样技术,如SMOTE(Synthetic Minority Over-sampling Technique)。

最后,迁移学习或者用GAN合成一些新样本也可帮助解决数据不足问题。

如何解决数据不均衡问题?

https://www.cnblogs.com/zhaokui/p/5101301.html

训练不收敛的具体表现是什么? 可能的原因是什么? 如何解决?

我们主要通过观察 loss 曲线来判断是否收敛, 根据不同的 loss 曲线, 有以下三种不收敛的情形:

  1. 从训练开始曲线就一直震荡或者发散
    • 可能原因: (1) 学习率设置的过大; (2) 向网络中输入的数据是错误数据, 如标签对应错误, 读取图片时将宽高弄反, 图片本身质量极差等;
    • 解决方法: 调节学习率; 检查数据读取代码
  2. 在训练过程中曲线突然发散
    • 可能原因: (1) 学习率设置过大, 或者没有采用衰减策略; (2) 读取到了个别的脏数据, 如标签对应错误, 或者标签为空等
    • 解决方法: 调整学习率及相应的衰减策略; 将 batch size 设为 1, shuffle 置为 false, 检查发散时对应的数据是否正确;
  3. 在训练过程中曲线突然震荡
    • 可能原因: (1) 损失函数中的正则化系数设置有问题, 或者损失函数本身存在 Bug; (2) 数据存在问题
    • 解决方法: 检查损失函数; 检查数据

训练过程中出现 Nan 值是什么原因? 如何解决?

Nan 是 “Not a number” 的缩写, 出现 Nan 的可能情况一般来说有两种:

  • 一种是梯度爆炸, 使得某一层计算出来的值超过了浮点数的表示范围
  • 另一种是由于损失函数中 $log$ 项的值出现的负值或者 0 导致的, 因为 $logx$ 只在 $x$ 大于 0 的时候才有意义.

解决梯度爆炸的方法通常是对数据进行归一化(BN, GN 等), 减小学习率, 加入 gradient clipping, 更换参数初始化方法(待商榷).

对于 $log$ 项出现负值或者 0 的情况(Softmax 激活函数的取值范围是 [0,1], 因此有可能输出 0), 首先确保网络使用了正确的初始化方法(若参数全为 0, 则输出也为 0), 其次, 检查数据本身是否存在问题, 因为实际业务上的真实数据通常还有大量的脏数据, 有时候数据本身就还有 Nan 值, 因此, 在训练网络之前 先要确保数据是正确的. 可以设计一个简单的小网络, 然后将所有数据跑一遍, 再根据日志信息去除其中的脏数据.

loss 的计算问题, 当我们采用先求取loss的和, 再做归一化除法时, 如果batch_size过大, 那么loss之和可能会超过数据类型的表示上限, 此时, 有两种解决方法, 一种是将数据类型的表示范围提高, 例如将float变成double, 但是这样也不保险, 较好的做法是在计算loss时, 避免添加操作, 或者预先估计loss的大小

1
2
3
4
# 提升 loss 的表示范围, 修改自 ssd.pytorch 代码
N = num_pos.data.sum().double()
loss_l = loss_l.double()
loss_c = loss_c.double()

如果以上方法都不能解决问题的话, 那应该就是网络结构本身或者损失函数可能存在 Bug, 需要进一步更细致的分析. 如将网络拆解开来, 减少层数, 对不同层进行测试等等.

过拟合是什么? 如何处理过拟合?

过拟合定义: 当模型在训练数据上拟合的非常好, 但是在训练数据意外的测试集上却不能很好的拟合数据, 此时就说明这个模型出现的过拟合现象.

解决方法:

  1. 使用正则项(Regularization): L1, L2 正则
  2. 数据增广(Data Augmentation): 水平或垂直翻转图像、裁剪、色彩变换、扩展和旋转等等, 也可利用GAN辅助生成(不常用)
  3. Dropout: Dropout是指在深度网络的训练中, 以一定的概率随机的”临时丢弃”一部分神经元节点. 具体来讲, Dropout作用于每份小批量训练数据, 由于其随机丢弃部分神经元的机制, 相当于每次迭代都在训练不同结构的神经网络, 可以被认为是一种实用的大规模深度神经网络的模型继承算法. 对于包含 $N$ 个神经元节点的网络, 在Dropout的作用下可以看作为 $2^N$ 个模型的集成, 这 $2^N$ 个模型可认为是原始网络的子网络, 它们共享部分权值, 并且拥有相同的网络层数, 而模型整个的参数数目不变, 大大简化了运算. 对于任意神经元来说, 每次训练中都与一组随机挑选的不同的神经元集合共同进行优化, 这个过程会减弱全体神经元之间的联合适应性, 减少过拟合的风险, 增强泛化能力. 工作原理和实现: 应用Dropout包括训练和预测两个阶段, 在训练阶段中, 每个神经元节点需要增加一个概率系数, 在前向传播时, 会以这个概率选择是否丢弃当前的神经元. 在测试阶段的前向传播计算时, 每个神经元的参数都会预先乘以概率系数p, 以恢复在训练中该神经元只有p的概率被用于整个神经网络的前向传播计算
  4. Drop Connect: Drop Connect 是另一种减少算法过拟合的正则化策略,是 Dropout 的一般化。在 Drop Connect 的过程中需要将网络架构权重的一个随机选择子集设置为零,取代了在 Dropout 中对每个层随机选择激活函数的子集设置为零的做法。由于每个单元接收来自过去层单元的随机子集的输入,Drop Connect 和 Dropout 都可以获得有限的泛化性能 [22]。Drop Connect 和 Dropout 相似的地方在于它涉及在模型中引入稀疏性,不同之处在于它引入的是权重的稀疏性而不是层的输出向量的稀疏性。
  5. 早停: 早停法可以限制模型最小化代价函数所需的训练迭代次数。早停法通常用于防止训练中过度表达的模型泛化性能差。如果迭代次数太少,算法容易欠拟合(方差较小,偏差较大),而迭代次数太多,算法容易过拟合(方差较大,偏差较小)。早停法通过确定迭代次数解决这个问题,不需要对特定值进行手动设置。

Reference:
https://www.cnblogs.com/callyblog/p/8094745.html

欠拟合是什么? 如何处理欠拟合?

过拟合定义: 当模型在训练数据和测试数据上都无法很好的拟合数据时, 说明出现了欠拟合

解决方法:

  1. 首先看看是否是神经网络本身的拟合能力不足导致的, 具体方法是让神经网络在每次训练时, 只迭代 同样的数据, 甚至每一个 batch 里面也是完全相同一模一样的数据, 再来看看 loss 值和 accurancy 值的变化. 如果这时候 loss 开始下降, accurancy 也开始上升了, 并且在训练了一段时间后神经网络能够正确地计算出所训练样本的输出值, 那么这种情况属于神经网络拟合能力不足. 因为对于大量的数据样本, 神经网络由于自身能力的原因无法去拟合全部数据, 只能拟合大量样本的整体特征, 或者少数样本的具体特征. 对于拟合能力不足问题, 通常可以增加网络层数, 增加神经元个数, 增大卷积核通道数等方法.
  2. 如果不是拟合能力不足导致的欠拟合, 就需要尝试其他方法, 更改网络初始化方法(Xavier, MSRA), 更改优化器, 降低学习率

Dropout 的实现方式在训练阶段和测试阶段有什么不同? 如何保持训练和测试阶段的一致性?

Dropout 的实现方式有两种:

  • 直接 Dropout: 使用较少, AlexNet 使用的是这种Dropout. 该方法在训练阶段会按照保留概率来决定是否将神经元的激活值置为0. 同时, 为了保持训练阶段和测试阶段数值的一致性, 会在测试阶段对所有的计算结果乘以保留概率.
  • Inverted Dropout: 这是目前常用的方法. 该方法在训练阶段会按照保留概率来决定是否将神经元的激活值置为0, 并且, 在训练阶段会令输出值都会乘以 $\frac{1}{\alpha_{dropout}}$, 这样一来, 在训练阶段可以随时更改 dropout 的参数值, 而对于测试阶段来说, 无需对神经元进行任何额外处理, 所有的神经元都相当于适配了训练过程中 dropout 对参数数值大小带来的影响.

Dropout 为什么可以起到防止过拟合的作用?

如何选取 Batch Size 的值? 显存中通常会存储哪些东西?