FA_CNN卷积神经网络十八---感知机到多层感知机PyTorch

1. 引言

线性回归输出的是一个实数,而感知机输出的是一个离散的类别。正是这一差别,把我们从「拟合数值」带入了「分类决策」的世界。本文沿着「单层感知机 → XOR 问题 → 多层感知机 → 激活函数 → 代码实战」的脉络,把这条主线梳理清楚,并给出可直接运行的 PyTorch 实现。

2. 单层感知机

2.1 感知机是什么

感知机可以看作是最简单的二分类模型:它先对输入做线性加权求和,再根据结果的符号输出类别。

y^=sign⁡(⟨w,x⟩+b) \hat{y} = \operatorname{sign}(\langle \mathbf{w}, \mathbf{x} \rangle + b) y^=sign(⟨w,x⟩+b)

与线性回归相比,二者的核心差异在于输出:线性回归输出实数,感知机输出离散的类。

2.2 训练感知机

感知机的损失函数可以写成:

ℓ(y,x,w)=max⁡(0,−y⟨w,x⟩) \ell(y, \mathbf{x}, \mathbf{w}) = \max(0, -y \langle \mathbf{w}, \mathbf{x} \rangle) ℓ(y,x,w)=max(0,−y⟨w,x⟩)

理解它的关键在于分类是否正确:

  • 如果分类正确,y⟨w,x⟩y\langle \mathbf{w}, \mathbf{x} \rangley⟨w,x⟩ 为正数,取负号后变为负数,max 之后输出为 0,梯度为 0,参数不更新。
  • 如果分类错误,y⟨w,x⟩y\langle \mathbf{w}, \mathbf{x} \rangley⟨w,x⟩ 为负数,取负号后变为正数,max 之后输出大于 0,梯度非零,参数被更新。

对应的更新规则非常直观:分类错了就把权重往正确方向拉一把。

w←w+η y x \mathbf{w} \leftarrow \mathbf{w} + \eta \, y \, \mathbf{x} w←w+ηyx

2.3 收敛半径

对于线性可分的数据,感知机算法在有限步内一定收敛,其收敛步数与数据分布的「间隔」有关。间隔越大,收敛越快;反之,数据越接近决策边界,需要的迭代次数越多。

2.4 XOR 问题

感知机的能力边界也很明显:它只能表示线性可分的决策边界。经典的 XOR(异或)问题就是它无法解决的例子------无论怎么画一条直线,都无法把 XOR 的两类样本正确分开。

x₁ x₂ y(XOR)
0 0 0
0 1 1
1 0 1
1 1 0

2.5 小结

单层感知机 = 线性模型 + 符号函数。它能解决线性可分问题,但面对 XOR 这类非线性问题就无能为力了。

3. 多层感知机

3.1 用多层结构学习 XOR

解决 XOR 的思路是「先分两步,再组合」:

  1. 先用一条线(例如蓝色线)把一部分样本分出来;
  2. 再用另一条线(例如黄色线)分出另一部分;
  3. 最后对两条线的判断结果做乘法(逻辑与),得到最终的 XOR 结果。

这正是「隐藏层」的直观含义:多个线性分类器的组合,可以表达非线性的决策边界。

3.2 单隐藏层结构

一个单隐藏层的多层感知机可以写成:

H=σ(XW1+b1),O=HW2+b2 \mathbf{H} = \sigma(\mathbf{X}\mathbf{W}_1 + \mathbf{b}_1), \qquad \mathbf{O} = \mathbf{H}\mathbf{W}_2 + \mathbf{b}_2 H=σ(XW1+b1),O=HW2+b2

这里必须强调一点:如果没有激活函数 σ\sigmaσ,多个全连接层叠加在一起,本质上仍然等价于一个最简单的线性函数。也就是说,堆叠层数再多也没有意义,激活函数才是引入非线性的关键。

3.3 常见激活函数

Sigmoid 函数

sigmoid⁡(x)=11+e−x \operatorname{sigmoid}(x) = \frac{1}{1 + e^{-x}} sigmoid(x)=1+e−x1

它把输出压缩到 (0,1)(0, 1)(0,1) 区间,历史上常用于输出概率,但存在梯度消失和指数运算开销大的问题。

Tanh 函数

tanh⁡(x)=1−e−2x1+e−2x \tanh(x) = \frac{1 - e^{-2x}}{1 + e^{-2x}} tanh(x)=1+e−2x1−e−2x

输出范围是 (−1,1)(-1, 1)(−1,1),以 0 为中心,通常比 Sigmoid 收敛更快。

