Python TensorFlow 自定义求导与 GradientTape 使用详解

阿澈
阿澈
发布时间:2026-10-16 | 15人浏览过
原创

本文详解 Python TensorFlow 中的自定义求导与 GradientTape 机制。介绍通过有限差分法近似计算导数的原理,演示如何计算多元函数偏导数、处理常量梯度以及二阶导数。重点解析 GradientTape 的默认非持久模式与 persistent=True 持久化模式的区别,结合 watch 函数与 optimizers 实现梯度下降优化。

自定义求导:(近似求导数的方法)

该方法通过让变量 x 向左偏移 eps 得到一个点,向右偏移 eps 得到另一个点,利用这两点构成的直线斜率来近似 x 处的导数值。

当 eps 取值足够小时,计算出的近似导数将无限接近真实导数值。

def f(x):
    return 3. * x ** 2 + 2. * x - 1
def approximate_derivative(f, x, eps=1e-3):
    return (f(x + eps) - f(x - eps)) / (2. * eps)
print(approximate_derivative(f, 1.))

运行结果:

7.999999999999119

多元函数的求导

def g(x1, x2):
    return (x1 + 5) * (x2 ** 2)
def approximate_gradient(g, x1, x2, eps=1e-3):
    dg_x1 = approximate_derivative(lambda x: g(x, x2), x1, eps)
    dg_x2 = approximate_derivative(lambda x: g(x1, x), x2, eps)
    return dg_x1, dg_x2
print(approximate_gradient(g, 2., 3.))

运行结果:

(8.999999999993236, 41.999999999994486)

在tensorflow中的求导

x1 = tf.Variable(2.0)
x2 = tf.Variable(3.0)
with tf.GradientTape() as tape:
    z = g(x1, x2)
dz_x1 = tape.gradient(z, x1)
print(dz_x1)

运行结果:

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

需要注意的是,tf.GradientTape() 默认只能使用一次,一旦执行梯度计算,该 tape 对象即被释放(消解)。

try:
    dz_x2 = tape.gradient(z, x2)
except RuntimeError as ex:
    print(ex)

运行结果:

A non-persistent GradientTape can only be used to compute one set of gradients (or jacobians)

解决方法是设置 persistent = True 以保留 tape 状态,但在不再需要时务必手动删除 tape 以释放资源。

x1 = tf.Variable(2.0)
x2 = tf.Variable(3.0)
with tf.GradientTape(persistent = True) as tape:
    z = g(x1, x2)
dz_x1 = tape.gradient(z, x1)
dz_x2 = tape.gradient(z, x2)
print(dz_x1, dz_x2)
del tape

运行结果:

tf.Tensor(9.0, shape=(), dtype=float32) tf.Tensor(42.0, shape=(), dtype=float32)

使用tf.GradientTape()

同时求x1,x2的偏导

x1 = tf.Variable(2.0)
x2 = tf.Variable(3.0)
with tf.GradientTape() as tape:
    z = g(x1, x2)
dz_x1x2 = tape.gradient(z, [x1, x2])
print(dz_x1x2)

运行结果:

[<tf.Tensor: shape=(), dtype=float32, numpy=9.0>, <tf.Tensor: shape=(), dtype=float32, numpy=42.0>]

对常量求偏导

x1 = tf.constant(2.0)
x2 = tf.constant(3.0)
with tf.GradientTape() as tape:
    z = g(x1, x2)
dz_x1x2 = tape.gradient(z, [x1, x2])
print(dz_x1x2)

运行结果:

[None, None]

可以通过 watch 函数显式关注常量上的导数,使其参与梯度计算。

x1 = tf.constant(2.0)
x2 = tf.constant(3.0)
with tf.GradientTape() as tape:
    tape.watch(x1)
    tape.watch(x2)
    z = g(x1, x2)
dz_x1x2 = tape.gradient(z, [x1, x2])
print(dz_x1x2)

运行结果:

[<tf.Tensor: shape=(), dtype=float32, numpy=9.0>, <tf.Tensor: shape=(), dtype=float32, numpy=42.0>]

也可以利用两个目标函数对同一个变量求导:

x = tf.Variable(5.0)
with tf.GradientTape() as tape:
    z1 = 3 * x
    z2 = x ** 2
tape.gradient([z1, z2], x)

运行结果:

<tf.Tensor: shape=(), dtype=float32, numpy=13.0>

结果 13 是 z1 对 x 的导数加上 z2 对于 x 的导数。

求二阶导数的方法

x1 = tf.Variable(2.0)
x2 = tf.Variable(3.0)
with tf.GradientTape(persistent=True) as outer_tape:
    with tf.GradientTape(persistent=True) as inner_tape:
        z = g(x1, x2)
    inner_grads = inner_tape.gradient(z, [x1, x2])
outer_grads = [outer_tape.gradient(inner_grad, [x1, x2])
               for inner_grad in inner_grads]
print(outer_grads)
del inner_tape
del outer_tape

运行结果:

[[None, <tf.Tensor: shape=(), dtype=float32, numpy=6.0>], [<tf.Tensor: shape=(), dtype=float32, numpy=6.0>, <tf.Tensor: shape=(), dtype=float32, numpy=14.0>]]

结果是一个 2x2 的矩阵,左上角是 z 对 x1 的二阶导数,右上角是 z 先对 x1 求导,在对 x2 求导。

左下角是 z 先对 x2 求导,在对 x1 求导,右下角是 z 对 x2 的二阶导数。

学会自定义求导就可以模拟梯度下降法了,梯度下降就是求导,再在导数的位置前进一点点 模拟梯度下降法:

learning_rate = 0.1
x = tf.Variable(0.0)
for _ in range(100):
    with tf.GradientTape() as tape:
        z = f(x)
    dz_dx = tape.gradient(z, x)
    x.assign_sub(learning_rate * dz_dx)
print(x)

运行结果:

<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=-0.3333333>

结合optimizers进行梯度下降法

learning_rate = 0.1
x = tf.Variable(0.0)
optimizer = keras.optimizers.SGD(lr = learning_rate)
for _ in range(100):
    with tf.GradientTape() as tape:
        z = f(x)
    dz_dx = tape.gradient(z, x)
    optimizer.apply_gradients([(dz_dx, x)])
print(x)

运行结果:

<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=-0.3333333>

以上就是python人工智能自定义求导tf_diffs详解的详细内容,更多关于python自定义求导tf_diffs的资料请关注本站其它相关文章!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表