感知机也是作为神经网络(深度学习)的起源的算法

最简单的深度网络称为多层感知机。多层感知机由多层神经元组成, 每一层与它的上一层相连,从中接收输入; 同时每一层也与它的下一层相连,影响当前层的神经元。 当训练容量较大的模型时,面临着过拟合的风险。 因此,本章将从基本的概念介绍开始讲起,包括过拟合欠拟合和模型选择。 为了解决这些问题,本章将介绍权重衰减暂退法等正则化技术。 我们还将讨论数值稳定性和参数初始化相关的问题, 这些问题是成功训练深度网络的关键。

最早的感知机:

感知机

感知机是什么

感知机接收多个输入信号,输出一个信号。这里所说的“信号”可以想象成电流或河流那样具备“流动性”的东西。像电流流过导线,向前方输送电子一样,感知机的信号也会形成流,向前方输送信息。但是,和实际的电流不同的是,感知机的信号只有“流/不流”(1/0)两种取值。在本书中, 0对应“不传递信号”, 1对应“传递信号”。

下面一个接收两个输入信号的感知机的例子。 x1、 x2是输入信号, y是输出信号, w1、 w2是权重(w是weight的首字母)。图中的○称为“神经元”或者“节点”。输入信号被送往神经元时,会被分别乘以固定的权重(w1x1、 w2x2)。神经元会计算传送过来的信号的总和,只有当这个总和超过了某个界限值时,才会输出1。这也称为“神经元被激活” 。这里将这个界限值称为阈值,用符号θ表示
 

感知机的多个输入信号都有各自固有的权重,这些权重发挥着控制各个信号的重要性的作用。权重越大,对应该权重的信号的重要性就越高

权重相当于电流里所说的电阻。电阻是决定电流流动难度的参数,电阻越低,通过的电流就越大。而感知机的权重则是值越大,通过的信号就越大。不管是电阻还是权重,在控制信号流动难度(或者流动容易度)这一点上的作用都是一样的。
 

感知机的收敛定理

简单逻辑电路

与门(一假则假)
与非门和或门

与非门:仅当x1和x2同时为1时输出0,其他时候则输出1

或门(一真则真):

感知机是无法实现这个异或门的。为什么用感知机可以实现与门、或门,却无法实现异或门?

首先,我们试着将或门的动作形象化。或门的情况下,当权重参数(b, w1, w2) = (-0.5, 1.0, 1.0)时,可满足图2-4的真值表条件。此时,感知机可用下面的式(2.3)表示。

上述表示的感知机会生成由直线-0.5 + x1 + x2 = 0分割开的两个空间。其中一个空间输出1,另一个空间输出0
 

感知机不能拟合XOR函数,它只能产生线性分割图

线性与非线性

感知机的局限性就在于它只能表示由一条直线分割的空间
曲线分割而成的空间称为非线性空间,由直线分割而成的空间称为线性空间。

总结

多层感知机

用异或门实现XOR函数

x1和x2表示输入信号, y表示输出信号。 x1和x2是与非门和或门的输入,而与非门和或门的输出则是与门的输入。

叠加了多层的感知机也称为多层感知机(multi-layered perceptron)。
 

上图感知机总共由3层构成,但是因为拥有权重的层实质上只有2层(第0层和第1层之间,第1层和第2层之间),所以称为“2层感知机”。不过,有的文献认为上图的感知机是由3层构成的,因而将其称为“3层感知机”
过程:

     1.第0层的两个神经元接收输入信号,并将信号发送至第1层的神经元。

     2.第1层的神经元将信号发送至第2层的神经元,第2层的神经元输出y。

从与非门到计算机

计算机是处理信息的机器。向计算机中输入一些信息后,它会按照某种既定的方法进行处理,然后输出结果。所谓“按照某种既定的方法进行处理”是指,计算机和感知机一样,也有输入和输出,会按照某个既定的规则进行计算。

