原文地址:http://suanfazu.com/t/topic/13742

上一次的分享我们提到了神经网络的几个基本概念,其中提到了随机梯度下降(SGD)算法是神经网络学习(或者更通用的,一般性参数优化问题)的主流方法。概念上,神经网络的学习非常简单,可以被归纳为下面的步骤:

(a) 构造神经网络结构(选择层数、激活函数等)
(b) 初始化构造出的神经网络参数
(c) 对于给定的训练样本与当前的,计算梯度
(d) 通过(随机)梯度下降算法更新
例如,不考虑任何正则化因子情况的最简单参数更新为

神经网络的初学者往往会发现,上述四个步骤当中,对于给定样本,计算其梯度是最 不直观 的一个步骤。本文我们玻森(bosonnlp.com)的讨论就围绕解决梯度的核心算法:后向传播 算法来展开。

首先理清一个概念,步骤(d)的梯度下降算法是一种优化算法,而我们要讨论的后向传播算法,是计算步骤(c)中所需要梯度的一种算法。下面的讨论,我们首先完成单参数(即只有一个参数需要学习)的特例情况下的推导,进而通过 动态规划(Dynamic programming) 思想,将其推导泛化到多变量的情况。需要注意的是,虽然后向传播概念上并不复杂,所用到的数学工具也很基本,但由于所涉及的变量较多、分层等特点,在推导的时候需要比较仔细,类似绣花。

单参数情况

特例
在讨论后向传播算法之前,我们简单回顾一下单变量微积分中的求导规则。来看个例子,假设我们有一个极端简化的网络,其中只有一个需要学习的参数,形式如下

并且假设损失函数Cost为平方误差(MSE)。

假设我们只有一个训练样本。因为这个形式非常简单,我们试试将样本直接带入损失函数:

显然当时,我们可以让损失函数为0,达到最优。下面让我们 假装 不知道最优解,考虑如何用梯度下降方法来求解。假设我们猜为最优,带入计算得到

嗯,不算太坏的一个初始值。让我们计算其梯度,或者损失函数关于的导数。

设置学习率参数,我们可以通过梯度下降方法来不断改进,以达到降低损失函数的目的。三十个迭代的损失函数变化如下:

生成上图采用的是如下Python代码

import matplotlib.pyplot as plt
w0, eta, n_iter = 2, 0.02, 30
gradient_w = lambda w: 2*(w**3)
cost = lambda w: 0.5*(w**4)
costs = []
w = w0
for i in range(n_iter):
costs.append(cost(w))
w = w – eta*gradient_w(w) # SGD
plt.plot(range(n_iter), costs)

可以发现,经过30次迭代后,我们的参数从初始的2改进到了0.597,正在接近我们的最优目标

对于一般的情况
回忆一下,上面的结果是基于我们给定 下得到的,注意这里我们假设输入信号为常量。我们将上面的求解步骤做一点点泛化。

重复上面的求解

关于w求导,

注意,上面求导用到了 链式法则(Chain Rule),即

或者写成偏导数形式:

对于一般性损失函数的情况
上式推导基于损失函数为平方最小下得出,那么我们再泛化一点,对于任意给定的可导损失函数,其关于的梯度:

其中是损失函数关于的导数。实际上这个形式很通用,对于 任意 特定的损失函数和神经网络的激活函数,都可以通过这个式子进行梯度计算。譬如,对于一个有三层的神经网络

同样通过链式法则,

上式看上去比较复杂,我们可以在符号上做一点简化。令每一层网络得到的激活函数结果为,即, 那么:

即:不论复合函数本身有多么复杂,我们都可以将其导数拆解成每一层函数的导数的乘积。

上面的推导我们给出了当神经网络仅仅被一个可学习参数所刻画的情况。一句话总结,在单参数的网络推导中,我们真正用到的唯一数学工具就是 链式法则。实际问题中,我们面对的参数往往是数以百万计的,这也就是为什么我们无法采用直觉去“猜”到最优值,而需要用梯度下降方法的原因。下面我考虑在多参数情况下,如何求解梯度。

多参数情况

首先,不是一般性的,我们假设所构建的为一个层的神经网络,其中每一层神经网络都经过线性变换和非线性变换两个步骤(为简化推导,这里我们略去对bias项的考虑):

定义网络的输入,而作为输出层。一般的,我们令网络第层具有个节点,那么。注意此时我们网络共有个参数需要优化。

为了求得梯度,我们关心参数关于损失函数的的导数:,但似乎难以把简单地与损失函数联系起来。问题在哪里呢?事实上,在单参数的情况下,我们通过链式法则,成功建立第一层网络的参数与最终损失函数的联系。譬如,的改变影响函数的值,而连锁反应影响到的函数结果。那么,对于值的改变,会影响,从而影响。通过的线性变换(因为),的改变将会影响到每一个

将上面的过程写下来:

可以通过上式不断展开进行其梯度计算。这个方式相当于我们枚举了 每一条 改变对最终损失函数影响的 路径。通过简单使用链式法则,我们得到了一个 指数级 复杂度的梯度计算方法。稍仔细观察可以发现,这个是一个典型的递归结构(为什么呢?因为定义的是一个递归结构),可以采用动态规划(Dynamic programming)方法,通过记录子问题答案的进行快速求解。设用于动态规划的状态记录。我们先解决最后一层的边界情况:

上式为通用形式。对于Sigmoid, Tanh等形式的element-wise激活函数,因为可以写成的形式,所示上式可以简化为:

即该情况下,最后一层的关于的导数与损失函数在导数和最后一层激活函数在的导数相关。注意当选择了具体的损失函数和每层的激活函数后,也被唯一确定了。下面我们看看动态规划的 状态转移 情况:

成功建立的递推关系,所以整个网络的可以被计算出。在确定了后,我们的对于任意参数的导数可以被简单表示出:

至此,我们通过链式法则和动态规划的思想,不失一般性的得到了后向传播算法的推导。

posted on 2016-06-22 14:41  一天不进步,就是退步  阅读(338)  评论(0)    收藏  举报