tensorflow多元函数高阶求导

目录

一阶偏导的计算

例一

例二

二阶偏导的计算

向量对向量求导。


在机器学习中,会遇到拉普拉斯方程问题。如

 $$-\Delta u=f$$

这里 u 是一个关于多变量的函数,譬如 u=u(x,y). 那么

$$\Delta u = \frac{\partial^2 u}{\partial x^2}+\frac{\partial^2 u}{\partial y^2}$$.

在tensorflow中单值输出关于多元变量的高阶导数是如何计算的呢? 本文为我的个人测试,如有不合适的地方,欢迎指正.

  • 一阶偏导的计算

例一

$$u = 3(x^3+y^3)-6(x^2+y^2)$$

我们很显然知道:u_x = 9x^2-12x, u_y = 9y^2-12y.那么程序结果呢?

def test_gradient0():
    with tf.device('/gpu:%s' % 0):
        with tf.variable_scope('vscope', reuse=tf.AUTO_REUSE):
            # 注意类型必须均为浮点型,并且一致
            # 变量
            x1 = tf.Variable(3, dtype=tf.float32, name='x_1')
            x2 = tf.Variable(1, dtype=tf.float32, name='x_2')
            y = 3 * (tf.pow(x1, 3)+tf.pow(x2, 3)) - 6*(tf.pow(x1, 2)+tf.pow(x2, 2))
            dx1, dx2 = tf.gradients(y, [x1, x2])  # 一阶导数

    # ConfigProto 加上allow_soft_placement=True就可以使用 gpu 了
    config = tf.ConfigProto(allow_soft_placement=True)  # 创建sess的时候对sess进行参数配置
    config.gpu_options.allow_growth = True  # True是让TensorFlow在运行过程中动态申请显存,避免过多的显存占用。
    config.allow_soft_placement = True  # 当指定的设备不存在时,允许选择一个存在的设备运行。比如gpu不存在,自动降到cpu上运行
    with tf.Session(config=config) as sess:
        sess.run(tf.global_variables_initializer())
        dx11, dx22 = sess.run([dx1, dx2], feed_dict={x1: 1, x2: 1})
        print(dx11)
        print(dx22)
        print('函数y在x_1=1, x_2=1处的关于x_1的一阶导数:dx1=', dx11, ',关于x_2的一阶导数:dx2=', dx22, sep='')

输出结果:

函数y在x_1=1, x_2=1处的关于x_1的一阶导数:dx1=-3.0,关于x_2的一阶导数:dx2=-3.0 

例二

$$u = 3(x^3+y^3)-6(x^2+y^2)+xy$$

我们很显然知道:u_x = 9x^2-12x+y, u_y = 9y^2-12y+x.那么程序结果呢?

def test_gradient1():
    with tf.device('/gpu:%s' % 0):
        with tf.variable_scope('vscope', reuse=tf.AUTO_REUSE):
            # 注意类型必须均为浮点型,并且一致
            # 变量
            x1 = tf.Variable(3, dtype=tf.float32, name='x_1')
            x2 = tf.Variable(1, dtype=tf.float32, name='x_2')
            y = 3 * (tf.pow(x1, 3)+tf.pow(x2, 3)) - 6*(tf.pow(x1, 2)+tf.pow(x2, 2)) + x1*x2
            dx1, dx2 = tf.gradients(y, [x1, x2])  # 一阶导数

    # ConfigProto 加上allow_soft_placement=True就可以使用 gpu 了
    config = tf.ConfigProto(allow_soft_placement=True)  # 创建sess的时候对sess进行参数配置
    config.gpu_options.allow_growth = True  # True是让TensorFlow在运行过程中动态申请显存,避免过多的显存占用。
    config.allow_soft_placement = True  # 当指定的设备不存在时,允许选择一个存在的设备运行。比如gpu不存在,自动降到cpu上运行
    with tf.Session(config=config) as sess:
        sess.run(tf.global_variables_initializer())
        dx11, dx22 = sess.run([dx1, dx2], feed_dict={x1: 1, x2: 1})
        print('函数y在x_1=1, x_2=1处的关于x_1的一阶导数:dx1=', dx11, ',关于x_2的一阶导数:dx2=', dx22, sep='')

输出结果:

函数y在x_1=1, x_2=1处的关于x_1的一阶导数:dx1=-2.0,关于x_2的一阶导数:dx2=-2.0

二阶偏导的计算

$$u = 3(x^3+y^3)-6(x^2+y^2)$$

我们很显然知道:u_{xx} = 18x-12, u_{yy} = 18y-12.

