优化器是用来最小化损失函数的方法,也就是找到定义的模型中参数最优值的方法。开始你假定了模型中权重和偏置量的初始值,然后在每一次迭代中,参数值朝优化器指明的方向去更新,最终将会稳定到最优值。
tf.train.Optimizer
tf.train.GradientDescentOptimizer
tf.train.AdadeltaOptimizer
tf.train.AdagradOptimizer
tf.train.AdagradDAOptimizer
tf.train.MomentumOptimizer
tf.train.AdamOptimizer
tf.train.FtrlOptimizer
tf.train.ProximalAdagradOptimizer
tf.train.ProximalGradientDescentOptimizer
tf.train.RMSPropOptimizer
标准梯度下降法:
标准梯度下降先计算所有样本汇总误差,然后根据总误差来更新权值
随机梯度下降法:
随机梯度下降随机抽取一个样本来计算误差,然后更新权值
批量梯度下降法:
批量梯度下降算是一种折中的方案,从总样本中选取一个批次(比如一共有10000个样本,随 机选取100个样本作为一个batch),然后计算这个batch的总误差,根据总误差来更新权 值。
符号 | 解释 |
---|---|
W | 要训练的参数 |
J(W) | 代价函数 |
∇wJ(W) | 代价函数的梯度 |
η | 学习率 |
当前权值的改变会受到上一次权值改变的影响,类似于小球向下滚动的时候带上了惯性。这样,可以加快小球的向下的速度。
NAG在TF中跟Momentum合并在同一个函数tf.train.MomentumOptimizer中,可以通过参数配置启用。 在Momentun中小球会盲目地跟从下坡的梯度,容易发生错误,所以我们需要一个更聪明的小球,这个小球提前知道它要去哪里,它还要知道走到坡底的时候速度慢下来而不是又冲上另一个坡。γvt−1会用来修改W的值,计算W−γvt−1可以表示小球下一个位置大概在哪里。从而我们可以提前计算下一个位置的梯度,然后使用到当前位置。
它是基于SGD的一种算法,它的核心思想是对比较常见的数据给予它比较小的学习率去调整 参数,对于比较罕见的数据给予它比较大的学习率去调整参数。它很适合应用于数据稀疏的数据集(比如一个图片数据集,有10000张狗的照片,10000张猫的照片,只有100张大象的照 片)。
Adagrad主要的优势在于不需要人为的调节学习率,它可以自动调节。它的缺点在于,随着 迭代次数的增多,学习率也会越来越低,最终会趋向于0。
RMS(Root Mean Square)是均方根的缩写。
RMSprop借鉴了一些Adagrad的思想,不过这里RMSprop只用到了前t-1次梯度平方的平均值加上当前梯度的平方的和的开平方作为学习率的分母。这样RMSprop不会出现学习率越来 越低的问题,而且也能自己调节学习率,并且可以有一个比较好的效果。
使用Adadelta我们甚至不需要设置一个默认学习率,在Adadelta不需要使用学习率也可以达 到一个非常好的效果。
就像Adadelta和RMSprop一样,Adam会存储之前衰减的平方梯度,同时它也会保存之前衰减的梯度。经过一些处理之后再使用类似Adadelta和RMSprop的方式更新参数。
为模型选择一个最好的优化器,收敛快并且能学到合适的权重和偏置量的值,是一个需要技巧的事情。
自适应技术(Adadelta,Adagrad等)对于复杂的神经网络模型来说是很好的优化器,收敛更快。大多数情况下,Adam可能是最好的优化器。Adam还优于其它的自适应技术,但是其计算成本很高。对于稀疏数据集来说(比如一个图片数据集,有10000张狗的照片,10000张猫的照片,只有100张大象的照 片),一些方法如SGD、NGA以及momentum不是最好的选择,能自适应调整学习率的方法才是。一个附加的好处就是不需要调整学习率,使用默认的学习率就可以达到最优解。
还是以手写数字为例,设计一个简单神经网络,使用SGD、Adam两种优化器做对比:
代码修改部分:
#使用梯度下降法进行训练
#train_step = tf.train.GradientDescentOptimizer(0.2).minimize(loss)
#使用AdamOptimizer优化器训练
train_step = tf.train.AdamOptimizer(1e-2).minimize(loss)
我们使用SGD的时候,学习率设为0.2,使用Adam的时候,学习率设为0.01,也就是1e-2。
一般我们使用Adam的时候,设置的学习率都比较小,这里0.01都算比较大的了。
完整代码如下:
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
#载入数据集
mnist = input_data.read_data_sets("MNIST_data",one_hot=True)
#每个批次的大小
batch_size = 100
#计算一共有多少个批次
n_batch = mnist.train.num_examples // batch_size
#定义两个placeholder
x = tf.placeholder(tf.float32,[None,784])
y = tf.placeholder(tf.float32,[None,10])
#创建一个简单的神经网络
W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))
prediction = tf.nn.softmax(tf.matmul(x,W) + b)
#二次代价函数
# loss = tf.reduce_mean(tf.square(y-prediction))
#使用softmax交叉熵代价函数
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y,logits=prediction))
#使用梯度下降法进行训练
#train_step = tf.train.GradientDescentOptimizer(0.2).minimize(loss)
#使用AdamOptimizer优化器训练
train_step = tf.train.AdamOptimizer(1e-2).minimize(loss)
#初始化变量
init = tf.global_variables_initializer()
#结果存放在一个布尔型列表中
#argmax返回一维张量中最大值所在的位置
correct_prediction = tf.equal(tf.argmax(y,1),tf.argmax(prediction,1))
#求准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
with tf.Session() as sess:
sess.run(init)
for epoch in range(21):
for batch in range(n_batch):
batch_xs,batch_ys = mnist.train.next_batch(batch_size)
sess.run(train_step,feed_dict = {x:batch_xs,y:batch_ys})
acc = sess.run(accuracy,feed_dict = {x:mnist.test.images,y:mnist.test.labels})
print("Iter"+str(epoch)+",Testing Accuracy"+str(acc))
使用SGD优化器结果:
Iter0,Testing Accuracy0.8243
Iter1,Testing Accuracy0.8882
Iter2,Testing Accuracy0.9009
Iter3,Testing Accuracy0.9052
Iter4,Testing Accuracy0.9089
Iter5,Testing Accuracy0.9103
Iter6,Testing Accuracy0.9111
Iter7,Testing Accuracy0.9128
Iter8,Testing Accuracy0.9145
Iter9,Testing Accuracy0.9158
Iter10,Testing Accuracy0.9192
Iter11,Testing Accuracy0.9181
Iter12,Testing Accuracy0.9184
Iter13,Testing Accuracy0.9191
Iter14,Testing Accuracy0.9195
Iter15,Testing Accuracy0.9196
Iter16,Testing Accuracy0.9212
Iter17,Testing Accuracy0.9213
Iter18,Testing Accuracy0.9204
Iter19,Testing Accuracy0.9213
Iter20,Testing Accuracy0.9211
使用Adam优化器结果:
Iter0,Testing Accuracy0.9244
Iter1,Testing Accuracy0.9256
Iter2,Testing Accuracy0.9298
Iter3,Testing Accuracy0.9262
Iter4,Testing Accuracy0.9275
Iter5,Testing Accuracy0.926
Iter6,Testing Accuracy0.9296
Iter7,Testing Accuracy0.9313
Iter8,Testing Accuracy0.9293
Iter9,Testing Accuracy0.929
Iter10,Testing Accuracy0.9305
Iter11,Testing Accuracy0.9326
Iter12,Testing Accuracy0.9307
Iter13,Testing Accuracy0.9328
Iter14,Testing Accuracy0.9295
Iter15,Testing Accuracy0.9324
Iter16,Testing Accuracy0.9282
Iter17,Testing Accuracy0.9328
Iter18,Testing Accuracy0.9297
Iter19,Testing Accuracy0.9325
Iter20,Testing Accuracy0.9297
结果分析
从结果来看,我们很可以看出来使用Adam的时候,收敛速度明显要比SGD要快。