神经网络

多层感知机

多层感知机的运算

多层感知机的含有 $1$ 个数据输入层,$1$ 个以上的隐藏层,$1$ 个数据输出层,各层神经元之间全连接,同一层神经元之间无连接。

信息传播公式:
$$ z^{(l)} = W^{(l)}·a^{(l-1)} + b^{(l)} \\
a^{(l)} = f_l(z^{(l)})$$

其中:

  • $L$ 代表层数
  • $n^l$ 代表第 $l$ 层的神经元数量
  • $f_l(·)$ 表示第 $l$ 层的激活函数
  • $W^{(l)} \in \mathbb{R}^{n^l\times n^{l-1}}$ 表示第 $l$ 层和第 $l-1$ 层之间的权重矩阵
  • $b^{(l)} \in \mathbb{R}^{n^l} $ 表示第 $l$ 层和第 $l-1$ 层之间的偏置量
  • $z^{(l)} \in \mathbb{R}^{n^l} $ 表示第 $l$ 层神经元的状态向量(输入)
  • $a^{(l)} \in \mathbb{R}^{n^l} $ 表示第 $l$ 层神经元的激活向量(输出)

非线性激活函数(包括硬门限阈值函数)是导致神经网络运算非线性的直接原因,如果用线性函数作为激活函数,无论多少层的神经网络会退化成一个线性回归, 不能处理非线性分类任务。

多层感知机的学习

输出的瞬时(第 $i$ 次)损失: $J(W,b;x^{(i)},y^{(i)})$
训练样本上(共 $N$ 个)平均损失:$\sum_{i=1}^N J(W,b;x^{(i)},y^{(i)})$

学习目标:调整神经元连接权重,使得平均误差能量最小,即最小化损失函数:

$$\sum_{i=1}^N J(W,b;x^{(i)},y^{(i)}) + \frac 1 2 \lambda ||W||_F^2 $$

于是有:
$$ W^{(l)} = W^{(l)} - \alpha \frac {\partial J(W,b)} {\partial W^{(l)}} = W^{(l)} - \alpha \sum_{i=1}^N \left(\frac {\partial J(W,b;x^{(i)},y^{(i)})} {\partial W^{(l)}} \right) \\ b^{(l)} = b^{(l)} - \alpha \frac {\partial J(W,b)} {\partial b^{(l)}} = b^{(l)} - \alpha \sum_{i=1}^N \left(\frac {\partial J(W,b;x^{(i)},y^{(i)})} {\partial b^{(l)}} \right)$$

对于参数的学习,有两种学习方法,批量学习和在线学习。

批量学习:共有 $N$ 个样本(一个 $batch$),随机采样 $batch$ 训练样本值,$batch-by-batch$ 地调整权重,优点是梯度向量形式固定,缺点是需要的内存资源大。
在线学习:$sample-by-sample$ 地调整权重,优点是易执行、存储量小、有效解决大规模和困难模式的分类,缺点是学习过程随机、不稳定。

误差反向传播算法

BP基本思想

$BP$ 算法全称叫作误差反向传播算法($Error\;Back\;Propagation$),或者也叫误差逆传播算法,其核心思想为数据正向传递,误差反向传播


变量依赖关系
由$ z^{(l)} = W^{(l)}·a^{(l-1)} + b^{(l)} ,a^{(l)} = f_l(z^{(l)})$ 得:

$$ z^{(l)} = W^{(l)}·f_l(z^{(l)}) + b^{(l)}$$

可见 $W^{(l)}$ 和 $b^{(l)}$ 都与 $z^{(l)}$ 有关,所以如果能够求取 $z^{(l)}$ 的局部梯度,就可以求出 $W^{(l)}$ 和 $b^{(l)}$ 的梯度。

如下图所示,反向越深的隐层与目标函数之间的变量依赖关系越复杂,使用近似计算的计算复杂度会相当高。

$BP$ 算法通过局部梯度迭代的策略,解决了这一问题:

BP算法过程

按照 $BP$ 的局部梯度迭代策略,问题也就转化成了已知 $l+1$ 层的局部梯度,求 $l$ 层的局部梯度。

