机器学习实战——基于Scikit-Learn和TensorFlow 阅读笔记 之 第十一章:训练深度神经网络

版权声明:访问者可将本博客提供的内容或服务用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯本网站及相关权利人的合法权利。除此以外,将本网站任何内容或服务用于其他用途时,须及时征得本网站及相关权利人的明确许可。 https://blog.csdn.net/qq_38262728/article/details/88558554
《机器学习实战——基于Scikit-Learn和TensorFlow》
这是一本非常好的机器学习和深度学习入门书,既有基本理论讲解,也有实战代码示例。
我将认真阅读此书,并为每一章内容做一个知识笔记。
我会摘录一些原书中的关键语句和代码,若有错误请为我指出。

在这里插入图片描述

第十一章 训练深度神经网络

1 梯度消失/爆炸问题

梯度下降在更低层网络连接权值更新方面基本没有改变,而且训练不会收敛到好的结果。 梯度消失问题
另一种现象是梯度越来越大,导致很多层的权值疯狂增大,使得算法发散。 梯度爆炸问题
受制于不稳定的梯度,不同层可能以完全不同的速度学习。

1.1 Xavier初始化和He初始化

提出需要保持每一层的输入和输出的方差一致,并且需要在反向流动过某一层时,前后的方差也要一致。
该方法的折中方案公式为Xavier初始化。

ReLU激活函数的初始化方法有时称为He初始化。

1.2 非饱和激活函数

结果表明深度神经网络中表现好的是ReLU激活函数。
因为它不稀释正值,且计算速度很快。

但是会出现dyingReLU问题:训练中一些神经元实际上已经死了,只输出0。

learkyReLU可以解决这个问题,LeakyReLU(z)=max(alpha*z,z)

2015年提出是ELU表现最好。

1.3 批量归一化

在每一层激活函数之前在模型里加一个操作,简单零中心化和归一化输入,之后再通过每层的两个新参数缩放和移动结果。

1.4 梯度裁剪

反向传播的过程中,简单地剪裁梯度。

一般仍然倾向于批量归一化。

2 重用预训练图层

从头开始训练庞大的DNN比较麻烦,可以去找一个能处理相似问题的已有的神经网络,然后重用低层网络。 迁移学习
一般来说,迁移学习只适用于新旧任务的输入具有相似的低层的特征的情况。

2.1 重用TensorFlow模型

reuse_vars = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES,
                               scope="hidden[123]") # regular expression
restore_saver = tf.train.Saver(reuse_vars) # to restore layers 1-3

init = tf.global_variables_initializer()
saver = tf.train.Saver()

with tf.Session() as sess:
    init.run()
    restore_saver.restore(sess, "./my_model_final.ckpt")

    for epoch in range(n_epochs):                                            # not shown in the book
        for X_batch, y_batch in shuffle_batch(X_train, y_train, batch_size): # not shown
            sess.run(training_op, feed_dict={X: X_batch, y: y_batch})        # not shown
        accuracy_val = accuracy.eval(feed_dict={X: X_valid, y: y_valid})     # not shown
        print(epoch, "Validation accuracy:", accuracy_val)                   # not shown

    save_path = saver.save(sess, "./my_new_model_final.ckpt")

2.2 重用其他框架的模型

其他框架,如theano训练出来的话,需要手动加载所有权重并将它赋给适当的参数。

2.3 冻结低层

低层权重不变,高层权重比较容易训练。

给优化器列出要训练的变量列表,除去低层的变量。

with tf.name_scope("train"):                                         # not shown in the book
    optimizer = tf.train.GradientDescentOptimizer(learning_rate)     # not shown
    train_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES,
                                   scope="hidden[34]|outputs")
    training_op = optimizer.minimize(loss, var_list=train_vars)

2.4 缓存冻结层

冻结层不会变化,所以有可能将每一个训练实例的最高冻结层的输出缓存起来。

2.5 调整、丢弃或替换高层

原始模型的输出层经常会被替换,因为对于新的任务基本没有什么用。

同样,原始模型的高隐藏层没有低层用处多。

首先,尝试冻结所有的复制层,然后训练你的模型观察效果。

接着尝试解冻一到两个顶部的隐藏层,用反向传播进行进行调整来观察是否有改善。
训练数据越多,越能解冻更多的层。

如果一直不能获得好的效果,而且训练数据很少,可尝试丢弃最高的一层或多层,然后重新冻结剩下的隐藏层。
一直迭代直到找到正确的重用层数。