人们一般会认为计算机内部进行的处理非常复杂,而令人惊讶的是,实际上只需要通过与非门的组合,就能再现计算机进行的处理。这一令人吃惊的事实说明了什么呢?说明使用感知机也可以表示计算机。前面也介绍了,与非门可以使用感知机实现。也就是说,如果通过组合与非门可以实现计算机的话,那么通过组合感知机也可以表示计算机(感知机的组合可以通过叠加了多层的单层感知机来表示)

感知机通过叠加层能够进行非线性的表示,理论上还可以表示计算机进行的处理
 

感知机是具有输入和输出的算法。给定一个输入后,将输出一个定的值。

感知机将权重和偏置设定为参数。

使用感知机可以表示与门和或门等逻辑电路。

异或门无法通过单层感知机来表示。

使用2层感知机可以表示异或门。

单层感知机只能表示线性空间,而多层感知机可以表示非线性空间。

多层感知机(在理论上)可以表示计算机。

隐藏层

线性模型可能会出错

对于深度神经网络,我们使用观测数据来联合学习隐藏层表示和应用于该表示的线性预测器

在网络中加入隐藏层

可以通过在网络中加入一个或多个隐藏层来克服线性模型的限制, 使其能处理更普遍的函数关系类型。 要做到这一点,最简单的方法是将许多全连接层堆叠在一起。 每一层都输出到上面的层,直到生成最后的输出。 我们可以把前L−1层看作表示,把最后一层看作线性预测器。 这种架构通常称为多层感知机(multilayer perceptron),通常缩写为MLP

这个多层感知机有4个输入,3个输出,其隐藏层包含5个隐藏单元。 输入层不涉及任何计算,因此使用此网络产生输出只需要实现隐藏层和输出层的计算。 因此,这个多层感知机中的层数为2。 注意,这两个层都是全连接的。 每个输入都会影响隐藏层中的每个神经元, 而隐藏层中的每个神经元又会影响输出层中的每个神经元

从线性到非线性

通用近似定理

多层感知机(Multilayer Perceptron, MLP)作为最基础的神经网络模型之一,其设计和工作机制遵循一些通用的相似原理,这些原理是其能够处理复杂非线性问题、实现特征学习的核心。以下从结构、功能和学习机制三个层面,总结其通用相似原理:

一、结构上的层级性与模块化

所有 MLP 都遵循 “分层堆叠” 的基本结构,这是其最显著的通用特征:

  • 输入层:接收原始数据(如像素、特征向量),不进行任何计算,仅作为数据传递的起点。
  • 隐藏层:由至少一层神经元组成(“多层” 的核心体现),是特征转换的核心模块。每层神经元与上一层全连接(全连接网络),通过权重对输入进行线性组合,并通过激活函数引入非线性。
  • 输出层:根据任务需求输出结果(如分类任务的类别概率、回归任务的预测值),神经元数量与任务目标匹配(如二分类用 1 个神经元,多分类用类别数对应的神经元)。

这种层级结构的核心是 “模块化递进”—— 每一层都在前一层的基础上加工信息,形成从原始特征到抽象特征的转换链。

二、非线性变换的必要性

单一层的感知机(线性模型)无法处理非线性问题(如异或问题),而多层感知机的通用能力依赖于非线性激活函数的引入,这是其能够拟合复杂函数的关键:

  • 隐藏层中每个神经元的计算过程为:先对输入进行线性组合(z=w⋅x+b),再通过激活函数(如 ReLU、sigmoid、tanh 等)进行非线性转换(a=σ(z))。
  • 激活函数的作用是打破 “多层线性叠加仍为线性” 的局限,使网络能够表示任意复杂的非线性关系。例如:ReLU 通过 “抑制负值、保留正值” 引入非线性,既简单又高效,成为主流选择。

共性逻辑:无论具体任务(分类 / 回归)或数据类型(图像 / 文本 / 数值),MLP 必须通过非线性激活函数实现从 “线性模型” 到 “非线性模型” 的跨越,否则多层结构将失去意义。