假设 $l+1$ 层的局部梯度是已知的:

$$ \delta_j^{(l+1)} = \frac {\partial L} {\partial z_j^{(l+1)}}$$

由图可知:
$$z_j^{(l+1)} = \sum_j a_i^{(l)}w_{ij}^{(l+1)} = \sum_i f_i(z_i^{(l)})w_{ij}^{(l+1)} $$

显然:

$$ \frac {\partial z_j^{(l+1)}} {\partial z_i^{(l)}} = \frac {\partial z_j^{(l+1)}} {\partial z_i^{(l)}}· \frac {\partial a_i^{(l)}} {\partial z_i^{(l)}} = f’_i(z_i^{(l)}) w_{ij}^{(l+1)} $$

于是可以得到局部梯度迭代公式:

$$ \delta_i^{(l)} = \sum_{j=1}^m \frac {\partial z_j^{(l+1)}} {\partial z_i^{(l)}} · \frac {\partial L} {\partial z_j^{(l+1)}} = \sum_{j=1}^m f’_i(z_i^{(l)}) w_{ij}^{(l+1)} \delta_i^{(l+1)} = f’_i(z_i^{(l)}) \sum_{j=1}^m w_{ij}^{(l+1)} \delta_i^{(l+1)} $$



输出层参数的学习:

在 $(1)$ 中,$y$ 代表的是感知机的输出,也就是第 $L$ 层的输出,和 $a^{(L)}$ 是等价的。

隐层参数的学习:

于是可以得到 $BP$ 算法的流程:

  1. 数据初始化
  2. $Epoch$ 采样
  3. 前向计算
  4. 反向梯度计算
    $$ 输出层:\delta_k^L = f’_k(z_k^L)\frac {\partial L} {\partial y_k} \quad 隐藏层:\delta_k^{(l)} = f’_k(z_k^{(l)}) \sum_{k=1}^m w_{ik}^{(l+1)}\delta_k^{(l+1)} $$
  5. 求参数梯度
    $$ \frac {\partial J} {\partial w_{ik}^{(l)}} = a_i^{(l-1)} \delta_k^{(l)} \quad \frac {\partial J} {\partial b_{ik}^{(l)}} = \delta_k^{(l)} $$
  6. 迭代步骤 $2-5$

梯度消失与梯度爆炸

根据 $BP$ 反向传播的算法,前面层上的梯度是来自于后面层上梯度的乘积。当层数达到一定的数量,若激活函数的梯度小于 $1$ 时,就会使前面层的梯度变得很小,更新速度过慢,导致梯度消失。若激活函数的梯度大于 $1$,经过层层迭代,前面的梯度将会成指数级增长,出现梯度爆炸问题。

梯度消失的一种解决方案是使用 $Relu$ 激活函数替换 $Sigmoid$ 函数,$Relu$ 函数的梯度不会随着 $x$ 的增大而变小,$Sigmoid$ 函数在 $x$ 取值较大时梯度趋近于 $0$。

梯度爆炸可以使用梯度剪裁的方法来解决:

  • 选取一个梯度剪裁的阈值 $clip\;norm$(一般选择 $1$)
  • 在计算完每个权重的梯度之后,我们并不像通常那样直接使用这些梯度进行权重更新,而是先求所有权重梯度的平方和 $global\;norm$
  • 最后把每个梯度乘以缩放因子 $clip\;norm / \max(global\;norm, clip\;norm)$

卷积神经网络

多层感知机是一种全连接的结构,但又是全连接的网络会存在一定程度的冗余,卷积神经网络($Convolutional\;Neural\;Network, CNN$)通过局部连接和权重共享的方法来实现对多层感知机的共享。

我们可以对通过下图对卷积神经网络的结构有一个直观的认识:

卷积层

卷积神经网络中每层卷积层由若干卷积单元组成。卷积运算的目的是提取输入的不同特征,第一层卷积层可能只能提取一些低级的特征如边缘、线条和角等层级,更多层的网络能从低级特征中迭代提取更复杂的特征。

一维卷积

给定一个序列 $x_t, t=1,2,\dots, n$ 和一个过滤器 $f_t, t=1,2,\dots, m$,卷积结果是:

