Skip to content

层不叠不成网

上回说到,MLP不只是向量,稍微扩展一下就变成矩阵了。这里又在说层啊网啊的,那什么是“层”?什么是“网”?层与层之间又是怎么“网”的?

首先把上回那个二层MLP拿过来

y=ReLU(w1x+b1)+ReLU(w2x+b2)

看一看它的结构,有ReLU,有运算,层级结构已经很明显了

x{h1=ReLU(w1x+b1)h2=ReLU(w2x+b2)y=w3h1+w4h2
  • x输入层,负责把原始数据送进来。
  • h1,h2隐藏层,里面住着带激活函数的“神经元”(也就是感知机),它们各自对输入做判断。
  • y输出层,把隐藏层的结果加权求和,给出最终答案。

不过注意,在上一篇的例子中,w3w4 都是 1,而且是写死的,并不是从数据中学来的。

换句话说,我们只是手动叠加了两个感知机,机器没有学会怎么叠加输出。

既然不算输入层的话,这个 MLP 已经叠了两层(一层隐藏 + 一层输出),那自然而然,我们可以叠三层、四层、五层……

x{h11=ReLU(w11x+b11)h12=ReLU(w12x+b12){h21=ReLU(W21[h11,h12]+b21)h22=ReLU(W22[h11,h12]+b22)y

每多叠一层,分段线性函数的“拐点”就指数级增长。在多边形建模里,顶点越多,曲面就越光滑,可以表现的曲面也可以越复杂。

实际上机器学习就是给数据流形建模的过程!简直就是从高模向低模拓扑一样!

简单的复杂函数与求偏导

可以看到,在第二层,就已经需要一个 2×2 矩阵(就是把 W21W22 合起来)来计算了。既然如此,把每一层都写成矩阵的形式

xh1=ReLU(W1x+b1)h2=ReLU(W2h1+b2)y

多层网络又简单又复杂:每一层都是线性的叠加(非线性向线性的拓扑),但是每一条线又是之前所有计算结果的结果(结果却是受全局影响的)。这就导致了完全计算所有权重的偏导都很难(就好像在高维系统里Jacobian算得特别慢一样),然而正是由于线性化,又可以抄近路计算偏导。

回忆一下梯度下降里是怎么逼近目标的

W1:=W1ηLW1,b1:=b1ηLb1,

显然,怎么求偏导 LWi 或者 Lbi 是一个问题。这里面又有ReLU,又有好多层,直接求太麻烦了。

但在高等数学中,我们学过求导数的链式法则,可以得到

LWi=LhLhLhL1hiWi

由于每一步都是线性化的,因此每一个偏导都很好算,这比直接求一个最终的偏导 Lwi 要快得多也方便得多。

反向传播

回到出租车计价函数,目标(损失函数)为

L=12e2=12(y^y)2

输出层是

y^=ReLU(W2h1+b2)

那么输出层的梯度就是

LW2=ReLU(W2h1+b2)eh1,Lb2=ReLU(W2h1+b2)e

那么第一层呢?再对 h1 求偏导

Lh1=Ly^y^h1=ey^h1

现在只剩求 y^h1

y^h1=ReLU(W2h1+b2)W2

那么 h1

h1=ReLU(W1x+b1)

当然为了发现规律我们可以把 x 写成 h0,于是

Lh0=Lh1h1h0=ey^h1h1h0

把最后一项求一下

h1h0=ReLU(W1h0+b1)W1

整理一下

Lh0=eReLU(W2h1+b2)W2ReLU(W1h0+b1)W1

也就是说,每一层的梯度都是误差 e 在每一层经过以下两步“传”回来的

  1. 乘上激活函数的导数 误差 δ 与 激活导数的逐元素相乘

ReLU的导数实际上就是1和0,刚好对应着神经元的激活和关闭,实际上最开始激活函数不是ReLU而是更复杂更连续的Sigmoid,后来发现ReLU比老方法好用。

其实想一想,如果对最终结果没贡献那确实应该在反向传播的时候也不考虑,ReLU实际上是严格明确了这一规则。

  1. 乘上权重矩阵的转置 误差通过 W 传回上一层

其实这不就是误差反馈控制和伴随方法吗?就好像是一环套一环的一个系统,就好像是在最优控制里伴随方程传递协态变量。如果再换成Jacobian,甚至可以把梯度下降写成控制器

WiWiηδihi1

其实不难发现,之前做的一切,输入 x 得到 y,只是在研究一个静态映射,没有“时间”、“传播”和”演化“的概念。

回头看刚才那个多层MLP:

h1=f(W1x)h2=f(W2h1)y^

这是在空间上把它叠了2层。如果把“层”这个概念换成“时间步”呢?如果不把网络往高处叠,而是让数据在同一个网络里随时间流动呢?

从空间到时间

状态空间是怎么表示系统的?

xk+1=Axk+Buk

A 是系统矩阵,表示系统怎么自己演化;B 是输入矩阵,表示输入如何影响系统的演化。此外,还有输出方程 yk=Cxk(这里省略直传矩阵 D),其中的输出矩阵 C 表示了怎么从状态获得输出。

这个方程最重要的意义在于,当前时刻的状态 xk+1,不仅取决于当前的输入 uk,还取决于上一时刻的状态 xk

从静态方程到动力学系统,是状态空间加上“时间”(状态转移)的概念;那么给多层网络加上“时间”的概念,让隐藏层不仅接收当前的输入,还接收上一时刻的自己,会变成什么呢?

来试一试。一个神经元有自己的 Wh+b,这时候考虑 h 在每个时间步的不同

h(t)=tanh(Whh(t1)+Wxx(t)+b)

然后给每一个部分取一个新名字,h(t) 对应的是状态 x,叫隐藏状态;Wh 对应了系统矩阵(状态转移矩阵)A,叫循环权重;Wx 对应输入矩阵 B,叫输入权重。最后再加上激活函数 tanh(),这就是循环神经网络RNN了。

这里用 tanh 主要是目标从绝对的值变为了对状态的缩放,因此激活函数 tanh 实际上做了一个到[-1,1]的映射

现在既有“空间”,又有“时间”了,一个下标不够用了。所以这里为了区分,把“空间位置”放到下标里,把“时间”放在括号里,即写作 hi(t),表示隐藏层 it 时刻的输出。

既然 hi 现在是时变的,那么链式求导实际上发生了一点点变化

LWi=LhL(t)hL(t)hL1(t)(hi(t)Wi+hi(t)hi(t1)hi(t1)Wi++hi(t)hi(t1)hi(2)hi(1)hi(1)Wi)

而中间的一串连乘实际上是连续的时间步偏导

hi(t)hi(t1)=diag[tanh()]Wi

这就是状态转移矩阵的幂次 AkAk 的谱半径决定了系统是稳定还是发散,换到神经网络上 Wik 是一样的道理,如果 Wi 的特征值都小于1,那么很显然最后算出来的梯度是0,这就是梯度消失问题,反之则又变成了梯度爆炸问题

如果看过我之前的文章,我已经在RLS递归最小二乘法上讲过历史依赖方法的增益消失问题,和这个问题就是一体两面。

这个问题的解决方案就和改进RLS思路一样,引入一个“遗忘因子”避免由于涉及时间步太多导致的统计学回归;RNN也可以引入这么一个“遗忘机制”,忘掉一些,记住一些,想起来一些。

没错,这个“遗忘机制”也有新名字,叫“门”。

欲知如何造门,请听下回分解!