如果有很多的训练数据,可以尝试替换顶部的隐藏层而不是丢弃它们,甚至可以添加一些隐藏层。

2.6 模型动物园

=> 自己已有的模型目录
=> 模型动物园
TensorFlow => https://github.com/tensorflow/models
caffe => https://goo.gl/XI02X3

2.7 无监督的预训练

逐层训练,利用无监督特性检测算法比如首先玻尔兹曼机或者自动编码器。
每一层都是基于提前训练好的图层(除去被冻结的训练层)的输出进行训练。
一旦所有层都用这个方式训练过之后,就可以用监督学习的方式(即反向传播)来位微调网络。

2.8 辅助任务中的预训练

在辅助任务中训练第一个神经网络,可以轻松获得或者生成标记过的训练数据,然后重用该网络的低层来实现你的实际任务。

3 快速优化器

提高训练速度的方法:

  • 连接权重上应用一个良好的初始化策略
  • 良好的激活函数
  • 批量归一化
  • 重用部分预处理网络

3.1 Momentum优化

m < = β m + η θ J ( θ ) m <= \beta m+\eta\nabla_\theta J (\theta)
θ < = θ m \theta <= \theta-m

梯度为加速度。

Momentum会以越来越快的速度滑向谷底。

标准的动量值 β \beta 为0.9。

3.2 Nesterov梯度加速

m < = β m + η θ J ( θ + β m ) m <= \beta m+\eta\nabla_\theta J(\theta+\beta m)
θ < = θ m \theta <= \theta-m

用未来的加速度更新现在的速度。

3.3 AdaGrad

s < = s + θ J ( θ ) θ J ( θ ) s <= s+\nabla_\theta J(\theta)\cdot \nabla_\theta J(\theta)
θ < = θ η θ / s + ϵ \theta <= \theta -\eta \nabla_\theta /\sqrt{s+\epsilon}

衰减了学习率。
适应性学习。

但是在训练神经网络时却经常很早就停滞了,在达到全局最优前算法就停止了。
尽管TensorFlow有此优化器,也不要使用它。

3.4 RMSProp

s < = β s + ( 1 β ) θ J ( θ ) θ J ( θ ) s <= \beta s+(1-\beta)\nabla_\theta J(\theta)\cdot \nabla_\theta J(\theta)
θ < = θ η θ J ( θ ) / s + ϵ \theta <= \theta -\eta \nabla_\theta J(\theta) /\sqrt{s+\epsilon}

仅累计最近迭代中的梯度解决了这个问题。

3.5 Adam优化

m < = β 1 m + ( 1 β 1 ) θ J ( θ ) m <= \beta_1 m+(1-\beta_1)\nabla_\theta J(\theta)
s < = β 2 s + ( 1 β 2 ) θ J ( θ ) θ J ( θ ) s <= \beta_2 s+(1-\beta_2)\nabla_\theta J(\theta)\cdot \nabla_\theta J(\theta)
m < = m / ( 1 β 1 T ) m <= m/(1-\beta_1^T)
s < = s / ( 1 β 2 T ) s <= s/(1-\beta_2^T)
θ < = θ η m / s + ϵ \theta <= \theta-\eta m / \sqrt{s+\epsilon}

3.6 学习速率调度

以高学习速率开始,然后一旦它停止快速过程就降低速率。

监督学习速率。 学习计划

  • 预定分段常数学习速率
  • 性能调度
  • 指数调度
  • 功能调度

4 通过正则化避免过度拟合

4.1 提前停止

当验证集的性能开始下降时停止训练。

定期对验证集进行模型评估,表现好的保存起来。

4.2 l1和l2正则化

加正则化加入到损失函数中。

4.3 dropout

最受欢迎的正则化技术。

超参数p为丢弃率,通常设置为50%。

dropout收敛变慢,但是如果微调合适,通常会收敛到一个更好的模型。

4.4 最大范数正则化

对每一个神经元,包含一个传入连接权值满足 w 2 r \left\|w\right\|_2 \leq r

w < = w r w 2 w <= w\frac{r}{\left\|w\right\|_2}

降低r会增加正则化数目,同时帮助减少过度拟合。

缓解梯度消失/爆炸问题。

4.5 数据扩充

图像=>旋转、平移、大小。

5 实用指南

略。

猜你喜欢

转载自blog.csdn.net/qq_38262728/article/details/88558554