def test_gradient2():
    with tf.device('/gpu:%s' % 0):
        with tf.variable_scope('vscope', reuse=tf.AUTO_REUSE):
            # 注意类型必须均为浮点型,并且一致
            # 变量
            x1 = tf.Variable(3, dtype=tf.float32, name='x_1')
            x2 = tf.Variable(1, dtype=tf.float32, name='x_2')
            y = 3 * (tf.pow(x1, 3)+tf.pow(x2, 3)) - 6*(tf.pow(x1, 2)+tf.pow(x2, 2))
            dx1, dx2 = tf.gradients(y, [x1, x2])  # 一阶导数
            ddx1, ddx2 = tf.gradients([dx1, dx2], [x1, x2])  # 二阶导数

    # ConfigProto 加上allow_soft_placement=True就可以使用 gpu 了
    config = tf.ConfigProto(allow_soft_placement=True)  # 创建sess的时候对sess进行参数配置
    config.gpu_options.allow_growth = True  # True是让TensorFlow在运行过程中动态申请显存,避免过多的显存占用。
    config.allow_soft_placement = True  # 当指定的设备不存在时,允许选择一个存在的设备运行。比如gpu不存在,自动降到cpu上运行
    with tf.Session(config=config) as sess:
        sess.run(tf.global_variables_initializer())
        ddx11, ddx22 = sess.run([ddx1, ddx2], feed_dict={x1: 1, x2: 1})
        print('函数y在x_1=1, x_2=1处的关于x_1的一阶导数:dx1=', ddx11, ',关于x_2的一阶导数:dx2=', ddx22, sep='')

函数y在x_1=1, x_2=1处的关于x_1的一阶导数:dx1=6.0,关于x_2的一阶导数:dx2=6.0

$$u = 3(x^3+y^3)-6(x^2+y^2)+xy$$

我们很显然知道:u_{xx} = 18x-12, u_{yy} = 18y-12.

def test_gradient3():
    with tf.device('/gpu:%s' % 0):
        with tf.variable_scope('vscope', reuse=tf.AUTO_REUSE):
            # 注意类型必须均为浮点型,并且一致
            # 变量
            x1 = tf.Variable(3, dtype=tf.float32, name='x_1')
            x2 = tf.Variable(1, dtype=tf.float32, name='x_2')
            y = 3 * (tf.pow(x1, 3)+tf.pow(x2, 3)) - 6*(tf.pow(x1, 2)+tf.pow(x2, 2))+x*y
            dx1, dx2 = tf.gradients(y, [x1, x2])  # 一阶导数
            ddx1, ddx2 = tf.gradients([dx1, dx2], [x1, x2])  # 二阶导数

    # ConfigProto 加上allow_soft_placement=True就可以使用 gpu 了
    config = tf.ConfigProto(allow_soft_placement=True)  # 创建sess的时候对sess进行参数配置
    config.gpu_options.allow_growth = True  # True是让TensorFlow在运行过程中动态申请显存,避免过多的显存占用。
    config.allow_soft_placement = True  # 当指定的设备不存在时,允许选择一个存在的设备运行。比如gpu不存在,自动降到cpu上运行
    with tf.Session(config=config) as sess:
        sess.run(tf.global_variables_initializer())
        ddx11, ddx22 = sess.run([ddx1, ddx2], feed_dict={x1: 1, x2: 1})
        print('函数y在x_1=1, x_2=1处的关于x_1的二阶导数:ddx1=', ddx11, ',关于x_2的二阶导数:ddx2=', ddx22, sep='')

$$u = 3(x^3+y^3)-6(x^2+y^2)+x^2y^2$$

我们很显然知道:u_{xx} = 18x-12+2y^2, u_{yy} = 18y-12+2x^2.

def test_gradient4():
    with tf.device('/gpu:%s' % 0):
        with tf.variable_scope('vscope', reuse=tf.AUTO_REUSE):
            # 注意类型必须均为浮点型,并且一致
            # 变量
            x1 = tf.Variable(3, dtype=tf.float32, name='x_1')
            x2 = tf.Variable(1, dtype=tf.float32, name='x_2')
            y = 3 * (tf.pow(x1, 3)+tf.pow(x2, 3)) - 6*(tf.pow(x1, 2)+tf.pow(x2, 2)) + (x1**2)*(x2**2)
            dx1, dx2 = tf.gradients(y, [x1, x2])  # 一阶导数
            ddx1, ddx2 = tf.gradients([dx1, dx2], [x1, x2])  # 二阶导数

    # ConfigProto 加上allow_soft_placement=True就可以使用 gpu 了
    config = tf.ConfigProto(allow_soft_placement=True)  # 创建sess的时候对sess进行参数配置
    config.gpu_options.allow_growth = True  # True是让TensorFlow在运行过程中动态申请显存,避免过多的显存占用。
    config.allow_soft_placement = True  # 当指定的设备不存在时,允许选择一个存在的设备运行。比如gpu不存在,自动降到cpu上运行
    with tf.Session(config=config) as sess:
        sess.run(tf.global_variables_initializer())
        ddx11, ddx22 = sess.run([ddx1, ddx2], feed_dict={x1: 1, x2: 1})
        print('函数y在x_1=1, x_2=1处的关于x_1的二阶导数:ddx1=', ddx11, ',关于x_2的二阶导数:ddx2=', ddx22, sep='')

划重点的来了,以上的变量都是独立的。如果变量是向量呢?是什么样子的。我们首先看一下,函数对向量的求导机制. f(\boldsymbol{x}) =f(x_1,x_2,x_3,\cdots,x_n),这里 \boldsymbol{x}=(x_1,x_2,x_3,\cdots,x_n)'.那么

