MLP(多层感知机)从零开始教程

写在前面

MLP 是最基础的神经网络,也是理解所有后续网络(CNN、RNN、Transformer)的起点。这篇文档从"一个神经元在做什么"讲起,逐步搭建到完整的 MLP 分类器,最后对照本项目的代码把每一行都讲透。


第一章 一个神经元——最小的"决策单元"

1.1 神经元的灵感来源

人脑有约 860 亿个神经元,每个神经元的工作模式是:

  1. 从其他神经元接收信号
  2. 把信号汇总
  3. 如果汇总结果超过某个阈值,就"激发",向下游发出信号;否则保持沉默

人工神经元直接模仿了这个过程。

1.2 人工神经元的数学表达

输入 x₁ ──→ ×w₁ ──┐
输入 x₂ ──→ ×w₂ ──┼──→ 加权求和 z = w₁x₁ + w₂x₂ + w₃x₃ + b ──→ 激活函数 f(z) ──→ 输出 y
输入 x₃ ──→ ×w₃ ──┘
符号 含义 直觉
x₁, x₂, x₃ 输入 从上游接收到的信号
w₁, w₂, w₃ 权重 每个输入有多重要(可正可负)
b 偏置 调节"激发门槛"的旋钮
z 加权求和 把所有信号汇总成一个数
f 激活函数 决定是否"激发"、输出多少
y 输出 传递给下游的信号

1.3 一个具体的例子

假设一个神经元用来判断"今天适不适合出门":

输入:
  x₁ = 温度(25°C → 归一化后 0.8)
  x₂ = 下雨概率(80% → 0.8)
  x₃ = 心情好不好(好 → 1.0)

权重(训练学到的):
  w₁ = +0.6  (温度越高越想出门)
  w₂ = -0.9  (下雨越大越不想出门)
  w₃ = +0.5  (心情好更想出门)
  b  = -0.1

计算:
  z = 0.6×0.8 + (-0.9)×0.8 + 0.5×1.0 + (-0.1)
    = 0.48 - 0.72 + 0.50 - 0.10
    = 0.16

  ReLU(0.16) = 0.16 > 0 → "激发",输出 0.16 → 倾向出门(但不太强烈)

权重的正负决定了这个输入是"鼓励"还是"抑制"输出。这些权重不是人工设定的,而是训练过程中自动学出来的。

1.4 单个神经元的局限

一个神经元只能画一条直线来划分"是/否"。现实中的问题往往需要弯弯曲曲的分类边界。解决办法:把很多神经元组合起来——这就是"层"和"网络"。


第二章 从单个神经元到"层"

2.1 什么是层

把多个神经元并排放在一起,它们接收相同的输入,但各自有各自的权重和偏置,各自输出一个值。

         神经元1 → y₁
输入 x →  神经元2 → y₂    ← 这就是一个"层",有 4 个神经元
         神经元3 → y₃
         神经元4 → y₄

4 个神经元就输出 4 个数,组成一个长度为 4 的向量。

一个常见的误解:一个神经元关注一个特性。实际上,一个神经元关注的是一种输入的组合模式。它的权重决定了它对哪些输入更敏感——可能侧重某一个(权重特别大),也可能综合多个。比如权重 [0.9, 0.01, 0.02] 几乎只看第一个输入,而 [0.4, 0.3, 0.3] 则均匀地看三个。很多神经元并排放一起,就有了很多种不同的"投票策略",合起来覆盖各种情况。

2.2 用矩阵表示

把 4 个神经元的权重排成一个矩阵,一层的计算就是一次矩阵乘法:

z=W⋅x+bz = W \cdot x + bz=Wx+b
y=f(z)y = f(z)y=f(z)

比如输入有 3 个值、这一层有 4 个神经元,那么 W 是 4×3 的矩阵,b 是长度 4 的向量。

这就是为什么深度学习离不开线性代数——一层的前向传播 = 一次矩阵乘法 + 一次激活

2.3 "全连接"是什么意思

如果每一个输入都和每一个神经元相连,就叫全连接层(Fully Connected,也叫 Dense 或 Linear)。

输入(3个)      全连接层(4个神经元)
  x₁ ─────┬──→ n₁
          ├──→ n₂     每个输入到每个神经元都有一条线 = 全连接
  x₂ ─────┼──→ n₃     一共 3×4 = 12 条线(12 个权重)
          ├──→ n₄
  x₃ ─────┘

