训练神经网络的注意事项

翻译自网络:http://karpathy.github.io/2019/04/25/recipe/

训练神经网络 - a leaky abstraction

神经网络的训练被过分的弱化了。大量的DNN库提供不到30行的代码就能让你完成对一个神经网络的训练,暗示你这东西好简单哟,比方说下面这个:

>>> your_data = 
>>> model = SuperCrossValidator(SuperDuper.fit, your_data, ResNet50, SGDOptimizer)

有些甚至提供网络API,而事实上神经网络远非这些代码所展示的那样简单。它们也远未到达那种开箱即用的程度。当你的训练数据稍微的有些不一样,可能结果会有大的差别。Backprop + SGD并不会像你想的那样能很轻松的解决神经网络的训练问题。Batch norm也不是那么神奇的能让网络快速的收敛。

神经网络的训练很容易失败

首先你得熟悉代码。错误的配置可能会不断的给你抛出异常,数据类型的不一致,输入参数的不一致,库文件的导入失败等等会让你抓狂。

语法的错误都好解决,难解决的是逻辑问题。比方说,做数据增强(data augmentation)的时候,你左右换了图像但没有把Labels做同样的处理;你的autoregressive model可能会将你要predict的变量变成了输入等等。

网络的训练不能靠激情,而应该靠深入的可视化分析。

方法

处理data

第一步先不要去处理任何跟网络有关的东西,而是人为的去检查你的数据,分析它们的分布,检测相关的特征。这样可以得出一些有用的信息,如:重复的样本,坏掉的图片等。对于这种人工的处理方法也要注意,因为他们很有可能对于我们建立对应的网络非常的有帮助。比如:是用局部特征还是全局特征?方差是多少,它是什么形式,是不是有一些可疑的数据需要去掉?空间信息是否重要,我们是不是需要average pool?等等

有的时候,当你的神经网络训练得不到你想要的结果的时候,你可以看看那些错误的数据,想想是什么原因造成神经网络的输出不准的,是不是某些数据本身就是脏数据,本不该有的,应该去掉的。所以这会促使你去想些数据预处理的方法。

建立训练/测试框架+找到合适的Benchmark

这一步需要建立一个完全的训练/测试框架,要确保它的准确性。这一步最好是用一些小的模型或者一些看起来很蠢的办法如线性规划,去训练、查看loss或者其它metrics,如accuracy。

对于这一步的几点建议:

  1. 固定random seed:保证两次跑出来同样的结果
  2. ** 简化**:这一步不要做一些不必要的fancy的事情,如做data augmentation,这一步的主要目的是为了除掉一些bug。
  3. 在eval数据上加上重要的数字:在分析的时候不能只Plot出test loss over batches。
  4. verify loss@init:loss的初始值得正确。比方说如果你初始化你的最后一层的初始化是正确的那你应该在初始化后用softmax度量一下。这对L2 regression, Huber loss同样适用。
  5. 参数初始化一定要做好:最后一层的参数初始化要做正确。比如,在做regression的时候,一些变量的均值为50,那么你可以把bias设置成50。再比如如果你的data是不平衡的,比方说数据比例是1:10 - positive:negative,那么最好把bias设置得使你的模型在初始化时的输入为0.1。这些小诀窍可以让网络快速的收敛。
  6. 用人做baseline:对于那些人能读懂的metrics,用人的结果做baseline来比较
  7. input-indepent baseline:最简单的方法是把输入全变成0,这时再 看你的神经网络会输出个什么。这个时候理应结果很差,但这个时候还很好的话那你的网络就是有问题了。
  8. 在一个batch数据上做overfit:这一步很关键,如果我们能在一二个数据在做到overfit,即达到最好的结果(比方说零误差),那么网络的capacity证明是足够的,如果不是的话那么就要考虑增加网络的容量了。
  9. verify decreasing training loss:到了这一步你应该是underfit你的数据的,因为这个时候你是用的一个小模型来训练,那么该考虑增大模型了。模型增大后,loss是不是减小了?
  10. 在输入网络前可视化数据:在y_hat = model(x)或sess.run前将你的数据可视化,这个可能是最有用的方法,去解决你在构建过程中的各种问题
  11. 可视化prediction的动态变化过程:这一过程可以让你更直观的感受到在训练的过程中你的网络是如何奋力的拟合你的数据的。过小或过大的learning rate也可以在这个过程中被发现。
  12. use backprop to chart dependencies: Your deep learning code will often contain complicated, vectorized, and broadcasted operations. A relatively common bug I’ve come across a few times is that people get this wrong (e.g. they use view instead of transpose/permute somewhere) and inadvertently mix information across the batch dimension. It is a depressing fact that your network will typically still train okay because it will learn to ignore data from the other examples. One way to debug this (and other related problems) is to set the loss to be something trivial like the sum of all outputs of example i, run the backward pass all the way to the input, and ensure that you get a non-zero gradient only on the i-th input. The same strategy can be used to e.g. ensure that your autoregressive model at time t only depends on 1..t-1. More generally, gradients give you information about what depends on what in your network, which can be useful for debugging.
  13. generalize a special case:先从简单的事做起再做难的,比方说在做vectorizing code的时候,先写fully loopy version然后再去把它们转变成向量化的乘法,保证不出错。

过拟合