\frac{df(\boldsymbol{x})}{d\boldsymbol{x}} = \left ( \frac{\partial f}{\partial x_1},\frac{\partial f}{\partial x_2},\frac{\partial f}{\partial x_3},\cdots,\frac{\partial f}{\partial x_n}\right )'

参考:机器学习中常用的矩阵求导公式 机器学习中常用的矩阵求导公式_jason的专栏-CSDN博客_常用矩阵求导

矩阵求导、几种重要的矩阵及常用的矩阵求导公式_青萍之末的博客-CSDN博客_矩阵求导

u=\sigma (W_2*\sigma (W_1*z+B_1)+B_2),z=(x,y)'

这里 \sigma 代表激活函数,如Relu。并且

W_1 =\left[ \begin{matrix} 1&2\\3&4 \end{matrix} \right], W_2 =\left[ \begin{matrix} 1&2\\3&4 \end{matrix} \right],W_3 =\left[2,1 \right], B_1 =\left[ \begin{matrix} 1\\3 \end{matrix} \right], B_2 =\left[ \begin{matrix} 2\\4 \end{matrix} \right], B_3 =\left[2 \right]

u的形式为(假设计算过程中值均为正值)

u=[2,1]*\left [ \begin{matrix} (x+2y+1)+2(3x+4y+3)+2\\ 3(x+2y+1)+4(3x+4y+3)+4 \end{matrix} \right ]+ 2= [2,1]*\left [ \begin{matrix} 7x+10y+9\\ 15x+22y+19 \end{matrix} \right ]=(7x+10y+9)+2(15x+22y+19)+2

def test_gradient6():
    with tf.device('/gpu:%s' % 0):
        with tf.variable_scope('vscope', reuse=tf.AUTO_REUSE):
            # 注意类型必须均为浮点型,并且一致
            # 变量
            x = tf.Variable([[0.1], [0.1]], dtype=tf.float32, name='x')
            W1 = np.array([[1, 2], [3, 4]], dtype=np.float32)
            B1 = np.array([[1], [3]], dtype=np.float32)
            W2 = np.array([[1, 2], [3, 4]], dtype=np.float32)
            B2 = np.array([[2], [4]], dtype=np.float32)
            W3 = np.array([[2, 1]], dtype=np.float32)
            B3 = np.array([[2]], dtype=np.float32)
            y = tf.nn.relu(tf.matmul(W1, x) + B1)
            y = tf.nn.relu(tf.matmul(W2, y) + B2)
            y = tf.nn.relu(tf.matmul(W3, y) + B3)
            dx = tf.gradients(y, x)  # 一阶导数
            ddx = tf.gradients(dx, x)  # 二阶导数

    # ConfigProto 加上allow_soft_placement=True就可以使用 gpu 了
    config = tf.ConfigProto(allow_soft_placement=True)  # 创建sess的时候对sess进行参数配置
    config.gpu_options.allow_growth = True  # True是让TensorFlow在运行过程中动态申请显存,避免过多的显存占用。
    config.allow_soft_placement = True  # 当指定的设备不存在时,允许选择一个存在的设备运行。比如gpu不存在,自动降到cpu上运行
    with tf.Session(config=config) as sess:
        sess.run(tf.global_variables_initializer())
        dx1, ddx1 = sess.run([dx, ddx], feed_dict={x: [[1], [1]]})
        print('函数y在x=[1,1]处的一阶导数:dx=', dx1, ',关于x的二阶导数:ddx=', ddx1, sep='')

函数y在x=[1,1]处的一阶导数:dx=[array([[29.],
       [42.]], dtype=float32)],关于x的二阶导数:ddx=[array([[0.],
       [0.]], dtype=float32)] 

向量对向量求导。

首先看一些概念。

例子

$$u = 3z^3-6z^2+z, z=(x,y)^T$$

我么有 

u = 3\left[ \begin{matrix} x^3\\ y^3 \end{matrix}\right ]- 6\left[ \begin{matrix} x^2\\ y^2 \end{matrix}\right ]+ \left[ \begin{matrix} x\\ y \end{matrix}\right ]= \left [ \begin{matrix} 3x^3-6x^2+x\\ 3y^3-6y^2+y \end{matrix} \right ]

u_1 = 3x^3-6x^2+x, u_2=3y^3-6y^2+y。那么

\frac{d u}{d z} = \frac{d\left (\begin{matrix} u_1\\u_2 \end{matrix} \right )}{d \left (\begin{matrix} x\\y \end{matrix} \right )} =\frac{d\left[ \begin{matrix} 9x^2-12x+1\\ 9y^2-12y+1 \end{matrix}\right ]}{d\left (\begin{matrix} x\\y \end{matrix} \right )}

这里需要注意,u_1 是一个关于 (x,y)'的常量,所以是标量对向量求导。结果应该是u_1u_2 分开的。最后排列成超向量或者矩阵都可以。如:

\left ( \begin{matrix} \frac{du_1}{dx}\\ \frac{du_1}{dy} \\ \frac{du_2}{dx} \\ \frac{du_2}{dy} \end{matrix} \right ),   \left ( \begin{matrix} \frac{du_1}{dx}& \frac{du_1}{dy} \\ \frac{du_2}{dx} &\frac{du_2}{dy} \end{matrix} \right )

def test_gradient5():
    with tf.device('/gpu:%s' % 0):
        with tf.variable_scope('vscope', reuse=tf.AUTO_REUSE):
            # 注意类型必须均为浮点型,并且一致
            # 变量
            x = tf.Variable([[0.1], [0.1]], dtype=tf.float32, name='x')
            y = 3*tf.pow(x, 3) - 6 * tf.pow(x, 2) + x
            dx = tf.gradients(y, x)  # 一阶导数
            ddx = tf.gradients(dx, x)  # 二阶导数

    # ConfigProto 加上allow_soft_placement=True就可以使用 gpu 了
    config = tf.ConfigProto(allow_soft_placement=True)  # 创建sess的时候对sess进行参数配置
    config.gpu_options.allow_growth = True  # True是让TensorFlow在运行过程中动态申请显存,避免过多的显存占用。
    config.allow_soft_placement = True  # 当指定的设备不存在时,允许选择一个存在的设备运行。比如gpu不存在,自动降到cpu上运行
    with tf.Session(config=config) as sess:
        sess.run(tf.global_variables_initializer())
        dx1, ddx1 = sess.run([dx, ddx], feed_dict={x: [[1], [1]]})
        print('函数y在x=[1;1]处的一阶导数:dx=', dx1, ',关于x的二阶导数:ddx=', ddx1, sep='')

运行结果. 函数y在x=[1;1]处的一阶导数:dx=[array([[-2.],
       [-2.]], dtype=float32)],关于x的二阶导数:ddx=[array([[6.],
       [6.]], dtype=float32)] 

这里有个问题,tensorflow中向量对向量求导(行对行,列对列)貌似有问题。留作慢慢研究。。。。。。。

下面看看如何实现 拉普拉斯 的二阶偏导。我们以简单的函数为例:

u = x^2+5xy+4y^2

一阶导数为 u_x = 2x+5y,u_y=8y+5x

二阶导数为 u_{xx}=2,u_{yy}=8

def test_gradient7():
    with tf.device('/gpu:%s' % 0):
        with tf.variable_scope('vscope', reuse=tf.AUTO_REUSE):
            # 注意类型必须均为浮点型,并且一致
            # 变量
            x = tf.Variable([[0.1], [0.1]], dtype=tf.float32, name='x')
            W1 = np.array([[1, 2], [3, 4]], dtype=np.float32)
            W2 = np.array([[1, 1]], dtype=np.float32)
            y = x*tf.matmul(W1, x)
            y = tf.matmul(W2, y)
            Dx = tf.gradients(y, x)[0]        # 一阶导数
            Dx1 = tf.gather(Dx, [0], axis=0)  # 将一阶导数关于x1的部分取出来
            Dx2 = tf.gather(Dx, [1], axis=0)  # 将一阶导数关于x2的部分取出来

            DDx1 = tf.gradients(Dx1, x)        # 对取出来额部分关于x求导,就可以得到关于x的二阶导数的向量
            DDx1 = tf.squeeze(DDx1)
            DDx1 = tf.gather(DDx1, [0])  # 将一阶导数关于x2的部分取出来

            DDx2 = tf.gradients(Dx2, x)  # 对取出来额部分关于x求导,就可以得到关于x的二阶导数的向量
            DDx2 = tf.squeeze(DDx2)
            DDx2 = tf.gather(DDx2, [1])  # 将一阶导数关于x1的部分取出来


    # ConfigProto 加上allow_soft_placement=True就可以使用 gpu 了
    config = tf.ConfigProto(allow_soft_placement=True)  # 创建sess的时候对sess进行参数配置
    config.gpu_options.allow_growth = True  # True是让TensorFlow在运行过程中动态申请显存,避免过多的显存占用。
    config.allow_soft_placement = True  # 当指定的设备不存在时,允许选择一个存在的设备运行。比如gpu不存在,自动降到cpu上运行
    with tf.Session(config=config) as sess:
        sess.run(tf.global_variables_initializer())
        dx, dx1, dx2, ddx1, ddx2 = sess.run([Dx, Dx1, Dx2, DDx1, DDx2], feed_dict={x: [[1], [1]]})
        print('dx:', dx)
        print('dx1:', dx1)
        print('dx2:', dx2)
        print('ddx1:', ddx1)
        print('ddx2:', ddx2)

运行结果:

dx:
 [[ 7.]
 [13.]]
dx1: [[7.]]
dx2: [[13.]]
ddx1: [2.]
ddx2: [8.]

求二阶导数的另一种方式

