深层DNN可能出现的问题:

  • 梯度消失、梯度爆炸问题,影响深度神经网络,导致底层训练困难
  • 网络庞大,训练缓慢
  • 容易overfitting

本章将会探讨梯度消失的流行解决方案,训练大模型明显提速的优化器(相对于平坦梯度下降 ),浏览针对大型神经网络的正则化技术。

Vanishing/Exploding Gradients Problems

第十章中讲到:反向传播算法再输出层反向作用到输入层的过程中传播误差梯度,一旦算法计算出成本函数梯度,就会根据梯度修正每一个参数。
DNN受制于不稳定梯度,不同层可能以完全不同速度来学习。

  • 梯度消失:梯度随着算法进展到更底层越来越小,导致梯度下降在更底层网络连接权值更新上基本没有改变,训练收敛不到好的结果。
  • 梯度爆炸:梯度随着算法进展到更底层越来越大,导致很多层的权值疯狂增大,使得算法发散(常出现在循环神经网络)

梯度消失的解决:用逻辑S激活函数和权重初始化技术结合(均值为0,方差为1正态分布随机初始化/均值为0的双曲正切函数):每一层输出方差比输入方差大很多,依层增加到激活函数最高层饱和。

如上图逻辑激活函数:输入增大(正或负方向),函数在0或1饱和,导数接近0——反向传播起作用时,并没有梯度通过网络反向作用,同时反向传播至顶层几乎没有梯度被稀释,所以也基本上没给低层留下什么。

Xavier and He Initialization

缓和梯度消失:让信号在两个方向都正确流动,预测保持正向,反向传播梯度保持反方向。不希望信号消亡、稀释、爆炸。要保持每一层输入输出方差一直,反向流动方差也要一致(很难实现),折中方案:连接权重按如下公式随机初始化。
如图所示为Xavier(Glorot)初始化:
ReLU激活函数及其变种(ELU函数)的初始化称为He初始化。

TF用tf.layers.dense()代替tensorflow.contrib.layers.fully_connected(),默认He初始化:

import tensorflow as tfreset_graph()n_inputs = 28 * 28  # MNIST
n_hidden1 = 300X = tf.placeholder(tf.float32, shape=(None, n_inputs), name="X")he_init = tf.variance_scaling_initializer()
hidden1 = tf.layers.dense(X, n_hidden1, activation=tf.nn.relu,kernel_initializer=he_init, name="hidden1")

Nonsaturating Activation Functions(非饱和激活函数)

ReLU在DNN表现好的原因是计算快,同时并不稀释正值,但会出现dying ReLU问题:当神经元权重更新到神经元输入的总权重为负值时,神经元开始输出0,除非ReLU的梯度为0且输入为负,则神经元不会开始工作。

解决此问题就要使用ReLU变种——如leaky ReLU(带泄露性整流函数):LeakyReLU_α=max(αz,z)。α表示函数泄露程度,即z<0的坡度,默认设为0.01(既保证不会死,又保证能醒过来)。(其实设0.2结果更好,但默认为0.01)

列举几个ReLU变种的激活函数:
RReLU:在训练中α为给定区间随机值,测试为固定平均值,可做正则降低overfitting风险
PReLU:α在训练中学习(作为反向传播参数),在大图片集表现好,小数据集容易overfitting。

ELU(加速线性单元)优于ReLU所有变种(训练时间更短,测试集表现更好),定义如下:


与ReLU不同之处:

  • z<0为负,允许单元平均输出接近0,缓解梯度消失,α通常设为1(用来z为极大负数接近本值)
  • z<0有一非零梯度,避免单元消失
  • 函数整体平滑,z=0处没有抖动,提高GB

ELU主要缺陷为,计算速度比ReLU和其变种慢(即使用更快收敛弥补)

DNN隐藏层使用激活函数优先顺序:ELU>leaky ReLU>ReLU>tanh>S(逻辑函数)
关注性能:leaky ReLU;不想改变超参数,默认α(leaky ReLU:0.01,ELU:1);时间性能充沛,交叉验证评估;过拟合:RReLU;大训练集:PReLU

TF调用:

reset_graph()X = tf.placeholder(tf.float32, shape=(None, n_inputs), name="X")def leaky_relu(z, name=None):return tf.maximum(0.01 * z, z, name=name)hidden1 = tf.layers.dense(X, n_hidden1, activation=leaky_relu, name="hidden1")

