深度学习入门站 · 理解深度学习
首页 › 第 4 章

深度神经网络

为什么要堆很多层?ReLU 激活函数和深度网络的直觉。
图 4-1:深度神经网络的层级堆叠与逐层抽象
图 4-1:深度神经网络的层级堆叠与逐层抽象

上一章我们认识了只有一个隐藏层的浅层网络——它已经能拟合很多函数了。可现实中的深度学习模型动辄几十层、上百层,大家为什么非要往"深"里堆?这一章我们就来揭开"深"的秘密:为什么层数多一点,表达能力就能暴涨;为什么小小的 ReLU 激活函数能"拯救"整个深度学习;以及"宽"和"深"到底该怎么选。学完这一章,你会明白"深的就是好的"背后真正的数学原理。

层层递进:深网络到底在"学"什么?

先抛开公式,想想人是怎么认出一张脸的。眼睛不会直接看到"脸",而是先看到横线、竖线、轮廓这些简单特征;然后把这些线条拼成鼻子、眼睛等局部部件;最后才组合出"一张脸"这个复杂概念。深层网络做的就是同一件事:低层学简单特征,高层学复杂特征,一层一层往上"组装"。

🏭
生活类比
深网络就像汽车流水线工厂:第一道工序只负责拧螺丝(简单特征),第二道工序把零件装成发动机(部件),最后总装成整车(复杂概念)。如果让一个工人从头到尾造一辆车,他必须样样精通,工厂效率极低;分层之后,每一层都只需要站在前一层的肩膀上,把已经造好的东西再组合一次。深网络的价值首先在于:它天然匹配"由简单到复杂"的认知结构。

你可能要问:浅层网络不也能拟合任何函数吗?没错,通用逼近定理保证:只要隐藏单元足够多,单层网络也能逼近任意连续函数。但"能"和"划算"是两回事——有些函数需要指数级多的单元才装得下,现实中根本训练不动。深层网络的价值,正是用更少的参数做到同样的事。下面来看它到底怎么做到的。

深度的秘密:折叠与复制

把两个浅层网络串起来——第一个网络的输出 $y$ 变成第二个网络的输入——会发生什么?回顾上一章,一个隐藏层网络做的事是:先对输入 $x$ 做线性变换,再过激活函数 $a[\cdot]$,最后把结果线性组合成输出:

$$h_j = a[\theta_{j0} + \theta_{j1} x], \qquad y = \phi_0 + \sum_j \phi_j h_j$$

这个式子的意思是:每个隐藏单元 $h_j$ 都是"一条直线加一个拐点",输出 $y$ 再把它们拼起来。现在把第二个同样的网络接在后面:

$$h'_j = a[\theta'_{j0} + \theta'_{j1} y], \qquad y' = \phi'_0 + \sum_j \phi'_j h'_j$$

如果激活函数是 ReLU,每个网络算出的都是分段线性函数。关键来了:假设第一个网络把输入 $x \in [-1, 1]$ 分成了 3 段(3 个线性区域),第二个网络也把 $y$ 分成 3 段。第一个网络会把 3 段不同的输入"折"到同一个输出区间,第二个网络在折好的区间上再切 3 段——结果不是 $3 + 3$,而是 3 × 3 = 9 个线性区域!再串一层就是 27 个。每多一层,区域数就成倍相乘地增长。

✂️
生活类比
这就像折纸剪窗花:一张纸对折一次,剪一刀得到 2 个洞;对折两次剪一刀,得到 4 个洞;对折 $K$ 次,得到 $2^K$ 个洞。深层网络的每一层都是一次"折叠 + 剪切":先折叠输入空间,再用 ReLU"剪"出新拐点。折的次数越多,最后剪出的独立区域就越多——这就是"深"的魔法。

宽度 vs 深度:同样的预算,谁更强?

网络的规模由两个"旋钮"决定,它们叫超参数(训练之前就要定好的量):宽度——每层有多少个隐藏单元;深度——有多少个隐藏层。现在算一笔账:同样是 1 个输入、1 个输出,每层 $D$ 个隐藏单元,浅层(1 层)和深层($K$ 层)各能创造多少个线性区域、要花多少个参数?

$$\text{浅层网络:区域} \le D + 1, \quad \text{参数} = 3D + 1$$ $$\text{深层网络(}K\text{ 层):区域} \le (D+1)^K, \quad \text{参数} = 3D + 1 + (K-1)D(D+1)$$

