Featured image of post 机器学习笔记(6):神经网络

机器学习笔记(6):神经网络

神经网络学习笔记


前言

   神经网络作为人工智能领域的核心分支,是一种旨在模拟生物神经系统结构与功能的计算范式。其根本目标在于构建能够从经验数据中自动学习复杂模式与潜在规律的计算模型,这标志着从传统基于规则的编程向数据驱动的自适应智能的根本性转变。
   神经网络的发展历程是理论突破与技术瓶颈交织的非线性过程。其理论基础可追溯至20世纪40年代 McCulloch 与 Pitts 对神经元的数学形式化,以及50年代 Rosenblatt 提出的“感知机”模型,这些早期工作奠定了连接主义(Connectionism)的基础。然而,由于 Minsky 与 Papert 在1969年深刻揭示了单层感知机的理论局限性(如无法解决XOR问题),该领域的研究一度陷入停滞。直至80年代,随着多层感知机及反向传播(Backpropagation)算法的重新发现与推广,神经网络才得以克服早期瓶颈,具备了表达非线性复杂函数的能力。尽管如此,诸如“梯度消失”等深度网络训练难题,使其在20世纪末的声誉再次被支持向量机(SVM)等统计学习方法所超越。
   进入21世纪,神经网络迎来了决定性的复兴。这一复兴并非源于单一突破,而是三大因素协同作用的结果:第一,以图形处理器(GPU)为代表的并行计算硬件提供了前所未有的算力支持;第二,互联网的普及带来了海量、高质量的标注数据集(Big Data);第三,算法层面的持续创新,包括新型激活函数(如ReLU)、优化策略及正则化技术,有效缓解了深度网络的训练困境。自2012年 AlexNet 在 ImageNet 竞赛中取得革命性成果以来,以深度神经网络(DNN)为核心的深度学习已成为人工智能研究与应用的主流范式。
   理解神经网络的意义至关重要,它不仅是实现图像识别、自然语言处理、语音识别等应用任务的关键技术,更代表了一种强大的特征表示学习(Representation Learning)框架。它驱动了从消费电子到自动驾驶、从金融科技到医疗诊断等众多领域的重大技术革新。因此,掌握神经网络的理论基础与实践方法,是理解并参与当前人工智能技术发展的核心要求。


神经元模型

   各学科对神经网络的定义多种多样,而使用得最广泛的一种,即 “神经网络是由具有适应性的简单单元组成的广泛并行互连的网络,它的组织能够模拟生物神经系统对真实世界物体所作出的交互反应”

   神经网络中最基本的成分是 神经元(neuron)模型 ,即上述定义中的“简单单元”。在机器学习中,神经元模型也被称为 “M-P神经元模型”(以其提出者McCulloch和Pitts的名字命名)。它是一个简化的数学模型,用来模拟生物神经元接受和处理信息的过程。每个神经元接收多个输入,对这些输入进行加权计算,然后通过一个“激活函数”来决定最终的输出。一个神经元主要由以下几个部分组成:

  • 输入(Inputs, $x_i$) :神经元来自其他神经元或外部数据源的信息。一个神经元可以有多个输入。
  • 权重(Weights. $w_i$) :每一个输入都对应一个权重。权重代表了这个输入的重要性。权重越高,说明这个输入对神经元的最终输出影响越大。 在模型训练过程中,机器主要就是学习和调整这些权重值
  • 阈值(Threshold, $\theta$) :神经元被激活所需要达到的内部标准或门槛。
  • 求和函数 (Summation Function):神经元会将所有的输入值与它们对应的权重相乘,然后将所有结果加起来,最后再减去阈值项。这个过程叫做“加权求和”。
  • 激活函数(Activation Function, $f$):这是神经元的“决策”部分。加权求和的结果会经过一个激活函数处理,最终得到这个神经元的输出。激活函数的主要作用是加入 非线性 因素,使得神经网络能够学习和拟合更复杂的模式。如果没有激活函数,那无论多少层的神经网络,最终都只是一个线性模型。
  • 输出 (Output, $y$): 经过激活函数处理后得到最终的输出值。这个值会作为下一个神经元的输入,或者直接作为整个网络的最终结果。
mp M-P 神经元模型 图源《机器学习》[周志华]

   神经元的工作可以概括为两步:

  1. 计算加权和:将所有输入与其对应的权重相乘后求和,得到输入信号的总强度

    $$ net = \sum_{i=1}^{n} w_i x_i $$
  2. 激活判断与输出:激活函数判断“加权和”是否超过“阈值”,并产生输出

    $$ y = f(net - \theta) = f(\sum_{i=1}^{n} w_i x_i - \theta) $$