Batch Normalization(批量一体化)

He初始化+ELU可以降低梯度消失/爆炸,但不能保证,使用批量一体化(BN)解决:在每一层激活函数之前在模型里加简单零中心化和归一化输入,再通过每层两个新参数,一个用来缩放结果,一个用来移动结果——让模型学会最佳规模和每层输入平均值。

零中心化和归一化输入需要评估输入平均值和标准方差,操作如下:

测试期间可以 用整个训练集平均值和方差替代经验平均值和经验标准方差。γ(scale), β (offset), μ (mean), and σ (standard deviation)为每一批量归一化层来学习的。

使用饱和激活函数(如tanh)和逻辑激活函数有效的改善了梯度消失问题,也可以使用更高的学习率,不仅减少了训练步骤而且效果很好,BN还可以同时正则化,降低其他正则化技术需求。
BN同时增加了复杂度,预测运算速度变慢。

一旦找到合适的γ(scale), β (offset),训练速度会迅速提升,否则很慢。

TF应用ELU

建图

reset_graph()n_inputs = 28 * 28  # MNIST
n_hidden1 = 300
n_hidden2 = 100
n_outputs = 10

定义X,y:

X = tf.placeholder(tf.float32, shape=(None, n_inputs), name="X")
y = tf.placeholder(tf.int32, shape=(None), name="y")

定义DNN:


with tf.name_scope("dnn"):hidden1 = tf.layers.dense(X, n_hidden1, activation=leaky_relu, name="hidden1")hidden2 = tf.layers.dense(hidden1, n_hidden2, activation=leaky_relu, name="hidden2")logits = tf.layers.dense(hidden2, n_outputs, name="outputs")

定义成本函数loss:

with tf.name_scope("loss"):xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y, logits=logits)loss = tf.reduce_mean(xentropy, name="loss")

定义optimizer:

learning_rate = 0.01with tf.name_scope("train"):optimizer = tf.train.GradientDescentOptimizer(learning_rate)training_op = optimizer.minimize(loss)

定义eval评估:

with tf.name_scope("eval"):correct = tf.nn.in_top_k(logits, y, 1)accuracy = tf.reduce_mean(tf.cast(correct, tf.float32))

初始变量并保存:

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

加载数据(下载到本地),划分选集:

from keras.datasets import mnist
(X_train, y_train), (X_test, y_test) =mnist.load_data('mnist/mnist.npz')
X_train = X_train.astype(np.float32).reshape(-1, 28*28) / 255.0
X_test = X_test.astype(np.float32).reshape(-1, 28*28) / 255.0
y_train = y_train.astype(np.int32)
y_test = y_test.astype(np.int32)
X_valid, X_train = X_train[:5000], X_train[5000:]
y_valid, y_train = y_train[:5000], y_train[5000:]

定义取mini-batch算法:

def shuffle_batch(X, y, batch_size):rnd_idx = np.random.permutation(len(X))n_batches = len(X) // batch_sizefor batch_idx in np.array_split(rnd_idx, n_batches):X_batch, y_batch = X[batch_idx], y[batch_idx]yield X_batch, y_batch

小批量训练:

n_epochs = 40
batch_size = 50with tf.Session() as sess:init.run()for epoch in range(n_epochs):for X_batch, y_batch in shuffle_batch(X_train, y_train, batch_size):sess.run(training_op, feed_dict={X: X_batch, y: y_batch})if epoch % 5 == 0:acc_batch = accuracy.eval(feed_dict={X: X_batch, y: y_batch})acc_valid = accuracy.eval(feed_dict={X: X_valid, y: y_valid})print(epoch, "Batch accuracy:", acc_batch, "Validation accuracy:", acc_valid)save_path = saver.save(sess, "./my_model_final.ckpt")

引用ReLU和SELU见jupyter

Implementing Batch Normalization with TensorFlow

过长不列举,见jupyter

Gradient Clipping

减轻梯度爆炸的另一种方法时应用GC(一般批量归一化),保证不超过阈值(对循环神经网络很有效)


threshold = 1.0optimizer = tf.train.GradientDescentOptimizer(learning_rate)
grads_and_vars = optimizer.compute_gradients(loss)
capped_gvs = [(tf.clip_by_value(grad, -threshold, threshold), var)for grad, var in grads_and_vars]#创建裁剪梯度
training_op = optimizer.apply_gradients(capped_gvs)#应用裁剪后的梯度

