跳转至

02 - 神经网络基础

重要性: ⭐⭐⭐⭐⭐ 实用度: ⭐⭐⭐⭐⭐ 学习时间: 5小时 必须掌握: 是


为什么学这一章?

神经网络是深度学习的基石。理解神经网络的基础原理能帮助你: - 理解深度学习模型的基本构建块 - 掌握前向传播的计算过程 - 理解神经网络的表达能力理论 - 能够从零实现简单的神经网络

学完这一章,你将能够: - ✅ 解释感知机的工作原理 - ✅ 理解多层感知机(MLP)的结构 - ✅ 手动计算简单网络的前向传播 - ✅ 理解万能逼近定理及其意义 - ✅ 理解深度vs宽度的理论分析 - ✅ 用NumPy实现一个MLP


📖 感知机:神经网络的起点

感知机模型

人工神经元模型

图注:人工神经元模型

感知机(Perceptron)是最简单的神经网络,由Rosenblatt于1958年提出。

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    感知机结构                                          │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│                         感知机(单输出)                               │
│                                                                     │
│     输入                    加权求和              激活                │
│   ┌─────┐                ┌─────────┐          ┌───────┐            │
│   │ x₁  │───w₁────────→ │         │          │       │            │
│   │ x₂  │───w₂────────→ │  Σwᵢxᵢ  │───→f()──→│ 输出 y │            │
│   │ x₃  │───w₃────────→ │  + b    │          │       │            │
│   │ ... │                │         │          └───────┘            │
│   │ xₙ  │───wₙ────────→ │         │                                │
│   └─────┘                └─────────┘                                │
│      ↑                       ↑                                      │
│   输入特征                  偏置b                                    │
│                                                                     │
│  数学公式:                                                          │
│  z = w₁x₁ + w₂x₂ + ... + wₙxₙ + b                                   │
│  y = f(z)                                                           │
│                                                                     │
│  其中:                                                              │
│  • xᵢ:输入特征(如像素值)                                           │
│  • wᵢ:权重(学习的参数)                                             │
│  • b:偏置(学习的参数)                                              │
│  • f:激活函数(如阶跃函数)                                          │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

感知机的决策边界

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    感知机的几何解释                                    │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  二分类问题(以二维为例):                                            │
│                                                                     │
│       x₂                                                            │
│        ↑                                                            │
│        │    ×    ×                                                  │
│        │  ×    ×    ×         决策边界: w₁x₁ + w₂x₂ + b = 0          │
│        │    ×    ×    ×     ╱                                       │
│        │  ×    ×    ×   ╱    ←──── 超平面(直线)                    │
│        │    ×    ×  ╱  ○                                            │
│        │  ×    × ╱    ○  ○                                          │
│        │    × ╱    ○    ○  ○                                        │
│        │  ╱    ○    ○    ○                                          │
│        └──────────────────────→ x₁                                  │
│                                                                     │
│  • ×:类别A(如:猫)                                                │
│  • ○:类别B(如:狗)                                                │
│  • 直线:决策边界,将两类分开                                         │
│                                                                     │
│  关键洞察:                                                          │
│  感知机学习的是输入空间中的一个超平面,将不同类别分开                   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

感知机的局限:XOR问题

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    感知机的局限:无法解决XOR问题                        │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  XOR问题(异或):                                                   │
│                                                                     │
│       x₂                                                            │
│        ↑                                                            │
│        │    0    1                                                  │
│        │         ↑                                                  │
│        │  0      │      无法用一条直线分开!                          │
│        │         │                                                  │
│        │  ──────┼──────                                             │
│        │         │                                                  │
│        │    1    │      0                                           │
│        │         ↓                                                  │
│        └──────────────────→ x₁                                      │
│                                                                     │
│  XOR真值表:                                                         │
│  ┌─────┬─────┬───────┐                                              │
│  │ x₁  │ x₂  │ x₁⊕x₂ │                                              │
│  ├─────┼─────┼───────┤                                              │
│  │  0  │  0  │   0   │                                              │
│  │  0  │  1  │   1   │                                              │
│  │  1  │  0  │   1   │                                              │
│  │  1  │  1  │   0   │                                              │
│  └─────┴─────┴───────┘                                              │
│                                                                     │
│  关键洞察:                                                          │
│  单层感知机只能解决线性可分问题                                       │
│  XOR问题不是线性可分的,需要多层网络                                  │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

