2-2 自动微分机制

神经网络通常依赖反向传播求梯度来更新网络参数,求梯度过程通常是一件非常复杂而容易出错的事情。

而深度学习框架可以帮助我们自动地完成这种求梯度运算。

Tensorflow一般使用梯度磁带tf.GradientTape()来记录正向运算过程,然后反播磁带自动得到梯度值。

这种利用tf.GradientTape求微分的方法叫做Tensorflow的自动微分机制。

一,利用梯度磁带求导数

  • 自动“监控”所有可训练变量:GradientTape 默认(watch_accessed_variables=True)将所有可训练变量(created by tf.Variable(), where trainable=True)视为需要“监控”的变量。
  • 对于不可训练的变量(比如tf.constant)可以使用tape.watch()对其进行“监控”。
  • 此外,还可以设定watch_accessed_variables=False,然后使用tf.watch()精确控制需要“监控”哪些变量。
import tensorflow as tf
tf.enable_eager_execution()
import numpy as np

# f(x) = a*x**2 + b*x + c的导数

x = tf.Variable(0.0, name="x", dtype=tf.float32)
a = tf.constant(1.0)
b = tf.constant(-2.0)
c = tf.constant(1.0)

# 构建梯度环境
with tf.GradientTape() as tape: 
	# 构建计算过程
    y = a * tf.pow(x, 2) + b * x + c

# 求导
dy_dx = tape.gradient(y, x)
print(dy_dx)

输出

tf.Tensor(-2.0, shape=(), dtype=float32)

对常量张量也可以求导,需要增加watch()

with tf.GradientTape() as tape:
    tape.watch([a,b,c])
    y = a*tf.pow(x,2) + b*x + c
    
dy_dx,dy_da,dy_db,dy_dc = tape.gradient(y,[x,a,b,c])
print(dy_da)
print(dy_dc)

输出

tf.Tensor(0.0, shape=(), dtype=float32)
tf.Tensor(1.0, shape=(), dtype=float32)

可以求二阶导数

with tf.GradientTape() as tape2:
    with tf.GradientTape() as tape1:   
        y = a*tf.pow(x,2) + b*x + c
    dy_dx = tape1.gradient(y,x)   
dy2_dx2 = tape2.gradient(dy_dx,x)

print(dy2_dx2)

输出

tf.Tensor(2.0, shape=(), dtype=float32)

二,利用梯度磁带和优化器求最小值

使用optimizer.apply_gradients()求最小值

# 求f(x) = a*x**2 + b*x + c的最小值
# 使用optimizer.apply_gradients
x = tf.Variable(0.0, name="x", dtype=tf.float32)
a = tf.constant(1.0)
b = tf.constant(-2.0)
c = tf.constant(1.0)

optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
for _ in range(1000):
    with tf.GradientTape() as tape:
        y = a * tf.pow(x, 2) + b * x + c
    dy_dx = tape.gradient(y, x)
    optimizer.apply_gradients(grads_and_vars=[(dy_dx, x)])

tf.print("y =", y, "; x =", x)

输出

y = 0 ; x = 0.999998569

使用optimizer.minimize() 求最小值

# 求f(x) = a*x**2 + b*x + c的最小值
# 使用optimizer.apply_gradients

x = tf.Variable(0.0, name="x", dtype=tf.float32)


# 注意f()无参数
def f():
    a = tf.constant(1.0)
    b = tf.constant(-2.0)
    c = tf.constant(1.0)
    y = a * tf.pow(x, 2) + b * x + c
    return (y)


optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
for _ in range(1000):
    optimizer.minimize(f)

tf.print("y =", f(), "; x =", x)

实际上根据官方文档的说明,minimize()就是compute_gradients()apply_gradients()这两个方法的简单组合,minimize()的源码如下:

  def minimize(self, loss, global_step=None, var_list=None,
               gate_gradients=GATE_OP, aggregation_method=None,
               colocate_gradients_with_ops=False, name=None,
               grad_loss=None):
    grads_and_vars = self.compute_gradients(
        loss, var_list=var_list, gate_gradients=gate_gradients,
        aggregation_method=aggregation_method,
        colocate_gradients_with_ops=colocate_gradients_with_ops,
        grad_loss=grad_loss)
 
    vars_with_grad = [v for g, v in grads_and_vars if g is not None]
    if not vars_with_grad:
      raise ValueError(
          "No gradients provided for any variable, check your graph for ops"
          " that do not support gradients, between variables %s and loss %s." %
          ([str(v) for _, v in grads_and_vars], loss))
 
    return self.apply_gradients(grads_and_vars, global_step=global_step,
                                name=name)

·compute_gradients()·: 根据loss目标函数计算梯度.
apply_gradients(): 使用计算得到的梯度来更新对应的variable.

为什么minimize()要分开两个步骤:

  • 有时候需要对梯度做一定的修正,例如为了防止 gradient vanishing(梯度消失)或 gradient explosion (梯度爆炸),需要事先采取一些干预措施以避免程序出现nan情况。
  • 有时候需要给计算得到的梯度乘以一个权重、或创建多GPU优化器、或其它操作。

#参考链接

  1. tensorflow计算图与自动求导——tf.GradientTape
  2. TensorFlow中Optimizer.minimize()与Optimizer.compute_gradients()和Optimizer.apply_gradients()的用法
  3. 以终为始:compute_gradients 和 apply_gradients
  4. tensorflow optimizer源码阅读笔记
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值