《机器学习实战——基于Scikit-Learn和TensorFlow》
这是一本非常好的机器学习和深度学习入门书,既有基本理论讲解,也有实战代码示例。
我将认真阅读此书,并为每一章内容做一个知识笔记。
我会摘录一些原书中的关键语句和代码,若有错误请为我指出。
梯度下降在更低层网络连接权值更新方面基本没有改变,而且训练不会收敛到好的结果。 梯度消失问题
另一种现象是梯度越来越大,导致很多层的权值疯狂增大,使得算法发散。 梯度爆炸问题
受制于不稳定的梯度,不同层可能以完全不同的速度学习。
提出需要保持每一层的输入和输出的方差一致,并且需要在反向流动过某一层时,前后的方差也要一致。
该方法的折中方案公式为Xavier初始化。
ReLU激活函数的初始化方法有时称为He初始化。
结果表明深度神经网络中表现好的是ReLU激活函数。
因为它不稀释正值,且计算速度很快。
但是会出现dyingReLU问题:训练中一些神经元实际上已经死了,只输出0。
learkyReLU可以解决这个问题,LeakyReLU(z)=max(alpha*z,z)
2015年提出是ELU表现最好。
在每一层激活函数之前在模型里加一个操作,简单零中心化和归一化输入,之后再通过每层的两个新参数缩放和移动结果。
反向传播的过程中,简单地剪裁梯度。
一般仍然倾向于批量归一化。
从头开始训练庞大的DNN比较麻烦,可以去找一个能处理相似问题的已有的神经网络,然后重用低层网络。 迁移学习
一般来说,迁移学习只适用于新旧任务的输入具有相似的低层的特征的情况。
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")
其他框架,如theano训练出来的话,需要手动加载所有权重并将它赋给适当的参数。
低层权重不变,高层权重比较容易训练。
给优化器列出要训练的变量列表,除去低层的变量。
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)
冻结层不会变化,所以有可能将每一个训练实例的最高冻结层的输出缓存起来。
原始模型的输出层经常会被替换,因为对于新的任务基本没有什么用。
同样,原始模型的高隐藏层没有低层用处多。
首先,尝试冻结所有的复制层,然后训练你的模型观察效果。
接着尝试解冻一到两个顶部的隐藏层,用反向传播进行进行调整来观察是否有改善。
训练数据越多,越能解冻更多的层。
如果一直不能获得好的效果,而且训练数据很少,可尝试丢弃最高的一层或多层,然后重新冻结剩下的隐藏层。
一直迭代直到找到正确的重用层数。
如果有很多的训练数据,可以尝试替换顶部的隐藏层而不是丢弃它们,甚至可以添加一些隐藏层。
=> 自己已有的模型目录
=> 模型动物园
TensorFlow => https://github.com/tensorflow/models
caffe => https://goo.gl/XI02X3
逐层训练,利用无监督特性检测算法比如首先玻尔兹曼机或者自动编码器。
每一层都是基于提前训练好的图层(除去被冻结的训练层)的输出进行训练。
一旦所有层都用这个方式训练过之后,就可以用监督学习的方式(即反向传播)来位微调网络。
在辅助任务中训练第一个神经网络,可以轻松获得或者生成标记过的训练数据,然后重用该网络的低层来实现你的实际任务。
提高训练速度的方法:
m < = β m + η ∇ θ J ( θ ) m <= \beta m+\eta\nabla_\theta J (\theta) m<=βm+η∇θJ(θ)
θ < = θ − m \theta <= \theta-m θ<=θ−m
梯度为加速度。
Momentum会以越来越快的速度滑向谷底。
标准的动量值 β \beta β为0.9。
m < = β m + η ∇ θ J ( θ + β m ) m <= \beta m+\eta\nabla_\theta J(\theta+\beta m) m<=βm+η∇θJ(θ+βm)
θ < = θ − m \theta <= \theta-m θ<=θ−m
用未来的加速度更新现在的速度。
s < = s + ∇ θ J ( θ ) ⋅ ∇ θ J ( θ ) s <= s+\nabla_\theta J(\theta)\cdot \nabla_\theta J(\theta) s<=s+∇θJ(θ)⋅∇θJ(θ)
θ < = θ − η ∇ θ / s + ϵ \theta <= \theta -\eta \nabla_\theta /\sqrt{s+\epsilon} θ<=θ−η∇θ/s+ϵ
衰减了学习率。
适应性学习。
但是在训练神经网络时却经常很早就停滞了,在达到全局最优前算法就停止了。
尽管TensorFlow有此优化器,也不要使用它。
s < = β s + ( 1 − β ) ∇ θ J ( θ ) ⋅ ∇ θ J ( θ ) s <= \beta s+(1-\beta)\nabla_\theta J(\theta)\cdot \nabla_\theta J(\theta) s<=βs+(1−β)∇θJ(θ)⋅∇θJ(θ)
θ < = θ − η ∇ θ J ( θ ) / s + ϵ \theta <= \theta -\eta \nabla_\theta J(\theta) /\sqrt{s+\epsilon} θ<=θ−η∇θJ(θ)/s+ϵ
仅累计最近迭代中的梯度解决了这个问题。
m < = β 1 m + ( 1 − β 1 ) ∇ θ J ( θ ) m <= \beta_1 m+(1-\beta_1)\nabla_\theta J(\theta) m<=β1m+(1−β1)∇θJ(θ)
s < = β 2 s + ( 1 − β 2 ) ∇ θ J ( θ ) ⋅ ∇ θ J ( θ ) s <= \beta_2 s+(1-\beta_2)\nabla_\theta J(\theta)\cdot \nabla_\theta J(\theta) s<=β2s+(1−β2)∇θJ(θ)⋅∇θJ(θ)
m < = m / ( 1 − β 1 T ) m <= m/(1-\beta_1^T) m<=m/(1−β1T)
s < = s / ( 1 − β 2 T ) s <= s/(1-\beta_2^T) s<=s/(1−β2T)
θ < = θ − η m / s + ϵ \theta <= \theta-\eta m / \sqrt{s+\epsilon} θ<=θ−ηm/s+ϵ
以高学习速率开始,然后一旦它停止快速过程就降低速率。
监督学习速率。 学习计划
当验证集的性能开始下降时停止训练。
定期对验证集进行模型评估,表现好的保存起来。
加正则化加入到损失函数中。
最受欢迎的正则化技术。
超参数p为丢弃率,通常设置为50%。
dropout收敛变慢,但是如果微调合适,通常会收敛到一个更好的模型。
对每一个神经元,包含一个传入连接权值满足 ∥ w ∥ 2 ≤ r \left\|w\right\|_2 \leq r ∥w∥2≤r
w < = w r ∥ w ∥ 2 w <= w\frac{r}{\left\|w\right\|_2} w<=w∥w∥2r
降低r会增加正则化数目,同时帮助减少过度拟合。
缓解梯度消失/爆炸问题。
图像=>旋转、平移、大小。
略。