Reusing Pretrained Layers

迁移学习(transfer learning):找相似的神经网络,重用底层网络。这样能极大提升训练速度,很大程度减少训练数据。


迁移学习只适用于新旧任务有相似的底层特征情况。

Reusing a TensorFlow Model

load图结构:

reset_graph()
saver = tf.train.import_meta_graph("./my_model_final.ckpt.meta")

你可以通过列举操作的方式来获取你想要训练重用的操作:

for op in tf.get_default_graph().get_operations():#列举所有操作print(op.name)

你也可以通过tfgraphviz看下图:

import tfgraphviz as tfg
tfg.board(tf.get_default_graph()).view()

知道你所需要的操作后,你就可以用get_operation_by_name()或get_tensor_by_name() 来操作:

X = tf.get_default_graph().get_tensor_by_name("X:0")
y = tf.get_default_graph().get_tensor_by_name("y:0")accuracy = tf.get_default_graph().get_tensor_by_name("eval/accuracy:0")training_op = tf.get_default_graph().get_operation_by_name("GradientDescent")

如果你只原模型作者,你可以通过建一个所有重要操作集合来方便复用:

for op in (X, y, accuracy, training_op):tf.add_to_collection("my_important_ops", op)
#复用
X, y, accuracy, training_op = tf.get_collection("my_important_ops")

回复模型,训练自己的数据:

在这里插入代码片with tf.Session() as sess:saver.restore(sess, "./my_model_final.ckpt")#训练模型

来测试以下表现如何:

在这里插入代码片with tf.Session() as sess:saver.restore(sess, "./my_model_final.ckpt")for epoch in range(n_epochs):for X_batch, y_batch in shuffle_batch(X_train, y_train, batch_size):sess.run(training_op, feed_dict={X: X_batch, y: y_batch})accuracy_val = accuracy.eval(feed_dict={X: X_valid, y: y_valid})print(epoch, "Validation accuracy:", accuracy_val)save_path = saver.save(sess, "./my_new_model_final.ckpt")

如果你只想用低层,用import_meta_graph()要加载整个图,你可以忽略其他,下面这个例子,我们复用低三层,再新建第四层、输出层,用一个新优化器最小化它,用另一个saver存储,再初始化。


reset_graph()n_hidden4 = 20  # new layer
n_outputs = 10  # new layersaver = tf.train.import_meta_graph("./my_model_final.ckpt.meta")X = tf.get_default_graph().get_tensor_by_name("X:0")
y = tf.get_default_graph().get_tensor_by_name("y:0")hidden3 = tf.get_default_graph().get_tensor_by_name("dnn/hidden3/Relu:0")new_hidden4 = tf.layers.dense(hidden3, n_hidden4, activation=tf.nn.relu, name="new_hidden4")
new_logits = tf.layers.dense(new_hidden4, n_outputs, name="new_outputs")with tf.name_scope("new_loss"):xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y, logits=new_logits)loss = tf.reduce_mean(xentropy, name="loss")with tf.name_scope("new_eval"):correct = tf.nn.in_top_k(new_logits, y, 1)accuracy = tf.reduce_mean(tf.cast(correct, tf.float32), name="accuracy")with tf.name_scope("new_train"):optimizer = tf.train.GradientDescentOptimizer(learning_rate)training_op = optimizer.minimize(loss)init = tf.global_variables_initializer()
new_saver = tf.train.Saver()with tf.Session() as sess:init.run()saver.restore(sess, "./my_model_final.ckpt")for epoch in range(n_epochs):for X_batch, y_batch in shuffle_batch(X_train, y_train, batch_size):sess.run(training_op, feed_dict={X: X_batch, y: y_batch})accuracy_val = accuracy.eval(feed_dict={X: X_valid, y: y_valid})print(epoch, "Validation accuracy:", accuracy_val)save_path = new_saver.save(sess, "./my_new_model_final.ckpt")

不用import_meta_graph而用原模型直接复用的代码再jupyter上(对应书),此不展示了。

Reusing Models from Other Frameworks

如果已有模型用其他框架训练,则需要手动加载所有权重,并赋值。
举个例子:

reset_graph()
n_inputs = 2
n_hidden1 = 3original_w = [[1., 2., 3.], [4., 5., 6.]] # Load the weights from the other framework
original_b = [7., 8., 9.]                 # Load the biases from the other frameworkX = tf.placeholder(tf.float32, shape=(None, n_inputs), name="X")
hidden1 = tf.layers.dense(X, n_hidden1, activation=tf.nn.relu, name="hidden1")
# [...] Build the rest of the model# Get a handle on the assignment nodes for the hidden1 variables
graph = tf.get_default_graph()
assign_kernel = graph.get_operation_by_name("hidden1/kernel/Assign")
assign_bias = graph.get_operation_by_name("hidden1/bias/Assign")
init_kernel = assign_kernel.inputs[1]
init_bias = assign_bias.inputs[1]init = tf.global_variables_initializer()with tf.Session() as sess:sess.run(init, feed_dict={init_kernel: original_w, init_bias: original_b})# [...] Train the model on your new taskprint(hidden1.eval(feed_dict={X: [[10.0, 11.0]]}))  # not shown in the book

另一个做法是建一个专门分配节点和转为辐,虽然不高效,但比较清晰:

reset_graph()n_inputs = 2
n_hidden1 = 3original_w = [[1., 2., 3.], [4., 5., 6.]] # Load the weights from the other framework
original_b = [7., 8., 9.]                 # Load the biases from the other frameworkX = tf.placeholder(tf.float32, shape=(None, n_inputs), name="X")
hidden1 = tf.layers.dense(X, n_hidden1, activation=tf.nn.relu, name="hidden1")
# [...] Build the rest of the model# Get a handle on the variables of layer hidden1
with tf.variable_scope("", default_name="", reuse=True):  # root scopehidden1_weights = tf.get_variable("hidden1/kernel")hidden1_biases = tf.get_variable("hidden1/bias")# Create dedicated placeholders and assignment nodes
original_weights = tf.placeholder(tf.float32, shape=(n_inputs, n_hidden1))
original_biases = tf.placeholder(tf.float32, shape=n_hidden1)
assign_hidden1_weights = tf.assign(hidden1_weights, original_weights)
assign_hidden1_biases = tf.assign(hidden1_biases, original_biases)init = tf.global_variables_initializer()with tf.Session() as sess:sess.run(init)sess.run(assign_hidden1_weights, feed_dict={original_weights: original_w})sess.run(assign_hidden1_biases, feed_dict={original_biases: original_b})# [...] Train the model on your new taskprint(hidden1.eval(feed_dict={X: [[10.0, 11.0]]}))

此时可以用get_collection或get_tensor_by_name

Freezing the Lower Layers

若第一个DNN底层已经学会某些我们所需要的检测低级特征,则你可以重用低层,即训练新DNN时,通常冻结权重——低层权重固定,高层权重容易训练。做法:给优化器列出要训练的变量列表,除去低层变量。

with tf.name_scope("train"):                                         # not shown in the bookoptimizer = tf.train.GradientDescentOptimizer(learning_rate)     # not shown#获取所有在隐藏层3、4及输出层的可训练变量(排除隐藏层1、隐藏层2)train_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES,scope="hidden[34]|outputs")#将可训练变量的受限列表传给优化器的minimize()函数                              training_op = optimizer.minimize(loss, var_list=train_vars)

即层1层2冻结,称为冻结层。其余代码见jupyter。

Caching the Frozen Layers

冻结层不会变化,所以可以将每一个训练实例的最高冻结层输出缓存。只需要在训练实例中遍历一次冻结层,所以速度飞提:h2_cache = sess.run(hidden2, feed_dict={X: X_train})甚至能在低层跑完数据。

训练中需要批量构建隐藏层的输出,feed the train:

import numpy as npn_batches = len(X_train) // batch_sizewith tf.Session() as sess:init.run()restore_saver.restore(sess, "./my_model_final.ckpt")h2_cache = sess.run(hidden2, feed_dict={X: X_train})h2_cache_valid = sess.run(hidden2, feed_dict={X: X_valid}) # not shown in the bookfor epoch in range(n_epochs):shuffled_idx = np.random.permutation(len(X_train))hidden2_batches = np.array_split(h2_cache[shuffled_idx], n_batches)y_batches = np.array_split(y_train[shuffled_idx], n_batches)for hidden2_batch, y_batch in zip(hidden2_batches, y_batches):#运行之前定义好的操作(冻结层1、2),把隐藏层2批量输出sess.run(training_op, feed_dict={hidden2:hidden2_batch, y:y_batch})accuracy_val = accuracy.eval(feed_dict={hidden2: h2_cache_valid, # not showny: y_valid})             # not shownprint(epoch, "Validation accuracy:", accuracy_val)               # not shownsave_path = saver.save(sess, "./my_new_model_final.ckpt")