理想的激活函数是如下的阶跃函数,它将输入值映射为输出值“0”或“1”:

$$ \text{sgn}(x) = \begin{cases} 1, \ \ x \geqslant 0; \\ 0, \ \ x \leqslant 0 \end{cases} $$

显然“1”对应于神经元兴奋,“0”对应于神经元抑制。然而,阶跃函数具有不连续、不光滑等不太好的性质,因此实际常用 Sigmoid 函数作为激活函数:

$$ \text{sigmoid}(x) = \frac{1}{1 + e^{-x}} $$

它把可能在较大范围内变化的输入值挤压到 $(0, 1)$ 输出值范围内,因此有时也称为“挤压函数”(squashing function)。

典型的神经元激活函数

感知机与多层网络

   感知机(Perceptron) 是神经元模型的一个实例,由两层神经元组成,输入层接收外接输入信号后传递给输出层,输出层是 M-P 神经元,亦称 “阈值逻辑单元”(threshold logic unit)

感知机网络结构示意图

   注意到如图 $y = f(\sum_i w_ix_i - \theta) = f(w_1 x_1 + w_2 x_2 - \theta)$ ,给定训练数据后,权重 $w_i$ 和阈值 $\theta$ 可以通过学习得到。阈值 $\theta$ 可以看做一个固定输入为 $-1.0$ 的 “哑结点”(dummy node) 所对应的连接权重 $w_{n+1}$ 。感知机的学习规则如下

  1. 对训练样例 $(\boldsymbol{x}, y)$ ,假设当前感知机的输出为 $\hat y$ ;

  2. 感知机的权重作如下调整:

    $$ w_i \leftarrow w_i + \Delta w_i ,\\ \Delta w_i = \eta (y - \hat y)x_i $$

    其中 $\eta \in (0,1)$ 称为学习率(learning rate)。

可以看出,若感知机对训练样例预测正确,即 $y = \hat y$ ,则不发生变化,否则将根据错误的程度进行权重调整。

   值得注意的是,感知机能实现与、或、非运算,例如:

  • 令 $w_1=w_2=1, \theta=2$ ,则 $y = f(1 \cdot x_1 + 1 \cdot x_2 - 2)$ ,仅在 $x_1=x_2=1$ 时,$y=1$ ;
  • 令 $w_1=w_2=1, \theta=0.5$ ,则 $y = f(1 \cdot x_1 + 1 \cdot x_2 - 0.5)$ ,当 $x_1=1$ 或 $x_2=1$ 时,$y=1$ ;
  • 令 $w_1=-0.6, w_2=0, \theta=-0.5$ ,则 $y = f(-0.6 \cdot x_1 + 0 \cdot x_2 +0.5)$ ,当 $x_1 = 1$ 时,$y = 0$ ,当$x_1 = 0$ 时,$y=1$ 。

能够实现以上运算的本质原因是与、或、非问题都是线性可分问题,即存在一个线性超平面将它们分开,此时感知机的学习过程一定会收敛,从而求得合适的权重向量。而对于非线性可分问题,感知机学习过程会发生 振荡(fluctuation) ,不能求得合适的解,比如异或问题。

problem
线性可分问题与非线性可分问题

   多层网络通过增加 ”隐藏层“(hidden layer) 来解决该问题,其核心在于两个方面:

  • 功能组合:复杂问题可以分解为简单问题的组合。比如异或(XOR)的逻辑可以分解为OR AND NAND。从而可以通过两层神经元来拟合出异或的逻辑。
  • 线性变换:这是多层网络的本质,即神经网络的每一层都在对数据进行一次空间变换。隐藏层接收原始坐标,通过线性变换将原始坐标系变换到新的特征空间,原始的非线性可分数据被重新排列,从而变得线性可分。
hidden
能解决异或问题的两层感知机

   更一般的结构称为 “多层前馈神经网络”(multi-layer feedforward neural networks) ,每层神经元与下一层神经元全互连,神经元之间不存在同层连接或跨层连接。其中输入层神经元接收外界输入,隐藏层与输出层神经元对信号进行加工,最后由输出层神经元输出。神经网络的学习过程,就是 根据训练数据来调整神经元之间的“连接权”以及每个功能神经元的阈值;换言之,神经网络“学”到的东西,蕴涵在连接权与阈值中

多层前馈神经网络结构示意