三、参数学习的统一机制:反向传播与梯度下降

所有 MLP 的训练过程都依赖于 “反向传播算法” 和 “梯度下降” 的组合,这是其参数优化的通用原理:

  1. 前向传播:输入数据从输入层流经隐藏层,最终在输出层产生预测值,同时计算预测值与真实值的损失(如均方损失、交叉熵损失)。
  2. 反向传播:根据损失函数,通过链式法则从输出层反向计算各层权重和偏置的梯度(即损失对参数的导数),反映参数对误差的 “贡献度”。
  3. 梯度下降:基于梯度方向,通过优化器(如 SGD、Adam)调整参数(w=w−η⋅∇w,η为学习率),最小化损失函数。

这种 “前向计算误差、反向更新参数” 的机制,是所有 MLP(乃至大多数神经网络)实现 “从数据中学习规律” 的通用逻辑。

四、通用近似能力:理论上的普适性

多层感知机的一个核心理论支撑是 **“通用近似定理”**,这体现了其作为学习模型的通用潜力:

  • 定理指出:只要隐藏层足够深(或神经元数量足够多),并使用非线性激活函数,MLP 可以以任意精度近似任何连续函数(在紧致集上)。
  • 这意味着,无论任务是拟合复杂的非线性映射(如图像分类中的 “像素→类别” 映射),还是学习数据中的潜在规律,MLP 在理论上都具备处理能力,只需通过调整网络深度、宽度等结构参数适配具体问题。

这种 “通用近似” 的特性,是 MLP 能够广泛应用于计算机视觉、自然语言处理、推荐系统等多个领域的底层原因。

五、特征学习的递进性

MLP 的隐藏层本质上是 “特征提取器”,其特征学习过程遵循 “从具体到抽象” 的递进逻辑,这是所有 MLP 处理复杂数据的通用模式:

  • 浅层隐藏层通常学习低阶特征(如原始数据的局部差异、简单模式,例如图像中的边缘、纹理);
  • 深层隐藏层则在浅层特征的基础上,组合形成高阶抽象特征(如 “边缘→部件→物体”,文本中的 “词→短语→语义”)。

例如,用 MLP 处理图像时,第一层可能学习到明暗变化的边缘特征,第二层将边缘组合成角、曲线等,更高层则组合出 “眼睛”“轮子” 等部件,最终输出层基于这些抽象特征判断图像类别。

总结

多层感知机的通用相似原理可概括为:以分层结构为框架,以非线性激活为核心,以反向传播为学习机制,通过特征递进实现对复杂函数的通用近似。这些原理不仅是 MLP 的设计基础,也为更复杂的神经网络(如 CNN、RNN)提供了重要启发,是深度学习领域的底层逻辑之一

激活函数

激活函数(activation function)通过计算加权和并加上偏置来确定神经元是否应该被激活, 它们将输入信号转换为输出的可微运算

%matplotlib inline
import torch
from d2l import torch as d2l

ReLU函数

激活函数(activation function)通过计算加权和并加上偏置来确定神经元是否应该被激活, 它们将输入信号转换为输出的可微运算。 大多数激活函数都是非线性的。

%matplotlib inline
import torch
from d2l import torch as d2l

x = torch.arange(-8.0, 8.0, 0.1, requires_grad=True)
y = torch.relu(x)
d2l.plot(x.detach(), y.detach(), 'x', 'relu(x)', figsize=(5, 2.5))

当输入为负时,ReLU函数的导数为0,而当输入为正时,ReLU函数的导数为1。 注意,当输入值精确等于0时,ReLU函数不可导。 在此时,我们默认使用左侧的导数,即当输入为0时导数为0。 我们可以忽略这种情况,因为输入可能永远都不会是0。 这里引用一句古老的谚语,“如果微妙的边界条件很重要,我们很可能是在研究数学而非工程”, 这个观点正好适用于这里。 下面我们绘制ReLU函数的导数。