Tweaking(调整), Dropping(丢弃), or Replacing the Upper Layers

原始输出层经常被替换。原始高隐藏层经常丢弃,需要确定新的层数重用。

首先冻结所有复制层,观察结果,逐渐解冻一到两个顶部隐藏层,用反向传播进行调整观察是否有改善,训练数据越多,越能解冻更多的层。
若不能得到好效果且训练数据很少,则尝试丢弃一层至多层,直至找到适合层数,数据多则可能需要替换或者添加隐藏层。

Model Zoos

几个比较流形模型库:

  • TensorFlow自己的库: 包含先进图片识别(VGG、Inception、Resnet等)包括代码、预训练模型、工具等。
  • Caffe:包括很多CV模型(LeNet, AlexNet, ZFNet, GoogLeNet, VGGNet, inception),在各种数据集(ImageNet, Places Database, CIFAR10等)经过训练,转换器

Unsupervised Pretraining

如果要完成一个没有太多标记训练数据的复杂任务,且没有找到在近似任务上训练过的模型。则可以运行无监督预训练:逐层开始从最低处训练无标记的训练数据,利用非监督特性检测算法(RBM或自动编码器),每一层都基于提前训练好的图层(除去被冻结过的训练层)的输出计算。一旦所有层使用此方式训练过后,则可使用监督学习(反向传播)微调网络。

Pretraining on an Auxiliary Task(辅助任务中地预训练)

最后一个选择是在辅助任务中训练第一个神经网络,可以轻松获得生成标记过的训练数据,重用该网络低层实现实现。即第一个神经网络的低层会学习,可能被第二个神经网络重用的特征检测器。这样用很少的数据就可以训练出一个很好的模型。
比如我们训练一个语言识别系统,手机到无标记数据全都设为True,破坏True的实例形成新实例,标记为Flase,然后训练第一个神经网络区分好坏。重用这个网络低层有助于很多语言处理任务。

另一种方法是训练第一个神经网络,让他输出每个训练实例得分,利用成本函数,确保T比F实例得分高,称为最大边界学习。

Faster Optimizers

训练一个很大的DNN可能会非常慢,有以下五个方法来提高训练速度:

  • 在连接权重上应用一个良好的初始化策略
  • 使用一个良好的激活函数
  • 使用批量一体化
  • 重用部分预处理网络
  • 使用快速优化器(本节)

快速优化器:

  • Momentum(动量优化)
  • NAG(Nesterov梯度加速)
  • AdaGrad
  • RMSProp
  • Adam优化

结论就是几乎一直用Adam优化,所以一般情况下直接使用就行了,默认参数表现良好,若要得到更好的方案需要微调。
默认用AdamOptimizer代替GradientDescentOptimizer就可以了;

optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate

Learning Rate Scheduling

学习率设置过高,则可能产生分歧, 设置过低,可能要通过长时间训练才能收敛到最优解。理想的学习速率学习速度非常快。
学习计划:从一个高学习率开始,一旦停止快速过程就降低速率,得到一个比最优学习速率更快速的方案,获得一个比固定学习速率更快速的方案。
常用学习计划

  • Predetermined piecewise constant learning rate(预约分段常数学习速率):搞清楚正确学习速率与使用时间
  • Performance scheduling(性能调度):每N个步骤测量验证错误,当错误停止出现时,将学习率设为1/λ
  • Exponential scheduling(指数调度):学习速率: η(t) = η0 *10^–t/r,学习速率每r步下降10
  • Power scheduling(功率调度): η(t) = η0*(1 + t/r)^–c,c固定为1,学习速率较慢。

TF实现:

with tf.name_scope("train"):       # not shown in the bookinitial_learning_rate = 0.1decay_steps = 10000decay_rate = 1/10global_step = tf.Variable(0, trainable=False, name="global_step")#不可训练变量跟踪当前训练迭代数learning_rate = tf.train.exponential_decay(initial_learning_rate, global_step,decay_steps, decay_rate)#定义指数衰减学习速率optimizer = tf.train.MomentumOptimizer(learning_rate, momentum=0.9)training_op = optimizer.minimize(loss, global_step=global_step)