误差逆传播算法

   假设我们有一个多层网络,其中有大量的权重( $w$ ) 和阈值( $\theta$ )。这些参数的初始值通常是随机设置的,我们的目标就是找到一套最佳参数,使得网络对于任何给定的输入,其输出都能 尽可能地接近真实值

   首先需要一个量化的指标来衡量网络输出值与( $\hat y$ )真实值( $y$ )之间的差距,即 损失函数 。常用的损失函数是均方误差。对于单个样本,其损失 $E$ 可以表示为:

$$ E = \frac{1}{2}(\hat y - y)^2 $$

注:前面的 $\frac{1}{2}$ 是为了后续求导计算方便,约掉一个系数2,对优化目标没有影响。

我们的目标,就是通过调整网络中的所有权重和阈值,来让损失的值变得尽可能小。

这里需要注意,标准 BP 算法 的更新规则是基于单个样本的 $E_k$ 推导而得,如果以累积误差来推导,最终得到 累积 BP 算法 ,即 累积误差逆传播(accumulated error backpropagation)算法 。二者侧重点不同,前者更新频率较快,适合训练集较大的情况,后者更新频率较慢,适合训练集不那么大的情况。下面的推导以累积误差为例。

   为了实现该目标,我们常使用 梯度下降 的方法。给定一个初始值,要找到损失最小的地方,最直观的方法是向减小最快的方向移动,在数学上就是 负梯度 的方向,而移动的距离由学习率来控制:

$$ w_{new} = w_{old} - \eta \frac{\partial E}{\partial w_{old}} $$

这个公式意味着:计算出损失对当前权重的梯度(最速上升方向),然后乘以一个学习率(步长),从当前权重中减去这个值,得到新的、更好的权重。

   误差逆传播(Backpropagation, BP)算法 ,本质上是一种高效计算梯度的技巧,其数学基础是微积分中的链式法则。

   BP 算法的执行可分为两个阶段:

阶段一:前向传播(Forward Propagation)

  1. 从输入层开始,将训练数据输入网络;
  2. 信号逐层向前传递,计算每一层神经元的净输入和激活后的输出值;
  3. 最终在输出层得到网络的预测值 $\hat y$ ;
  4. 根据预测值 $\hat y$ 和真实值 $y$ ,计算出总损失 $E$ 。

这个过程是为了得到“结果”和“差距”。

阶段二:反向传播(Backward Propagation)

   先定义一个三层神经网络的结构和符号:

  • 输入层 (索引为 $i$) -> 隐藏层 (索引为 $j$) -> 输出层 (索引为 $k$);
  • $w_{ij}$:从输入层神经元 $i$ 到隐藏层神经元 $j$ 的权重;
  • $w_{jk}$:从隐藏层神经元 $j$ 到输出层神经元 $k$ 的权重;
  • $y_j$:隐藏层神经元 $j$ 的输出值;
  • $y_k$:输出层神经元 $k$ 的输出值(即预测值 $\hat y$ );
  • $t_k$:输出层神经元 $k$ 对应的真实目标值;
  • $net_j = \sum_i w_{ij}x_i$:隐藏层神经元 $j$ 的加权输入和(为简化,暂时忽略阈值);
  • $net_k = \sum_j w_{jk}y_j$:输出层神经元 $k$ 的加权输入和;
  • $y_j = f(net_j)$:$net_j$ 经过激活函数 $f$ 后的输出;
  • $E = \frac{1}{2} \sum_k (t_k - y_k)^2$:对单个输出神经元的均方误差损失。

首先计算输出层权重的梯度 $\frac{\partial E}{\partial w_{jk}}$ ,我们想知道改变隐藏层到输出层的权重 $w_{jk}$ 会对最终的损失 $E$ 造成多大影响,根据链式法则,这个影响可以分为两步:

  1. 权重 $w_{jk}$ 的改变,会引起输出神经元 $k$ 的 加权输入和 $net_k$ 的改变;
  2. $net_k$ 的改变,会引起最终损失 $E$ 的改变。

因此可以写出:

$$ \frac{\partial E}{ \partial w_{jk}} = \frac{\partial E}{\partial net_k} \frac{\partial net_k}{\partial w_{jk}} $$

