forward和backward

深度学习的本质是,在已知变量x的情况下,求出 \( y = f(w|x) \) 的最优解,绝大部分情况下,都是求f(w|x)的极值。问题就在于,这里所说的极值,是针对哪个自变量的极值。因为前馈神经网络训练过程中分为两步:forward和backward,这两个步骤中的自变量是不一样的。在forward过程中,自变量是x,但在backward过程中,自变量变为了w和b。十几年的方程学习导致我们过拟合了,看到x就觉得它应该是自变量,而w则应该是固定不变的,这是理解该问题最大的障碍。

backward

举个例子,求 \(y=w*x\) 的极小值。我们当然知道该函数是一个无极值的函数

计算机不知道,它只能顺着曲线不断向下找,看能不能找到一个极值点,这就是SGD,随机梯度下降法。

我们知道SGD权重更新公式为:\( w_{new} = w_{old} – μ\frac {\partial f(x)}{\partial w} \),它是怎么来的?表达了什么意思?

SGD是backward的一个过程,那么和上面那个图就不一样了

注意看,此时横轴自变量已经是w了,它和上面那个图本质上是两个图形,只不过因为函数的特殊性,导致长得相似而已。而我们真正要求的极值,实际上是这个函数的极值(即:x作为斜率固定不变,w作为自变量)。

SGD会尝试寻找该函数的极小值:每次将w减小一点,这样得到的y也就小一点,不断尝试,直到w到负无穷也是找不到极值点的。这就有两个问题:

  1. SGD如何知道w是应该增大还是应该减小?
  2. SGD如何知道每轮迭代下,w的变化量是多大?

解决这两个问题很简单,对第一个问题来说,若权重x为正,则应该减小w(如上图),反之则增加。而变化量你可以设定一个定值,更好的方式则是让其在每轮迭代过程中动态变化。而w在某个点上的导数则可以很好得解决这两个问题。

\( \frac {\partial y} {\partial w} \)正好等于x,而其值的绝对值大小也正好对应着斜率的大小——主观上来说,某点的斜率越大,则其离极值点的距离可能就越远。所以就有了SGD的权重更新公式

forward

写代码时,我总是担心对模型的输入x做处理会影响模型训练过程,实际上这种担心是完全多余的,因为单纯对x做函数映射处理对上述backward过程来说是完全透明的——模型的输入对该模型的backward过程来说,只是函数的一些参数,它在模型图建立起来之后就是固定不变的,我们要做的只是调整模型的参数即函数的自变量。

激活函数

但要注意的是上面说的只是单纯对模型输入做处理,像激活函数这种则不是,激活函数的输入本身就是一个模型的输出,也就是(x, w),这么一个元组。它就不止包含模型输入x了,同时还有模型参数w。故在backward链式求导过程中,就要求激活函数可导。

但对于leru这类激活函数来说,它本身在0点就不可导,这也就意味着当模型在backward到w=0时,会不知所措——我到底是该减小权重,还是该保持该权重不变?实际上,该点导数约定俗成就是0

总结

backward过程中,我们总是在针对某个特定的输入x,来不断调整w,是的函数因变量y不断逼近一个期望值。需要注意的是,我们每次都是针对这一个固定的x做调整,即在该输入x下,使得模型拟合的函数接近期望的函数。

应该能想到,每一个x都对应一个函数,我们的目的就是让这所有的函数都能在同一个w下近似拟合期望的函数。为什么可以这样,因为这些x都来自同一个已观测到的样本,他们本身就是服从同一个分布。它就类似于贝叶斯理论中的后验概率了。

例如对于函数 \(y=wx\),假设实际情况是,x只能为正值,而观测的x样本也都是正值,只不过它们的取值不同。则可画出以下backward图形

可见,虽然在某w下,对不同的输入x,对w的更新量不同,但总体方向都是一样的,都是负的,所以模型仍然会继续学习。当对不同输入x时,w出现了反复振荡,则模型可能找到了极值点

Leave a Comment