黄石规划建设局网站,如何搭建一个企业子账号网站,上海做app开发公司,贵阳网站建设 网站制作概要
深度学习网络的训练可能会很慢、也可能无法收敛#xff0c;本文介绍使用keras进行深度神经网络训练的加速技巧#xff0c;包括解决梯度消失和爆炸问题的策略#xff08;参数初始化策略、激活函数策略、批量归一化、梯度裁剪#xff09;、重用预训练层方法、更快的优化…概要
深度学习网络的训练可能会很慢、也可能无法收敛本文介绍使用keras进行深度神经网络训练的加速技巧包括解决梯度消失和爆炸问题的策略参数初始化策略、激活函数策略、批量归一化、梯度裁剪、重用预训练层方法、更快的优化器算法以及使用正则化避免过拟合的算法。
目录
一、梯度消失或者梯度爆炸
解法方案一权重参数初始化
解决方案二非饱和激活函数 解决方案三批量归一化Batch Normalization 解决方案四梯度裁剪
二、重用预训练层
例子使用Keras进行迁移学习
三、更快的优化器
1. 动量优化
原始Momentum算法
Nesterov加速梯度
2. 自适应学习率算法
3. 学习率调度
四、通过正则化避免过拟合
L1和L2正则化
Dropout
最大范数正则化
五、实用指南 一、梯度消失或者梯度爆炸
梯度向下传播到较低层是梯度通常会越来越小结果是提督下降的更新导致较低层连接权重不变训练不能收敛到一个良好的解称为梯度消失相反的情况是提督越来越大各层需要更新很大的权重直到算法发散称为梯度爆炸。
梯度消失或者梯度爆炸是2000年代初期深度神经网络被抛弃的原因之一。
解法方案一权重参数初始化
理论每层大输出方差等于输入方差反方向流经某层的之前和之后的梯度具有相同的方差实际上很难满足只能采取折中方案
主要有3种初始化策略Xavier初始化或Glorot初始化、LeCun初始化、He初始化 默认情况下Keras使用均匀分布的Xavier初始化通过kernel_initializer进行设置
keras.layers.Dense(10, activationrelu, kernel_initializerhe_normal)
解决方案二非饱和激活函数
sigmoid函数存在饱和区容易导致梯度消失问题
ReLU函数通常比sigmoid函数表现要好但在输入小于0时梯度是0输出一直是0导致这些神经元“死亡”了严重的情况可能出现一般的神经元“死亡”。
ReLU变体LeakyReLU在输入小于0时为一个小斜率直线LeakyReLUmax(az,z)。 ReLU函数变体 ELUExponential Linear Unit指数线型单位 SELUScaled ELU为ELU的变体即加入一个参数lamda使得使用该激活函数网络时自动归一化的 相比ReLU函数ELU的主要问题是计算速度较慢 解决方案三批量归一化Batch Normalization
尽管权重参数初始化策略和激活函数策略可以缓解梯度消失和爆炸问题但仍然会出现这个时候通过BN可以减少这个问题且使得可以使用饱和激活函数。
BN层对于浅层网络可能效果不明显但对于深层网络非常有用 解决方案四梯度裁剪
对于梯度在反向传播期间设定一个阈值使得梯度不超过该阈值称为梯度裁剪可缓解梯度爆炸问题通常用在RNN中原因是RNN中难以使用BN。
实现方法为在创建优化器是设置clipvalue或者clipnorm。
optimizer keras.optimizers.SGD(clipvalue1.0) model.compile(lossmse, optimizeroptimizer)
上述代码将限制所有的梯度再-1到1之间这种设置可能会改变梯度的方向比如原始梯度向量为[0.9,100.0]梯度主要指向第二个轴方向按梯度裁剪后得到[0.9,1.0]基本指向两个轴对角线。要想不改变梯度方向则应该使用clipnorm进行裁剪比如clipnorm1.0则得到梯度向量为[0.009,0.999]
二、重用预训练层
从头开始训练非常大的DNN通常不是一个好的主意试图找到一个与现有问题类似的神经网络然后用该网络的较低层此技术称为迁移学习。它能够大大的加快训练速度减少对训练数据的要求。
假设你可以访问一个经过训练的DNN将图片分为100个不同类别其中包括动物、植物和车辆。现在需要训练DNN来对特质类型的车辆进行分类这些任务非常相似因此应该尝试利用第一个网络中的一部分。 通常应该替换掉原始模型的输出层而保留较底层因为对于新的任务有用的高级特征可能与原始任务存在很大的区别甚至对于新的任务没有正确数量的输出任务约相似保留的隐藏层就越多。
例子使用Keras进行迁移学习
假设Fashion MNIST数据集仅仅包括8个类别除了凉鞋和衬衫之外的所有类别有人在该数据集上训练了Keras模型并且获得了相当不错的性能精度90%我们称此模型为A。
现在需要处理另外一项任务要训练一个二分类器正例衬衫负例凉鞋但数据集非常小只有200张图片。你意识到新任务和任务A非常相似也许可以通过迁移学习会有所帮助让我们看看该怎么做。
首先我们需要加载模型A并基于该模型层创建一个新模型我们重用除输出层之外的所有层。
# 对模型A进行克隆这样在训练模型B_on_A的时候不回对模型的参数进行修改
model_A_clone keras.models.clone_model(model_A)
model_A_clone.set_weights(model_A.get_weights())model_B_on_A keras.models.Sequential(model_A_clone.layers[:-1]) # 去除模型A的输出层
model_B_on_A.add(keras.layers.Dense(1, activationsigmoid)) # 增加新模型的输出层# 由于新的输出层是随机初始化的在最初的几个轮次中会产生较大的错误存在较大的错误梯度这会破坏重用的权重。为避免这种情况在前几个轮次的训练时冻结重用层给新层一些时间来学习合理权重为此将重用层的训练属性设置为False。for layer in model_B_on_A.layers[:-1]: layer.trainable Falsemodel_B_on_A.compile(lossbinary_crossentropy,optimizerkeras.optimizers.SGD(learning_rate1e-3),metrics[accuracy])history model_B_on_A.fit(X_train_B, y_train_B, epochs4,validation_data(X_valid_B, y_valid_B))# 几轮训练后可以对重用层进行解冻参数可以更新for layer in model_B_on_A.layers[:-1]:layer.trainable Truemodel_B_on_A.compile(lossbinary_crossentropy,optimizerkeras.optimizers.SGD(learning_rate1e-3),metrics[accuracy])
history model_B_on_A.fit(X_train_B, y_train_B, epochs16,validation_data(X_valid_B, y_valid_B))
三、更快的优化器
训练一个非常大的神经网络可能会非常缓慢前面已经知道了五种加速训练的方法
权重参数初始化使用良好的激活函数批量归一化梯度裁剪重用预训练网络中的一部分
与常规的梯度下降相比使用更快的有花期也可以带来巨大的速度提升包括动量优化算法原始动量优化和Nesterov加速梯度以及自适应学习率优化AdaGrad、RMSProp、Adam、Nadam。
1. 动量优化
参考这两篇文章机器学习 | 优化——动量优化法更新方向优化 - 简书
优化算法Optimizer比较和总结 - 知乎
momentum算法思想权重参数更新时在一定程度上保留之前更新的方向同时又利用当前batch的梯度微调最终的更新方向简言之就是通过积累之前的动量来加速当前的梯度。
原始Momentum算法
下面一张图可以很直观地表达Momentum算法的思想。举个简单例子假设上次更新时梯度是往前走的这次更新的梯度算出来是往左走这变化太剧烈了所以我们来做个折中往左前方走。感觉上像是上次更新还带有一定的惯性。 具体算法如下 Momentum算法的优点 当某个参数在最近一段时间内的梯度方向不一致时其真实的参数更新幅度变小相反当在最近一段时间内的梯度方向都一致时其真实的参数更新幅度变大起到加速作用。 一般而言在迭代初期梯度方向都比较一致动量法会起到加速作用可以更快地到达最优点。在迭代后期梯度方向会取决不一致在收敛值附近震荡动量法会起到减速作用增加稳定性。从某种角度来说当前梯度叠加上部分的上次梯度一定程度上可以近似看作二阶梯度。 ——参考邱锡鹏《神经网络与深度学习》 Nesterov加速梯度
Nesterov 加速梯度Nesterov Accelerated GradientNAG也叫 Nesterov 动量法Nesterov Momentum是对Momentum算法的一种改进可以看成是Momentum算法的一种 变体。
动量法每下降一步都是由前面下降方向的一个累积和当前点的梯度方向组合而成。于是一位大神Nesterov就开始思考既然每一步都要将两个梯度方向历史梯度、当前梯度做一个合并再下降那为什么不先按照历史梯度往前走那么一小步按照前面一小步位置的“超前梯度”来做梯度合并呢
如此一来小球就可以先不管三七二十一先往前走一步在靠前一点的位置看到梯度然后按照那个位置再来修正这一步的梯度方向。
2. 自适应学习率算法
学习率是一个非常重要的超参数但是学习率是非常难确定的虽然可以通过多次训练来确定合适的学习率但是一般也不太确定多少次训练能够得到最优的学习率玄学事件对人为的经验要求比较高所以是否存在一些策略自适应地调节学习率的大小从而提高训练速度。 目前的自适应学习率优化算法主要有AdaGrad算法RMSProp算法Adam算法以及AdaDelta算法。
AdaGradAdaptive Gradient算法梯度更新时要除以“梯度的累积平方和根”因此梯度前期更新较快中后期分母上梯度累加的平方和会越来越大使得参数更新量趋近于0使得训练提前结束。
RMSPropRoot Mean Square Propagation算法梯度更新时“梯度的累积平方和根”会进行衰减最近一步“梯度平方和根”有一定权重。
AdamAdaptive Moment estimation 算法结合了动量优化和RMSProp思想像动量优化一样跟踪梯度指数衰减像RMSProp一样关注梯度平方和根的衰减。 3. 学习率调度
一般可以先设置较大的学习率然后逐步降低学习率以使得模型快速收敛。主要有幂调度、指数调度、分段恒定调度、性能调度、周期调度几种方法。
幂调度将学习率设置为lr lr0 / (1 steps / s)**cKeras uses c1经过s个步骤之后学习率下降为原来的1/2在keras实现幂调度非常简单
initial_learning_rate 0.1
decay_steps 10.0
decay_rate 0.5
learning_rate_fn keras.optimizers.schedules.InverseTimeDecay(initial_learning_rate, decay_steps, decay_rate)
optimizer tf.keras.optimizers.SGD(learning_rate learning_rate_fn)
指数调度
分段恒定调度对于一定的轮次使用一个固定的学习率比如前5个轮次使用0.16-20轮次使用0.0521轮次以后使用0.01以此类推。可以使用keras.optimizers.schedules.PiecewiseConstantDecay
step tf.Variable(0, trainableFalse)
boundaries [5, 20]
values [0.1, 0.05, 0.1]
learning_rate_fn keras.optimizers.schedules.PiecewiseConstantDecay(boundaries, values)# Later, whenever we perform an optimization step, we pass in the step.
learning_rate learning_rate_fn(step)
性能调度每N步测量一次验证误差并且当误差停止下降时讲学习率降低lamda倍。
四、通过正则化避免过拟合
L1和L2正则化
keras可以使用keras.regularizers.l1()、keras.regularizers.l2()、keras.regularizers.l1-l2()来分别实现l1、l2、以及l1l2正则化。
model keras.models.Sequential([keras.layers.Flatten(input_shape[28, 28]),keras.layers.Dense(300, activationelu,kernel_initializerhe_normal,kernel_regularizerkeras.regularizers.l2(0.01)),keras.layers.Dense(100, activationelu,kernel_initializerhe_normal,kernel_regularizerkeras.regularizers.l2(0.01)),keras.layers.Dense(10, activationsoftmax,kernel_regularizerkeras.regularizers.l2(0.01))
])
由于通常需要将相同的正则化应用于网络中的所有层上述方法重复了相同的参数切容易出错可以考虑使用python 的functools.partial()函数
from functools import partialRegularizedDense partial(keras.layers.Dense,activationelu,kernel_initializerhe_normal,kernel_regularizerkeras.regularizers.l2(0.01))model keras.models.Sequential([keras.layers.Flatten(input_shape[28, 28]),RegularizedDense(300),RegularizedDense(100),RegularizedDense(10, activationsoftmax)
])
Dropout
对深度学习dropout是最受欢迎的正则化技术之一由Geoffrey Hinton在2012年提出。在每个训练步骤中每个神经元不包括输出神经元都有暂时被“删除”的概率p但在下一步骤中可能处于激活状态超参数p称为dropout率一般设置为10%到50%。dropout只能用于训练不会用于预测因此在悬链完后我们需要将每个输入权重乘以保留概率1-p。 model keras.models.Sequential([keras.layers.Flatten(input_shape[28, 28]),keras.layers.Dropout(rate0.2),keras.layers.Dense(300, activationelu, kernel_initializerhe_normal),keras.layers.Dropout(rate0.2),keras.layers.Dense(100, activationelu, kernel_initializerhe_normal),keras.layers.Dropout(rate0.2),keras.layers.Dense(10, activationsoftmax)
])
model.compile(losssparse_categorical_crossentropy, optimizernadam, metrics[accuracy])
n_epochs 2
history model.fit(X_train_scaled, y_train, epochsn_epochs,validation_data(X_valid_scaled, y_valid))
最大范数正则化
对每个神经元限制传入链接的权重W使得, r称为最大范数超参数。最大范数正则化不会正则化损失添加到总体损失中而是在每个训练步骤后计算如果大于r则进行缩放。
五、实用指南
默认DNN超参数配置 如果网络时密集层的简单堆叠可以使用自归一化可以使用下表的参数配置
自归一化网络的DNN配置