简介

目前,基于神经网络的深度学习方法在图像、语音、文本等应用领域取得了一系列令人兴奋的成果。2015年ImageNet比赛中图像识别错误率为3.56%,远超过人类水平(5.1%);在语音识别方面,语音识别已经智能手机的标配,可基本听懂人们的指令;在文本方面,机器翻译也取得不错的效果…等等。然而在深入理解复杂的深度学习方法之前,弄懂基本神经网络的运行原理是首要且不可或缺的步骤。

原理

先看看神经网络的基本概念-节点和权重。

节点和连接权重
节点和连接权重

其中\(x_0\), \(x_1\), \(x_2\) 为标量,分别表示该层各个节点的输出,如果该层为输入层,则为输入特征,\(X\)为特征的行向量形式。\(w_0\), \(w_1\), \(w_2\) 同为标量,表示当前节点到与之相连节点的权重,该参数控制着节点对与之连接节点的影响程度,是需要学习的参数,\(W\) 为权重的行向量形式,在这里为\((w_0、w_1、w_2)\)。\(b\) 为bias(偏置),可理解为线性变换中y轴方向的偏移,也是需要学习的参数。\(g(x)\) 为激活函数,一般为非线性函数,是神经网络的核心部分。常用的激活函数有sigmoid,tanh,softmax,relu函数等,作用为对线性输入进行非线性转换,起到特征组合与变换的效果。则图中的红色节点的输出\(a\) 为:

\[z = W \cdot X^T + b = w_0 \cdot x_0 + w_1 \cdot x_1 + w_2 \cdot x_2 + b\tag{1}\]

\[a = g(z)\tag{2}\]

有了节点,通过组合和连接方式,就可以组成基本的神经网络,如下图所示。

神经网络
神经网络

神经网络包含不同的层(Layer),不同的层又由多个节点组成。层是一个逻辑单元,是同等位置节点形成的,因为层与层之间的连接实际为不同层节点之间的连接。图中的神经网络由三层组成,分别为输入层,隐藏层和输出层。以神经网络进行二分类任务为例,训练样本为\((X_i, y_i)\), \(i = 1,2,...,N\); \(y_i \in \{0, 1\}\); 其中\(X_i\) 为第\(i\) 个训练数据的特征向量,\(y_i\) 是第\(i\) 个训练数据的真实label值。那么,输入层输入的数据为\(X_i\),依次计算隐藏层各个节点的值,最后输出层会计算出一个预测值\(\hat{y_i}\),这个预测值与真实label值\({y_i}\)可能存在一定的差距。而神经网络的终极目标是使得尽可能多的训练数据的预测值越来越接近其真实label值。用数学的语言来说:\(\min \frac{1}{N}{\sum_{1}^{N}(\left | \hat{y_i} - {y_i} \right | )}\) 。一般地,\(\left | \hat{y_i} - {y_i} \right |\) 可以用其他损失函数代替,如平方损失函数\((\hat{y_i} - {y_i})^2\)。这里损失函数不作为重点,具体可参考这里。为了求导方便,加上\(\frac{1}{2}\) ,所以,最后的损失函数(或者代价函数)为

\[L(w, b) = \min_{w, b}\frac{1}{N}{\sum_{1}^{N}\frac{1}{2}(\hat{y_i} - {y_i})^2}\tag{3}\]

接下来如何让预测值越来越接近真实值呢?我们知道,特征是固定,调节的是参数\(w\) 和\(b\)。如果\(w\) 和\(b\) 分别改变\(\Delta w\) 和\(\Delta b\),那么预测值\(\hat{y}\) 会慢慢地接近\(y\)。那\(\Delta w\) 和\(\Delta b\) 如何得到呢?
令\(\theta = (w, b)\),\(f\)为损失函数, 则\(L(\theta) = f(\theta)\)的泰勒一阶展开式为:

\[f(\theta) \approx f({\theta}_0) + \frac{\partial f({\theta}_0)}{\partial {\theta}_0} \cdot (\theta - {\theta}_0)\tag{4}\]

要使得\(f(\theta) < f({\theta}_0)\), 可让:

\[\theta - {\theta}_0 = - \alpha \cdot \frac{\partial f(\theta)}{\partial \theta} \text{; }(\alpha > 0)\tag{5}\]

使用随机梯度下降时,\(\theta\) 替换为第t次更新后的参数\({\theta}_{t+1}\),\({\theta}_0\) 替换为第t次更新前的参数\({\theta}_{t}\) 。每次参数更新方法为:

\[{\theta}_{t+1} = \theta_{t} - \alpha \cdot \frac{\partial f(\theta_{t})}{\partial \theta_{t}}\tag{6}\]

参数更新推导

