【翻译】神经网络训练方法


文章翻译自 A Recipe for Training Neural Networks



引言

很多人遇到了一个很大的障碍,那就是如何将“卷积神经网络是怎么工作的”进展到“我们的网络实现了SOTA性能”。

我主要想谈一谈怎么避免那些常见的问题(或者找到快速debug的方法),其中的窍门就是根据一套debug流程,首先来谈谈两个主要的经验总结。


神经网络训练实际上是抽象泄露

很多人都宣传“训练神经网络就是调调包调调参,很简单!”,这种虚假宣传就导致新手都觉得神经网络是“即插即用”的,但是这种想法完全是错误的。

当开发者真正着手于构建一个简单的imageNet二分类网络时,就会发现这不是一个现成的工具。我之前写过一些文章,谈论学习反向传播的重要性——单纯使用反向传播和SGD不能让你的神经网络正常工作、使用BatchNorm不能奇迹般让你收敛过程加快、RNN网络也不意味着你可以插入文本信息。如果你不理解一个工具就去使用它,你很大可能会一事无成。


神经网络无声无息地训练失败

或许代码的语法上没有任何问题,但是网络训练的结果却不像你想象的那样好,其中很多的问题是难以分辨出的,因为整个网络是一个庞大复杂、强逻辑性的系统,难以分模块进行测试。

罗列一些问题:1)你在数据增强的过程中,将图片的次序反转了,但是没有反转相应的标签;2)你原本打算裁剪梯度,但是不小心裁剪了损失值,导致了异常值被忽视;3)你没有按照原论文的设置,就引用了一个预训练模型;4)你把正则化、学习率、学习率的损失率、模型大小等设定都弄错了。

所以,“又快又急”地训练一个神经网络是很大概率导致网络不能正常工作的,但是通过足够仔细的检查以及使用可视化工具,就可能避免很多问题。我在深度学习中总结的最好的特质就在于,要足够耐心且足够仔细。



方法

我个人总结了一套非常详尽的方法来将神经网络应用到一个全新的问题上,其中主要基于两个原则。这套方法从简单到复杂,并且在每一步中,我们都对可能发生的问题进行了详细的假设,并且通过一些实验和调查来帮助我们解决这些问题。


1、变成数据大师

在根据一套数据集处理一个新问题前,先不要接触任何神经网络的代码,首先先观察数据集,这是最关键的一个步骤。我一般喜欢花费大量的时间浏览数据集中的各种样本,从而了解数据的分布情况、样式特征,我们的大脑十分擅长寻找这些规律。我主要关注数据集是否存在不平衡或者偏置,并且思考自己要怎么处理这些问题,然后自然而然就会构思一个神经网络的架构来实现我们的目的。

举个例子:局部特征是不是已经足够了,我们还需要全局特征嘛;有哪些数据预处理方法是有用的或者无用的,我们需要怎么排除;数据的空间特性是否重要,我们是否需要通过池化来进行平均;我们最大程度可以怎么样降采样这些数据?

当你对于数据集有了了解和一个大致的神经网络设计想法时候,可以写一些代码来验证一下,比如可以尝试分类/过滤/寻找一些标签、标注大小等,也可以把数据分布情况可视化。


2、设置端到端的训练/测试流程

现在我们还不能直接开始使用ResNet等复杂网络搭建模型,直接上手就搭建一个复杂网络必然会导致最后有各种错误。这一阶段的第一步就是构建出一套完整的训练、测试流程,并且通过一系列简单的实验来验证你想法的可靠性。于此同时,网络不要搭建得过于复杂,使用一些简单的线性分类器或者卷积网络,这些模型不是那么容易崩坏(你完全知道网络的结构且你可以debug主要问题)。

