python人工智能自定义求导tf_diffs详解

作者:plum_blossom 时间:2023-06-11 13:31:51 

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

让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>

来源:https://juejin.cn/post/7124959932725592072

标签:python,人工智能,自定义求导,tf,diffs
0
投稿

猜你喜欢

  • Bootstrap每天必学之表单

    2024-05-09 10:39:31
  • MySQL replace函数替换字符串语句的用法

    2024-01-12 16:56:29
  • Vue CLI3.0中使用jQuery和Bootstrap的方法

    2023-07-02 17:08:15
  • Python3压缩和解压缩实现代码

    2022-05-04 09:42:19
  • 利用python控制Autocad:pyautocad方式

    2023-08-03 00:05:20
  • MySQL5.5.21安装配置教程(win7)

    2024-01-29 09:20:48
  • 决策树的python实现方法

    2023-04-22 04:25:02
  • Python进阶篇之字典操作总结

    2021-08-02 20:34:44
  • 基于Python实现网页文章转PDF文档

    2022-08-23 08:50:17
  • Python获取网络时间戳的两种方法详解

    2023-04-11 06:38:21
  • OpenCV-Python使用分水岭算法实现图像的分割与提取

    2021-04-20 13:04:03
  • Vue 通过自定义指令回顾v-内置指令(小结)

    2023-07-02 16:56:42
  • JavaScript转换与解析JSON方法实例详解

    2024-04-17 10:22:44
  • Python实现一个发送程序和接收程序

    2023-06-18 09:04:38
  • 怎样设计"帮助"最有效?

    2008-04-12 14:18:00
  • pyenv命令管理多个Python版本

    2023-10-18 15:44:38
  • Python获取时间范围内日期列表和周列表的函数

    2023-03-25 15:16:39
  • vue.js表格分页示例

    2024-05-02 16:40:45
  • python基础教程项目三之万能的XML

    2022-09-22 05:33:25
  • 探讨如何计算age的sql函数

    2024-01-21 12:44:31
  • asp之家 网络编程 m.aspxhome.com