2-3,自动微分机制

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

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

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

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

一,利用梯度磁带求导数

  1. import tensorflow as tf
  2. import numpy as np
  3. # f(x) = a*x**2 + b*x + c的导数
  4. x = tf.Variable(0.0,name = "x",dtype = tf.float32)
  5. a = tf.constant(1.0)
  6. b = tf.constant(-2.0)
  7. c = tf.constant(1.0)
  8. with tf.GradientTape() as tape:
  9. y = a*tf.pow(x,2) + b*x + c
  10. dy_dx = tape.gradient(y,x)
  11. print(dy_dx)
  1. tf.Tensor(-2.0, shape=(), dtype=float32)
  1. # 对常量张量也可以求导,需要增加watch
  2. with tf.GradientTape() as tape:
  3. tape.watch([a,b,c])
  4. y = a*tf.pow(x,2) + b*x + c
  5. dy_dx,dy_da,dy_db,dy_dc = tape.gradient(y,[x,a,b,c])
  6. print(dy_da)
  7. print(dy_dc)
  1. tf.Tensor(0.0, shape=(), dtype=float32)
  2. tf.Tensor(1.0, shape=(), dtype=float32)
  1. # 可以求二阶导数
  2. with tf.GradientTape() as tape2:
  3. with tf.GradientTape() as tape1:
  4. y = a*tf.pow(x,2) + b*x + c
  5. dy_dx = tape1.gradient(y,x)
  6. dy2_dx2 = tape2.gradient(dy_dx,x)
  7. print(dy2_dx2)
  1. tf.Tensor(2.0, shape=(), dtype=float32)
  1. # 可以在autograph中使用
  2. @tf.function
  3. def f(x):
  4. a = tf.constant(1.0)
  5. b = tf.constant(-2.0)
  6. c = tf.constant(1.0)
  7. # 自变量转换成tf.float32
  8. x = tf.cast(x,tf.float32)
  9. with tf.GradientTape() as tape:
  10. tape.watch(x)
  11. y = a*tf.pow(x,2)+b*x+c
  12. dy_dx = tape.gradient(y,x)
  13. return((dy_dx,y))
  14. tf.print(f(tf.constant(0.0)))
  15. tf.print(f(tf.constant(1.0)))
  1. (-2, 1)
  2. (0, 0)

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

  1. # 求f(x) = a*x**2 + b*x + c的最小值
  2. # 使用optimizer.apply_gradients
  3. x = tf.Variable(0.0,name = "x",dtype = tf.float32)
  4. a = tf.constant(1.0)
  5. b = tf.constant(-2.0)
  6. c = tf.constant(1.0)
  7. optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)
  8. for _ in range(1000):
  9. with tf.GradientTape() as tape:
  10. y = a*tf.pow(x,2) + b*x + c
  11. dy_dx = tape.gradient(y,x)
  12. optimizer.apply_gradients(grads_and_vars=[(dy_dx,x)])
  13. tf.print("y =",y,"; x =",x)
  1. y = 0 ; x = 0.999998569
  1. # 求f(x) = a*x**2 + b*x + c的最小值
  2. # 使用optimizer.minimize
  3. # optimizer.minimize相当于先用tape求gradient,再apply_gradient
  4. x = tf.Variable(0.0,name = "x",dtype = tf.float32)
  5. #注意f()无参数
  6. def f():
  7. a = tf.constant(1.0)
  8. b = tf.constant(-2.0)
  9. c = tf.constant(1.0)
  10. y = a*tf.pow(x,2)+b*x+c
  11. return(y)
  12. optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)
  13. for _ in range(1000):
  14. optimizer.minimize(f,[x])
  15. tf.print("y =",f(),"; x =",x)
  1. y = 0 ; x = 0.999998569
  1. # 在autograph中完成最小值求解
  2. # 使用optimizer.apply_gradients
  3. x = tf.Variable(0.0,name = "x",dtype = tf.float32)
  4. optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)
  5. @tf.function
  6. def minimizef():
  7. a = tf.constant(1.0)
  8. b = tf.constant(-2.0)
  9. c = tf.constant(1.0)
  10. for _ in tf.range(1000): #注意autograph时使用tf.range(1000)而不是range(1000)
  11. with tf.GradientTape() as tape:
  12. y = a*tf.pow(x,2) + b*x + c
  13. dy_dx = tape.gradient(y,x)
  14. optimizer.apply_gradients(grads_and_vars=[(dy_dx,x)])
  15. y = a*tf.pow(x,2) + b*x + c
  16. return y
  17. tf.print(minimizef())
  18. tf.print(x)
  1. 0
  2. 0.999998569
  1. # 在autograph中完成最小值求解
  2. # 使用optimizer.minimize
  3. x = tf.Variable(0.0,name = "x",dtype = tf.float32)
  4. optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)
  5. @tf.function
  6. def f():
  7. a = tf.constant(1.0)
  8. b = tf.constant(-2.0)
  9. c = tf.constant(1.0)
  10. y = a*tf.pow(x,2)+b*x+c
  11. return(y)
  12. @tf.function
  13. def train(epoch):
  14. for _ in tf.range(epoch):
  15. optimizer.minimize(f,[x])
  16. return(f())
  17. tf.print(train(1000))
  18. tf.print(x)
  1. 0
  2. 0.999998569

如果对本书内容理解上有需要进一步和作者交流的地方,欢迎在公众号”Python与算法之美”下留言。作者时间和精力有限,会酌情予以回复。

也可以在公众号后台回复关键字:加群,加入读者交流群和大家讨论。

image.png