$$ y_t = \sum_{k=1}^m f_k · x_{t-k+1}$$


-w444

二维卷积

给定一个图像 $x_{ij},1 \le i \le M,1 \le j \le N $ 和一个过滤器 $f_{ij},1 \le i \le m,1 \le j \le n$,卷积结果是:

$$ y_{ij} = \sum_{u=1}^m \sum_{v=1}^n f_{uv} · x_{i-u+1,j-v+1} $$

在二维图像中,卷积意味着区域内像素的加权平均

输出尺度和参数个数

填充设置
填充设置 $Pad$ 是卷积中的另外一个参数,根据填充设置的不同,卷积的结果有窄卷积,等长卷积和宽卷积,通常情况下,填充的内容都为 $0$,在上面的演示中,一维卷积我们使用的是窄卷积,二维卷积我们使用的是等长卷积。
窄卷积:信号两端不补 $0$,输出信号长度为 $N-M+1$
宽卷积:信号两端补 $0$,输出信号长度为 $N+M-1$
等长卷积:信号两端补 $0$,输出信号长度为 $N$

输出尺度

输入尺度:
宽度 $W_1 = 32$
高度 $H_1 = 32$
深度 $D_1 = 32$
输出尺寸:
宽度 $W_2 = 1+ (W_1-F_W+2P)/S = 32$
高度 $H_2 = 1+ (H_1-F_H+2P)/S = 32$
深度 $D_2 = K = 10$
其中,$F_W$ 是过滤器宽度,$F_H$ 是过滤器高度,$K$ 是过滤器个数,$P$ 是填充大小,$S$ 是步长。

注:不同的过滤器可能是对不同层采样,也可能使用不同的参数对同一层采样。

参数个数

参数个数 $P = (F_W \times F_H \times D_1 + 1) \times K$,其中的 $1$ 表示阈值。

卷积层有一个概念就是权值共享,如没有这个原则,则特征图由 $10$ 个$32\times 32\times 1$ 的特征图组成,即每个特征图上有 $1024$ 个神经元,每个神经元对应输入图像上一块 $5\times 5\times 3$ 的区域,即一个神经元和输入图像的这块区域有 $75$ 个连接,即 $75$ 个权值参数,这是非常复杂的,因此卷积神经网络引入权值共享原则,即一个特征图上每个神经元对应的 $75$ 个权值参数被每个神经元共享,这样则只需 $75\times10=750$ 个权值参数,而每个特征图的阈值也共享,即需要 $10$ 个阈值,则总共需要$750+10=760$ 个参数。

子采样层

池化($Pooling$)是卷积神经网络中另一个重要的概念,它实际上是一种形式的下采样。当前最大池化($Max\;Pooling$)是最为常见,它是将输入的图像划分为若干个矩形区域,对每个子区域输出最大值。

直觉上,这种机制能够有效地原因在于,在发现一个特征之后,它的精确位置远不及它和其他特征的相对位置的关系重要。池化层会不断地减小数据的空间大小,因此参数的数量和计算量也会下降,这在一定程度上也控制了过拟合。通常来说,$CNN$ 的卷积层之间都会周期性地插入池化层。

池化层通常会分别作用于每个输入的特征并减小其大小。$Max\;Pooling$ 每隔 $2$ 个元素从图像划分出 $2\times 2$ 的区块,然后对每个区块中的 $4$ 个数取最大值,这将会减少百分之七十五的数据量。

除了最大池化之外,池化层也可以使用其他池化函数,例如“平均池化”甚至“$L2$范数池化”等,由于池化层过快地减少了数据的大小,目前文献中的趋势是在池化运算时使用较小的区块,甚至不再使用池化层。

递归神经网络

递归神经网络($RNN$)是两种人工神经网络的总称,一种是时间递归神经网络($Recurrent\;Neural\;Network$,即常说的循环神经网络),另一种是递归神经网络($Recursive\;Neural\;Network$)。

基本递归结构