神经网络有很多层参数,需要对每层参数都进行更新操作。为了方便说明每层参数的更新方式,我们对神经网络前向传播公式(1) 和公式(2) 重新定义:

\[z_{j}^{(l+1)} = W^{(l)} \cdot a^{(l)T} + b^{(l)} = (\sum_{i} w_{ij}^{(l)} \cdot a_i^{(l)}) + b_j^{(l+1)}\tag{7}\]

\[a_{j}^{(l+1)} = g(z_{j}^{(l+1)})\tag{8}\]

其中\(a_{j}^{l}\) 表示第\(l\) 层第\(j\) 个节点,\(w_{ij}^{(l)}\) 表示连接第\(l\) 层第\(i\) 个节点到第\((l+1)\) 层第\(j\) 个节点的权重。\(b_j^{(l+1)}\) 为第\((l+1)\) 层第\(j\) 个节点的偏置。
在图2中,为了更新参数,需要分别计算\(\frac{\partial L}{\partial w_{ij}^{(1)}}\) 和\(\frac{\partial L}{\partial w_{ij}^{(2)}}\)。因为\(w_{ij}^{(2)}\) 离L较近,我们先求\(\frac{\partial L}{\partial w_{ij}^{(2)}}\),根据链式求导法则:
\[\frac{\partial L}{\partial w_{ij}^{(2)}} = \frac{\partial L}{\partial a_{j}^{(3)}} \cdot \frac{\partial a_{j}^{(3)}}{\partial z_{j}^{(3)}} \cdot \frac{\partial z_{j}^{(3)}}{\partial w_{ij}^{(2)}}\]

根据公式(8),得:
\[\frac{\partial a_{j}^{(3)}}{\partial z_{j}^{(3)}} = g'(z_{j}^{(3)})\]

根据公式(7),得:
\[\frac{\partial z_{j}^{(3)}}{\partial w_{ij}^{(2)}} = a_{i}^{(2)}\]

所以:
\[\frac{\partial L}{\partial w_{ij}^{(2)}} = \frac{\partial L}{\partial a_{j}^{(3)}} \cdot g'(z_{j}^{(3)}) \cdot a_{i}^{(2)}\tag{9}\]

同样地,通过\(L\) 对\(w_{ij}^{(1)}\) 进行链式求导得:
\[\frac{\partial L}{\partial w_{ij}^{(1)}} = \frac{\partial L}{\partial a_{j}^{(2)}} \cdot \frac{\partial a_{j}^{(2)}}{\partial z_{j}^{(2)}} \cdot \frac{\partial z_{j}^{(2)}}{\partial w_{ij}^{(1)}}\]

化简得:
\[\frac{\partial L}{\partial w_{ij}^{(1)}} = \frac{\partial L}{\partial a_{j}^{(2)}} \cdot g'(z_{j}^{(2)}) \cdot a_{i}^{(1)}\tag{10}\]

仔细对比公式(9) 和公式(10),我们发现,等式右边前两项具有相同形式,令\(\delta_{j} = \frac{\partial L}{\partial z_{j}} = \frac{\partial L}{\partial a_{j}} \cdot \frac{\partial a_{j}}{\partial z_{j}} = \frac{\partial L}{\partial a_{j}} \cdot g'(z_{j})\),所以公式(9) 和公式(10)可统一表示为:
\[\frac{\partial L}{\partial w_{ij}^{(l)}} = \delta_{j}^{(l+1)} \cdot a_{i}^{(l)}\tag{11}\]

这里主要是\(\frac{\partial L}{\partial a_{j}^{(2)}}\)稍微复杂些,如果再回过头看看公式(7),\(a_{j}^{(2)}\)和\(z_{i}^{(3)}\)是有联系的,有:

\[\frac{\partial L}{\partial a_{j}^{(l)}} = \sum_{i}\frac{\partial L}{\partial z_{i}^{l+1}} \cdot \frac{\partial z_{i}^{(l+1)}}{\partial a_{j}^{(l)}} = \sum_{i}\frac{\partial L}{\partial z_{i}^{l+1}} \cdot w_{ji} = \sum_{i}\delta_{i}^{(l+1)} \cdot w_{ji}\tag{12}\]

两边同时乘以\(g'(z_{j})\),则:
\[\delta_{j}^{(l)} = (\sum_{i}\delta_{i}^{(l+1)} \cdot w_{ji}) \cdot g'(z_{j}^{l})\tag{13}\]

综上推导,神经网络反向传播时,可以依靠公式(13),将训练误差依次传递到前面的层;然后利用公式(11)对各层的参数进行更新。经过反复训练,最终可以得到一个有效的分类器。详细实现代码在github,欢迎试用。

参考资料:

  1. BP神经网络的数学原理及其算法实现
  2. 神经网络反向传播的数学原理