🏗️ 多层感知机(MLP)

从单层到多层

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    多层感知机(MLP)结构                               │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  输入层        隐藏层1         隐藏层2         输出层                  │
│  ┌─────┐     ┌─────┐        ┌─────┐        ┌─────┐                 │
│  │ x₁  │────→│ h₁  │   ┌───→│ h₁' │   ┌───→│ y₁  │                 │
│  │ x₂  │────→│ h₂  │───┤    │ h₂' │───┤    │ y₂  │                 │
│  │ x₃  │────→│ h₃  │   │    │ h₃' │   │    │ ... │                 │
│  │ ... │     │ ... │   │    │ ... │   │    │ yₖ  │                 │
│  │ xₙ  │────→│ hₘ  │───┘    └─────┘   └───→└─────┘                 │
│  └─────┘     └─────┘                                                │
│                                                                     │
│  层间连接:                                                          │
│  • 输入层 → 隐藏层1:全连接(每个输入连接到每个隐藏单元)              │
│  • 隐藏层1 → 隐藏层2:全连接                                          │
│  • 隐藏层2 → 输出层:全连接                                           │
│                                                                     │
│  为什么能解决XOR?                                                    │
│  多层网络可以学习非线性决策边界!                                      │
│                                                                     │
│       x₂                                                            │
│        ↑                                                            │
│        │    0    1                                                  │
│        │    ╲   ╱                                                   │
│        │     ╲ ╱     两条直线组合成非线性边界                          │
│        │      ×                                                     │
│        │     ╱ ╲                                                    │
│        │    1   ╲    0                                              │
│        └──────────────────→ x₁                                      │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

前向传播计算

神经网络前向传播

神经网络前向传播

图注:神经网络前向传播

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    前向传播计算过程                                    │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  示例:2-3-1网络(2输入,3隐藏单元,1输出)                            │
│                                                                     │
│  输入: x = [x₁, x₂] = [0.5, 0.3]                                    │
│                                                                     │
│  第1层(输入层 → 隐藏层):                                           │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │ 权重 W¹ = [[w₁₁, w₁₂, w₁₃],      偏置 b¹ = [b₁, b₂, b₃]      │   │
│  │            [w₂₁, w₂₂, w₂₃]]                                  │   │
│  │                                                              │   │
│  │ z₁ = x₁·w₁₁ + x₂·w₂₁ + b₁                                   │   │
│  │ z₂ = x₁·w₁₂ + x₂·w₂₂ + b₂                                   │   │
│  │ z₃ = x₁·w₁₃ + x₂·w₂₃ + b₃                                   │   │
│  │                                                              │   │
│  │ h₁ = f(z₁), h₂ = f(z₂), h₃ = f(z₃)   ← 激活函数              │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  第2层(隐藏层 → 输出层):                                           │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │ 权重 W² = [w₁, w₂, w₃]ᵀ          偏置 b² = b                 │   │
│  │                                                              │   │
│  │ z = h₁·w₁ + h₂·w₂ + h₃·w₃ + b                               │   │
│  │                                                              │   │
│  │ y = f(z)                         ← 输出激活函数              │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  矩阵形式(更简洁):                                                  │
│  h = f(x · W¹ + b¹)                                                 │
│  y = f(h · W² + b²)                                                 │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