通用逼近定理:如果网络具有充分多的隐藏神经元,任意的非线性动态系统可以由递归神经网络以期望的精度来逼近,对于状态空间的紧致性没有限制。

  • 可控和可观测:递归网络具有局部线性可控和局部可观测性
  • 计算能力:所有图灵机都可由建立在用 $sigmoid$ 激活函数的神经元上的完全连接递归网络模拟

循环神经网络

循环神经网络类似于上文所述的第二种结构,基本的循环单元如下图所示:

按照时间上延展开:

分回合训练

同样,梯度是反向传播的,问题在于求 $W_a$,$W_b$,$W_c$,其中,$W_a$,$W_b$ 的梯度依赖于局部梯度,$W_a$ 相当于多层感知机的隐层,$W_c$ 相当于输出层。

局部梯度迭代:

采用 $BP$ 算法的思想,显然有:

$$ \delta_k = \frac {\partial L} {\partial v_k} = \frac {\partial\left(\sum_{l=k}^n L(y_l) \right)} {\partial v_k} = \frac {\partial L(y_k)} {\partial v_k} + \frac {\partial\left(\sum_{l=k}^n L(y_l) \right)} {\partial v_k} = \frac {\partial L(y_k)} {\partial v_k} + \frac {\partial v_{k+1}} {\partial v_k}\delta_{k+1} $$

其中:

$$\frac {\partial L(y_k)} {\partial v_k} = \frac {\partial s_k} {\partial v_k} \frac {\partial y_k} {\partial s_k} \frac {\partial L(y_k)} {\partial y_k} = diag(\sigma’(v_k))W_c^TL’(y_k) $$

$$ \frac {\partial v_{k+1}} {\partial v_k} \delta_{k+1} = \frac {\partial s_k} {\partial v_k} \frac {\partial v_{k+1}}{\partial s_k} \delta_{k+1} = diag(\sigma’(v_k))W_a^T\delta_{k+1} $$

当 $k = n$ 时
$$ \delta_k = \frac {\partial L} {\partial v_k}= \frac {\partial L(y_k)} {\partial v_k} = diag(\sigma’(v_k))W_c^T L’(y_k) $$

当 $k \ne n$ 时
$$ \delta_k = \frac {\partial L} {\partial v_k}= \frac {\partial L(y_k)} {\partial v_k} + \frac {\partial s_{k+1}} {\partial v_k} \delta_{k+1} = diag(\sigma’(v_k))(W_c^T L’(y_k)+W_a^T\delta_{k+1}) $$

参数更新:

$$ W_a = W_a - \eta_1 \delta_k \frac {\partial v_k}{\partial W_a} = W_a - \eta_1 \delta_k \sum_{k=1}^n s_{k-1}^T
\\ W_b = W_b - \eta_2 \delta_k \frac {\partial v_k}{\partial W_b} = W_b - \eta_2 \delta_k \sum_{k=1}^n x_k^T
\\ W_c = W_c - \eta_3 \delta_k \frac {\partial v_k}{\partial W_c} = W_c - \eta_3 \sum_{k=1}^n s_k^T$$

实时递归训练

RNN扩展结构

$RNN$ 可以较好地处理短依赖关系,但是往往无法较好地处理长时依赖关系,下图所示的是一个标准的 $RNN$ 按时序的延展结构,

在自然语言处理的环境中,有时候只考虑前面的词是远远不够的,于是就出现了双向循环神经网络结构:

从上图可以看出,双向卷积神经网络的隐藏层要保存两个值,一个 $A$ 参与正向计算,另一个值 $A’$ 参与反向计算,最终的输出值 $y_n$ 取决于 $A_n$ 和 $A_n’$ 。正向计算时,隐藏层的值与 $s_t$ 和 $s_{t-1}$ 有关;反向计算时,隐藏层的值与 $s_t’$ 和 $s_{t+1}’$ 有关,最终的输出取决于正向和反向计算的加和,正向计算和反向计算的权重矩阵都是不相同的。

长短时记忆神经网络

如下图所示的是一个传统的 $RNN$ 单元结构,梯度消失和梯度爆炸是传统 $RNN$ 中最为致命的一个缺陷。