在这一步的时候我们应该对dataset以及training+evaluation的整个工作流程非常的清晰。对于任一个模型我们能计算一个我们信任的metric;我们有一个input-independent baseline;一些比较简单的用于对比的baseline;人工检测的baseline。这些信息将有助于我们后面去发现一个更优的模型。

关于发现一个更优的模型,一般有两步:首先得到一个大的模型使其可以在training dataset上过拟合,然后使用合适的regularization,即丢掉适当的training loss,以提升validation loss。这么做的原因是如果我们无法利用任何模型达到一个很小的error rate,那么很有可能哪出问题了。

对于这一步的几点建议:

  1. 选择模型:不要一开始就上来想自己搭新框架,别把自己想得太牛逼。最好的办法是找一个与自己处理相同问题的文章,把它们的模型复制过来,先跑一遍再说。比方说,对于image classification,先把ResNet-50拿过来跑了再说。之后再考虑对它做一些优化工作。
  2. adam is safe:采用adam并利用3e-4的learning rate是有效的。据经验, adam对hyperparameters的错误设定的容忍度更高,包括learning rate。对于卷积神经网络来说,一个调校好了的SGD会永远稍优于Adam,但是最优的learning rate的选择比较窄,且容易出问题。还是那个建议,先看相关的文章是怎么弄的。
  3. 一次只增加一种复杂度:如果你有多个信号,最好是一次只放一种到你的classifier里面。别一次喂太多。另外也有一些其它的方法来增加complexity,比方说先从小的image开始,然后再去做大的图片分类。‘
  4. 不要相信learning rate decay defaults:如果你是从其它domain re-purposing code,你要特别小心learning rate decay。Not only would you want to use different decay schedules for different problems, but - even worse - in a typical implementation the schedule will be based current epoch number, which can vary widely simply depending on the size of your dataset. E.g. ImageNet would decay by 10 on epoch 30. If you’re not training ImageNet then you almost certainly do not want this. If you’re not careful your code could secretely be driving your learning rate to zero too early, not allowing your model to converge.总之,在刚开始的时候,最好还是只用恒定的learning rate。

Regulization

现在,我们有一个足够大的模型,它能够很好的,至少在training set上得到很低的loss。现在我们该regulize它使validation accuracy提高。

这一步的建议如下:

  1. 收集更多的数据:到目前为止,最好的regulization的办法就是得到更多的regulization data。与其在一个小数据集上不断的挤牙膏式的改进,还不如多花点时间多去收集些数据。收集更多的数据是一定可以网络的性能更好的。另外的办法是用ensembles如果条件允许的话,但是最多不要超过五个models。
  2. data augmentation:half-fake data。
  3. creative augmentation:如果half-fake data不怎么凑效的话可以试试更多的办法。如domain randomization[https://openai.com/blog/learning-dexterity/
    ],仿真http://vladlen.info/publications/playing-data-ground-truth-computer-games/, clever hybridshttps://arxiv.org/abs/1708.01642
    ,或者现在流行的GAN。
  4. pretrain:在已经训练过的网络再训练往往会更好,即使你拥有足够的data。
  5. 先supervised learning再说:千玩不要过分的对unsupervised learning抱有太大的希望。很少情况下unsupervised learning会更好,除了少部分用于NLP的。
  6. smaller input dimensionality:减少那些含有突变信号的特征。任何spurious input都会导致overfit,如果你的dataset足够的小。同样的,如果low-level details不太重要的话,尝试减少输入维度。
  7. 更小的model size:在很多情形下,你可以采用domain knowledge去减小模型的大小。比方说原来ImageNet上面往往是FC层,但后面发现简单的average pooling就能完事的,而且这种方法减少了不少的参数。
  8. 减少batch size:由于batch norm里面的normalization,小的batch size在某种程度上能够实现更强的regulization。
  9. dropout:增加dropout层,但是要注意这个dropout对于normalization工作得不是很好。
  10. weight decay: 增加weight decay penalty.
  11. early stopping:当在validation set上的loss达到一定程度是可以提早的停止训练
  12. 更大的model:大的model理论上会增加overfit的可能性,但是如果利用好early stop,它们的性能往往比小模型要好得多。

最后,为了更加确信你的网络是做出了合理的假设,对于Conv图像分类问题,往往可以visualize网络的第一层,看是不是边缘比较清晰,如果你的第一层像是noise,那么有可能是有问题了。同样的,activations有时候也能显示一些奇怪的artifacts,这也是有问题的表现。

Tune

到这一步,应该在利用dataset寻找更好的模型以实现更小的validation loss。

  1. random over grid search: For simultaneously tuning multiple hyperparameters it may sound tempting to use grid search to ensure coverage of all settings, but keep in mind that it is best to use random search instead. Intuitively, this is because neural nets are often much more sensitive to some parameters than others. In the limit, if a parameter a matters but changing b has no effect then you’d rather sample a more throughly than at a few fixed points multiple times.
  2. hyper-parameter optimization:有一堆利用bayesian hyper-parameter 优化工具箱并且被证实有效。

最后一步

  1. ensemble:大部分的ensembles能够保证提高约2%的精度。如果由于利用ensemble而计算量过大,则可以尝试knowledge distillation.
  2. leave it training:大多数人喜欢在validation loss达到某一程度后就停止了。有的时候让它一直跑一直跑也不定是坏事。

你可能感兴趣的:(训练神经网络的注意事项)