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

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

y=f(x1,x2)=logx1+x1x2sinx2y=f(x1,x2)=log⁡x1+x1x2−sin⁡x2

对自动微分采用一种比较特别的符号表示法,与Bingio的《Deep Learning》书中MLP章节中的表示法类似,采用三段表示法。
  • 输入向量
    我们假设自变量维度为n,在这个例子中n=2,我们用vv来表示自变量:vin=xi,i=1,2,...,n,以本例为例,我们用v1v−1表示x1x1,用v0v0表示x2x2
  • 中间变量
    我们同样用vv表示中间变量,假设共有l个中间变量,表示为:vi,i=1,2,...,lvi,i=1,2,...,l
  • 输出向量
    我们用yy来表示输入向量,假设输出向量维度为k,表示为:yki=vli,i=k1,...,0yk−i=vl−i,i=k−1,...,0,还以本例为例,输出向量只有1维,则k=1k=1,则y1=vly1=vl
    这里写图片描述
    我们先来讲前向模式,这种模式即可求出计算图的输出,同时也可以求出导数值。但是如果以深度学习的角度来看,前向模式就只需要完成计算出计算图中各节点的值就可以了。而求导数则由反向模式来实现。
    我们首先给输入节点赋值:v1=x1v−1=x1v0=x2v0=x2
    接着我们计算v1v1节点:v1=logv1=logx1v1=log⁡v−1=log⁡x1
    我们再计算v2v2节点:v2=v1v0=x1x2v2=v−1v0=x1x2
    我们再来计算v3v3节点:v3=v1+v2=logx1+x1x2v3=v1+v2=log⁡x1+x1x2
    计算v4v4节点:v4=sinv0=sinx2v4=−sin⁡v0=−sin⁡x2
    计算输出节点v5v5y1=v5=v3+v4=logx1+x1x2sinx2y1=v5=v3+v4=log⁡x1+x1x2−sin⁡x2
    至此我们就计算出了计算图中所有节点的值。
    下面我们来介绍在正向模式下导数的计算。假设我们想求yx1∂y∂x1的值,我们也是由输入开始计算。
    v1v−1节点:v1x1=1∂v−1∂x1=1,因为v1=x1v−1=x1
    v0v0节点:v0x1=0∂v0∂x1=0,因为v0=x2v0=x2其与x1x1无关。
    v1v1节点:v1x1=x1logx1=1x1∂v1∂x1=∂∂x1log⁡x1=1x1
    v2v2节点:v2x1=x1x1x2=x2∂v2∂x1=∂∂x1x1x2=x2
    v3v3节点:v3x1=v1x1+v2x1=1x1+x2∂v3∂x1=∂v1∂x1+∂v2∂x1=1x1+x2
    v4v4节点:v4x1=x1sinx2=0∂v4∂x1=∂∂x1sin⁡x2=0
    v5v5节点:v5x1=v3x1v4x1=1x1+x2∂v5∂x1=∂v3∂x1−∂v4∂x1=1x1+x2
    由上面的计算可以看出,我们每次前向计算,只能计算输入向量一维的导数,如果输入向量有n=2n=2维,则需要计算两次,当nn很大时,这种方法的效率就会比较低了。
    对于深度学习问题,我们通常会研究Jacobian矩阵,假设输入向量xRn,而输出向量用yRky∈Rk,则Jacobian矩阵定义为:
    J=y1x1...ykx1y1x2...ykx2.........y1xn...ykxnJ=[∂y1∂x1∂y1∂x2...∂y1∂xn............∂yk∂x1∂yk∂x2...∂yk∂xn]

    我们可以看出,一次前向计算,可以求出Jacobian矩阵的一列数据。
    为了讨论方便,我们这里假设x1=2x1=2x2=5x2=5,我们首先按照前向模式计算出各节点的值,如下图所示:
    这里写图片描述
    我们再来看导数部分。
    v5v5节点有v5=v3v4v5=v3−v4,我们首先求v5v3=(v3v4)v3=1∂v5∂v3=∂(v3−v4)∂v3=1,将结果写在v3v3指向v5v5的边上。
    我们再来求v5v4=(v3v4)v4=1∂v5∂v4=∂(v3−v4)∂v4=−1,将结果写在v4v4指向v5v5的边上。
    我们再来求v4v0=sinv0v0=cosv0=0.284∂v4∂v0=∂sin⁡v0∂v0=cos⁡v0=0.284,将结果写在v0v0指向v4v4的边上。
    我们再来求v3v1=(v1+v2)v1=1∂v3∂v1=∂(v1+v2)∂v1=1,将结果写在v1v1指向v3v3的边上。
    我们再来求v3v2=(v1+v2)v2=1∂v3∂v2=∂(v1+v2)∂v2=1,将结果写在v2v2指向v3v3的边上。
    我们再来求v1v1=logv1v1=1x1=0.5∂v1∂v−1=∂log⁡v−1∂v−1=1x1=0.5,将结果写在v1v−1指向v1v1的边上。
    我们再来求v2v1=(v1v0)v1=v0=5∂v2∂v−1=∂(v−1v0)∂v−1=v0=5,将结果写在v1v−1指向v2v2的边上。
    我们再来求v2v0=(v1v0)v0=v1=2∂v2∂v0=∂(v−1v0)∂v0=v−1=2,将结果写在v0v0指向v2v2的边上。
    至此我们已经求出了所有步的偏导数的值,我们计算y1x1∂y1∂x1就是从y1y1开始,反向走回x1x1节点,可能有多条路径,对每一条路径,将每个边上的值连乘,最后将多条路径的值相加,即可求出y1x1∂y1∂x1的值。y1x2∂y1∂x2的值与此类似。
    如图所示,从y1y1走到x1x1共有两条路径,分别为:
    v5v3v1v1v5→v3→v1→v−1110.5=0.51∗1∗0.5=0.5
    v5v3v2v1v5→v3→v2→v−1115=5.01∗1∗5=5.0
    所以y1x1=0.5+5.0=5.5∂y1∂x1=0.5+5.0=5.5
    用同样的方法我们可以计算y1x2∂y1∂x2的值。由y1y1y1x2∂y1∂x2x2x2的路径也有两条:
    v5v3v2v0v5→v3→v2→v0112=2.01∗1∗2=2.0
    v5v4v0v5→v4→v0(1)0.284=0.284(−1)∗0.284=−0.284
    所以y1y1y1x2=2.0+(0.284)=1.716∂y1∂x2=2.0+(−0.284)=1.716
    相对于正向模式而言,反向模式可以通过一次反向传输,就计算出所有偏导数,而这对于深度学习中的如多层感知器(MLP)模型来说,非常方便,而且中间的偏导数计算只需计算一次,减少了重复计算的工作量,当然这是以增加存储量需求为代价的。
    在本篇博文中,我们详细讲解了自动微分概念,自动微分概念是一个比较老的概念,但是将其引入深度学习领域,还是一个新鲜事务,这就是最近Yann Lecun提到的“深度学习已死,可微分编程永生”中的技术。在下一篇博文中,我们将向大家介绍自动微分在深度学习中的应用。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值