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