欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

TensorFlow深度学习:2.3.自动微分机制

程序员文章站 2022-03-06 21:00:28
...


Tensorflow一般使用梯度磁带tf.GradientTape来记录正向运算过程,然后反播磁带自动得到梯度值。
这种利用tf.GradientTape求微分的方法叫做Tensorflow的自动微分机制。

1.利用梯度磁带求导数

1.1.示例

import tensorflow as tf
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)

# 对常量张量也可以求导,需要增加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)

例子中的watch函数把需要计算梯度的变量x加进来了。**GradientTape默认只监控由tf.Variable创建的traiable=True属性(默认)的变量。**上面例子中的a,b,c是constant,因此计算梯度需要增加g.watch(x)函数。当然,也可以设置不自动监控可训练变量,完全由自己指定,设置watch_accessed_variables=False就行了(一般用不到)

1.2.tf.GradientTape()方法

watch(tensor)
作用:确保某个tensor被tape追踪
参数:

  • tensor: 一个Tensor或者一个Tensor列表
    gradient(target,sources,output_gradients=None,unconnected_gradients=tf.UnconnectedGradients.NONE)
    作用:根据tape上面的上下文来计算某个或者某些tensor的梯度
    参数:
  • target: 被微分的Tensor或者Tensor列表,你可以理解为经过某个函数之后的值
  • sources: Tensors 或者Variables列表(当然可以只有一个值). 你可以理解为函数的某个变量
    GradientTape也可以嵌套多层用来计算高阶导数:
# 可以求二阶导数
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)

2.利用梯度磁带和优化器求最小值

2.1.optimizer方法

computer_gradients(loss, val_list)
作用:计算loss对于指定val_list的导数的,最终返回的是元组列表,即[(gradient, variable),…]。
参数:

  • val_list:进行求偏导的变量的列表,默认为graph中收集的变量列表
    apply_gradients(grads_and_vars,name=None)
    作用:把计算出来的梯度更新到变量上面去。
    参数:
  • grads_and_vars: (gradient, variable) 对的列表.
    minimize(loss,varlist)
    作用:minimize的内部存在两个操作:(1)计算各个变量的梯度 (2)用梯度更新这些变量的值,相当于先用tape求gradient,再apply_gradient

2.2.示例

# 求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.keras.optimizers.SGD(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)
# 使用optimizer.minimize
#注意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.keras.optimizers.SGD(learning_rate=0.01)   
for _ in range(1000):
    optimizer.minimize(f,[x])   
    
tf.print("y =",f(),"; x =",x)

自动图中完成最小值的求解

# 在autograph中完成最小值求解
# 使用optimizer.apply_gradients

x = tf.Variable(0.0,name = "x",dtype = tf.float32)
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)

@tf.function
def minimizef():
    a = tf.constant(1.0)
    b = tf.constant(-2.0)
    c = tf.constant(1.0)
    
    for _ in tf.range(1000): 
    #注意autograph时使用tf.range(1000)而不是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)])
        
    y = a*tf.pow(x,2) + b*x + c
    return y

tf.print(minimizef())
tf.print(x)

# 使用optimizer.minimize

x = tf.Variable(0.0,name = "x",dtype = tf.float32)
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)   

@tf.function
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)

@tf.function
def train(epoch):  
    for _ in tf.range(epoch):  
        optimizer.minimize(f,[x])
    return(f())


tf.print(train(1000))
tf.print(x)