train loss相关问题

一、train loss 收敛慢,把learning_rate调高

二、train loss不下降:

1、观察数据中是否有异常样本或异常label导致数据读取异常
2、调小初始化权重,以便使softmax输入的feature尽可能变小
3、降低学习率,这样就能减小权重参数的波动范围,从而减小权重变大的可能性。这条也是网上出现较多的方法。

4、调大batch_size
5、如果有BN(batch normalization)层,finetune时最好不要冻结BN的参数,否则数据分布不一致时很容易使输出值变的很大。

6、神经网络不够深。

7、训练的epoch不够。

https://blog.csdn.net/u010159842/article/details/83614791

train loss 不断下降,test loss不断下降,说明网络仍在学习;

train loss 不断下降,test loss趋于不变,说明网络过拟合;

train loss 趋于不变,test loss不断下降,说明数据集100%有问题;

train loss 趋于不变,test loss趋于不变,说明学习遇到瓶颈,需要减小学习率或批量数目;

train loss 不断上升,test loss不断上升,说明网络结构设计不当,训练超参数设置不当,数据集经过清洗等问题。

二,

这个比较长,比较完整 Loss和神经网络训练

https://blog.csdn.net/u011534057/article/details/51452564

有1.梯度检验2.训练前检查,3.训练中监控4.首层可视化5.模型融合和优化等等等

三,https://www.zhihu.com/question/38937343

四,https://blog.csdn.net/u010911921/article/details/71079367

原文地址:http://blog.csdn.net/u010911921/article/details/71079367
这段在使用caffe的时候遇到了两个问题都是在训练的过程中loss基本保持常数值,特此记录一下。
1.loss等于87.33不变

loss等于87.33这个问题是在对Inception-V3网络不管是fine-tuning还是train的时候遇到的,无论网络迭代多少次,网络的loss一直保持恒定。

查阅相关资料以后发现是由于loss的最大值由FLT_MIN计算得到,FLT_MIN是其对应的自然对数正好是-87.3356,这也就对应上了loss保持87.3356了。

这说明softmax在计算的过程中得到了概率值出现了零,由于softmax是用指数函数计算的,指数函数的值都是大于0的,所以应该是计算过程中出现了float溢出的异常,也就是出现了inf,nan等异常值导致softmax输出为0.

当softmax之前的feature值过大时,由于softmax先求指数,会超出float的数据范围,成为inf。inf与其他任何数值的和都是inf,softmax在做除法时任何正常范围的数值除以inf都会变成0.然后求loss就出现了87.3356的情况。

解决办法

由于softmax输入的feature由两部分计算得到:一部分是输入数据,另一部分是各层的权值等组成

    减小初始化权重,以使得softmax的输入feature处于一个比较小的范围

    降低学习率,这样可以减小权重的波动范围

    如果有BN(batch normalization)层,finetune时最好不要冻结BN的参数,否则数据分布不一致时很容易使输出值变得很大(注意将batch_norm_param中的use_global_stats设置为false )。

    观察数据中是否有异常样本或异常label导致数据读取异常

    本文遇到的情况采用降低学习率的方法,learning rate设置为0.01或者原来loss的或者。

2.loss保持0.69左右

采用VGG-16在做一个二分类问题,所以计算loss时等价与下面的公式:

当p=0.5时,loss正好为0.693147,也就是训练过程中,无论如何调节网络都不收敛。最初的网络配置文件卷积层的参数如下所示:

从VGG-16训练好的模型进行fine-tuning也不发生改变,当在网络中加入初始化参数和decay_mult以后再次训练网络开始收敛。


但是具体是什么原因造成的,暂时还没有找到,难道是初始化参数的问题还是?
参考资料

http://blog.csdn.net/jkfdqjjy/article/details/52268565?locationNum=14

https://groups.google.com/forum/#!topic/caffe-users/KEgrRlwXz9c


https://www.zhihu.com/question/68603783

loss一直不下降的原因有很多,可以从头到尾滤一遍: 1)数据的输入是否正常,data和label是否一致。 2)网络架构的选择,一般是越深越好,也分数据集。 并且用不用在大数据集上pre-train的参数也很重要的 3)loss 对不对。

具体到语音,很多是把audio转成频谱图送给CNN训练。

NIPS16 有个soundNet(torch的code),语音分类的performance很高,我觉得可以用来初始化你的model 参数, 可以参考下。

还有我见的3D-CNN 多用于视频,做audio 用3D 的工作比较少,倒是见过是用1维卷积做audio的
--------------------- 

 三、trian/dev loss和acc的结果都很正常,但inference时的结果不行。即二分类sigmoid之后测试集结果很多都是0或1.

神经元饱和:在训练过程中sigmoid激活函数易梯度消失,检查一下梯度是否等于0.

加了BN,缓解了这个问题

 

四、一些小总结:

loss训练下降缓慢,收敛慢问题:

train loss 在epoch到200\300次才收敛,小数据量时收敛更快,train loss可能在0.6几收敛,acc 也上升缓慢,