def test_gradient8():
    with tf.device('/gpu:%s' % 0):
        with tf.variable_scope('vscope', reuse=tf.AUTO_REUSE):
            # 注意类型必须均为浮点型,并且一致
            # 变量
            x1 = tf.Variable([[0.1]], dtype=tf.float32, name='x1')
            x2 = tf.Variable([[0.1]], dtype=tf.float32, name='x1')
            x = tf.concat([x1, x2], axis=0)
            W1 = np.array([[1, 2], [3, 4]], dtype=np.float32)
            W2 = np.array([[1, 1]], dtype=np.float32)
            y = x*tf.matmul(W1, x)
            y = tf.matmul(W2, y)
            Dx = tf.gradients(y, x)[0]        # 一阶导数

            Dx1 = tf.gradients(y, x1)[0]
            DDx1 = tf.gradients(Dx1, x1)[0]       # 对取出来额部分关于x求导,就可以得到关于x的二阶导数的向量

            Dx2 = tf.gradients(y, x2)[0]
            DDx2 = tf.gradients(Dx2, x2)[0]  # 对取出来额部分关于x求导,就可以得到关于x的二阶导数的向量

    # ConfigProto 加上allow_soft_placement=True就可以使用 gpu 了
    config = tf.ConfigProto(allow_soft_placement=True)  # 创建sess的时候对sess进行参数配置
    config.gpu_options.allow_growth = True  # True是让TensorFlow在运行过程中动态申请显存,避免过多的显存占用。
    config.allow_soft_placement = True  # 当指定的设备不存在时,允许选择一个存在的设备运行。比如gpu不存在,自动降到cpu上运行
    with tf.Session(config=config) as sess:
        sess.run(tf.global_variables_initializer())
        dx, dx1, dx2, ddx1, ddx2 = sess.run([Dx, Dx1, Dx2, DDx1, DDx2], feed_dict={x: [[1], [1]]})
        print('dx:\n', dx)
        print('dx1:', dx1)
        print('dx2:', dx2)
        print('ddx1:', ddx1)
        print('ddx2:', ddx2)

结果:

dx:
 [[ 7.]
 [13.]]
dx1: [[7.]]
dx2: [[13.]]
ddx1: [[2.]]
ddx2: [[8.]]

对于多维输入,结果也类似。代码如下:

def test_gradient9():
    with tf.device('/gpu:%s' % 0):
        with tf.variable_scope('vscope', reuse=tf.AUTO_REUSE):
            # 注意类型必须均为浮点型,并且一致
            # 变量
            x = tf.placeholder(tf.float32, name='X_it', shape=[2, 3])
            # x = tf.Variable([[0.1, 0.1, 0,1], [0.1, 0.1, 0,1]], dtype=tf.float32, name='x')
            W1 = np.array([[1, 2], [3, 4]], dtype=np.float32)
            W2 = np.array([[1, 1]], dtype=np.float32)
            y = x*tf.matmul(W1, x)
            y = tf.matmul(W2, y)
            Dx = tf.gradients(y, x)[0]        # 一阶导数
            Dx1 = tf.gather(Dx, [0], axis=0)  # 将一阶导数关于x1的部分取出来
            Dx2 = tf.gather(Dx, [1], axis=0)  # 将一阶导数关于x2的部分取出来

            DDx1 = tf.gradients(Dx1, x)        # 对取出来额部分关于x求导,就可以得到关于x的二阶导数的向量
            DDx1 = tf.squeeze(DDx1)
            DDx1 = tf.gather(DDx1, [0], axis=0)  # 将一阶导数关于x2的部分取出来

            DDx2 = tf.gradients(Dx2, x)  # 对取出来额部分关于x求导,就可以得到关于x的二阶导数的向量
            DDx2 = tf.squeeze(DDx2)
            DDx2 = tf.gather(DDx2, [1], axis=0)  # 将一阶导数关于x1的部分取出来

    # ConfigProto 加上allow_soft_placement=True就可以使用 gpu 了
    config = tf.ConfigProto(allow_soft_placement=True)  # 创建sess的时候对sess进行参数配置
    config.gpu_options.allow_growth = True  # True是让TensorFlow在运行过程中动态申请显存,避免过多的显存占用。
    config.allow_soft_placement = True  # 当指定的设备不存在时,允许选择一个存在的设备运行。比如gpu不存在,自动降到cpu上运行
    with tf.Session(config=config) as sess:
        sess.run(tf.global_variables_initializer())
        dx, dx1, dx2, ddx1, ddx2 = sess.run([Dx, Dx1, Dx2, DDx1, DDx2], feed_dict={x: [[1, 1, 1], [1, 1, 1]]})
        print('dx:\n', dx)
        print('dx1:', dx1)
        print('dx2:', dx2)
        print('ddx1:', ddx1)
        print('ddx2:', ddx2)

运行结果:

dx:
 [[ 7.  7.  7.]
 [13. 13. 13.]]
dx1: [[7. 7. 7.]]
dx2: [[13. 13. 13.]]
ddx1: [[2. 2. 2.]]
ddx2: [[8. 8. 8.]]

接下来,我们看如何求混合偏导数。u_{xy}=5

