O
How to train a network
KR
数据及其预处理
-
模型训练只是逼近一个函数能逼近的极限,数据清洗和特征才是决定识别的上限。
-
数据的shuffle 和augmentation。这个没啥好说的, aug也不是瞎加,比如行人识别一般就不会加上下翻转的,因为不会碰到头朝下的异型种
-
数据预处理方法一般也就采用数据归一化即可。
-
数据增强是用来扩充数据集,可以进一步减缓模型过拟合的情况。在图像分类任务中,图像的翻转、旋转、颜色改变、边缘处理等操作都不会改变图像的标签。在其他任务中,也可以使用类似的数据增强操作。数据增强一般在训练过程中动态进行,因此每次迭代过程中都会有不同的图像进行训练。在预测阶段,也可以对图像进行数据扩增,然后对扩增图像的结果进行平均操作。(数据增强应该在模型调参正常的情况下再用,模型不work数据增强反而让自己迷失调参方向)
-
数据扩增和数据增强的区别是数据扩增在开始阶段增加数据量,但是方法大致和数据增强差不多。怎么选择结合情况而定。
模型选择
- 如果数据很少,低于百万,直接拿imagenet预训练的模型微调即可。
- 模型方面,可以先用2或3层LSTM试一下,通常效果都不错。
- 结构化数据用机器学习中的树算法,图像和音频分类用CNN(经典的是vgg和resnet), 文本和语音识别用RNN类, 模态变换用GAN,数据表示降维用自编码器。
- 不管什么模型,先在一个较小的训练集上train和test,看看它能不能过拟合。如果不能过拟合,可能是学习率太大,或者代码写错了。先调小学习率试一下,如果还不行就去检查代码,先看dataloader输出的数据对不对,再看模型每一步的size是否符合自己期待。
- GRU和LSTM在大部分任务上效果差不多。
模型结构
- 激活函数选择:常用的激活函数有relu、leaky-relu、sigmoid、tanh等。对于输出层,多分类任务选用softmax输出,二分类任务选用sigmoid输出,回归任务选用线性输出。而对于中间隐层,则优先选择relu激活函数(relu激活函数可以有效的解决sigmoid和tanh出现的梯度弥散问题,多次实验表明它会比其他激活函数以更快的速度收敛)。另外,构建序列神经网络(RNN)时要优先选用tanh激活函数。
- 残差块与BN层:
如果你希望训练一个更深更复杂的网络,那么残差块绝对是一个重要的组件,它可以让你的网络训练的更深。有CNN的地方就用shortcut。CNN层数加到某一个值之后对结果影响就不大了,这个值作为参数可以调一下。
BN层具有加速训练速度,有效防止梯度消失与梯度爆炸,具有防止过拟合的效果,所以构建网络时最好要加上这个组件。 - 分类问题用dropout,只需要最后1层softmax 前用基本就可以了,能够防止过
拟合,可能对accuracy提高不大,但是dropout 前面的那层如果是之后要使用的feature的话,性能会大大提升。 - weight decay可以试一下,我一般用1e-4。
- 网络层数,参数量什么的都不是大问题,在性能不丢的情况下,减到最小。
- relu+bn。 这套好基友组合是万精油,可以满足95%的情况,除非有些特殊情况会用identity,比如回归问题,比如resnet的shortcut支路。
- 损失函数: 一般分类就是categorical-cross-entropy+softmax,回归就是L2的loss。但是loss也要规范化,尤其回归问题的loss可能会很大。多任务,loss限制在一个量级上。
超参数
- 优化器优先用adam,学习率设1e-3或1e-4,再试Radam(LiyuanLucasLiu/RAdam)。不推荐sgdm,因为很慢。
- 学习率衰减也比较重要。随着网络训练的进行,学习率要逐渐降下来,如果你有tensorboard, 你有可能发现,在学习率下降的一瞬间,网络会有个巨大的性能提升,(用这个加上adam系的optimizer基本就不用怎么调学习率了)
- batchsize设置小一点通常会有一些提升,某些任务batchsize设成1有奇效。
训练
- 看train/eval的loss曲线,正常的情况应该是train loss呈log状一直下降最后趋于稳定,eval loss开始时一直下降到某一个epoch之后开始趋于稳定或开始上升,这时候可以用early stopping保存eval loss最低的那个模型。如果loss曲线非常不正常,很有可能是数据处理出了问题,比如label对应错了,回去检查代码。
- 防止过拟合: 一般常用的防止过拟合方法有使用L1正则项、L2正则项、dropout、提前终止、数据集扩充等。如果模型在训练集上表现比较好但在测试集上表现欠佳可以选择增大L1或L2正则的惩罚力度(L2正则经验上首选1.0,超过10很少见),或增大dropout的随机失活概率(经验首选0.5);或者当随着训练的持续在测试集上不增反降时,使用提前终止训练的方法。当然最有效的还是增大训练集的规模,实在难以获得新数据也可以使用数据集增强的方法,比如CV任务可以对数据集进行裁剪、翻转、平移等方法进行数据集增强,这种方法往往都会提高最后模型的测试精度。
- 根据train_loss和val_loss的上升下降情况观察参数应该如何调整。如都下降,说明网络仍在学习;如train_loss下降,val_loss上升,说明过拟合。如train_loss下降,val_loss不变,欠拟合。train_loss,val_loss均不变,陷入瓶颈。train_loss不断上升,val_loss不断上升,模型有问题。train_loss上升,val_loss下降,数据集有问题。……
最后的提升
- 交叉验证法(Cross Validation, CV)
将训练集划分成 K 份,将其中的 K-1 份作为训练集,剩余的 1 份作为验证集,循环 K 训练。这种划分方式是所有的训练集都是验证集,最终模型验证精度是 K 份平均得到。这种方式的优点是验
证集精度比较可靠,接近测试集的结果。训练 K 次可以得到 K 个有多样性差异的模型; CV 验证的缺点是需要训练 K次,不适合数据量很大的情况。 - 模型融合
在训练得到模型之后,还可以考虑使用模型融合来继续提高精度,特别是在机器学习竞赛中。原始模型能够决定 90% 的精度,通过模型融合或许能够继续提高 10% 的精度。模型融合是基于模型多样性的基础之上的,模型越多样最终融合的结果就越稳定。
可以从偏差与方差的角度来进一步介绍,不同的模型会有不同的偏差和方差,多个模型的融合会减少偏差,最终得到的精度更高的结果。必须要指出的是,模型融合是要求单模型有多样性,也要求各个单模型精度都足够好,最终融合模型的结果才会有提高。模型融合主要有Blending和Stacking。
Blending
此种融合方式是直接对模型的输出结果进行融合,是直接对结果文件进行操作的过程。对于分类任务,可以使用多个模型进行投票(Vote)操作进行融合;对于回归任务,可以使用多个模型结果进行平均(Average)操作进行融合;对于排序任务,可以使用多个模型的结果进行排序(Rank)操作进行融合。Blending 操作简单,最终的本地验证结果也更加可靠。
Stacking
Stacking 操作则是有学习的过程,可以理解为模型结果的二次学习。通过 K-Fold 的划分方式,模型对训练集的每个部分进行一次“独立”的预测(Out-Of-Fold, OOF),会对测试集进行 K 次预测。注意这个独立含义,这
里的意思是模型把训练集的每一部分都当做未知样本预测了一遍,通过 K-Fold 的训练方式,模型会对训练集有一个预测结果,同时对测试集有一个预测结果(将 K个预测结果进行平均得到)。那么就可以把模型的预测结果看成为一维新的特征,新特征可以加到原始特征进行一起训练。 Stacking 将多个模型的新特征拼接一起进行训练,得到最终的预测结果
TIP:
如果真要做深度学习,深度学习问题很多,还是往芯片、部署优化上靠拢,以后好转好。调参本身就是个笑话,所谓的调参手段更是皇帝的新衣。