📑 本页目录(点开跳转)
07 / 先看直觉,再看细节
先看直线分不开什么,
再给模型加一层变化。
非线性激活让多层网络不再等价于一个线性变换。先理解这一点,再记层数和形状。
先抓住一个具体结果
异或:对角线上的点属于同类
(0,0)、(1,1) 是一类,(0,1)、(1,0) 是另一类。单条直线无法把四个点全部分对;加入非线性隐藏层,才有机会表示这种边界。
一层网络的计算
接下来,按需要选一项
你现在想看什么?
这些入口是选择,不是必须按顺序完成的任务。
可以停在这里
非线性激活让多层网络不再等价于一个线性变换。先理解这一点,再记层数和形状。
需要更多细节时,继续看完整正文 →原有正文、图解和例子都在下方。按需跳转,不必一次读完。
07 · 从线性到神经网络
⏱ 28 分钟 | ⭐ 核心 | 🔨 有代码
🎯 一句话
神经网络 = 线性层 + 非线性激活,堆起来。 关键在「非线性激活」这四个字——没有它,堆一百层也还是一条直线。
💥 一、先看线性模型的死穴:异或问题
🔨 实测(三行代码,结论惊人)
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.neural_network import MLPClassifier
X = np.array([[0,0],[0,1],[1,0],[1,1]], dtype=float)
y = np.array([0, 1, 1, 0], dtype=float) # XOR
print("逻辑回归(线性) ", LogisticRegression().fit(X,y).score(X,y))
print("MLP(隐层4,tanh) ", MLPClassifier(hidden_layer_sizes=(4,), activation="tanh",
max_iter=5000, random_state=1).fit(X,y).score(X,y))
print("MLP但激活=identity", MLPClassifier(hidden_layer_sizes=(4,), activation="identity",
max_iter=5000, random_state=1).fit(X,y).score(X,y))
算一算
逻辑回归:本例可能得到约 50%,关键是单条直线无法全部分对
MLP(隐层 4,tanh):有能力分对全部四点,能否训练到取决于优化过程
MLP(identity 激活):仍是线性模型,增加隐藏层不能解决非线性可分问题
🔑 第三行是本章的灵魂: 有隐层不等于有能力。真正带来能力的是「非线性激活」。 因为线性套线性还是线性:
W₂(W₁x) = (W₂W₁)x,等价于一个单层线性模型。
🧱 二、神经网络的结构
- ① 线性:z = Σwᵢxᵢ + b —— 就是第 3 章的线性模型
- ② 非线性:a = 激活函数(z) —— 关键!
一层的完整计算(记住这个式子,整个深度学习都是它的堆叠):
$$\mathbf{a}^{(l)} = f\left(W^{(l)}\mathbf{a}^{(l-1)} + \mathbf{b}^{(l)}\right)$$
💡 人话:上一层的输出 → 乘个矩阵加个偏置 → 过一个非线性函数 → 交给下一层。
🔗 连接:这就是全景导论主线 2 · 模型怎样看懂一句话里 Transformer 那个 FFN 的结构。 Transformer 只是在这基础上加了注意力机制。
👁️ 神经网络到底在做什么(一个几何直觉)
流程图
💡 换个说法:
本节的分类 MLP 最后一层是线性输出层,再配合相应的分类损失。其他任务的输出头可以不同,不能推广成所有神经网络都如此。 前面所有层的工作,都是把数据变换成"线性可分"的样子。
⭐ 所以"深度学习"本质上是"自动的特征工程" —— 你在第 16 章手工造的那些交叉特征, 神经网络在用梯度下降自己造。
回头看异或:
结果对照
⚡ 三、激活函数(选 ReLU 就对了)
| 函数 | 公式 | 特点 |
|---|---|---|
| Sigmoid | $\frac{1}{1+e^{-z}}$ | 压到 (0,1)。⚠️ 两端梯度趋近 0 → 梯度消失。现在只用在输出层做二分类 |
| Tanh | $\frac{e^z-e^{-z}}{e^z+e^{-z}}$ | 压到 (-1,1),零中心。比 Sigmoid 好,但仍会梯度消失 |
| ReLU ⭐ | $\max(0, z)$ | 默认首选。计算极快、正区间梯度恒为 1 不消失 |
| Leaky ReLU | $\max(0.01z, z)$ | 解决 ReLU 的"神经元死亡"(负区间梯度为 0) |
| GELU / SwiGLU | 平滑版 ReLU | Transformer 时代的主流 |
🔑 ReLU 为什么是深度学习的转折点: Sigmoid 两端梯度接近 0,反向传播时层层相乘会指数级衰减 → 深层网络根本训不动。 ReLU 正区间导数为 1,不会在这一段像 Sigmoid 那样继续缩小梯度。但完整梯度还要经过权重矩阵等运算,ReLU 不保证没有梯度消失或爆炸。
算一下差距有多大:
对照
只比较激活导数的连乘,暂时忽略权重矩阵
Sigmoid 导数最大为 0.25:10 个相乘约为 9.5×10⁻⁷
30 个相乘约为 8.7×10⁻¹⁹:很小,但不是数学上的零
ReLU 在正区间导数为 1:这些局部导数连乘仍是 1
完整网络的梯度还受权重、路径和激活区间影响
⚠️ ReLU 的代价:神经元死亡
关键信息
三个解法:
| 解法 | 说明 |
|---|---|
| 降学习率 ⭐ | 最常见的根因就是 lr 太大 |
| Leaky ReLU / GELU | 负区间给一点点梯度,不会彻底死 |
| 合适的初始化 | He 初始化(PyTorch 的 kaiming_normal_)就是为 ReLU 设计的 |
💡 自检方法:训练后统计
(activation == 0).float().mean()。 单个批次中一半激活为 0 并不能判定死亡。 要逐个神经元观察多个代表性批次、多个训练步骤,确认是否一直不激活,再检查学习率、输入分布与梯度。
🔧 初始化:一个容易被跳过但很关键的细节
因果链
💡 PyTorch 的默认初始化对
nn.Linear已经不错,但用 ReLU 时显式指定更稳:nn.init.kaiming_normal_(layer.weight, nonlinearity="relu")
🌈 四、万能近似定理(以及它的误导性)
理论:只要隐藏层够宽,一个隐藏层的神经网络就能逼近任意连续函数。
⚠️ 但这个定理有很强的误导性:
| 定理说的 | 定理没说的 |
|---|---|
| 存在这样的网络 | 怎么找到它(能否用梯度下降训出来) |
| 一层就够 | 需要指数级宽才行 |
| 能拟合训练数据 | 能否泛化到新数据 |
实践结论:深比宽更高效。 同样的参数量,深层网络能表达的函数复杂度远高于浅层—— 因为每一层都在前一层的特征上做组合,是层级抽象(第 12 章 CNN 会看得很清楚)。
🏗️ 五、一个完整 MLP 的样子
import torch.nn as nn
model = nn.Sequential(
nn.Linear(30, 64), # 输入 30 个特征 → 64 个神经元
nn.ReLU(), # ⭐ 非线性
nn.Dropout(0.2), # 正则化(第 10 章)
nn.Linear(64, 32),
nn.ReLU(),
nn.Linear(32, 1), # 输出 1 个数
# 二分类不用加 Sigmoid —— 用 BCEWithLogitsLoss,它内部做了且数值更稳
)
结构怎么定(经验值):
| 决策 | 经验 |
|---|---|
| 几层 | 表格数据 2–4 层就够;再深收益很小 |
| 每层多宽 | 常见 64/128/256,逐层递减 |
| 激活 | ReLU(不确定时的默认) |
| 输出层 | 回归:不加激活;二分类:不加(用 BCEWithLogitsLoss);多分类:不加(用 CrossEntropyLoss) |
⚠️ 表格数据的现实:神经网络在中小规模表格数据上经常打不过 GBDT(第 4 章)。 别默认上神经网络——第 19 章挑战 B 会让你亲手验证这一点。
🔗 和站内其他章的关系
| 相关的地方 | 根因在这 |
|---|---|
| 推荐算法第 8 章的 DeepFM、DIN | 它们的"Deep"部分就是本章的 MLP |
| 全景导论主线 2 · 模型怎样看懂一句话的 FFN | 就是本章的线性层+激活 |
| Kaggle 板块里 NN 常输给 LightGBM | 表格数据上 GBDT 的归纳偏置更合适 |
| 第 3 章逻辑回归 | 就是"零隐层的神经网络" |
✅ 检查点
- 异或实验里,
activation="identity"的 MLP 为什么也是 50%? - 一层神经网络做哪两件事?写出那个式子。
- 用几何直觉说:神经网络到底在做什么?为什么说它是"自动的特征工程"?
- 为什么 ReLU 是深度学习的转折点?Sigmoid 10 层后梯度剩多少?
- ReLU 的代价是什么?三个解法?怎么自检?
- 初始化太小/太大分别会怎样?He 初始化为什么要乘 2?
- 万能近似定理有哪三个误导性?
- 为什么二分类的输出层不加 Sigmoid?
👀 答案
- identity 激活 = 没有非线性,线性套线性还是线性(W₂W₁x 等价于单层),所以退化成逻辑回归,画不出异或的分界。
- ①线性变换 z=Wx+b ②非线性激活 a=f(z)。式子:a⁽ˡ⁾ = f(W⁽ˡ⁾a⁽ˡ⁻¹⁾ + b⁽ˡ⁾)。
- 线性变换与非线性激活逐层学习表示。本节分类 MLP 的末端用线性层输出分类分数;这是常见结构,不是所有网络的固定形式。
- 单看激活导数,10 个 Sigmoid 导数的乘积最多约为 9.5×10⁻⁷;正区间的 ReLU 导数连乘为 1。完整梯度还包括权重等因素,不能把这两个数当成任意网络的最终梯度。
- 神经元持续处在 ReLU 负区间时,该路径局部导数为 0。检查学习率、初始化,或尝试有负区间响应的激活。要跨多个批次和步骤追踪单个神经元;单批次零激活比例超过 50% 不是死亡判据。
- 太小→信号层层衰减深层收不到信息;太大→激活值爆炸。好的初始化让每层激活值方差保持一致。He 乘 2 是因为 ReLU 砍掉了一半(负区间归零),要补回来。
- 只说存在不说怎么找到、一层需要指数级宽、能拟合不代表能泛化。实践上深比宽更高效。
- 用
BCEWithLogitsLoss,它内部合并了 Sigmoid 和交叉熵,数值上更稳定(避免 log(0))。
🛑 可以停在这里
⚡ 走神救援
- 线性层后加非线性,才有机会表示异或这类单条直线分不开的问题。
- 一层的动作:加权求和、加偏置、过激活;矩阵只是把多个单元一起算。
- ReLU 不保证梯度畅通;检查初始化,并跨批次观察是否有持续不激活的单元。
- 能表示不等于能学会,更不等于能泛化。表格任务仍应和树模型基线比较。
下一节 👉 08-反向传播.md