def test_gradient11(batch_size=3):
    with tf.device('/gpu:%s' % 0):
        with tf.variable_scope('vscope', reuse=tf.AUTO_REUSE):
            # 注意类型必须均为浮点型,并且一致
            # 变量
            x = tf.placeholder(tf.float32, name='X_it', shape=[None, 2])
            W1 = np.array([[1, 2], [3, 4]], dtype=np.float32)
            W2 = np.array([[1], [1]], dtype=np.float32)
            y = x*tf.matmul(x, W1)
            y = tf.matmul(y, W2)
            Dx = tf.gradients(y, x)[0]        # 一阶导数
            DDx = tf.gradients(Dx, x)[0]      # 二阶导数
            Dx1 = tf.gather(Dx, [0], axis=-1)  # 将一阶导数关于x1的部分取出来
            Dx2 = tf.gather(Dx, [1], axis=-1)  # 将一阶导数关于x2的部分取出来

            DDx1x2 = tf.gradients(Dx1, x)[0]        # 对取出来额部分关于x求导,就可以得到关于x的二阶导数的向量
            DDx2x1 = tf.gradients(Dx2, x)[0]

    # ConfigProto 加上allow_soft_placement=True就可以使用 gpu 了
    config = tf.ConfigProto(allow_soft_placement=True)  # 创建sess的时候对sess进行参数配置
    config.gpu_options.allow_growth = True  # True是让TensorFlow在运行过程中动态申请显存,避免过多的显存占用。
    config.allow_soft_placement = True  # 当指定的设备不存在时,允许选择一个存在的设备运行。比如gpu不存在,自动降到cpu上运行
    with tf.Session(config=config) as sess:
        sess.run(tf.global_variables_initializer())
        dx, ddx, dx1, dx2, ddxy, ddyx= sess.run([Dx, DDx, Dx1, Dx2, DDx1x2, DDx2x1], feed_dict={x: [[1, 1], [1, 1], [1, 1]]})
        print('dx:\n', dx)
        print('ddx:\n', ddx)
        print('dx1:\n', dx1)
        print('dx2:\n', dx2)
        print('ddxy:\n', ddxy)
        print('ddyx:\n', ddyx)

运行结果:(根据之前的工作,很容易提取出来混合偏导的结果)

dx:
 [[ 7. 13.]
 [ 7. 13.]
 [ 7. 13.]]
ddx:
 [[ 7. 13.]
 [ 7. 13.]
 [ 7. 13.]]
dx1:
 [[7.]
 [7.]
 [7.]]
dx2:
 [[13.]
 [13.]
 [13.]]
ddxy:
 [[2. 5.]
 [2. 5.]
 [2. 5.]]
ddyx:
 [[5. 8.]
 [5. 8.]
 [5. 8.]]

最新的策略:当要解决的问题,维数比较大的时候,用以上方法计算高阶导数,计算量比较大。下面为一种新的计算高阶导数的方法。请参考:https://ins.sjtu.edu.cn/people/xuzhiqin/pub/laplaciancode.pdf

看一个例子:

y=x^2+4y^2+5xy

代码中:

out_1=(x,y)\bigl(\begin{smallmatrix} 1 & 2\\ 3& 4 \end{smallmatrix}\bigr)=(x+3y,2x+4y)

out_2 = (x,y)\odot out_1=(x,y)\odot (x+3y,2x+4y)=(x^2+3y,2xy+4y^2)

out = out_2*\begin{bmatrix} 1\\1 \end{bmatrix}=(x^2+3xy,2xy+4y^2)\begin{bmatrix} 1\\1 \end{bmatrix}=x^2+4y^2+5xy

def test_gradient14(batch_size=3):
    with tf.device('/gpu:%s' % 0):
        with tf.variable_scope('vscope', reuse=tf.AUTO_REUSE):
            xit_unstack = []
            # 注意类型必须均为浮点型,并且一致
            x_it = tf.placeholder(tf.float32, name='X_it', shape=[batch_size, 2])

            # 将x_it解耦,对解耦的扩维或者转置为[-1,1]的形状。然后拼接,这样x_it的分量就分开了,
            # 解耦后的变量作为神经网络的输入,然后进行计算
            unstack_xit = tf.unstack(x_it, axis=-1)
            for x_tmp in unstack_xit:
                xit_unstack.append(tf.expand_dims(x_tmp, axis=-1))

            _x_it = tf.concat(xit_unstack, axis=-1)
            W1 = np.array([[1, 2], [3, 4]], dtype=np.float32)
            W2 = np.array([[1], [1]], dtype=np.float32)
            ee = tf.matmul(_x_it, W1)
            y1 = _x_it * tf.matmul(_x_it, W1)
            y = tf.matmul(y1, W2)

            Dx = tf.gradients(y, _x_it)[0]  # 关于x=(x1,x2)一阶导数

            Dx1 = tf.gather(Dx, [0], axis=-1)  # 将一阶导数关于x1的部分取出来
            Dx2 = tf.gather(Dx, [1], axis=-1)  # 将一阶导数关于x2的部分取出来

            DDx1 = tf.gradients(Dx1, xit_unstack[0])[0]  # 关于x=(x1,x2)二阶导数
            DDx2 = tf.gradients(Dx2, xit_unstack[1])[0]  # 关于x=(x1,x2)二阶导数

            DDx1x2 = tf.gradients(Dx1, xit_unstack[1])[0]  # 关于x=(x1,x2)二阶偏导数

    # ConfigProto 加上allow_soft_placement=True就可以使用 gpu 了
    config = tf.ConfigProto(allow_soft_placement=True)  # 创建sess的时候对sess进行参数配置
    config.gpu_options.allow_growth = True  # True是让TensorFlow在运行过程中动态申请显存,避免过多的显存占用。
    config.allow_soft_placement = True  # 当指定的设备不存在时,允许选择一个存在的设备运行。比如gpu不存在,自动降到cpu上运行
    with tf.Session(config=config) as sess:
        sess.run(tf.global_variables_initializer())
        dx, dx1, dx2, ddx1, ddx2, ddx1x2= sess.run([Dx, Dx1, Dx2, DDx1, DDx2, DDx1x2], feed_dict={x_it: [[1, 1], [1, 1], [1, 1]]})
        print('dx:\n', dx)
        print('dx1:\n', dx1)
        print('dx2:\n', dx2)
        print('ddx1:\n', ddx1)
        print('ddx2:\n', ddx2)
        print('ddx1x2:\n', ddx1x2)