在梯度的反向传播过程中,当到达一个梯度几乎为零的阶段 $t$ ,从这个时刻开始再继续往前传播,得到的梯度就不会对最终的梯度值有任何贡献,这就相当于无论 $t$ 之前的网络状态是什么,在训练中都不会对权重数组的更新产生影响,也就是网络事实上已经忽略了 $t$ 时刻之前的状态,这就是原始 $RNN$ 无法处理长距离依赖的原因。

长短时记忆神经网络($Long\; Short-Term\;Memory\;Neural\;Network, LSTM$)是 $RNN$ 的一个变体,可以有效地解决简单循环神经网络的梯度爆炸或消失问题。


$LSTM$ 模型的关键是引入了一组记忆单元($Memory\;Units$),允许网络可以学习何时遗忘历史信息,何时用新信息更新记忆单元。在时刻 $t$ 时,记忆单元 $c_t$ 记录了到当前时刻为止的所有历史信息,并受三个门控制:输入门 $i_t$, 遗忘门 $f_t$ 和输出门 $o_t$,三个门的元素的值在 $[0,1]$ 之间。

$LSTM$ 中最为核心的就是贯穿整个网络的记忆,也就是细胞的状态,用来记录目前为止的所有历史信息。

除此之外,还有门的概念,门由一个 $sigmoid$ 层和一个点乘运算组成,使用 $sigmoid$ 函数意味着要么使信息全部通过,要么阻止全部信息,每个门都可开可关,而且门在每个步骤都会重新组合开关状态。



$\sigma$ 符号表示 $sigmoid$ 激活函数,用于决定什么信息需要遗忘/输入/输出
点乘符号来执行遗忘/输入/输出操作,遗忘/输入/输出那些我们在 $sigmoid$ 层决定遗忘/输入/输出的信息

遗忘门

$LSTM$ 的第一步是决定要丢弃多少历史信息(遗忘细胞中的记忆),遗忘门($Forget\;Gate$)就是来做这个工作的。它输入 $h_{t−1}$ 和 $x_t$,然后为 $C_{t−1}$ 中的每个神经元生成一个 $0~1$ 之间的数字,$0$ 代表完全丢弃,$1$ 代表完全保留。所以我们期望让它需要记住一些确切的东西时,它可以被完全激活;当不再需要这些信息时,它可以被再次关闭。

符号含义:
$f_t$:遗忘门的输出
$W_f$:遗忘门的权重矩阵
$b_f$:遗忘门的偏移量
$h_{t−1}$:$t-1$ 时刻的输出,同时也是 $t$ 时刻的输入
$x_t$:$t$ 时刻新输入的内容
$\sigma$:$sigmoid$ 激活函数

模拟一个语言模型的场景,在神经元状态或许包括当前主语中的性别信息,所以可以使用正确的代词。当我们看到一个新的主语,我们会去遗忘之前的性别信息。

输入门

下一步的工作就是我们要决定在决定了是否要在记忆细胞中保存从新输入的信息,这个模块包括两个部分,一个部分是输入门($Input\;Gate$),决定我们要更新的数值,一个部分创建一个新的候选值,这都是为下一步的状态更新做准备。

符号含义:
$i_t$:输入门的输出
$W_i$:输入门的权重矩阵
$b_i$:输入门的偏移量
$h_{t−1}$:$t-1$ 时刻的输出,同时也是 $t$ 时刻的输入
$x_t$:$t$ 时刻新输入的内容
$\sigma$:$sigmoid$ 激活函数

$\tilde C_t$:新输入的全部信息
$W_C$:输入状态的权重矩阵
$b_C$:输入状态的偏移量
$\tanh$:双曲正切激活函数

在语言模型的例子中,我们想给神经元状态增加新的主语的性别,替换我们将要遗忘的旧主语。

关于激活函数:
$sigmoid$ 用在各种门上,产生 $[0,1]$ 之间的值,这个工作只有 $sigmoid$ 可以胜任。
$tanh$ 用在状态和输出上,是对数据的处理,产生的是 $[-1,1]$ 之间的值,这个工作使用其他的激活函数或许也可以。

更新记忆

