自动梯度与优化器
待优化张量
为了区分需要计算梯度信息的张量(如参数)与不需要计算梯度信息的普通张量,tensorflow增加了一种专门的数据类型来支持梯度信息的记录:tf.Variable
可以通过tf.Variable()
方法将普通张量转换成待优化张量
a=tf.constant([1,2,3])
aa=tf.Variable(a)
tf.Variable()
也可以直接创建待优化张量,用法与tf.constant()
相同
a=tf.Variable([[1,2],[3,4]])
梯度带
tf.GradientTape()
是一个自动求梯度的记录器。只要进入了 with tf.GradientTape() as tape
的上下文环境,则默认在该环境中的所有待优化张量的计算步骤都会被自动记录。
离开上下文环境后,记录停止,但是tape依旧可用,可以通过y_grad = tape.gradient(y,x)
tensorflow将根据记录的计算步骤求张量 y
对变量 x
的导数
import tensorflow as tf
x = tf.Variable(initial_value=3.)
with tf.GradientTape() as tape: #tf.GradientTape() 的上下文内,所有计算步骤都会被记录以用于求导
y = tf.square(x)
y_grad = tape.gradient(y, x) # 计算y关于x的导数
print([y, y_grad]) #输出标量9.0 和标量6.0
梯度带默认记录tf.Variable
创建的待优化张量,如果想记录普通张量,可使用GradientTape.watch()
方法
x = tf.constant(3.0)
with tf.GradientTape() as tape:
tape.watch(x)
y = x * x
dy_dx = tape.gradient(y, x) # Will compute to 6.0
默认情况下,只要调用一次GradientTape.gradient()
,就会释放GradientTape拥有的资源。要在同一计算上计算多个梯度,请创建一个持久梯度带,将参数persisent=True:
x = tf.constant(3.0)
with tf.GradientTape(persistent=True) as g:
g.watch(x)
y = x * x
z = y * y
dz_dx = g.gradient(z, x) # 108.0 (4*x^3 at x = 3)
dy_dx = g.gradient(y, x) # 6.0
del g # Drop the reference to the tape
可以通过嵌套梯度带计算高层导数
x = tf.constant(3.0)
with tf.GradientTape() as g:
g.watch(x)
with tf.GradientTape() as gg:
gg.watch(x)
y = x * x
dy_dx = gg.gradient(y, x) # Will compute to 6.0
d2y_dx2 = g.gradient(dy_dx, x) # Will compute to 2.0
优化器
优化器是继承自tf.optimizers.Optimizer
类的子类,例如随机梯度下降优化器 tf.optimizers.SGD
,Adam优化器tf.optimizers.Adam
,通过调用Optimizer.minimize()
方法实现自动梯度并更新参量。
tf.keras.optimizers 和 tf.optimizers 完全相同,tf.optimizers.SGD即tf.keras.optimizers.SGD
优化器实例化
不同优化器有不同的实例化参数,但是大同小异,以SGD为例,下面是SGD的实例化方法
__init__(
learning_rate=0.01,#浮点型超参数,应该>0,学习率
momentum=0.0,#浮点型大于0的超参数,动量,帮助加速收敛
nesterov=False,#是否使用nesterovd动量
name='SGD',
**kwargs
)
其中kwargs为关键字参数, 允许指为 {clipnorm
, clipvalue
, lr
,decay
}。clipnorm
按范数梯度截断,当梯度得L2范数值大于一定值时发生截断; clipvalue
按值梯度截断,当梯度大于一定值时发生截断, decay
是为了向后兼容所以被包含在kwargs中,该参量用于设计学习率的逆时衰减; lr
也是为了向后兼容,现在推荐用learning_rate取代kwargs的lr。
简单SGD只需设置学习率即可,实例化一个SGD优化器对象:
opt = tf.optimizers.SGD(learning_rate=0.1)
此后可以通过opt.*
的方式调用优化器的的相关方法
minimize方法
优化器的minimize
方法定义如下:
minimize(
loss,#一个函数对象,要求无参数且有可以被最小化的返回值,minimize方法会通过更新参量令将该函数的返回值最小
var_list, #元素为tf.Variable类型的序列对象,loss函数的返回值应该依赖这些待优化张量,minimize调用会改变这些张量
grad_loss=None,#可选,loss的梯度张量
name=None #可选
)
使用过程如下:
opt = tf.keras.optimizers.SGD(learning_rate=0.1) #创建优化器对象
loss = lambda: 3 * var1 * var1 + 2 * var2 * var2 #定义损失函数,loss应该是一个无参且有返回值函数对象
opt.minimize(loss, var_list=[var1, var2]) #eager模式中(tf2默认开启),直接调用opt.minimize()即可根据优化器的优化算法(本例的SGD)更新var_list中的张量
opt.minimize()
方法干了两件事:
- 使用
tf.GradientTape
计算梯度 - 使用
opt.apply_gradients()
依据优化器的优化算法更新参量
apply_gradients方法
apply_gradients方法定义如下
apply_gradients(
grads_and_vars,#元素为(梯度,待优化张量)对的列表对象
name=None
)
opt.apply_gradients()
会直接根据优化器的优化算法,将梯度应用在可优化张量上,使其更新。
注意参数grads_and_vars
期望的是(gradient, variable)
对的列表,通常借助python的zip函数:
X = tf.constant(X)
y = tf.constant(y)
a = tf.Variable(initial_value=0.)
b = tf.Variable(initial_value=0.)
with tf.GradientTape() as tape:
y_pred = a * X + b
loss = 0.5 * tf.reduce_sum(tf.square(y_pred - y))
grads = tape.gradient(loss, [a, b])
optimizer.apply_gradients(grads_and_vars=zip(grads, [a, b]))
#zip()被称为拉链函数,会将两个等长序列对象中的元素按对应位置两两一组行程值对,存于list之中
如果想在应用梯度之前对梯度进行处理,则需要进行以下三个步骤:
- 使用
tf.GradientTape
计算梯度 - 对梯度进行处理
- 使用
opt.apply_gradients()
依据优化器的优化算法更新参量
注意
从一定程度上讲,使用minimize或者使用apply_gradients都能达成目标,在不考虑进行优化前对梯度进行的处理的情况下,二者作用等价,显然minimize更为简洁,但是有需要注意:
- minimize的参数loss,要求为无参数且有具体的返回值的可调用对象,注意没有参数,tf内预设的loss函数是有参数的,不能直接拿来用,可套上lambda使用。
- apply_gradients的参数,要求的是张量列表,列表元素是
(梯度,待优化张量)
,其中梯度由tape.gradient(loss, [a, b])
得到,tape.gradient
也是接受具体的张量。tf内预设的loss函数会返回计算后的张量,所以可直接将其返回值作为tape.gradient
的参数进行计算
TF2预设的优化器
Adadelta优化器
: Optimizer that implements the Adadelta algorithm.
Adagrad优化器
: Optimizer that implements the Adagrad algorithm.
Adam优化器
: Optimizer that implements the Adam algorithm.
Adamax优化器
: Optimizer that implements the Adamax algorithm.
Ftrl优化器
: Optimizer that implements the FTRL algorithm.
Nadam优化器
: Optimizer that implements the NAdam algorithm.
RMSprop优化器
: Optimizer that implements the RMSprop algorithm.
SGD优化器
: Stochastic gradient descent and momentum optimizer.
本文摘录、翻译自
Keras中文文档
https://keras.io/zh/
TensorFlow官方
https://tensorflow.google.cn/
最全Tensorflow2.0 入门教程持续更新
https://zhuanlan.zhihu.com/p/59507137
简单粗暴TensorFlow2
https://tf.wiki/zh/preface.html