dx:
 [array([[ 7., 13.],
       [ 7., 13.],
       [ 7., 13.]], dtype=float32)]
dx1:
 [[[7.]
  [7.]
  [7.]]]
dx2:
 [[[13.]
  [13.]
  [13.]]]
ddx1:
 [[2.]
 [2.]
 [2.]]
ddx2:
 [[8.]
 [8.]
 [8.]]
ddx1x2:
 [[5.]
 [5.]
 [5.]]

下面看三阶导数的计算

y=x^3+4y^3+3x^2y+2xy^2

def test_gradient15(batch_size=3):
    with tf.device('/gpu:%s' % 0):
        with tf.variable_scope('vscope', reuse=tf.AUTO_REUSE):
            xit_unstack = []
            # 注意类型必须均为浮点型,并且一致
            x_it = tf.placeholder(tf.float32, name='X_it', shape=[batch_size, 2])

            # 将x_it解耦,对解耦的扩维或者转置为[-1,1]的形状。然后拼接,这样x_it的分量就分开了,
            # 解耦后的变量作为神经网络的输入,然后进行计算
            unstack_xit = tf.unstack(x_it, axis=-1)
            for x_tmp in unstack_xit:
                xit_unstack.append(tf.expand_dims(x_tmp, axis=-1))

            _x_it = tf.concat(xit_unstack, axis=-1)
            W1 = np.array([[1, 2], [3, 4]], dtype=np.float32)
            W2 = np.array([[1], [1]], dtype=np.float32)
            y1 = _x_it * tf.matmul(_x_it, W1)
            y2 = _x_it * y1
            y = tf.matmul(y2, W2)

            Dx = tf.gradients(y, _x_it)[0]  # 关于x=(x1,x2)一阶导数

            DDx = tf.gradients(Dx, _x_it)[0]  # 关于x=(x1,x2)一阶导数

            Dx1 = tf.gather(Dx, [0], axis=-1)  # 将一阶导数关于x1的部分取出来
            Dx2 = tf.gather(Dx, [1], axis=-1)  # 将一阶导数关于x2的部分取出来

            DDx1 = tf.gradients(Dx1, xit_unstack[0])[0]  # 关于x=(x1,x2)二阶导数
            DDx2 = tf.gradients(Dx2, xit_unstack[1])[0]  # 关于x=(x1,x2)二阶导数

            DDx1x2 = tf.gradients(Dx1, xit_unstack[1])[0]  # 关于x=(x1,x2)二阶导数

            DDDx1 = tf.gradients(DDx1, xit_unstack[0])[0]  # 关于x=(x1,x2)三阶导数
            DDDx2 = tf.gradients(DDx2, xit_unstack[1])[0]  # 关于x=(x1,x2)三阶导数

    # ConfigProto 加上allow_soft_placement=True就可以使用 gpu 了
    config = tf.ConfigProto(allow_soft_placement=True)  # 创建sess的时候对sess进行参数配置
    config.gpu_options.allow_growth = True  # True是让TensorFlow在运行过程中动态申请显存,避免过多的显存占用。
    config.allow_soft_placement = True  # 当指定的设备不存在时,允许选择一个存在的设备运行。比如gpu不存在,自动降到cpu上运行
    with tf.Session(config=config) as sess:
        sess.run(tf.global_variables_initializer())
        dx, dx1, dx2, ddx, ddx1, ddx2, ddx1x2, dddx1, dddx2 = sess.run(
            [Dx, Dx1, Dx2, DDx, DDx1, DDx2, DDx1x2, DDDx1, DDDx2], feed_dict={x_it: [[1, 1], [1, 1], [1, 1]]})
        print('dx:\n', dx)
        print('dx1:\n', dx1)
        print('dx2:\n', dx2)
        print('ddx:\n', ddx)
        print('ddx1:\n', ddx1)
        print('ddx2:\n', ddx2)
        print('ddx1x2:\n', ddx1x2)
        print('dddx1:\n', dddx1)
        print('dddx2:\n', dddx2)