Tricks
1)固定随机种子:使用固定的随机种子,保证你通过同一套网络和输入数据得到的结果是相同的;
2)简化:保证你的代码没有花里胡哨的东西,比如把你数据增强的部分全部屏蔽掉,在之后的阶段可能会有帮助,但是在现阶段只会导致一系列问题;
3)在验证的时候使用“大数”:最好在整个数据集上验证网络的性能,而不是在batch上做测试并且之后进行平滑优化;
4)验证损失函数的初始化:验证你的损失函数的初始值是正确的;
5)选择合适的初始化参数:正确初始化最后一层的权重参数,比如,如果数据的均值为50那么就将最后一层的偏置参数设置为50,如果面对一个不平衡的数据集,比如正样本与负样本的比例为1:10,那么就在初始化的时候调整偏置参数,使得结果接近于0.1,这可以加速网络后来的收敛速度;
6)人脑的baseline:观测损失值之外的指标,比如准确率等(这些指标人脑可以做到一定程度的量化),然后可以将你人脑辨识的准确率和模型的准确率进行一个简单的对比;
7)与输入无关baseline:将你的输入置零,看看网络是不是真的可以学习到输入数据中的任何有效信息;
8)在一个batch上过拟合:在一个足够小的数据集上实现数据的过拟合,我们通过构建更加复杂的网络来证明我们可以在这些数据上实现最小的损失值,于此同时我也喜欢可视化标签和预测,观察在损失值最小的时候,两者是不是完美对齐的,如果我们做不到这一点,那么我们的网络、训练/验证流程可能存在问题,我们需要想办法修复;
9)验证下降的训练损失
10)可视化进入网络前的数据:最应该可视化数据的位置,毫无疑问,应该是输入网络模型之前,你需要可视化什么数据进入到了你的网络,并且节原始的数据和标签进行可视化,这可以将数据预处理和数据增强中的大量问题显示出来;
11)动态可视化标签:在训练的过程中,我喜欢在一个固定的测试batch上可视化模型的预测结果,这样可以动态观察到训练的过程;
12)使用反向传播来记录相关性:一般来说深度学习代码会包含复杂、向量化的操作,而且这种问题出现的时候,网络仍然会自顾自学习,但是没有从样本中学习到任何有效的数据,有一种debug的策略就是将损失值设置为样本i所有结果的和,然后执行反向传播,并且保证样本i作为输入是可以得到非零的梯度值的;


3、过拟合

在这个阶段,我们对于数据集已经有了一定的了解,同时我们构建了完整的训练和测试流程。套用任何一套现有的模型,我们都可以相应编写出测试程序。我们还对于数据集和任务有了一套与输入无关的baseline、几个简单模型的baseline以及人脑baseline,在该阶段我们的主要目标是训练出一个比较好的模型。

在这个阶段我们通过两个步骤来得到一个比较好的模型:
首先,先找到一个比较大的模型并且让它在数据集上过拟合
随后,再正则化它(可以通过删除某些损失函数完成正则化的过程);

Tricks
1)选择模型:为了实现一个比较好的训练损失,你需要为你的数据集和任务选择一个合适的网络架构,我的建议是,“步子不要迈的太大!”,有些人喜欢像搭建积木一样设计花里胡哨的、看似有道理的网络,这在刚刚开始构建网络的阶段是非常错误的,应该从最相关的论文中选择相对简单的模型架构来,就比如说,有的人对于一个简单的分类任务直接就使用Resnet-50,这很不对,应该选择合适的网络并且一步一步提升。
2)使用adam优化器:在构建模型的早期,我习惯于使用Adam优化器,并且将学习率设置在3e-4,因为Adam优化器对于超参数的宽容度比较高,尤其是它能够宽容一个比较离谱的学习率,虽然SGD优化器的性能更加好,但是它对于超参数的宽容度比较低,需要根据任务进行细致的调参来选择最好的学习率。
3)一点点提高任务的复杂度:(一个任务可以人为进行简化和复杂化,译者补充),对于一个分类器,每次只复杂化任务的其中一部分,然后一点点提高模型的性能,不要一次把最完整最复杂的任务给网络处理。
4)不要相信默认的学习率衰减参数:如果你从其他领域的问题中,迁移了一套代码(网络)到你的任务上时,很多情况下,原始代码中,学习率会根据网络训练迭代的次数发生改变,但是学习率的改变根据数据集的大小不同会有很显著的区别,比如,你是不可能希望在ImageNet上训练网络的时候,让你的学习率每隔30轮就衰减1/10的,这会导致你的模型不收敛,我自己一般固定一个学习率,并且在之后慢慢调整。