test loss 前期step几乎没变。

原因及修改:

  1、因为learning rate采用的是指数下降,可能learning rate下降太快,修改成1000步才下降0.96,优化器采用的是GD,现在改成Adam。

  2、数据量太大时,每次train batch都算一次全量的test loss会导致训练速度慢,初始显得train loss收敛慢,所以采取每100个batch才算一次test loss。

  3、同时还增大了keep_prob。

 

如果出现资源耗尽的报错(OOM),原因有:

   1、确定是train_step OOM 还是test_step OOM。

   2、如果是train_step,则batch_size调小试试。减少模型复杂度(减小卷积核数量还有全连接层神经元个数也可以试试)

   3、如果是test_step OOM ,将test的数据集数量减少,因为test session.run的时候是全量跑的,不是batch跑的。

   4、去查看一下显存占比:nvidia-smi -l

    -----------------------------------------------------------------------------+
| NVIDIA-SMI 418.40.04    Driver Version: 418.40.04    CUDA Version: 10.1     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla P40           Off  | 00000000:02:00.0 Off |                    0 |
| N/A   49C    P0   115W / 250W |  11129MiB / 22919MiB |     87%      Default |
+-------------------------------+----------------------+----------------------+
|   1  Tesla P40           Off  | 00000000:03:00.0 Off |                    0 |
| N/A   23C    P8    10W / 250W |      0MiB / 22919MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   2  Tesla P40           Off  | 00000000:83:00.0 Off |                    0 |
| N/A   25C    P8     9W / 250W |      0MiB / 22919MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   3  Tesla P40           Off  | 00000000:84:00.0 Off |                    0 |
| N/A   22C    P8    10W / 250W |      0MiB / 22919MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|

       注意Memory-Usage:每次同一交互式训练是,如果直接interrupt kernel的话,再重跑train,显存是不释放的,需要restart整个代码才会释放,解决方法:不用notebook来跑,存成py脚本来跑。

    在代码中加入:

        os.environ["CUDA_VISIBLE_DEVICES"] = "0"
        config = tf.ConfigProto()  
        config.gpu_options.per_process_gpu_memory_fraction = 0.5 #指定GPU分配不超过0.5,如果超过则执行以下步骤
        config.gpu_options.allow_growth=True # allocate when needed
        
        sess = tf.Session(config = config)

 第一次train loss就等于0。

https://blog.csdn.net/qq_34661230/article/details/88313252

最后一层的输出函数用错了,我用的是tf.nn.softmax_cross_entropy_with_logits来计算cost。 我们知道softmax一般是用来做multiclass classifier的,也就是输出的类别要大于两个。对于一个binary classifier而言,很明显我们要用sigmoid函数也就是tf.nn.sigmoid_cross_entropy_with_logits来计算cost,于是问题解决。

为什么?
那么为什么在binary classifier中使用了softmax之后cost就一直是0呢?可以看一下softmax的公式。

第一次train auc就等于100%,检查计算auc的公式正不正确。

五、深度学习网络调参

https://zhuanlan.zhihu.com/p/24720954?utm_source=zhihu&utm_medium=social

好的实验环境是成功的一半

由于深度学习实验超参众多,代码风格良好的实验环境,可以让你的人工或者自动调参更加省力,有以下几点可能需要注意:

  • 将各个参数的设置部分集中在一起。如果参数的设置分布在代码的各个地方,那么修改的过程想必会非常痛苦。
  • 可以输出模型的损失函数值以及训练集和验证集上的准确率。
  • 可以考虑设计一个子程序,可以根据给定的参数,启动训练并监控和周期性保存评估结果。再由一个主程序,分配参数以及并行启动一系列子程序。

画图

画图是一个很好的习惯,一般是训练数据遍历一轮以后,就输出一下训练集和验证集准确率。同时画到一张图上。这样训练一段时间以后,如果模型一直没有收敛,那么就可以停止训练,尝试其他参数了,以节省时间。 
如果训练到最后,训练集,测试集准确率都很低,那么说明模型有可能欠拟合。那么后续调节参数方向,就是增强模型的拟合能力。例如增加网络层数,增加节点数,减少dropout值,减少L2正则值等等。 
如果训练集准确率较高,测试集准确率比较低,那么模型有可能过拟合,这个时候就需要向提高模型泛化能力的方向,调节参数。

从粗到细分阶段调参

实践中,一般先进行初步范围搜索,然后根据好结果出现的地方,再缩小范围进行更精细的搜索。

  1. 建议先参考相关论文,以论文中给出的参数作为初始参数。至少论文中的参数,是个不差的结果。
  2. 如果找不到参考,那么只能自己尝试了。可以先从比较重要,对实验结果影响比较大的参数开始,同时固定其他参数,得到一个差不多的结果以后,在这个结果的基础上,再调其他参数。例如学习率一般就比正则值,dropout值重要的话,学习率设置的不合适,不仅结果可能变差,模型甚至会无法收敛。
  3. 如果实在找不到一组参数,可以让模型收敛。那么就需要检查,是不是其他地方出了问题,例如模型实现,数据等等。可以参考我写的深度学习网络调试技巧