手动计算示例

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    手动计算示例                                        │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  网络结构:2-2-1(2输入,2隐藏单元,1输出)                            │
│                                                                     │
│  给定:                                                              │
│  输入: x = [1.0, 0.5]                                               │
│                                                                     │
│  权重(已学习得到):                                                 │
│  W¹ = [[0.1, 0.2],     b¹ = [0.1, 0.2]                              │
│       [0.3, 0.4]]                                                   │
│                                                                     │
│  W² = [0.5, 0.6]ᵀ      b² = 0.3                                     │
│                                                                     │
│  激活函数:Sigmoid: f(z) = 1 / (1 + e^(-z))                         │
│                                                                     │
│  ─────────────────────────────────────────────────────────────────  │
│                                                                     │
│  Step 1: 计算隐藏层输入                                               │
│  z₁ = 1.0×0.1 + 0.5×0.3 + 0.1 = 0.35                                │
│  z₂ = 1.0×0.2 + 0.5×0.4 + 0.2 = 0.60                                │
│                                                                     │
│  Step 2: 应用激活函数                                                 │
│  h₁ = sigmoid(0.35) = 1/(1+e^(-0.35)) ≈ 0.587                       │
│  h₂ = sigmoid(0.60) = 1/(1+e^(-0.60)) ≈ 0.646                       │
│                                                                     │
│  Step 3: 计算输出层输入                                               │
│  z = 0.587×0.5 + 0.646×0.6 + 0.3 ≈ 0.981                            │
│                                                                     │
│  Step 4: 应用输出激活函数                                             │
│  y = sigmoid(0.981) ≈ 0.727                                         │
│                                                                     │
│  ─────────────────────────────────────────────────────────────────  │
│                                                                     │
│  最终结果:y ≈ 0.727                                                 │
│                                                                     │
│  如果这是二分类问题(输出0或1):                                      │
│  y > 0.5 → 预测为类别1                                               │
│  y ≤ 0.5 → 预测为类别0                                               │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

🧮 核心理论:万能逼近定理

什么是万能逼近定理?

万能逼近定理(Universal Approximation Theorem)是神经网络理论的基石,它证明了神经网络的强大表达能力。

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    万能逼近定理                                        │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  定理陈述(Cybenko, 1989; Hornik et al., 1989):                     │
│                                                                     │
│  具有至少一个隐藏层的前馈神经网络,只要隐藏层有足够多的神经元,         │
│  并且使用非线性激活函数(如Sigmoid、ReLU),就可以以任意精度           │
│  逼近任意连续函数。                                                   │
│                                                                     │
│  数学表述:                                                          │
│                                                                     │
│  对于任意连续函数 f: [0,1]ⁿ → ℝ 和任意 ε > 0,                       │
│  存在一个具有单隐藏层的神经网络 g,使得:                              │
│                                                                     │
│  |f(x) - g(x)| < ε   对所有 x ∈ [0,1]ⁿ 成立                         │
│                                                                     │
│  ─────────────────────────────────────────────────────────────────  │
│                                                                     │
│  直观理解:                                                          │
│                                                                     │
│  目标函数 f(x) = sin(2πx)              神经网络逼近 g(x)              │
│       │╲    ╱│                              │╲    ╱│                │
│       │ ╲  ╱ │                              │ ╲  ╱ │                │
│       │  ╲╱  │                              │  ╲╱  │                │
│       └──────┘                              └──────┘                │
│                                                                     │
│  只要隐藏层神经元足够多,神经网络可以逼近任意复杂的函数!               │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

万能逼近定理的直观解释

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    为什么神经网络能逼近任意函数?                       │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  核心思想:用多个" bump函数 "组合逼近任意函数                           │
│                                                                     │
│  单个神经元(Sigmoid):                                              │
│                                                                     │
│       1 │        ╭──────╮                                           │
│         │       ╱        ╲                                          │
│       0 │──────╱          ╲────────                                 │
│         └────────────────────────→ x                                │
│                                                                     │
│  两个神经元的组合:                                                   │
│                                                                     │
│       1 │    ╭──╮      ╭──╮                                         │
│         │   ╱    ╲    ╱    ╲                                        │
│       0 │──╱      ╲──╱      ╲────                                   │
│         └────────────────────────→ x                                │
│                                                                     │
│  多个神经元的组合可以逼近任意形状:                                    │
│                                                                     │
│       1 │    ╭─╮  ╭──╮   ╭╮    ╭──╮                                │
│         │   ╱   ╲╱    ╲ ╱  ╲  ╱    ╲                               │
│       0 │──╱          ╳      ╳       ╲───                          │
│         └────────────────────────→ x                                │
│                                                                     │
│  关键洞察:                                                          │
│  • 每个神经元学习一个局部的"特征"                                     │
│  • 足够多的神经元可以组合出任意复杂的函数                              │
│  • 这就是深度学习的表达能力来源!                                     │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