dx:
 [[11. 19.]
 [11. 19.]
 [11. 19.]]
dx1:
 [[11.]
 [11.]
 [11.]]
dx2:
 [[19.]
 [19.]
 [19.]]
ddx:
 [[22. 38.]
 [22. 38.]
 [22. 38.]]
ddx1:
 [[12.]
 [12.]
 [12.]]
ddx2:
 [[28.]
 [28.]
 [28.]]
ddx1x2:
 [[10.]
 [10.]
 [10.]]
dddx1:
 [[6.]
 [6.]
 [6.]]
dddx2:
 [[24.]
 [24.]
 [24.]]

def test_gradient16(batch_size=3, indim=2):
    with tf.device('/gpu:%s' % 0):
        with tf.variable_scope('vscope', reuse=tf.AUTO_REUSE):
            # 注意类型必须均为浮点型,并且一致
            x_it = tf.placeholder(tf.float32, name='X_it', shape=[None, indim])

            # 将x_it解耦,对解耦的扩维或者转置为[-1,1]的形状。然后拼接,这样x_it的分量就分开了,
            # 解耦后的变量作为神经网络的输入,然后进行计算
            unstack_xit = tf.unstack(x_it, axis=-1)

            _x_it = tf.stack(unstack_xit, axis=-1)
            W1 = np.array([[1, 2], [3, 4]], dtype=np.float32)
            W2 = np.array([[1], [1]], dtype=np.float32)
            y1 = _x_it * tf.matmul(_x_it, W1)
            y2 = _x_it * y1
            y = tf.matmul(y2, W2)

            Dx = tf.gradients(y, _x_it)[0]  # 关于x=(x1,x2)一阶导数

            DDx = tf.gradients(Dx, _x_it)[0]  # 关于x=(x1,x2)一阶导数

            Dx1 = tf.gather(Dx, [0], axis=-1)  # 将一阶导数关于x1的部分取出来
            Dx2 = tf.gather(Dx, [1], axis=-1)  # 将一阶导数关于x2的部分取出来

            DDx1 = tf.reshape(tf.gradients(Dx1, unstack_xit[0])[0], shape=[-1,1])  # 关于x=(x1,x2)二阶导数
            DDx2 = tf.reshape(tf.gradients(Dx2, unstack_xit[1])[0], shape=[-1,1])  # 关于x=(x1,x2)二阶导数

            DDx1x2 = tf.reshape(tf.gradients(Dx1, unstack_xit[1])[0], shape=[-1,1])  # 关于x=(x1,x2)二阶导数

            DDDx1 = tf.reshape(tf.gradients(DDx1, unstack_xit[0])[0], shape=[-1,1])  # 关于x=(x1,x2)二阶导数
            DDDx2 = tf.reshape(tf.gradients(DDx2, unstack_xit[1])[0], shape=[-1,1])  # 关于x=(x1,x2)二阶导数

    # ConfigProto 加上allow_soft_placement=True就可以使用 gpu 了
    config = tf.ConfigProto(allow_soft_placement=True)  # 创建sess的时候对sess进行参数配置
    config.gpu_options.allow_growth = True  # True是让TensorFlow在运行过程中动态申请显存,避免过多的显存占用。
    config.allow_soft_placement = True  # 当指定的设备不存在时,允许选择一个存在的设备运行。比如gpu不存在,自动降到cpu上运行
    with tf.Session(config=config) as sess:
        sess.run(tf.global_variables_initializer())
        dx, dx1, dx2, ddx, ddx1, ddx2, ddx1x2, dddx1, dddx2 = sess.run(
            [Dx, Dx1, Dx2, DDx, DDx1, DDx2, DDx1x2, DDDx1, DDDx2], feed_dict={x_it: [[1, 1], [1, 1], [1, 1]]})
        print('dx:\n', dx)
        print('dx1:\n', dx1)
        print('dx2:\n', dx2)
        print('ddx:\n', ddx)
        print('ddx1:\n', ddx1)
        print('ddx2:\n', ddx2)
        print('ddx1x2:\n', ddx1x2)
        print('dddx1:\n', dddx1)
        print('dddx2:\n', dddx2)

dx:
 [[11. 19.]
 [11. 19.]
 [11. 19.]]
dx1:
 [[11.]
 [11.]
 [11.]]
dx2:
 [[19.]
 [19.]
 [19.]]
ddx:
 [[22. 38.]
 [22. 38.]
 [22. 38.]]
ddx1:
 [[12.]
 [12.]
 [12.]]
ddx2:
 [[28.]
 [28.]
 [28.]]
ddx1x2:
 [[10.]
 [10.]
 [10.]]
dddx1:
 [[6.]
 [6.]
 [6.]]
dddx2:
 [[24.]
 [24.]
 [24.]]

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值