提高速度

调参只是为了寻找合适的参数,而不是产出最终模型。一般在小数据集上合适的参数,在大数据集上效果也不会太差。因此可以尝试对数据进行精简,以提高速度,在有限的时间内可以尝试更多参数。

  • 对训练数据进行采样。例如原来100W条数据,先采样成1W,进行实验看看。
  • 减少训练类别。例如手写数字识别任务,原来是10个类别,那么我们可以先在2个类别上训练,看看结果如何。

超参数范围

建议优先在对数尺度上进行超参数搜索。比较典型的是学习率和正则化项,我们可以从诸如0.001 0.01 0.1 1 10,以10为阶数进行尝试。因为他们对训练的影响是相乘的效果。不过有些参数,还是建议在原始尺度上进行搜索,例如dropout值: 0.3 0.5 0.7)。

经验参数

这里给出一些参数的经验值,避免大家调参的时候,毫无头绪。

  • learning rate: 1 0.1 0.01 0.001, 一般从1开始尝试。很少见learning rate大于10的。学习率一般要随着训练进行衰减。衰减系数一般是0.5。 衰减时机,可以是验证集准确率不再上升时,或固定训练多少个周期以后。 
    不过更建议使用自适应梯度的办法,例如adam,adadelta,rmsprop等,这些一般使用相关论文提供的默认值即可,可以避免再费劲调节学习率。对RNN来说,有个经验,如果RNN要处理的序列比较长,或者RNN层数比较多,那么learning rate一般小一些比较好,否则有可能出现结果不收敛,甚至Nan等问题。
  • 网络层数: 先从1层开始。
  • 每层结点数: 16 32 128,超过1000的情况比较少见。超过1W的从来没有见过。
  • batch size: 128上下开始。batch size值增加,的确能提高训练速度。但是有可能收敛结果变差。如果显存大小允许,可以考虑从一个比较大的值开始尝试。因为batch size太大,一般不会对结果有太大的影响,而batch size太小的话,结果有可能很差。
  • clip c(梯度裁剪): 限制最大梯度,其实是value = sqrt(w1^2+w2^2….),如果value超过了阈值,就算一个衰减系系数,让value的值等于阈值: 5,10,15
  • dropout: 0.5
  • L2正则:1.0,超过10的很少见。
  • 词向量embedding大小:128,256
  • 正负样本比例: 这个是非常忽视,但是在很多分类问题上,又非常重要的参数。很多人往往习惯使用训练数据中默认的正负类别比例,当训练数据非常不平衡的时候,模型很有可能会偏向数目较大的类别,从而影响最终训练结果。除了尝试训练数据默认的正负类别比例之外,建议对数目较小的样本做过采样,例如进行复制。提高他们的比例,看看效果如何,这个对多分类问题同样适用。 
    在使用mini-batch方法进行训练的时候,尽量让一个batch内,各类别的比例平衡,这个在图像识别等多分类任务上非常重要。

自动调参

人工一直盯着实验,毕竟太累。自动调参当前也有不少研究。下面介绍几种比较实用的办法:

  • Gird Search. 这个是最常见的。具体说,就是每种参数确定好几个要尝试的值,然后像一个网格一样,把所有参数值的组合遍历一下。优点是实现简单暴力,如果能全部遍历的话,结果比较可靠。缺点是太费时间了,特别像神经网络,一般尝试不了太多的参数组合。
  • Random Search。Bengio在Random Search for Hyper-Parameter Optimization中指出,Random Search比Gird Search更有效。实际操作的时候,一般也是先用Gird Search的方法,得到所有候选参数,然后每次从中随机选择进行训练。
  • Bayesian Optimization. 贝叶斯优化,考虑到了不同参数对应的实验结果值,因此更节省时间。和网络搜索相比简直就是老牛和跑车的区别。具体原理可以参考这个论文: Practical Bayesian Optimization of Machine Learning Algorithms ,这里同时推荐两个实现了贝叶斯调参的Python库,可以上手即用:

总结

  • 合理性检查,确定模型,数据和其他地方没有问题。
  • 训练时跟踪损失函数值,训练集和验证集准确率。
  • 使用Random Search来搜索最优超参数,分阶段从粗(较大超参数范围训练较少周期)到细(较小超参数范围训练较长周期)进行搜索。

参考资料

这里列了一些参数资料,大家有时间,可以进一步阅读。 
Practical recommendations for gradient-based training of deep architectures by Yoshua Bengio (2012)
Efficient BackProp, by Yann LeCun, Léon Bottou, Genevieve Orr and Klaus-Robert Müller
Neural Networks: Tricks of the Trade, edited by Grégoire Montavon, Geneviève Orr, and Klaus-Robert Müller.

 

posted on 2019-07-02 13:42  吱吱了了  阅读(17390)  评论(0编辑  收藏  举报

导航