万能逼近定理的局限性

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    万能逼近定理的局限性                                │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  定理只保证存在性,不保证:                                           │
│                                                                     │
│  1. 网络能找到最优权重                                               │
│     ┌─────────────────────────────────────────┐                     │
│     │ 训练可能陷入局部最优                   │                     │
│     │ 梯度下降不保证找到全局最优             │                     │
│     └─────────────────────────────────────────┘                     │
│                                                                     │
│  2. 网络能在合理时间内收敛                                            │
│     ┌─────────────────────────────────────────┐                     │
│     │ 可能需要指数级的训练时间               │                     │
│     │ 实际应用中需要优化算法和技巧           │                     │
│     └─────────────────────────────────────────┘                     │
│                                                                     │
│  3. 网络能泛化到新数据                                                │
│     ┌─────────────────────────────────────────┐                     │
│     │ 可能过拟合训练数据                     │                     │
│     │ 需要正则化、早停等技术                 │                     │
│     └─────────────────────────────────────────┘                     │
│                                                                     │
│  4. 网络规模是可行的                                                  │
│     ┌─────────────────────────────────────────┐                     │
│     │ 可能需要指数级数量的神经元             │                     │
│     │ 深层网络可以用更少参数表示复杂函数     │                     │
│     └─────────────────────────────────────────┘                     │
│                                                                     │
│  这就是为什么需要:                                                   │
│  • 深层网络(深度比宽度更重要)                                       │
│  • 更好的优化算法(Adam、学习率调度)                                  │
│  • 正则化技术(Dropout、权重衰减)                                     │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

📊 深度 vs 宽度:网络架构的理论分析

深度与宽度的权衡

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    深度 vs 宽度:网络架构设计                           │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  浅而宽的网络                      深而窄的网络                        │
│                                                                     │
│  ┌─────────────────┐              ┌───┐                             │
│  │  输入           │              │输入│                             │
│  └────────┬────────┘              └───┘                             │
│           ↓                          ↓                              │
│  ┌─────────────────┐              ┌───┐                             │
│  │  隐藏层         │              │H1 │                             │
│  │  (1000神经元)   │              └───┘                             │
│  └────────┬────────┘                 ↓                              │
│           ↓                       ┌───┐                             │
│  ┌─────────────────┐              │H2 │                             │
│  │  输出           │              └───┘                             │
│  └─────────────────┘                 ↓                              │
│                                   ┌───┐                             │
│                                   │H3 │                             │
│                                   └───┘                             │
│                                      ↓                              │
│                                   ┌───┐                             │
│                                   │H4 │                             │
│                                   └───┘                             │
│                                      ↓                              │
│                                   ┌───┐                             │
│                                   │H5 │                             │
│                                   └───┘                             │
│                                      ↓                              │
│                                   ┌───┐                             │
│                                   │输出│                             │
│                                   └───┘                             │
│                                                                     │
│  参数数量相似,但表达能力不同!                                        │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