AdaGrad, RMSProp, and Adam在训练中自动降低了学习速率,不需要额外加入学习计划,其他算法,用指数衰减或性能调度可有效提高收敛速度。

Avoiding Overfitting Through Regularization

神经网络最受欢迎正则化技术:

  • 提前停止
  • l1和l2正则化
  • dropout
  • 最大范数正则化
  • 数据扩充

Early Stopping

当验证集的性能开始下降时停止训练,避免过度拟合(可以通过结合其他正则化技术获得更高性能)

#ℓ1 and ℓ2 Regularization

通过l1和l2正则化约束一个神经网络的连接权重(通常不是其方差)
TF实现:将适当的正则项加在成本函数中
假设只有一个隐藏层W1,输出层W2

with tf.name_scope("loss"):xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y,logits=logits)base_loss = tf.reduce_mean(xentropy, name="avg_xentropy")reg_losses = tf.reduce_sum(tf.abs(W1)) + tf.reduce_sum(tf.abs(W2))loss = tf.add(base_loss, scale * reg_losses, name="loss")

若层数较多,首先用partial()建层:

scale = 0.001
my_dense_layer = partial(tf.layers.dense, activation=tf.nn.relu,kernel_regularizer=tf.contrib.layers.l1_regularizer(scale))with tf.name_scope("dnn"):hidden1 = my_dense_layer(X, n_hidden1, name="hidden1")hidden2 = my_dense_layer(hidden1, n_hidden2, name="hidden2")logits = my_dense_layer(hidden2, n_outputs, activation=None,name="outputs")

把正则化损失加到基本损失函数上

with tf.name_scope("loss"):                                     # not shown in the bookxentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(  # not shownlabels=y, logits=logits)                                # not shownbase_loss = tf.reduce_mean(xentropy, name="avg_xentropy")   # not shownreg_losses = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)loss = tf.add_n([base_loss] + reg_losses, name="loss")

Dropout

dropout是最受欢迎的DNN正则化技术,加上就能提高正确度。
原理就是每一个步骤,每一个神经元都有暂时被丢弃的可能性p(这次训练步骤被完全忽略,下一步会被激活),这就是丢弃率,通常设为50%,训练后,神经元不会再被丢弃。

dropout的强大还在于,每一个训练步骤都会创建一个独立的神经网络,所以可能会创建很多神经网络,最后得到的神经网络就是这些较小神经网络的集合。
一个小细节,假设p=50,在测试期间,一个神经元将会被连接到训练期间输入神经元的两倍,所以需要在训练之后给每一个神经元的输入权重乘以0.5(1-p),也叫保持可能性。

TF中实现dropput,直接在输入层和每一个隐藏层输出调用dropput(),训练中,函数会随机丢弃一些项(设为0),给剩下的项输出除以保持可能性。

reset_graph()X = tf.placeholder(tf.float32, shape=(None, n_inputs), name="X")
y = tf.placeholder(tf.int32, shape=(None), name="y")training = tf.placeholder_with_default(False, shape=(), name='training')dropout_rate = 0.5  # == 1 - keep_prob
X_drop = tf.layers.dropout(X, dropout_rate, training=training)
#overfitting 提高dropout_rate,underfitting降低dropout_rate
with tf.name_scope("dnn"):hidden1 = tf.layers.dense(X_drop, n_hidden1, activation=tf.nn.relu,name="hidden1")hidden1_drop = tf.layers.dropout(hidden1, dropout_rate, training=training)hidden2 = tf.layers.dense(hidden1_drop, n_hidden2, activation=tf.nn.relu,name="hidden2")hidden2_drop = tf.layers.dropout(hidden2, dropout_rate, training=training)logits = tf.layers.dense(hidden2_drop, n_outputs, name="outputs")with tf.name_scope("loss"):xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y, logits=logits)loss = tf.reduce_mean(xentropy, name="loss")with tf.name_scope("train"):optimizer = tf.train.MomentumOptimizer(learning_rate, momentum=0.9)training_op = optimizer.minimize(loss)    with tf.name_scope("eval"):correct = tf.nn.in_top_k(logits, y, 1)accuracy = tf.reduce_mean(tf.cast(correct, tf.float32))init = tf.global_variables_initializer()
saver = tf.train.Saver()n_epochs = 20
batch_size = 50with tf.Session() as sess:init.run()for epoch in range(n_epochs):for X_batch, y_batch in shuffle_batch(X_train, y_train, batch_size):sess.run(training_op, feed_dict={X: X_batch, y: y_batch, training: True})#训练时设True,测试时设Falseaccuracy_val = accuracy.eval(feed_dict={X: X_valid, y: y_valid})print(epoch, "Validation accuracy:", accuracy_val)save_path = saver.save(sess, "./my_model_final.ckpt")