为什么要全连接? 让每个神经元都能"看到"全部输入信息,自己决定关注什么。如果某个神经元只连了部分输入,它就永远看不到其余输入的信息,哪怕那些信息很重要。全连接保证了信息不被人为截断——至于每个输入到底重不重要,交给权重去学:重要的权重变大,不重要的趋近于 0。

缺点:输入一多,连接数就爆炸。3072 个输入 × 1024 个神经元 = 300 万条线。这也是后来 CNN 用卷积代替全连接的动机——不需要每个像素都和每个神经元相连,只看局部就够了。

全连接层是 MLP 的唯一"砖块"。


第三章 MLP = 多层全连接网络

3.1 什么是 MLP

MLP(Multi-Layer Perceptron,多层感知机)就是把多个全连接层串起来,每两层之间加一个激活函数。

输入层          隐藏层1         隐藏层2         输出层
(原始数据)      (中间特征)      (更高级特征)     (分类得分)

 x₁ ──┐     ┌── h₁ ──┐     ┌── h₁ ──┐     ┌── y₁
 x₂ ──┼──→  ├── h₂ ──┼──→  ├── h₂ ──┼──→  ├── y₂
 x₃ ──┤     ├── h₃ ──┤     └── h₃ ──┘     └── y₃
  ⋮   ┘     └── h₄ ──┘

3.2 为什么叫"深度"学习

只有一个隐藏层的 MLP 叫"浅层网络"。有两个及以上隐藏层的就算"深层网络"——这也是"深度学习"这个名字的由来。层数越多,网络能表达的函数越复杂。

3.3 每一层在干什么

作用 比喻
输入层 接收原始数据 把题目摆到桌上
隐藏层 提取中间特征 画草稿、做中间推理
输出层 给出最终结果 写下最终答案

隐藏层之所以叫"隐藏",是因为我们只能看到输入和输出,中间层学到的东西是网络自己决定的,对我们是"隐藏"的。

3.4 激活函数为什么必须存在

如果去掉所有激活函数,整个 MLP 就变成了:

y=W3⋅(W2⋅(W1⋅x))=(W3W2W1)⋅x=W′⋅xy = W_3 \cdot (W_2 \cdot (W_1 \cdot x)) = (W_3 W_2 W_1) \cdot x = W' \cdot xy=W3(W2(W1x))=(W3W2W1)x=Wx

多层线性变换等价于一层线性变换——深度白加了。激活函数(ReLU)在每层之后引入"拐点",才让多层叠加有了意义。

常见误解:激活函数是为了去掉不重要的参数。 不是。激活函数的目的是引入非线性——让网络能画出弯曲的分类边界,而不只是一条直线。之所以会有这个误解,是因为 ReLU 恰好会把负数归零,看起来像在"丢东西"。但换成 Tanh(输出在 -1 到 1 之间,不归零)同样能当激活函数,因为它也是非线性的。一句话:激活函数 = 给网络装弯道,没有它只能走直线。


第四章 MLP 处理图片——拍平的代价

4.1 图片怎么变成 MLP 能接收的输入

MLP 的输入必须是一维向量。但图片是二维的(宽×高),还有颜色通道(RGB),所以是三维的。

解决办法很粗暴:直接拍平

一张 32×32×3 的彩色图片:

    R 通道(32×32)   G 通道(32×32)   B 通道(32×32)
    ┌──────────┐     ┌──────────┐     ┌──────────┐
    │          │     │          │     │          │
    │  32×32   │     │  32×32   │     │  32×32   │
    │          │     │          │     │          │
    └──────────┘     └──────────┘     └──────────┘

            ↓ Flatten(拍平)

    [ r₁, r₂, ..., r₁₀₂₄, g₁, g₂, ..., g₁₀₂₄, b₁, b₂, ..., b₁₀₂₄ ]
    └───────────────────────── 3072 个数字 ──────────────────────────────┘

4.2 拍平丢掉了什么

拍平后,所有的空间位置关系都没了:

  • 左上角的像素和右下角的像素在向量里可能相邻,也可能相隔很远
  • 一只猫的眼睛和耳朵明明是邻居,拍平后网络不知道它们挨着
  • 即使把图片旋转 90°、翻转,拍平后得到的向量完全不同——MLP 认不出是同一张图