为什么深度更重要?

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    深度的指数级优势                                    │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  理论结果(Eldan & Shamir, 2016; Telgarsky, 2016):                  │
│                                                                     │
│  存在一类函数,浅层网络需要指数级数量的神经元才能表示,                │
│  而深层网络只需要多项式数量的神经元。                                  │
│                                                                     │
│  具体例子:                                                          │
│                                                                     │
│  函数:f(x) = x²ⁿ(n次平方)                                         │
│                                                                     │
│  浅层网络(2层):                                                    │
│  • 需要 O(2ⁿ) 个神经元                                               │
│  • 指数级增长,不可行                                                │
│                                                                     │
│  深层网络(O(n)层):                                                 │
│  • 只需要 O(n) 个神经元                                              │
│  • 线性增长,完全可行                                                │
│                                                                     │
│  ─────────────────────────────────────────────────────────────────  │
│                                                                     │
│  直观解释:                                                          │
│                                                                     │
│  深层网络的每一层都在进行"特征组合":                                  │
│                                                                     │
│  第1层:学习边缘(简单特征)                                          │
│       ↓                                                             │
│  第2层:学习纹理(组合边缘)                                          │
│       ↓                                                             │
│  第3层:学习部件(组合纹理)                                          │
│       ↓                                                             │
│  第4层:学习对象(组合部件)                                          │
│                                                                     │
│  每一层都在前一层的基础上构建更复杂的特征!                            │
│  这种层次化结构符合现实世界的组织方式。                                │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

深度与宽度的实践指导

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    网络架构设计实践指南                                │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  一般原则:                                                          │
│                                                                     │
│  1. 优先增加深度                                                     │
│     ┌─────────────────────────────────────────┐                     │
│     │ 从3-5层开始,逐步增加深度              │                     │
│     │ ResNet可以训练100+层的网络             │                     │
│     │ 深度带来的收益通常大于宽度             │                     │
│     └─────────────────────────────────────────┘                     │
│                                                                     │
│  2. 合理设置宽度                                                     │
│     ┌─────────────────────────────────────────┐                     │
│     │ 隐藏层神经元数:64, 128, 256, 512...   │                     │
│     │ 通常每层宽度相同或递减                 │                     │
│     │ 输入层→隐藏层→输出层:宽→窄           │                     │
│     └─────────────────────────────────────────┘                     │
│                                                                     │
│  3. 避免过宽或过深                                                   │
│     ┌─────────────────────────────────────────┐                     │
│     │ 太宽:容易过拟合,计算效率低           │                     │
│     │ 太深:梯度消失/爆炸,训练困难          │                     │
│     │ 需要残差连接、批归一化等技术           │                     │
│     └─────────────────────────────────────────┘                     │
│                                                                     │
│  典型架构:                                                          │
│                                                                     │
│  简单任务(MNIST):                                                  │
│  输入(784) → 隐藏层1(256) → 隐藏层2(128) → 输出(10)                   │
│                                                                     │
│  中等复杂度(CIFAR-10):                                             │
│  使用CNN:Conv → Conv → Pool → Conv → Conv → Pool → FC → FC → Output  │
│                                                                     │
│  复杂任务(ImageNet):                                               │
│  ResNet-50:50层,包含残差连接                                        │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

🔧 激活函数:引入非线性

为什么需要激活函数?

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    为什么需要激活函数?                                │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  假设没有激活函数(线性激活):                                        │
│                                                                     │
│  第1层:h = x · W¹ + b¹                                             │
│  第2层:y = h · W² + b²                                             │
│                                                                     │
│  合并:y = (x · W¹ + b¹) · W² + b²                                  │
│       y = x · (W¹·W²) + (b¹·W² + b²)                                │
│       y = x · W' + b'                                               │
│                                                                     │
│  结论:多层线性网络等价于单层线性网络!                                │
│       无法学习非线性模式!                                            │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  没有激活函数                        有激活函数               │   │
│  │                                                              │   │
│  │  输入 ──→ [线性] ──→ [线性] ──→ 输出   输入 ──→ [线性+非线性] ──→  │   │
│  │              ↓        ↓                                      │   │
│  │           等价于单层网络              可以学习复杂模式         │   │
│  │           只能解决线性问题            可以解决非线性问题       │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  关键洞察:                                                          │
│  激活函数引入非线性,使网络能学习复杂模式                              │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

