因为大多数机器学习任务就是最小化损失,在损失定义的情况下,后面的工作就交给了优化器。因为深度学习常见的是对于梯度的优化,也就是说,优化器最后其实就是各种对于梯度下降算法的优化。
常用的optimizer类
- Optimizer
- GradientDescentOptimizer
- AdagradOptimizer
- AdagradDAOptimizer
- MomentumOptimizer
- AdamOptimizer
- FtrlOptimizer
- RMSPropOptimizer
1. class tf.train.Optimizer
优化器(optimizers)类的基类。这个类定义了在训练模型的时候添加一个操作的API。你基本上不会直接使用这个类,但是你会用到他的子类比如GradientDescentOptimizer, AdagradOptimizer, MomentumOptimizer.等等这些。
操作 | 描述 |
---|---|
class tf.train.Optimizer | 基本的优化类,该类不常常被直接调用,而较多使用其子类,比如GradientDescentOptimizer, AdagradOptimizer或者MomentumOptimizer |
tf.train.Optimizer.init(use_locking, name) | 创建一个新的优化器,该优化器必须被其子类(subclasses)的构造函数调用 |
tf.train.Optimizer.minimize(loss, global_step=None, var_list=None, gate_gradients=1, aggregation_method=None, colocate_gradients_with_ops=False, name=None, grad_loss=None) | 添加操作节点,用于最小化loss,并更新var_list该函数是简单的合并了compute_gradients()与apply_gradients()函数返回为一个优化更新后的var_list,如果global_step非None,该操作还会为global_step做自增操作 |
tf.train.Optimizer.apply_gradients(grads_and_vars, global_step=None, name=None) | 将计算出的梯度应用到变量上,是函数minimize()的第二部分,返回一个应用指定的梯度的操作Operation,对global_step做自增操作 |
tf.train.Optimizer.compute_gradients(loss,var_list=None, gate_gradients=1, aggregation_method=None, colocate_gradients_with_ops=False, grad_loss=None) | 对var_list中的变量计算loss的梯度该函数为函数minimize()的第一部分,返回一个以元组(gradient, variable)组成的列表 |
即:
minimize() 函数处理了梯度计算和参数更新两个操作
compute_gradients() 函数用于获取梯度
apply_gradients() 用于更新参数
其中的minimize可以拆为以下两个步骤:
① 梯度计算
② 将计算出来的梯度应用到变量的更新中
拆开的好处是,可以对计算的梯度进行限制,防止梯度消失和爆炸
class tf.train.Optimizer 用法
# Create an optimizer with the desired parameters.
opt = GradientDescentOptimizer(learning_rate=0.1)
# Add Ops to the graph to minimize a cost by updating a list of variables.
# "cost" is a Tensor, and the list of variables contains tf.Variable objects.
opt_op = opt.minimize(cost, var_list=<list of variables>)
# Execute opt_op to do one step of training:
opt_op.run()
或者
# 梯度下降
import tensorflow as tf
x = tf.Variable(5, name='x', dtype=tf.float32)
log_x = tf.log(x)
log_x_squared = tf.square(log_x)
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.5)
train_op = optimizer.minimize(log_x_squared)
init = tf.initialize_all_variables()
def optimize():
with tf.Session() as session:
session.run(init)
# print(session.run(log_x_squared))
print("starting at", "x:", session.run(x), "log(x)^2:", session.run(log_x_squared))
for step in range(100): # 迭代100次
session.run(train_op)
print("step", step, "x:", session.run(x), "log(x)^2:", session.run(log_x_squared))
optimize()
注意事项:在使用它们之前处理梯度
使用minimize()操作,该操作不仅可以计算出梯度,而且还可以将梯度作用在变量上。如果想在使用它们之前处理梯度,可以按照以下三步骤使用optimizer :
1、使用函数compute_gradients()计算梯度
2、按照自己的愿望处理梯度
3、使用函数apply_gradients()应用处理过后的梯度
例如:
# 创建一个optimizer.
opt = GradientDescentOptimizer(learning_rate=0.1)
# 计算<list of variables>相关的梯度
grads_and_vars = opt.compute_gradients(loss, <list of variables>)
# grads_and_vars为tuples (gradient, variable)组成的列表。
#对梯度进行想要的处理,比如cap处理
capped_grads_and_vars = [(MyCapper(gv[0]), gv[1]) for gv in grads_and_vars]
# 令optimizer运用capped的梯度(gradients)
opt.apply_gradients(capped_grads_and_vars)
实际例子
# 方法1:拆开为两部分
import tensorflow as tf
tf.reset_default_graph()
# 创建变量
with tf.variable_scope('var'):
weights=tf.get_variable(name='w',initializer=tf.constant(2.0))
input=tf.get_variable(name='x',initializer=tf.constant(3.0))
loss=weights*input*input #定义优化器,计算梯度和应用梯度
print(loss) # Tensor("var/mul_1:0", shape=(), dtype=float32)
print('weight_name:', weights.name) # weight_name: var/w:0
print('input_name:', input.name) # input_name: var/x:0
optimizer=tf.train.GradientDescentOptimizer(learning_rate=0.4)
# 返回list格式为:[(grad1,var_initial1),(grad2,var_initial2)]
list_of_grad_var1 = optimizer.compute_gradients(loss,[weights,input])
# print('-->', list_of_grad_var1)
# 这里不能不加copy(),不加则list_of_grad_var1会跟着list_of_grad_var2变化,最终两个是一模一样的
list_of_grad_var2=list_of_grad_var1.copy()
# 也可以用下面这个计算梯度,只是不会返回var_initial
# grad=tf.gradients(loss,[weights,input])
# 剪切梯度,防止梯度消失和爆炸
for i,(grad,var_initial) in enumerate(list_of_grad_var1):
# 这里比较的是2范数,具体公式自己查
list_of_grad_var2[i] = (tf.clip_by_norm(grad,10),var_initial) # 梯度裁剪
# 更新变量
train_op = optimizer.apply_gradients(list_of_grad_var2) #一定要记住,这里是x和w都要被更新的!!!
# 执行
config=tf.ConfigProto()
config.gpu_options.allow_growth = True
with tf.Session(config=config) as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(list_of_grad_var1)) # 原始的梯度(9,12)
print(sess.run(list_of_grad_var2)) # 剪切后的梯度(9,10)
sess.run(train_op) #更新loss
print(sess.run(loss)) #降低的loss:从原来的18降低为了 -1.6
# #输出
# Tensor("var/mul_1:0", shape=(), dtype=float32)
# weight_name: var/w:0
# input_name: var/x:0
# [(9.0, 2.0), (12.0, 3.0)]
# [(9.0, 2.0), (10.0, 3.0)]
# -1.6