这就是 MLP 做图像分类天生的劣势,也是后来 CNN 被发明的直接原因。

4.3 那 MLP 做图片分类还有什么意义

作为基线(baseline)。在实验中先用 MLP 跑一组结果,再用 CNN 跑一组,对比之下就能清楚地看出 CNN 的优势有多大。


第五章 本项目 MLP 的完整结构

5.1 网络结构图

输入: [batch, 3, 32, 32]  ← 一批 32×32 的 RGB 图片

  Flatten                  → [batch, 3072]     把图片拍成一维向量
      ↓
  Linear(3072 → 1024)     → [batch, 1024]     第一个全连接层
  ReLU                     → [batch, 1024]     激活:负数归零
  Dropout(0.3)             → [batch, 1024]     随机关掉 30% 的神经元
      ↓
  Linear(1024 → 512)      → [batch, 512]      第二个全连接层
  ReLU                     → [batch, 512]      激活
  Dropout(0.3)             → [batch, 512]      再随机关掉 30%
      ↓
  Linear(512 → 100)       → [batch, 100]      输出层:100 个类别各一个得分

最终: 取 100 个得分中最大的那个对应的类别,作为预测结果

5.2 逐层解读

Flatten:拍平

把 32×32×3 = 3072 个像素值排成一行。这一步没有任何可学习的参数,纯粹是数据形状变换。

Linear(3072, 1024):第一个全连接层

3072 个输入,1024 个输出。参数量 = 3072×1024 + 1024(偏置)= 3,146,752

这一层做的事情:把 3072 维的原始像素信息"混合压缩"成 1024 维的中间表示。你可以想象成:3072 个人投票,1024 个委员会成员分别统计不同维度的民意。

ReLU:激活

把负数变成 0。没有可学习参数。作用:让网络能表达非线性关系。

Dropout(0.3):防过拟合

训练时随机关掉 30% 的神经元。没有可学习参数。作用:防止网络死记硬背训练数据。

测试时所有神经元都打开(PyTorch 的 model.eval() 自动处理)。

Linear(1024, 512):第二个全连接层

把 1024 维进一步压缩到 512 维。参数量 = 1024×512 + 512 = 524,800

这一层在提取更高级的特征组合。

Linear(512, 100):输出层

512 维压缩到 100 维。每个输出值代表"这张图属于第 i 类的得分"。参数量 = 512×100 + 100 = 51,300

注意输出层没有激活函数——因为交叉熵损失函数内部自带 softmax,不需要额外加。

5.3 参数量总结

参数量 占比
Linear(3072→1024) 3,146,752 84.5%
Linear(1024→512) 524,800 14.1%
Linear(512→100) 51,300 1.4%
总计 3,722,852 100%

绝大多数参数集中在第一层——因为输入维度太高(3072)。而 CNN 用卷积的权重共享机制,同样的输入只需要几千个参数就能处理,这是 CNN 参数效率远高于 MLP 的根本原因。


第六章 MLP 的训练过程

6.1 整体流程

┌──────────────────────────────────────────────────┐
│                                                  │
│  ① 取一批图片 → ② 拍平 → ③ 前向传播得到预测      │
│                                    ↓             │
│                              ④ 和标签比较算损失    │
│                                    ↓             │
│                              ⑤ 反向传播算梯度      │
│                                    ↓             │
│                              ⑥ 优化器更新参数      │
│                                    ↓             │
│                              回到 ① 取下一批 ────→│
│                                                  │
└──────────────────────────────────────────────────┘
         一个 epoch = 把训练集完整过一遍

6.2 前向传播的数值示例

用一个极简版(3 个输入、2 个隐藏、2 个输出)演示一轮计算:

输入: x = [0.5, 0.3, 0.8]

第一层 Linear(3→2):
  W₁ = [[0.1, 0.4, -0.2],    b₁ = [0.1, -0.1]
        [0.3, -0.1, 0.5]]

  z₁ = W₁·x + b₁ = [0.1×0.5 + 0.4×0.3 + (-0.2)×0.8 + 0.1,
                      0.3×0.5 + (-0.1)×0.3 + 0.5×0.8 + (-0.1)]
     = [0.05 + 0.12 - 0.16 + 0.1,  0.15 - 0.03 + 0.40 - 0.1]
     = [0.11, 0.42]