ReLU 函数

ReLU⁡(x)=max⁡(x,0) \operatorname{ReLU}(x) = \max(x, 0) ReLU(x)=max(x,0)

ReLU 的最大好处在于不需要执行指数运算。在 CPU 上,一次指数运算的开销大致相当于上百次乘法运算,因此 ReLU 在计算效率上优势明显,也是目前最常用的默认选择。

3.4 多类分类

把输出层从单个神经元扩展到多个神经元,再配合 Softmax 与交叉熵损失,多层感知机就可以处理多类分类任务。Fashion-MNIST 的 10 分类就是典型场景。

3.5 小结

多层感知机 = 隐藏层 + 激活函数 + 输出层。隐藏层提供表达能力,激活函数提供非线性,二者缺一不可。

4. 代码实战:从零实现多层感知机

下面用自定义参数的方式实现一个单隐藏层(256 个隐藏单元)的多层感知机。

python 复制代码
import torch
from torch import nn
from d2l import torch as d2l

batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

# 输入、输出由数据决定,256 个隐藏单元是调参时自己决定的
num_inputs, num_outputs, num_hiddens = 784, 10, 256

W1 = nn.Parameter(torch.randn(num_inputs, num_hiddens, requires_grad=True))
b1 = nn.Parameter(torch.zeros(num_hiddens, requires_grad=True))
W2 = nn.Parameter(torch.randn(num_hiddens, num_outputs, requires_grad=True))
b2 = nn.Parameter(torch.zeros(num_outputs, requires_grad=True))
params = [W1, b1, W2, b2]

# 实现 ReLU 激活函数
def relu(X):
    a = torch.zeros_like(X)  # 数据类型、形状都一样,但值全为 0
    return torch.max(X, a)

# 实现模型
def net(X):
    X = X.reshape((-1, num_inputs))  # -1 为自适应的批量大小
    H = relu(X @ W1 + b1)
    return (H @ W2 + b2)

# 损失
loss = nn.CrossEntropyLoss()  # 交叉熵损失

# 多层感知机的训练过程与 softmax 回归的训练过程完全一样
num_epochs, lr = 30, 0.1
updater = torch.optim.SGD(params, lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, updater)

可以看到,多层感知机的训练流程与 softmax 回归几乎完全一致,区别只在于模型前向计算中多了一层隐藏变换。

5. 代码实战:使用框架实现

调用高级 API 可以更简洁地实现同样的模型。

python 复制代码
import torch
from torch import nn
from d2l import torch as d2l

# 隐藏层包含 256 个隐藏单元,并使用了 ReLU 激活函数
net = nn.Sequential(
    nn.Flatten(),
    nn.Linear(784, 256),
    nn.ReLU(),
    nn.Linear(256, 10)
)

def init_weights(m):
    if type(m) == nn.Linear:
        nn.init.normal_(m.weight, std=0.01)

net.apply(init_weights)

# 训练过程
batch_size, lr, num_epochs = 256, 0.1, 10
loss = nn.CrossEntropyLoss()
trainer = torch.optim.SGD(net.parameters(), lr=lr)
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)

nn.Sequential 把「展平 → 线性 → ReLU → 线性」串成一条流水线,代码可读性和可维护性都明显更好。

6. 整体流程梳理

