TensorFlow可微编程实践2---自动微分符号体系

自动微分采用一套与常规机器学习和深度学习不同的符号体系,我们只有熟悉了这个符号体系,才能比较轻松的看懂自动微分的文章。本篇博文将向大家介绍自动微分中使用的符号体系。
我们以下面这个函数为例,讲解一下自动微分的符号表示法:

y = f ( x 1 , x 2 ) = log x 1 + x 1 x 2 sin x 2

对自动微分采用一种比较特别的符号表示法,与Bingio的《Deep Learning》书中MLP章节中的表示法类似,采用三段表示法。

  • 输入向量
    我们假设自变量维度为n,在这个例子中n=2,我们用 v 来表示自变量: v i n = x i , i = 1 , 2 , . . . , n ,以本例为例,我们用 v 1 表示 x 1 ,用 v 0 表示 x 2
  • 中间变量
    我们同样用 v 表示中间变量,假设共有 l 个中间变量,表示为: v i , i = 1 , 2 , . . . , l
  • 输出向量
    我们用 y 来表示输入向量,假设输出向量维度为 k ,表示为: y k i = v l i , i = k 1 , . . . , 0 ,还以本例为例,输出向量只有1维,则 k = 1 ,则 y 1 = v l
    这里写图片描述
    我们先来讲前向模式,这种模式即可求出计算图的输出,同时也可以求出导数值。但是如果以深度学习的角度来看,前向模式就只需要完成计算出计算图中各节点的值就可以了。而求导数则由反向模式来实现。
    我们首先给输入节点赋值: v 1 = x 1 v 0 = x 2
    接着我们计算 v 1 节点: v 1 = log v 1 = log x 1
    我们再计算 v 2 节点: v 2 = v 1 v 0 = x 1 x 2
    我们再来计算 v 3 节点: v 3 = v 1 + v 2 = log x 1 + x 1 x 2
    计算 v 4 节点: v 4 = sin v 0 = sin x 2
    计算输出节点 v 5 y 1 = v 5 = v 3 + v 4 = log x 1 + x 1 x 2 sin x 2
    至此我们就计算出了计算图中所有节点的值。
    下面我们来介绍在正向模式下导数的计算。假设我们想求 y x 1 的值,我们也是由输入开始计算。
    v 1 节点: v 1 x 1 = 1 ,因为 v 1 = x 1
    v 0 节点: v 0 x 1 = 0 ,因为 v 0 = x 2 其与 x 1 无关。
    v 1 节点: v 1 x 1 = x 1 log x 1 = 1 x 1
    v 2 节点: v 2 x 1 = x 1 x 1 x 2 = x 2
    v 3 节点: v 3 x 1 = v 1 x 1 + v 2 x 1 = 1 x 1 + x 2
    v 4 节点: v 4 x 1 = x 1 sin x 2 = 0
    v 5 节点: v 5 x 1 = v 3 x 1 v 4 x 1 = 1 x 1 + x 2
    由上面的计算可以看出,我们每次前向计算,只能计算输入向量一维的导数,如果输入向量有 n = 2 维,则需要计算两次,当 n 很大时,这种方法的效率就会比较低了。
    对于深度学习问题,我们通常会研究Jacobian矩阵,假设输入向量 x R n ,而输出向量用 y R k ,则Jacobian矩阵定义为:
    J = [ y 1 x 1 y 1 x 2 . . . y 1 x n . . . . . . . . . . . . y k x 1 y k x 2 . . . y k x n ]

    我们可以看出,一次前向计算,可以求出Jacobian矩阵的一列数据。
    为了讨论方便,我们这里假设 x 1 = 2 x 2 = 5 ,我们首先按照前向模式计算出各节点的值,如下图所示:
    这里写图片描述
    我们再来看导数部分。
    v 5 节点有 v 5 = v 3 v 4 ,我们首先求 v 5 v 3 = ( v 3 v 4 ) v 3 = 1 ,将结果写在 v 3 指向 v 5 的边上。
    我们再来求 v 5 v 4 = ( v 3 v 4 ) v 4 = 1 ,将结果写在 v 4 指向 v 5 的边上。
    我们再来求 v 4 v 0 = sin v 0 v 0 = cos v 0 = 0.284 ,将结果写在 v 0 指向 v 4 的边上。
    我们再来求 v 3 v 1 = ( v 1 + v 2 ) v 1 = 1 ,将结果写在 v 1 指向 v 3 的边上。
    我们再来求 v 3 v 2 = ( v 1 + v 2 ) v 2 = 1 ,将结果写在 v 2 指向 v 3 的边上。
    我们再来求 v 1 v 1 = log v 1 v 1 = 1 x 1 = 0.5 ,将结果写在 v 1 指向 v 1 的边上。
    我们再来求 v 2 v 1 = ( v 1 v 0 ) v 1 = v 0 = 5 ,将结果写在 v 1 指向 v 2 的边上。
    我们再来求 v 2 v 0 = ( v 1 v 0 ) v 0 = v 1 = 2 ,将结果写在 v 0 指向 v 2 的边上。
    至此我们已经求出了所有步的偏导数的值,我们计算 y 1 x 1 就是从 y 1 开始,反向走回 x 1 节点,可能有多条路径,对每一条路径,将每个边上的值连乘,最后将多条路径的值相加,即可求出 y 1 x 1 的值。 y 1 x 2 的值与此类似。
    如图所示,从 y 1 走到 x 1 共有两条路径,分别为:
    v 5 v 3 v 1 v 1 1 1 0.5 = 0.5
    v 5 v 3 v 2 v 1 1 1 5 = 5.0
    所以 y 1 x 1 = 0.5 + 5.0 = 5.5
    用同样的方法我们可以计算 y 1 x 2 的值。由 y 1 y 1 x 2 x 2 的路径也有两条:
    v 5 v 3 v 2 v 0 1 1 2 = 2.0
    v 5 v 4 v 0 ( 1 ) 0.284 = 0.284
    所以 y 1 y 1 x 2 = 2.0 + ( 0.284 ) = 1.716
    相对于正向模式而言,反向模式可以通过一次反向传输,就计算出所有偏导数,而这对于深度学习中的如多层感知器(MLP)模型来说,非常方便,而且中间的偏导数计算只需计算一次,减少了重复计算的工作量,当然这是以增加存储量需求为代价的。
    在本篇博文中,我们详细讲解了自动微分概念,自动微分概念是一个比较老的概念,但是将其引入深度学习领域,还是一个新鲜事务,这就是最近Yann Lecun提到的“深度学习已死,可微分编程永生”中的技术。在下一篇博文中,我们将向大家介绍自动微分在深度学习中的应用。

猜你喜欢

转载自blog.csdn.net/yt7589/article/details/80734428
今日推荐