ReLU:
  h₁ = [max(0, 0.11), max(0, 0.42)] = [0.11, 0.42]  (都是正数,不变)

第二层 Linear(2→2):
  W₂ = [[0.2, -0.3],    b₂ = [0.0, 0.1]
        [-0.1, 0.6]]

  z₂ = W₂·h₁ + b₂ = [0.2×0.11 + (-0.3)×0.42 + 0.0,
                       (-0.1)×0.11 + 0.6×0.42 + 0.1]
     = [-0.104, 0.341]

输出(logits): [-0.104, 0.341]
→ 第 2 类得分更高 → 模型预测为第 2 类

6.3 损失函数怎么算

假设真实标签是第 1 类(索引 0),交叉熵损失会说:“你给第 1 类打了 -0.104 分,给第 2 类打了 0.341 分,你打错了,损失很大!”

然后反向传播从这个损失出发,算出 W₁、b₁、W₂、b₂ 每个参数该怎么调,优化器执行调整,下一轮预测就会更准一点。

6.4 训练多久

本项目默认训练 10 个 epoch,每个 epoch 遍历全部训练集一次。每个 epoch 结束后在验证集上测一次准确率,记录最好的那一轮模型。


第七章 MLP 的弱点与 CNN 的优势对比

维度 MLP CNN
处理图片方式 拍平成向量,丢掉空间信息 保留二维结构,用卷积扫描
参数量 第一层就 300 万+ 卷积层参数很少(权重共享)
平移不变性 没有,图片移动一下结果就变 有,同一个卷积核到处扫
适合的数据 表格数据、低维特征 图像、音频等有空间/时间结构的数据
在 CIFAR-100 上的表现 较差(通常 30-40%) 较好(通常 50-70%)

为什么 MLP 在图片上差这么多

一个核心原因:MLP 学不到"局部模式可以在任意位置出现"这个先验

比如"猫耳朵"可能出现在图片的左上角,也可能在右下角。CNN 用同一个卷积核在整张图上滑动,只要学会"猫耳朵长什么样",不管它在哪都能检测到。而 MLP 把图片拍平后,左上角和右下角的像素在向量里位置不同,它需要分别学两套权重来识别,等于同一个知识学了两遍——数据不够时就学不好。


第八章 MLP 的适用场景

虽然 MLP 不擅长图片,但在很多其他场景它是主力:

场景 输入 为什么 MLP 够用
表格数据分类 年龄、收入、学历等特征 没有空间结构,不需要卷积
推荐系统 用户特征 + 物品特征 拼接成向量后全连接就能学
Transformer 的内部 注意力层的输出 Transformer 每个块里都有一个两层 MLP(叫 FFN)
强化学习 状态向量 DQN、PPO 的 Q 网络和策略网络本质就是 MLP
嵌入层之后 低维表示 任何网络的最后几层分类头通常就是 MLP

一句话:MLP 是深度学习的"万金油",几乎所有网络内部都在用它,只是不擅长直接处理有空间结构的原始数据。


总结:MLP 核心概念一页纸

┌─────────────────────────────────────────────────────────────┐
│                    MLP 核心概念速查                           │
├─────────────┬───────────────────────────────────────────────┤
│  神经元      │ 加权求和 + 偏置 + 激活函数 = 最小决策单元      │
│  权重 w      │ 每个输入的"重要程度",正=鼓励,负=抑制         │
│  偏置 b      │ 调节激发门槛的旋钮                            │
│  全连接层    │ 每个输入连接每个输出,一次矩阵乘法              │
│  隐藏层      │ 输入和输出之间的中间层,提取特征                │
│  ReLU       │ max(0, x),引入非线性,负数归零                │
│  Dropout    │ 训练时随机关神经元,防过拟合                    │
│  Flatten    │ 多维数据拍成一维向量,MLP 处理图片的前提         │
│  前向传播    │ 输入 → 逐层计算 → 输出预测                    │
│  反向传播    │ 从损失出发,逆向算每个参数的梯度                │
│  参数量      │ 全连接层参数 = 输入维度 × 输出维度 + 偏置       │
│  局限性      │ 拍平丢掉空间信息,不适合直接处理图像             │
│  真正擅长    │ 表格数据、作为其他网络的内部组件                 │
└─────────────┴───────────────────────────────────────────────┘
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