dropout虽然收敛挺慢,但微调合适后会得到更好模型。

Max-Norm Regularization

最大范数正则化:对于每个神经元,包含一个传入连接权重w满足 ∥ w ∥2 ≤ r,r最大范数超参数,|| ||2是l2范数。
操作:每一次训练步骤后计算 ∥ w ∥2,如果需要会裁剪(w=w*r/∥ w ∥2)
降低r会增加正则化数目,减少过度拟合,最大范数正则化可以同时帮助缓解梯度消失/爆炸(若不使用批量归一化)
TF没有提供现成最大范数正则化器,实现:
构建一个结点clipped_weights ,该节点沿着第二个轴削减weights变量,使每一个行向量最大范数为1.0

threshold = 1.0
weights = tf.get_default_graph().get_tensor_by_name("hidden1/kernel:0")
clipped_weights = tf.clip_by_norm(weights, clip_norm=threshold, axes=1)
clip_weights = tf.assign(weights, clipped_weights)

每一个训练步骤后执行:

with tf.Session() as sess:                                              # not shown in the bookinit.run()                                                          # not shownfor epoch in range(n_epochs):                                       # not shownfor X_batch, y_batch in shuffle_batch(X_train, y_train, batch_size): # not shownsess.run(training_op, feed_dict={X: X_batch, y: y_batch})clip_weights.eval()clip_weights2.eval()                                        # not shownacc_valid = accuracy.eval(feed_dict={X: X_valid, y: y_valid})   # not shownprint(epoch, "Validation accuracy:", acc_valid)                 # not shownsave_path = saver.save(sess, "./my_model_final.ckpt")

定义一个max_norm_regularizer()获取权重weight:

def max_norm_regularizer(threshold, axes=1, name="max_norm",collection="max_norm"):def max_norm(weights):clipped = tf.clip_by_norm(weights, clip_norm=threshold, axes=axes)clip_weights = tf.assign(weights, clipped, name=name)tf.add_to_collection(collection, clip_weights)return None # there is no regularization loss termreturn max_norm

调用:


max_norm_reg = max_norm_regularizer(threshold=1.0)with tf.name_scope("dnn"):hidden1 = tf.layers.dense(X, n_hidden1, activation=tf.nn.relu,kernel_regularizer=max_norm_reg, name="hidden1")hidden2 = tf.layers.dense(hidden1, n_hidden2, activation=tf.nn.relu,kernel_regularizer=max_norm_reg, name="hidden2")logits = tf.layers.dense(hidden2, n_outputs, name="outputs")

执行:虽然最大范数正则化不需要将正则化损失项加入整体函数,所以max_norm()返回None,需要在每一个训练步骤制后返回clip_weights操作,才可获得句柄

clip_all_weights = tf.get_collection("max_norm")with tf.Session() as sess:init.run()for epoch in range(n_epochs):for X_batch, y_batch in shuffle_batch(X_train, y_train, batch_size):sess.run(training_op, feed_dict={X: X_batch, y: y_batch})sess.run(clip_all_weights)acc_valid = accuracy.eval(feed_dict={X: X_valid, y: y_valid}) # not shownprint(epoch, "Validation accuracy:", acc_valid)               # not shownsave_path = saver.save(sess, "./my_model_final.ckpt")             # not shown

Data Augmentation

数据扩充可以通过从已有实例构建新的训练实例,认为提高训练集大小。可减少过度拟合。
棘手的是构建可用的训练实例,进行的修改是可学习的。偏向在训练过程中快速生成训练实例,而不是浪费存储空间和网络带宽。

举例子,TF提供许多图片处理操作,如转置(偏移),旋转,调整大小、翻转裁剪,调整亮度、对比度、饱和度、色调

另一种训练DNN的有效技术是跳过连接(把层输入加到高层输出上)

Practical Guidelines(实用指南)

默认DNN配置:

若需要调整:

  • 找不到良好的学习速率,尝试添加一个类似指数衰减的学习计划
  • 训练集有点小,采用数据扩充
  • 需要稀疏矩阵,在混合中添加l1正则化(训练后选择权重为0),再稀疏,尝试用FTRL代替Adam优化,搭配l1正则化。
  • 需要快速闪电模型,丢弃批量归一化,需要用leaky ReLU代替ELU,采用稀疏矩阵

