原文:基于Pre-trained模型加速模型学习的6点建议 - 2018.05.26

出处:深度学习与NLP - 微信公众号

1. 为什么要调整模型?

像卷积神经网络( CNN )这样的深度学习模型具有大量的参数;一般称之为超参数,因为它们不是固定值,需要迭代优化. 通常可以通过网格搜索的方法来查找这些超参数的最佳值,但需要大量硬件和时间开销. 那么,一个真正的数据科学家是否满足于只是猜测这些超参数呢?答案当然是否定的.

改进模型的最佳方法之一是,基于专业团队的设计和体系结构上来进行改进,但这些专业的知识往往需要对某一领域具有深入的了解,且通常需要有强大的硬件支持. 一般这些专业的团队都喜欢把他们的训练好的模型(pre-trained model)开源出来,无偿提供给别人使用. 基于这些 pre-trained model 来做研究和应用,可以省去大量的时间和资源.

2. 深度学习技巧

这里分享几种方法,如何基于预训练好的模型来降低深度学习模型训练时间,提升模型的准确性:

[1] - 选择最适用于做pre-trained模型的网络结构

了解迁移学习(transfer learning)的优点,或者一些强大的CNN网络结构.

主要考虑,有些领域之间看起来不明显,但领域之间却共享一些具有潜在特性(share potential latent features).

[2] - 使用较小的学习率

由于预先训练的权重(weights) 通常比随机初始化的权重更好,因此调整需要更精细!

如何选择主要取决于training landscape和学习的进展情况,但需要仔细检查每个epoch的training errors,分析如何能让模型达到收敛.

[3] - 使用Dropout

就像 Ridge 和 LASSO 正则化技术对于回归模型一样,对于所有模型都存在需要优化的参数 alpha 或Dropout. 这是一个超参数,取决于需要解决的具体问题,只能通过不停实验的方法得到. 先对超参数做比较大的调整(gridsearch 时选择一个比较大的变化范围),比如 NP. logspace(),然后像上面的一样减小学习速率. 循环上述过程直到找到最优值.

[4] - 限制权重大小

可以限制某些层的权重的最大范数(绝对值),可以提升模型泛化的能力.

[5] - 不要改变第一层网络的权值

神经网络的第一个隐含层倾向于捕捉通用和可解释(universal and interpretable)的特征,如形状、曲线或交叉(shapes、curves and interactions),这些特征通常与跨域(domains)相关. 应该经常把这些特征放到一边,把重点放在进一步优化meta latent level在水平上. 这可能意味需要添加隐藏层!

[6] - 修改输出层

把模型参数替换成适用于要解决新领域的新的激活函数和输出大小. 但是,不要把自己局限于最明显的解决方案中. 比如,尽管 MNIST 只需要10个输出类,但这些数字有共同的变化,允许有12 - 16个类可能会更好地解决这些问题,并提高模型性能!

3. Keras 中的技巧

如何在Keras MNIST中修改Dropout和限制权重的大小:

# dropout in input and hidden layers
# weight constraint imposed on hidden layers
# ensures the max norm of the weights does not exceed 5.

model = Sequential()
model.add(Dropout(0.2, input_shape=(784, ))) # dropout on the inputs
# this helps mimic noise or missing data

model.add(Dense(128, input_dim=784, 
               kernel_initializer='normal',
               activation='relu',
               kernel_constraint=maxnorm(5)))

model.add(Dropout(0.5))
model.add(Dense(128, kernel_initializer='normal',
               activation='tanh',
               kernel_constraint=maxnorm(5)))

model.add(Dropout(0.5))
model.add(Dense(1, kernel_initializer='normal',
               activation='sigmoid'))

4. Dropout最佳实践

[1] - 使用 20–50% 的,比较小的Dropout,建议 20%的输入(Inputs). 值取得太小,不起作用;值取得太大,不好收敛.

[2] - 在输入层和隐藏层上使用 Dropout. 这一方法已被证明可以提高深入学习的效果.

[3] - 使用较大的(带衰减率)学习速率(learning rate with decay),以及较大的动量(momentum).

[4] - 限制模型的权重!大的学习速率容易导致梯度爆炸. 通过对网络权值施加约束(如最大范数正则化(max-norm regularization),其大小为5 )可以改善结果.

[5] - 使用更大的网络. 在较大的网络上使用Dropout,可能会获得更好的性能,从而使模型有更多的机会学习独立表示(Independent representations).

给一个例子,如何在Keras中修改MNIST模型最后一层,输出14个类别:

from keras.layers.core import Activation, Dense

model.layers.pop() # defaults to last
model.outputs = [model.layers[-1].output]
model.layers[-1].outbound_nodes = []
model.add(Dense(14, activation='softmax'))

如何在网络的最初五层中固定网络的权值(Freeze weights):

for layer in model.layers[:5]:
    layer.trainable = False

此外,可以将该层的学习速率设置为零,或者使用参数的自适应学习算法,如 Adadelta 或 Adam. 这有点复杂,在 Caffe 等其他平台上可以更好地实现.

5. 预训练模型库

5.1. Keras

5.2. TensorFlow

5.3. Torch

5.4. Caffe

6. TensorBoard的Graph的可视化

了解模型的整体结构通常很重要.

下面给出一个例子,如何直接使用Python可视化训练的模型:

http://nbviewer.jupyter.org/github/tensorflow/tensorflow/blob/master/tensorflow/examples/tutorials/deepdream/deepdream.ipynb

Last modification:January 22nd, 2019 at 09:33 pm