4、正则化

理想状态下,我们在训练集上已经有了一个高准确率的大模型了(这里的大指相对大,译者补充)。现在需要做的就是,牺牲训练集上的准确率来提高测试集上的准确率。

Tricks
1)获取更加多的数据:正则化一个模型最好的方法是扩大训练集的大小,当你可以收集一个更加大的数据集,但是却费劲苦心在一个小数据集上做优化,是很不好的一种方法。
2)数据增强:可以尝试使用比较激进的数据增强手段。
3)预训练:使用预训练网络一般都不会出错。
4)有监督学习:不要对无监督预训练有过度的期待,在计算机视觉领域,还没有特别高性能的无监督学习手段(NLP领域有一些不错的无监督学习工作)。
5)缩小输入数据的维度:去除可能包含有害信号的特征,向你的模型中输入任何有害数据最后都有可能导致你的模型过拟合到有害特征上(有害特征指的是与任务无关特征,译者补充),如果细粒度特征对你的任务不重要,可以尝试将输入数据的分辨率降低。
6)缩小模型参数量:神经网络自然会学习到一部分域信息,这部分域信息可能可以帮助你减小网络的尺寸,例如在ImageNet上经常会加一层全连接层,但是之后这个全连接层被简单的平均池化替代了,节约了大量的参数。
7)缩小batch size:相对小一点的batch size往往对应着更加强的正则化,batch的平均值/方差往往是对于全局(整个数据集)的均值/方差的一种近似模拟,通过缩小batch size可以让均值/方差的迁移更加大。
8)drop:使用dropout,但是dropout与BN的兼容性不太好。
9)权重衰减:增加权重衰减。
10)提前停止训练:根据在验证集上的损失值来提前停止训练以防过拟合。
11)尝试使用更加大的模型:大模型更加容易出现过拟合,但是对于大模型使用提前停止训练,似乎可以实现更加好的性能。

最后一点就是,给你的网络设计一个合理的分类器,我喜欢将网络第一层的权重可视化,如果你的第一层滤波器看上去存在大量噪声信号,说明可能出了问题,类似的,网络中的激活出错的时候也可能会反映某些问题。


5、调整

在这个阶段,你通过不断了解你的数据集并且寻找更加好的模型结构,你已经实现了一个比较低的验证损失

Tricks
1)使用随机搜索而不是栅格搜索:使用栅格搜索会对超参的各种取值进行遍历,似乎很有吸引力,但是神经网络往往对于某一个参数更加敏感,所以使用随机搜索,对于某几个参数进行更加多遍历,会是更加好的选择。
2)超参优化:找个实习生来干这个活。


6、挤干水分

即使你确定了最好的网络结构和超参(你目前认为的最好的),你依旧可以通过一些技巧来将系统的性能全部发挥出来。
1)模型集成:使用模型集成是一种很好的提高性能的手段,可能可以在最终结果上涨点2%左右。
2)让它训:让模型不停训练(但是对于发论文验证一个idea的性能不太适用,译者补充)



结论

阅读到这里,你应该有了成功设计模型的潜质了:你对于神经网络的技术有了新的理解 —— 你学会了分析数据集和你的任务、你设计了一套完整的训练和测试流程并且得到了比较高的准确率、你去尝试了更加复杂的网络模型。你现在可以试着读更加多的论文、做实验,得到SOTA结果,祝好!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值