首頁 > 軟體

python人工智慧自定義求導tf_diffs詳解

2022-07-29 22:02:03

自定義求導:(近似求導數的方法)

讓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()只能使用一次,使用一次之後就會被消解

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刪除掉

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的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com