常用激活函数

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    常用激活函数对比                                    │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  1. Sigmoid                                                         │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  f(z) = 1 / (1 + e^(-z))                                    │   │
│  │                                                              │   │
│  │       1 │        ╭──────╮                                   │   │
│  │         │       ╱        ╲                                  │   │
│  │     0.5 │──────╱          ╲────────                         │   │
│  │         │     ╱            ╲                                │   │
│  │       0 │────╱              ╲──────                         │   │
│  │         └────────────────────────→ z                        │   │
│  │            -4  -2   0   2   4                               │   │
│  │                                                              │   │
│  │  导数:f'(z) = f(z) · (1 - f(z))                            │   │
│  │                                                              │   │
│  │  优点:输出范围(0,1),可解释为概率                            │   │
│  │  缺点:梯度消失(两端饱和),输出非0中心化                     │   │
│  │  用途:二分类输出层                                           │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  2. Tanh(双曲正切)                                                 │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  f(z) = (e^z - e^(-z)) / (e^z + e^(-z))                     │   │
│  │                                                              │   │
│  │       1 │        ╭──────╮                                   │   │
│  │         │       ╱        ╲                                  │   │
│  │       0 │──────╱          ╲────────                         │   │
│  │         │     ╱            ╲                                │   │
│  │      -1 │────╱              ╲──────                         │   │
│  │         └────────────────────────→ z                        │   │
│  │            -4  -2   0   2   4                               │   │
│  │                                                              │   │
│  │  导数:f'(z) = 1 - f(z)²                                    │   │
│  │                                                              │   │
│  │  优点:输出范围(-1,1),0中心化                                │   │
│  │  缺点:仍有梯度消失问题                                       │   │
│  │  用途:隐藏层(早期使用)                                      │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  3. ReLU(Rectified Linear Unit)⭐ 最常用                           │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  f(z) = max(0, z)                                           │   │
│  │                                                              │   │
│  │         │        ╱                                          │   │
│  │         │       ╱                                           │   │
│  │         │      ╱                                            │   │
│  │       0 │─────╱────────────────                               │   │
│  │         │    ╱                                              │   │
│  │         └────────────────────────→ z                        │   │
│  │            -4  -2   0   2   4                               │   │
│  │                                                              │   │
│  │  导数:f'(z) = 1 if z > 0, else 0                           │   │
│  │                                                              │   │
│  │  优点:计算简单,缓解梯度消失,收敛快                          │   │
│  │  缺点:Dead ReLU(负数区域梯度为0)                           │   │
│  │  用途:隐藏层默认选择                                         │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  4. Softmax(多分类输出)                                            │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  f(zᵢ) = e^(zᵢ) / Σⱼe^(zⱼ)                                  │   │
│  │                                                              │   │
│  │  将任意实数向量转换为概率分布(和为1)                          │   │
│  │                                                              │   │
│  │  输入: [2.0, 1.0, 0.1]                                       │   │
│  │  输出: [0.7, 0.2, 0.1]  ← 概率分布                           │   │
│  │                                                              │   │
│  │  用途:多分类问题的输出层                                      │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

🧪 动手实验:NumPy实现MLP

让我们从零开始,用NumPy实现一个多层感知机。

完整代码

Python
import numpy as np