机器学习实战(十一):Training Deep Neural Nets相关推荐

  1. ENABLING SPIKE-BASED BACKPROPAGATION FOR TRAINING DEEP NEURAL NETWORK ARCHITECTURES

    能够基于脉冲的反向传播的训练深层神经网络 然鹅,ANN-SNN转换框架不能够获取时域动态特征.另一方面,由于信号的不连续性,以及脉冲函数的不可微分性质,利用输入脉冲事件直接训练深度snn仍然是一个困难 ...

  2. 关于Training deep neural networks for binary communication with the Whetstone method的代码实现

    GitHub网址如下: https://github.com/SNL-NERL/Whetstone/blob/master/examples/adaptive_mnist.py 实现过程中解决的问题: ...

  3. A 'Brief' History of Neural Nets and Deep Learning, Part 4

    原文作者为andreykurenkov.本文系转载,仅供各位深度学习爱好者学习使用. "Ask anyone in machine learning what kept neural net ...

  4. [论文阅读笔记58]Learning from Noisy Labels with Deep Neural Networks:A Survey

    1.题目 Learning from Noisy Labels with Deep Neural Networks: A Survey 作者团队:韩国科学技术院(KAIST) Song H , Kim ...

  5. Practical Advice for Building Deep Neural Networks

    practical-advice-for-building-deep-neural-networks/ In our machine learning lab, we've accumulated t ...

  6. Paper:Xavier参数初始化之《Understanding the difficulty of training deep feedforward neural networks》的翻译与解读

    Paper:Xavier参数初始化之<Understanding the difficulty of training deep feedforward neural networks>的 ...

  7. A Taxonomy of Deep Convolutional Neural Nets for Computer Vision

    A Taxonomy of Deep Convolutional Neural Nets for Computer Vision 基本信息 摘要 1. Introduction 2. Introduc ...

  8. Paper之DL之BP:《Understanding the difficulty of training deep feedforward neural networks》

    Paper之DL之BP:<Understanding the difficulty of training deep feedforward neural networks> 目录 原文解 ...

  9. 经典DL论文研读(part1)--Understanding the difficulty of training deep feedforward neural networks

    学习笔记,仅供参考,有错必纠 文章目录 Understanding the difficulty of training deep feedforward neural networks Abstra ...

最新文章

  1. 理解MVC—从实例出发:基于MVC模式的简易算术计算器
  2. 探索Android中的Parcel机制(上)
  3. mybatis 多租户saas_MybatisPlus 多租户架构(SaaS)实现
  4. Apache Camel 2.11发布
  5. dmsetup remove_all 这命令干啥的_分一个小知识,服务器上的一个解压与压缩文件的命令....
  6. 大一计算机导论期中考试,大一计算机导论试题
  7. 集成sleuth_Spring Cloud集成ELK、采用RabbitMQ收集Zipkin数据
  8. lamp怎么使用mysql_lamp(四)mysql操作
  9. Moses Staff攻陷以色列网络并加密数据,拒绝谈判
  10. Jira中的BUG导出
  11. Jquery Dialog 详解(正在学习jquery,详解转载)
  12. Azure SQL作業
  13. 9.Shell 编程从入门到精通 --- 进程
  14. 《编程之美》阅读分享
  15. python制作通讯录
  16. 可见光植被指数,RGB影像植被指数
  17. access_token VS refresh_token
  18. 深入理解OkHttp3:(六)Https
  19. IT运维大咖带你玩转企业信息运维自动化
  20. 开发工作流程_您应该了解的9个开发工作流程升级

热门文章

  1. java批量上传文件_Spring boot 实现单个或批量文件上传功能
  2. sql修改表属性常见错误之——多个对象访问某一列
  3. 有没有什么好用的图文转换工具啊?
  4. python要多久_怎么自学python,大概要多久?
  5. unity 射线 碰撞 连线烘焙
  6. BroadcastReceiver详解以及应用
  7. U盘安装linux系统【RHEL 6.3 server】
  8. 单片机是什么?单片机和计算机、PLC的区别
  9. 基于 GoogleMap 离线 API 源码在内网中加载卫星地图的方法
  10. vue报错 Avoided redundant navigation to current location: “/search“