#mermaid-svg-vx8l84kyaXNcGFAr{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-vx8l84kyaXNcGFAr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-vx8l84kyaXNcGFAr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-vx8l84kyaXNcGFAr .error-icon{fill:#552222;}#mermaid-svg-vx8l84kyaXNcGFAr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-vx8l84kyaXNcGFAr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-vx8l84kyaXNcGFAr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-vx8l84kyaXNcGFAr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-vx8l84kyaXNcGFAr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-vx8l84kyaXNcGFAr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-vx8l84kyaXNcGFAr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-vx8l84kyaXNcGFAr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-vx8l84kyaXNcGFAr .marker.cross{stroke:#333333;}#mermaid-svg-vx8l84kyaXNcGFAr svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-vx8l84kyaXNcGFAr p{margin:0;}#mermaid-svg-vx8l84kyaXNcGFAr .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-vx8l84kyaXNcGFAr .cluster-label text{fill:#333;}#mermaid-svg-vx8l84kyaXNcGFAr .cluster-label span{color:#333;}#mermaid-svg-vx8l84kyaXNcGFAr .cluster-label span p{background-color:transparent;}#mermaid-svg-vx8l84kyaXNcGFAr .label text,#mermaid-svg-vx8l84kyaXNcGFAr span{fill:#333;color:#333;}#mermaid-svg-vx8l84kyaXNcGFAr .node rect,#mermaid-svg-vx8l84kyaXNcGFAr .node circle,#mermaid-svg-vx8l84kyaXNcGFAr .node ellipse,#mermaid-svg-vx8l84kyaXNcGFAr .node polygon,#mermaid-svg-vx8l84kyaXNcGFAr .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-vx8l84kyaXNcGFAr .rough-node .label text,#mermaid-svg-vx8l84kyaXNcGFAr .node .label text,#mermaid-svg-vx8l84kyaXNcGFAr .image-shape .label,#mermaid-svg-vx8l84kyaXNcGFAr .icon-shape .label{text-anchor:middle;}#mermaid-svg-vx8l84kyaXNcGFAr .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-vx8l84kyaXNcGFAr .rough-node .label,#mermaid-svg-vx8l84kyaXNcGFAr .node .label,#mermaid-svg-vx8l84kyaXNcGFAr .image-shape .label,#mermaid-svg-vx8l84kyaXNcGFAr .icon-shape .label{text-align:center;}#mermaid-svg-vx8l84kyaXNcGFAr .node.clickable{cursor:pointer;}#mermaid-svg-vx8l84kyaXNcGFAr .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-vx8l84kyaXNcGFAr .arrowheadPath{fill:#333333;}#mermaid-svg-vx8l84kyaXNcGFAr .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-vx8l84kyaXNcGFAr .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-vx8l84kyaXNcGFAr .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vx8l84kyaXNcGFAr .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-vx8l84kyaXNcGFAr .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vx8l84kyaXNcGFAr .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-vx8l84kyaXNcGFAr .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-vx8l84kyaXNcGFAr .cluster text{fill:#333;}#mermaid-svg-vx8l84kyaXNcGFAr .cluster span{color:#333;}#mermaid-svg-vx8l84kyaXNcGFAr div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-vx8l84kyaXNcGFAr .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-vx8l84kyaXNcGFAr rect.text{fill:none;stroke-width:0;}#mermaid-svg-vx8l84kyaXNcGFAr .icon-shape,#mermaid-svg-vx8l84kyaXNcGFAr .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vx8l84kyaXNcGFAr .icon-shape p,#mermaid-svg-vx8l84kyaXNcGFAr .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-vx8l84kyaXNcGFAr .icon-shape .label rect,#mermaid-svg-vx8l84kyaXNcGFAr .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vx8l84kyaXNcGFAr .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-vx8l84kyaXNcGFAr .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-vx8l84kyaXNcGFAr :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 输入特征 X
线性变换 W1, b1
激活函数 ReLU
线性变换 W2, b2
Softmax + 交叉熵损失
反向传播更新参数

7. 总结

  • 感知机是线性分类器,输出离散类别,只能处理线性可分问题。
  • XOR 问题说明单层结构存在表达瓶颈,需要引入隐藏层。
  • 没有激活函数时,多层线性叠加仍等价于单层线性模型,激活函数是引入非线性的关键。
  • ReLU 因无需指数运算而成为高效且常用的激活函数。
  • 多层感知机的训练流程与 softmax 回归一致,差别仅在于模型结构。
相关推荐
青少儿编程课堂1 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:字典树前缀树与单词检索统计
c++·python·算法·bfs·信息学竞赛
irislinAmelia1 小时前
汽车产线端侧AI视觉质检完整指南
人工智能·汽车
Highcharts.js1 小时前
CSUN 2026|Highcharts无障碍数据与AI分享
javascript·人工智能·数据分析·highcharts·图表开发
J-JunLiang1 小时前
提示词修炼手册-04-让AI先想后说
人工智能·提示词工程·agent prompt·agent提问·提示词修炼手册
終不似少年遊*1 小时前
【Skill】为中型研发团队制作的敏捷迭代AI副驾Skill
人工智能·python·华为云·agent·ai编程·skill
呆萌的代Ma1 小时前
python使用ThreadPoolExecutor自带队列将多线程变串行执行
python
爱吃火鸡面呀1 小时前
BERT 从入门到实战:为什么需要它、核心原理与工程落地全解析
人工智能·自然语言处理·bert
电子科技圈1 小时前
2026 RISC-V中国峰会观察:编译调试工具链的“在场节奏”,释放了什么信号?
大数据·人工智能·设计模式·软件工程·软件构建·代码规范·risc-v
echome8881 小时前
Python 正则表达式:5 个日常够用的模式
python·正则表达式