class MLP:
    """
    多层感知机(MLP)的NumPy实现

    架构:输入层 → 隐藏层 → 输出层
    """

    def __init__(self, input_size, hidden_size, output_size):  # __init__构造方法,创建对象时自动调用
        """
        初始化网络参数

        Args:
            input_size: 输入特征维度
            hidden_size: 隐藏层神经元数量
            output_size: 输出类别数量
        """
        # 初始化权重(使用He初始化,适用于ReLU激活函数)
        self.W1 = np.random.randn(input_size, hidden_size) * np.sqrt(2.0 / input_size)
        self.b1 = np.zeros(hidden_size)

        self.W2 = np.random.randn(hidden_size, output_size) * np.sqrt(2.0 / hidden_size)
        self.b2 = np.zeros(output_size)

        print(f"网络结构: {input_size}-{hidden_size}-{output_size}")
        print(f"参数数量: {input_size*hidden_size + hidden_size + hidden_size*output_size + output_size}")

    def relu(self, x):
        """ReLU激活函数"""
        return np.maximum(0, x)

    def softmax(self, x):
        """Softmax激活函数"""
        exp_x = np.exp(x - np.max(x, axis=1, keepdims=True))
        return exp_x / np.sum(exp_x, axis=1, keepdims=True)

    def forward(self, X):
        """
        前向传播

        Args:
            X: 输入数据,形状 (batch_size, input_size)

        Returns:
            输出概率,形状 (batch_size, output_size)
        """
        # 第1层:输入 → 隐藏层
        self.z1 = np.dot(X, self.W1) + self.b1  # 线性变换
        self.h = self.relu(self.z1)              # ReLU激活

        # 第2层:隐藏层 → 输出层
        self.z2 = np.dot(self.h, self.W2) + self.b2  # 线性变换
        self.y_pred = self.softmax(self.z2)          # Softmax激活

        return self.y_pred

    def compute_loss(self, y_pred, y_true):
        """
        计算交叉熵损失

        Args:
            y_pred: 预测概率 (batch_size, output_size)
            y_true: 真实标签 (batch_size,)

        Returns:
            平均损失
        """
        batch_size = y_pred.shape[0]
        # 获取正确类别的概率
        correct_logprobs = -np.log(y_pred[range(batch_size), y_true] + 1e-8)
        return np.sum(correct_logprobs) / batch_size

    def predict(self, X):
        """预测类别"""
        y_pred = self.forward(X)
        return np.argmax(y_pred, axis=1)

    def accuracy(self, X, y):
        """计算准确率"""
        predictions = self.predict(X)
        return np.mean(predictions == y)

# ==================== 测试代码 ====================

if __name__ == "__main__":
    # 生成模拟数据(3类分类问题)
    np.random.seed(42)

    # 训练数据:100个样本,4维特征,3个类别
    X_train = np.random.randn(100, 4)
    y_train = np.random.randint(0, 3, 100)

    # 创建网络
    model = MLP(input_size=4, hidden_size=10, output_size=3)

    # 测试前向传播
    print("\n测试前向传播...")
    output = model.forward(X_train[:5])  # 切片操作取子序列
    print(f"输入形状: {X_train[:5].shape}")
    print(f"输出形状: {output.shape}")
    print(f"输出概率和: {output.sum(axis=1)}")  # 应该接近1

    # 测试预测
    print("\n测试预测...")
    predictions = model.predict(X_train[:10])
    print(f"预测结果: {predictions}")
    print(f"真实标签: {y_train[:10]}")
    print(f"准确率: {model.accuracy(X_train[:10], y_train[:10]):.2%}")

    # 测试损失计算
    print("\n测试损失计算...")
    loss = model.compute_loss(output, y_train[:5])
    print(f"损失值: {loss:.4f}")

    print("\n✅ 所有测试通过!")

运行结果

Text Only
网络结构: 4-10-3
参数数量: 73

测试前向传播...
输入形状: (5, 4)
输出形状: (5, 3)
输出概率和: [1. 1. 1. 1. 1.]

测试预测...
预测结果: [1 1 0 0 1 0 1 1 1 2]
真实标签: [0 2 1 0 1 2 2 0 0 2]
准确率: 20.00%

测试损失计算...
损失值: 1.0986

✅ 所有测试通过!

注意:准确率较低是因为权重是随机初始化的,还没有训练。下一章我们将学习如何训练网络!


💡 核心要点总结

感知机

  • 最简单的神经网络单元
  • 学习线性决策边界
  • 无法解决非线性可分问题(如XOR)

多层感知机(MLP)

  • 通过多层结构学习非线性映射
  • 每层执行:线性变换 + 非线性激活
  • 可以逼近任意连续函数(万能逼近定理)

万能逼近定理

  • 单隐藏层网络可以逼近任意连续函数
  • 只保证存在性,不保证能找到或泛化
  • 深层网络可以用更少参数表示复杂函数

深度 vs 宽度

  • 深度比宽度更重要
  • 深层网络具有指数级表达能力优势
  • 实际设计中优先增加深度

前向传播

