自动微分采用一套与常规机器学习和深度学习不同的符号体系,我们只有熟悉了这个符号体系,才能比较轻松的看懂自动微分的文章。本篇博文将向大家介绍自动微分中使用的符号体系。
我们以下面这个函数为例,讲解一下自动微分的符号表示法:
对自动微分采用一种比较特别的符号表示法,与Bingio的《Deep Learning》书中MLP章节中的表示法类似,采用三段表示法。
-
输入向量
我们假设自变量维度为n,在这个例子中n=2,我们用来表示自变量:,以本例为例,我们用表示,用表示。 -
中间变量
我们同样用表示中间变量,假设共有个中间变量,表示为: -
输出向量
我们用来表示输入向量,假设输出向量维度为,表示为:,还以本例为例,输出向量只有1维,则,则。
我们先来讲前向模式,这种模式即可求出计算图的输出,同时也可以求出导数值。但是如果以深度学习的角度来看,前向模式就只需要完成计算出计算图中各节点的值就可以了。而求导数则由反向模式来实现。
我们首先给输入节点赋值:和
接着我们计算节点:
我们再计算节点:
我们再来计算节点:
计算节点:
计算输出节点:
至此我们就计算出了计算图中所有节点的值。
下面我们来介绍在正向模式下导数的计算。假设我们想求的值,我们也是由输入开始计算。
对节点:,因为
对节点:,因为其与无关。
对节点:
对节点:
对节点:
对节点:
对节点:
由上面的计算可以看出,我们每次前向计算,只能计算输入向量一维的导数,如果输入向量有维,则需要计算两次,当很大时,这种方法的效率就会比较低了。
对于深度学习问题,我们通常会研究Jacobian矩阵,假设输入向量,而输出向量用,则Jacobian矩阵定义为:
我们可以看出,一次前向计算,可以求出Jacobian矩阵的一列数据。
为了讨论方便,我们这里假设且,我们首先按照前向模式计算出各节点的值,如下图所示:
我们再来看导数部分。
对节点有,我们首先求,将结果写在指向的边上。
我们再来求,将结果写在指向的边上。
我们再来求,将结果写在指向的边上。
我们再来求,将结果写在指向的边上。
我们再来求,将结果写在指向的边上。
我们再来求,将结果写在指向的边上。
我们再来求,将结果写在指向的边上。
我们再来求,将结果写在指向的边上。
至此我们已经求出了所有步的偏导数的值,我们计算就是从开始,反向走回节点,可能有多条路径,对每一条路径,将每个边上的值连乘,最后将多条路径的值相加,即可求出的值。的值与此类似。
如图所示,从走到共有两条路径,分别为:
:
:
所以。
用同样的方法我们可以计算的值。由到的路径也有两条:
:
:
所以。
相对于正向模式而言,反向模式可以通过一次反向传输,就计算出所有偏导数,而这对于深度学习中的如多层感知器(MLP)模型来说,非常方便,而且中间的偏导数计算只需计算一次,减少了重复计算的工作量,当然这是以增加存储量需求为代价的。
在本篇博文中,我们详细讲解了自动微分概念,自动微分概念是一个比较老的概念,但是将其引入深度学习领域,还是一个新鲜事务,这就是最近Yann Lecun提到的“深度学习已死,可微分编程永生”中的技术。在下一篇博文中,我们将向大家介绍自动微分在深度学习中的应用。