现在我们来更新记忆细胞中的信息,我们在上一步已经确定了有什么信息需要更新,现在只需要把它们结合到一起。我们给旧的记忆乘以 $f_t$,遗忘掉我们之前决定要遗忘的信息,然后给新的候选记忆 $\tilde C_t$ 乘以 $i_t$,加入我们之前决定要加入的信息,加入的信息量的多少取决于我们决定更新每个状态的程度。

符号含义:
$f_t$:遗忘门的输出
$C_{t_1}$:上一时刻的全部信息
$i_i$:输入门的输出
$\tilde C_t$:新输入的全部信息
$C_t$:当前时刻的全部信息

在状态更新的时候,$LSTM$ 是用的乘法函数和加法函数结合的方法,所以就不容易出现总梯度逐渐接近 $0$ 的情况,从而解决了 $RNN$ 出现梯度消失,不能进行长时依赖的问题。

在语言模型的例子中,这里就是我们实际上要丢弃旧主语的性别信息,增加新主语性别信息的地方。

输出门

最后,我们要做的是决定当前环节的输出,首先使用一个输出门($Output\;Gate$)决定输出细胞状态的哪个部分,接着用 $tanh$ 函数处理细胞状态(使其值域在 $[-1,1]$ 之间),再将其和输出门的输出相乘,输出我们确定要输出的部分。

符号含义:
$o_t$:输出门的输出
$W_o$:输出门的权重矩阵
$b_o$:输出门的偏移量
$h_{t−1}$:$t-1$ 时刻的输出,同时也是 $t$ 时刻的输入
$x_t$:$t$ 时刻新输入的内容
$\sigma$:$sigmoid$ 激活函数

$C_t$:当前时刻的全部信息
$h_t$:当前时刻的输出
$\tanh$:双曲正切激活函数

在语言模型的例子中,当我们看到一个主语的时候,我们或许想输出相关的动词信息,例如我们可能需要根据单复数信息来输出“他”或者“他们”。

所以在时刻 $t$,$LSTM$ 的更新公式为:

$$ i_t = \sigma(W_ix_t + U_ih_{t-1} + V_ic_{t-1})
\\ f_t = \sigma(W_fx_t + U_fh_{t-1} + V_fc_{t-1})
\\ o_t = \sigma(W_ox_t + U_oh_{t-1} + V_oc_{t-1})
\\ \tilde C_t = tanh(W_Cx_t + U_Ch_{t-1})
\\ C_t = f_t · c_{t-1} + i_t · \tilde C_t
\\ h_t = o_t · tanh(c_t)$$

这里,$x_t$ 是当前时刻的输入,$\sigma$ 是 $sigmoid$ 函数,$V_i, V_f, V_o$ 是对角矩阵。
遗忘门 $f_t$ 控制每一个内存单元需要遗忘多少信息
输入门 $i_t$ 控制每一个内存单元加入多少新的信息
输出门 $o_t$ 控制每一个内存单元输出多少信息

LSTM变种结构

Peephole

加入了窥视孔连接。这意味着门限层也将单元状态作为输入,上图中所有的门限中都加入了窥视孔,但是许多论文都只使用部分窥视孔。

GRU

门限循环单元($Gated\;Recurrent\;Unit, GRU$)是一种 $LSTM$ 的简化版本。$GRU$ 将输入门与和遗忘门合并成一个门:更新门($Update\;Gate$),同时还合并了记忆单元 $c_t$ 和神经元活性 $h_t$。

$GRU$ 模型:更新门 $z$ 和重置门 $r$

  • 更新门 $z$:用来控制当前的状态需要遗忘多少历史信息和接受多少新信息
  • 重置门 $r$:用来控制候选状态中有多少信息是从历史信息中得到

$GRU$ 因为比 $LSTM$ 更加简单,并且效果也没有显著下降,所以现在正在变得越来越流行。

参考文献:
[1] 周晓飞,《统计机器学习》,中国科学院大学2017年秋季研究生课程
[2] 刘康,《知识图谱导论》,中国科学院大学2017年秋季研究生课程
[3] 卷积神经网络-维基百科
[4] 递归神经网络-维基百科
[5] Understanding LSTM Networks-Chris Olah