Text Only
输入 → [线性: z = xW + b] → [激活: h = f(z)] → 输出

激活函数

函数 公式 优点 缺点 隐藏层推荐度 典型用途
Sigmoid $\(\sigma(z) = \frac{1}{1+e^{-z}}\)$ 输出概率 梯度消失 ⭐ (不推荐) 二分类输出层
Tanh $\(\tanh(z) = \frac{e^z-e^{-z}}{e^z+e^{-z}}\)$ 0中心化 梯度消失 ⭐⭐ (较少用) RNN隐藏层
ReLU $\(\text{ReLU}(z) = \max(0,z)\)$ 简单、快速 Dead ReLU ⭐⭐⭐⭐⭐ (默认) CNN/MLP隐藏层
LeakyReLU $\(\text{LeakyReLU}(z) = \max(\alpha z,z)\)$ 避免Dead ReLU 需调α ⭐⭐⭐⭐ GAN、深层网络
Softmax $\(\text{Softmax}(z_i) = \frac{e^{z_i}}{\sum_j e^{z_j}}\)$ 概率分布 - - (仅输出层) 多分类输出层

❓ 常见问题

Q1:为什么需要偏置(bias)?

A:偏置允许决策边界不经过原点。没有偏置,网络只能学习经过原点的线性变换,限制了表达能力。

Q2:权重为什么要随机初始化?

A:如果所有权重初始化为相同值,所有神经元将学习相同的特征,网络失去意义。随机初始化打破对称性,让每个神经元学习不同的特征。

Q3:隐藏层需要多少神经元?

A:没有固定规则,通常: - 从较少神经元开始(如64、128) - 根据任务复杂度调整 - 更多神经元 = 更强表达能力,但也更容易过拟合

Q4:需要多少层隐藏层?

A: - 简单问题:1-2层 - 复杂问题:3-5层或更多 - 现代深度网络:几十到几百层(ResNet、Transformer)

Q5:如何选择激活函数?

A: - 隐藏层:默认使用ReLU - 二分类输出:Sigmoid - 多分类输出:Softmax - 回归输出:线性(无激活)

Q6:万能逼近定理意味着什么?

A:它证明了神经网络具有强大的表达能力,理论上可以逼近任何函数。但这只是存在性定理,实际训练中还需要考虑优化、泛化等问题。

Q7:为什么深度比宽度更重要?

A:深层网络可以通过层次化组合特征,用指数级更少的参数表示复杂函数。这符合现实世界的层次化结构(如图像的边→纹理→部件→对象)。

Q8:什么是Batch Normalization?为什么有效?

A: - BN的作用:对每一层的输入进行归一化,使其均值为0,方差为1 - 为什么有效: 1. 缓解内部协变量偏移(Internal Covariate Shift) 2. 允许使用更大的学习率,加速收敛 3. 减少对初始化的敏感性 4. 有轻微的正则化效果 - 训练vs测试:训练时使用当前batch的统计量,测试时使用训练集的移动平均统计量


📝 自测问题

  1. 感知机为什么不能解决XOR问题?MLP如何解决?
  2. 写出2-3-2网络的前向传播公式。
  3. 为什么激活函数必须是非线性的?
  4. ReLU相比Sigmoid有什么优势?
  5. 什么是万能逼近定理?它有什么局限性?
  6. 为什么深度比宽度更重要?
  7. 用NumPy实现一个2-4-3的MLP前向传播。

📚 扩展阅读

  1. 《Perceptrons》 - Minsky & Papert(感知机局限性的经典著作)
  2. 《Neural Networks and Deep Learning》 - Michael Nielsen(第1-2章)
  3. Approximation by Superpositions of a Sigmoidal Function - Cybenko, 1989(万能逼近定理)
  4. The Power of Depth for Feedforward Neural Networks - Eldan & Shamir, 2016(深度vs宽度)
  5. CS231n Lecture 4 - Backpropagation and Neural Networks

🎯 下一步

继续学习 03-激活函数详解04-损失函数与优化,然后学习反向传播算法,完成手写神经网络的训练。