第一个式子是说:一层网络里 $D$ 个隐藏单元顶多切出 $D + 1$ 段,代价是 $3D + 1$ 个参数。第二个式子是说:$K$ 层网络每层都把已有的每一段再切开,区域数变成 $(D+1)^K$,而参数只是随层数线性增加。代入具体数字感受一下:$K = 5$ 层、每层 $D = 10$ 个单元,参数 $3 \times 10 + 1 + 4 \times 10 \times 11 = 471$ 个,却能创造 $11^5 = 161{,}051$ 个线性区域。同样的 471 个参数如果堆在单层(约 157 个单元),最多只有 158 个区域——差了整整一千倍!

💡
核心要点:深度的价值在于——用同样的参数预算,换来指数级多的线性区域。每一层 ReLU 的"剪切"都把上一层的每个区域再切开,区域数随层数相乘增长,参数却只随层数相加增长。这就是"深而窄"能打败"浅而宽"的数学根源,也是"深度效率"一词的由来:有些函数,浅层网络需要指数级多的隐藏单元才能逼近,深层网络用少得多的参数就能做到。

不过也要泼盆冷水:区域多不等于一定好。深层网络创造的海量区域之间存在着复杂的依赖和对称性,只有当真实世界的函数恰好有类似的结构(比如确实由简单函数组合而成)时,深度才真正占便宜;而且层数过深会让训练变难。所以"越深越好"是有条件的。

为什么 ReLU 那么重要?

前面反复提到 ReLU,它到底是什么?ReLU(Rectified Linear Unit,线性整流单元)就是一个"把负数清零"的函数:

$$a[z] = \max(0, z) = \begin{cases} z & z > 0 \\ 0 & z \le 0 \end{cases}$$

意思是:输入大于 0 就原样输出,小于等于 0 就输出 0。就这么一个简单函数,却是现代深度学习的功臣之一,因为它解决了一个致命问题——梯度消失。

早期网络爱用 sigmoid 激活函数,但它的两端会"饱和":输入很大或很小时,曲线变平,导数趋近于 0。确切地说,sigmoid 的导数最大也只有 0.25:

$$\sigma'(z) = \sigma(z)\,(1 - \sigma(z)) \le 0.25$$

这个式子的意思是:sigmoid 的坡度最陡时也只有 0.25。训练时梯度要从输出层一层层往回传(反向传播),每过一层就要乘一次导数。乘 10 次之后 $0.25^{10} \approx 10^{-6}$,梯度被"吃"得几乎为零,前面的层根本学不动,这就是梯度消失(vanishing gradient)。

而 ReLU 的妙处在于:$z > 0$ 时它的导数恒为 1,梯度连乘时不再被层层缩小,深层网络的前面几层也能好好更新;$z \le 0$ 时输出恒为 0,等于把没用的部分"剪掉",还顺带创造了新拐点。正因如此,2012 年 AlexNet 在图像分类上取得划时代突破时,ReLU 与大数据、强算力、随机梯度下降并称四大功臣。一句话概括 ReLU 的三个好处:计算快(一次比较)、缓解梯度消失(导数恒为 1)、配合深度创造海量线性区域(剪切出新拐点)。

动手:用 PyTorch 搭一个深层网络

理论讲完,动手验证一下。下面用 PyTorch 定义一个 3 层全连接网络(2 个隐藏层 + 1 个输出层)。代码里的 nn.Linear 就是权重矩阵 $\boldsymbol{\Omega}$ 和偏置 $\boldsymbol{\beta}$,torch.relu 就是那个"剪切"函数:

import torch
import torch.nn as nn

class DeepNet(nn.Module):
    def __init__(self):
        super().__init__()
        # 宽度 = 每层隐藏单元数,深度 = 隐藏层层数
        self.layer1 = nn.Linear(8, 16)   # 第一层:8 个输入 → 16 个隐藏单元
        self.layer2 = nn.Linear(16, 8)   # 第二层:16 → 8
        self.layer3 = nn.Linear(8, 1)    # 输出层:8 → 1

    def forward(self, x):
        x = torch.relu(self.layer1(x))   # 线性变换 + ReLU 剪切
        x = torch.relu(self.layer2(x))
        return self.layer3(x)

net = DeepNet()
x = torch.randn(4, 8)      # 一批 4 个样本,每个 8 维
print(net(x).shape)        # 输出形状: [4, 1]

把 self.layer2 删掉,这个网络就退化成了浅层网络——试试看同样的数据,深浅两个网络能拟合的函数复杂度差多少。理解了这一章,你就看懂了后面所有现代网络架构(卷积、Transformer)里"层"的角色。

🎯 小测验

1. 为什么同样数量的参数,深层网络能表达比浅层网络复杂得多的函数?
2. 相比 sigmoid,ReLU 能缓解梯度消失,主要原因是?
3. 深度学习里所说的"网络宽度"指的是什么?