因为 $net_k = \sum_{j^{'}} w_{j^{'}k}y_{j^{'}}$ ,显然有

$$ \frac{\partial E}{\partial w_{jk}} = y_j $$

而 $y_k = f(net_k)$ ,则

$$ \frac{\partial E}{\partial net_k} = \frac{\partial E}{\partial y_k} \frac{\partial y_k}{\partial net_k} $$
  • $\frac{\partial E}{\partial y_k} = -(t_k - y_k)$
  • $\frac{\partial y_k}{\partial net_k} = f'(net_k)$

从而得到:

$$ \frac{\partial E}{\partial net_k} = -(t_k - y_k) f'(net_k) $$

将这一整项定义为 输出层误差项 $\delta_k$:

$$ \delta_k = \frac{\partial E}{\partial net_k} = -(t_k - y_k) f'(net_k) $$

则输出层权重的最终梯度为:

$$ \frac{\partial E}{\partial w_{jk}} = \delta_k y_j $$

然后计算隐藏层权重的梯度 $\frac{\partial E}{\partial w_{ij}}$,同理,用链式法则展开为:

$$ \frac{\partial E}{\partial w_{ij}} = \frac{\partial E}{\partial net_j} \frac{\partial net_j}{\partial w_{ij}} $$

由于 $net_j = \sum_{i^{'}} w_{i^{'}j}x_{i^{'}}$ ,则

$$ \frac{\partial net_j}{\partial w_{ij}} = x_i $$

而 $net_j$ 通过 $y_j = f(net_j)$ 影响损失,但 $y_j$ 会作为所有下一层神经元的输入,所以它的影响会通过多条路径传递到最终的损失 $E$ :

$$ \frac{\partial E}{\partial net_j} = \frac{\partial E}{\partial y_j} \frac{\partial y_j}{\partial net_j} $$
  • $\frac{\partial y_j}{\partial net_j} = f'(net_j)$
  • 计算 $\frac{\partial E}{\partial y_j}$ 时,需要将 $y_j$ 传递到所有输出层神经元的路径上的影响全部加起来:$\frac{\partial E}{\partial y_j} = \sum_k \left( \frac{\partial E}{\partial net_k} \frac{\partial net_k}{\partial y_j} \right)$ ,我们可以发现 $\frac{\partial E}{\partial net_k}$ 正是第一步中定义的输出层误差项 $\delta_k$ ,而 $\frac{\partial net_k}{\partial y_j}$ 则是连接神经元 $j$ 和 $k$ 的权重 $w_{jk}$ ,所以有$$\frac{\partial E}{\partial y_j} = \sum_k \delta_k w_{jk}$$

将最后的乘积定义为 隐藏层误差项 $\delta_j$:

$$ \delta_j = \frac{\partial E}{\partial net_j} = \left( \sum_k \delta_k w_{jk} \right) f'(net_j) $$

隐藏层权重的最终梯度为

$$ \frac{\partial E}{\partial w_{ij}} = \delta_j x_i $$

可以看出,误差是从后向前、层层传递的,因此称为“误差逆传播算法”。这个“前向计算结果 -> 反向传播误差 -> 更新参数”的完整流程,被称为一次迭代 (Iteration)。通过成千上万次迭代,网络的参数被不断微调,使得总损失越来越小,网络的预测也越来越准。

   由于其强大的表示能力,BP 神经网络经常遭遇过拟合,训练误差持续降低,但测试误差却可能上升。由两种策略来缓解过拟合:

  • “早停”(early stopping) :将数据分成训练集和验证集,训练集用来计算梯度、更新连接权和阈值,验证集用来估计误差,若训练集误差降低但验证集误差升高,则停止训练,同时返回具有最小验证集误差的连接权和阈值;

  • “正则化”(regularization) :其基本思想是在误差目标函数中增加一个用于描述网络复杂度的部分,例如连接权与阈值的平方和,仍令 $E_k$ 表示第 $k$ 个训练样例上的误差,$w_i$ 表示连接权和阈值,则误差目标函数改变为

    $$ E = \lambda \frac{1}{m} \sum_{k=1}^m E_k + (1-\lambda)\sum_i w_i^2 $$

    其中 $\lambda \in (0, 1)$ 用于对经验误差与网络复杂度这两项进行折中,常通过交叉验证法来估计。

全局最小与局部极小

   在上一节中,我们优化的目标是找到一组参数,使得损失函数 $E$ 的值达到最小。

  • 全局最小值(Global Minimum) :这是损失函数在整个参数空间中的真正最低点。找到了它,就意味着我们找到了理论上最优的模型解。
  • 局部极小值 (Local Minima): 这是损失函数在一个局部邻域内的最低点
minimum
全局最小与局部极小

核心问题在于,标准的梯度下降算法本身无法区分停下的地方是局部极小值还是全局最小值,如果陷入了一个比较差的局部极小值,那么无论再怎么训练,模型的效果也无法达到最优化。尤其是神经网络的损失函数是一个在 极高维度空间 中(参数动辄成千上万甚至上亿)的、极其复杂的 非凸函数 (Non-convex Function) ,这意味着它的“地形”异常复杂,充满了无数的局部极小值、以及比局部极小值更麻烦的 鞍点 (Saddle Points)平坦区域 (Plateaus) 。因此,在训练过程中,优化算法很容易被“困住”。

   为了解决这个问题,研究者们提出了很多比朴素梯度下降更强大的优化策略。它们的核心思想,都是 给优化过程增加一些“扰动”或“惯性” ,帮助它冲出局部极小值的陷阱。

  1. 随机梯度下降 (Stochastic Gradient Descent, SGD) 标准的梯度下降在每一步都使用全部训练数据来计算梯度,路线平滑但容易陷入局部最小。而SGD在每一步只随机取一个样本来计算梯度。这样做会带来大量的噪声,使得下降的路径变得非常“曲折和摇晃”。这种“摇晃”有时反而能帮助算法“震荡”出浅的局部极小值,去寻找更广阔的空间。小批量梯度下降 (Mini-batch GD) 是一个折中方案,每次使用一小批数据,既保证了效率,又引入了适度的噪声。
  2. 动量 (Momentum) 这个方法为梯度下降引入了“惯性”的概念。想象一个从山上滚下来的铁球,即使它滚到一个小坑里(局部极小),由于自身的惯性(动量),它很可能会直接冲出这个小坑,继续向下滚动。在数学上,它不仅考虑了当前步骤的梯度,还结合了一定比例的上一步更新的方向。
  3. 自适应学习率算法 (Adaptive Learning Rate) 例如 AdamRMSprop 等。这些是目前最主流的优化器。它们不再对所有参数使用固定的学习率 $\eta$ ,而是为每个参数动态地、自适应地调整学习率。在平坦区域,它们可能会加大步长以快速通过;在陡峭的峡谷,它们会减小步长以防“冲过头”。这种精细化的控制,使得它们在复杂地形中(尤其是穿越鞍点时)表现得非常出色。
  4. 随机初始化 (Random Initialization) 既然一次下降可能会走到错误的谷底,那就多尝试几次不同的位置。在实践中,我们会用不同的随机初始值多次训练同一个网络,然后选择在验证集上表现最好的那个模型。

现代观点:在现代深度学习中,随着网络变得越来越大、参数越来越多,一个有趣的现象是,真正的“坏”的局部极小值问题似乎没有想象中那么严重了。很多研究表明,在高维空间中,大部分局部极小值点的损失与全局最小值相差无几。目前,优化算法面临的更大挑战是如何快速穿越广阔的鞍点平坦区域,而动量和自适应学习率算法在应对这些问题上效果显著。

深度学习

   由于深度学习将来会专门学习,在此只作为一个拓展与总结。

   深度学习的“深”,直截了当地说,就是其核心模型——神经网络的层数非常多。相对于只有一两个隐藏层的传统神经网络,深度神经网络(Deep Neural Networks, DNN)拥有成百上千的层次。我们熟知的CNN、RNN等,在现代应用中都属于DNN的范畴。

   我们为何追求“深度”?因为深度赋予了网络一种强大的能力:层次化特征学习。网络会自动地从原始数据中学习:

  • 底层网络 学习基础特征(如边缘、颜色);
  • 中层网络 组合基础特征,形成复杂特征(如眼睛、纹理);
  • 高层网络 组合复杂特征,识别出具体概念(如人脸、汽车)。

这种逐层抽象的能力,使得深度网络能够以一种高效的方式理解高度复杂的数据,而这是浅层网络难以企及的。通过多层处理,逐渐将初始的“底层”特征表示转化为“高层”特征表示后,用“简单模型”即可完成复杂的分类等学习任务,因此可将深度学习理解为进行“特征学习”(feature learning)或“表示学习”(representation learning)。

   深度学习是建立在基础神经网络理论之上,由数据、算力和算法共同推动的一场技术革命。它通过构建深度模型来自动学习数据的层次化表示,从而在计算机视觉、自然语言处理等诸多领域取得了前所未有的突破。


Licensed under CC BY-NC-SA 4.0
萌ICP备20259913
Powered by Hugo with Stack
使用 Hugo 构建
主题 StackJimmy 设计, 由 秦时月 修改