y.backward(torch.ones_like(x), retain_graph=True)
d2l.plot(x.detach(), x.grad, 'x', 'grad of relu', figsize=(5, 2.5))

使用ReLU的原因是,它求导表现得特别好:要么让参数消失,要么让参数通过。 这使得优化表现得更好,并且ReLU减轻了困扰以往神经网络的梯度消失问题。

注意,ReLU函数有许多变体,包括参数化ReLU(Parameterized ReLU,pReLU) 函数 (He et al., 2015)。 该变体为ReLU添加了一个线性项,因此即使参数是负的,某些信息仍然可以通过:

sigmoid函数

对于一个定义域在R中的输入, sigmoid函数将输入变换为区间(0, 1)上的输出。 因此,sigmoid通常称为挤压函数(squashing function): 它将范围(-inf, inf)中的任意输入压缩到区间(0, 1)中的某个值:

在最早的神经网络中,科学家们感兴趣的是对“激发”或“不激发”的生物神经元进行建模。 因此,这一领域的先驱可以一直追溯到人工神经元的发明者麦卡洛克和皮茨,他们专注于阈值单元。 阈值单元在其输入低于某个阈值时取值0,当输入超过阈值时取值1。

当人们逐渐关注到到基于梯度的学习时, sigmoid函数是一个自然的选择,因为它是一个平滑的、可微的阈值单元近似。 当我们想要将输出视作二元分类问题的概率时, sigmoid仍然被广泛用作输出单元上的激活函数 (sigmoid可以视为softmax的特例)。 然而,sigmoid在隐藏层中已经较少使用, 它在大部分时候被更简单、更容易训练的ReLU所取代。 在后面关于循环神经网络的章节中,我们将描述利用sigmoid单元来控制时序信息流的架构。

with autograd.record():
    y = npx.sigmoid(x)
d2l.plot(x, y, 'x', 'sigmoid(x)', figsize=(5, 2.5))

sigmoid函数的导数图像如下所示。 注意,当输入为0时,sigmoid函数的导数达到最大值0.25; 而输入在任一方向上越远离0点时,导数越接近0。

y.backward()
d2l.plot(x, x.grad, 'x', 'grad of sigmoid', figsize=(5, 2.5))

  • 多层感知机在输出层和输入层之间增加一个或多个全连接隐藏层,并通过激活函数转换隐藏层的输出。

  • 常用的激活函数包括ReLU函数、sigmoid函数和tanh函数。

练习:

计算pReLU激活函数的导数

import torch

def prelu_derivative(x, alpha):
    """计算PReLU对输入x的导数"""
    # 将输入转换为PyTorch张量
    x_tensor = torch.tensor(x, dtype=torch.float32)
    alpha_tensor = torch.tensor(alpha, dtype=torch.float32)
    return torch.where(x_tensor >= 0, torch.tensor(1.0), alpha_tensor)

def alpha_derivative(x, grad_output, alpha):
    """计算损失对参数alpha的导数"""
    # 将输入转换为PyTorch张量
    x_tensor = torch.tensor(x, dtype=torch.float32)
    grad_output_tensor = torch.tensor(grad_output, dtype=torch.float32)
    
    # 只考虑x < 0的情况
    mask = x_tensor < 0
    return torch.sum(grad_output_tensor[mask] * x_tensor[mask])

# 测试函数
p = prelu_derivative(1, 0.25)
print(p)  # 应该输出 tensor(1.)

p = prelu_derivative(-1, 0.25)
print(p)  # 应该输出 tensor(0.25)

证明一个仅使用ReLU(或pReLU)的多层感知机构造了一个连续的分段线性函数

证明\tanh \left ( x \right ) + 1 = 2sigmoid(2x)

  • 假设我们有一个非线性单元,将它一次应用于一个小批量的数据。这会导致什么样的问题?

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