第1章:深度学习与计算机视觉数学基础
在深度学习驱动的计算机视觉革命中,数学不仅是理解模型行为的钥匙,更是设计高效算法的基石。目标检测与分割任务,因其对空间位置和像素级精度的苛刻要求,尤为依赖于坚实的数学基础。许多工程师与研究者往往满足于调用高级框架的API,却对背后微积分、概率与优化的精妙设计一知半解,这导致面对模型收敛失败、损失震荡或精度瓶颈时束手无策。本章将系统梳理支撑目标检测与分割先进技术的核心数学工具,从向量微积分到概率推断,从优化理论到张量操作,通过严格的公式推导与底层NumPy实现,为读者构建一个贯穿理论与实践的知识框架。我们不仅会解释“是什么”,更将深入“为什么”——例如,为何交叉熵损失比均方误差更适合分类?为何IoU Loss能直接优化分割任务的核心指标?Dropout的随机丢弃为何从贝叶斯推断视角看是一种正则化?这些问题的答案,深植于数学原理之中。掌握这些基础,将使你不仅能熟练使用现有模型,更能具备批判性思维与创新能力,在未来的技术演进中立于不败之地。
向量与矩阵微积分:神经网络的微分语言
深度学习模型本质上是可微函数的复合。从单层感知机到百层残差网络,其前向传播可视为一系列向量与矩阵运算的流水线,而训练过程则依赖于反向传播算法对这些运算求导。因此,向量与矩阵微积分是理解神经网络梯度的数学语言。
标量、向量与矩阵的导数
在标准微积分中,我们处理标量函数对单变量的导数,如 $f(x) = x^2$,其导数为 $\frac{df}{dx} = 2x$。然而,神经网络的参数(权重 $W$、偏置 $b$)通常是向量或矩阵,损失函数 $L$ 是这些高维变量的标量函数。因此,我们需要定义导数在更高维度上的推广。
向量对标量求导:若 $\mathbf{x} \in \mathbb{R}^n$ 是向量,$f: \mathbb{R}^n \to \mathbb{R}$ 是标量函数,则 $f$ 对 $\mathbf{x}$ 的导数是一个行向量(或梯度向量),记为 $\nabla_{\mathbf{x}} f$ 或 $\frac{\partial f}{\partial \mathbf{x}}$,其第 $i$ 个元素为 $\frac{\partial f}{\partial x_i}$。例如,设 $f(\mathbf{x}) = \mathbf{a}^T \mathbf{x} = \sum_{i=1}^n a_i x_i$,其中 $\mathbf{a}$ 是常向量,则 $\frac{\partial f}{\partial \mathbf{x}} = \mathbf{a}^T$。在实现中,我们通常使用列向量,因此梯度常表示为列向量 $\nabla_{\mathbf{x}} f = \mathbf{a}$(此时需注意转置约定,不同文献可能不同,但核心是方向一致性)。
标量对向量求导:若 $f: \mathbb{R}^n \to \mathbb{R}$,则 $\frac{\partial f}{\partial \mathbf{x}}$ 是行向量。但有时我们遇到向量函数对向量求导,如 $\mathbf{y} = f(\mathbf{x})$,其中 $\mathbf{y} \in \mathbb{R}^m$,$\mathbf{x} \in \mathbb{R}^n$,则导数是一个 $m \times n$ 的雅可比矩阵 $J$,其 $(i,j)$ 元素为 $\frac{\partial y_i}{\partial x_j}$。在神经网络中,反向传播时,我们常计算损失 $L$(标量)对某层输入 $\mathbf{x}$ 的梯度(行向量),以及对该层参数 $W$(矩阵)的梯度(与 $W$ 同形的矩阵)。
矩阵求导:当变量是矩阵时,导数可视为一个四维张量,但实践中我们通常利用矩阵运算的已知导数规则,避免显式处理高阶张量。关键规则包括:
- 设 $Z = W X + b$,其中 $W \in \mathbb{R}^{m \times n}$,$X \in \mathbb{R}^{n \times p}$,$b \in \mathbb{R}^{m}$(广播),则 $\frac{\partial \text{Tr}(Z)}{\partial W} = X^T$,$\frac{\partial \text{Tr}(Z)}{\partial X} = W^T$,其中 $\text{Tr}$ 表示迹。
- 对于二次型 $f(W) = \text{Tr}(W A W^T B)$,其导数为 $B W A^T + B^T W A$(若 $A,B$ 对称则简化)。
这些规则可通过矩阵微积分中的“迹技巧”统一推导,其核心是将标量损失 $L$ 与矩阵参数 $W$ 的导数 $\frac{\partial L}{\partial W}$ 表示为 $X$ 和上游梯度 $\frac{\partial L}{\partial Z}$ 的乘积。
链式法则与反向传播
反向传播的本质是链式法则在多层网络中的递归应用。考虑一个简单网络:输入 $\mathbf{x}$,经线性变换 $Z = W \mathbf{x} + b$,再经激活函数 $A = \sigma(Z)$,最终损失为 $L(A)$。我们的目标是计算 $\frac{\partial L}{\partial W}$ 和 $\frac{\partial L}{\partial b}$。
根据链式法则: $$ \frac{\partial L}{\partial W} = \frac{\partial L}{\partial A} \frac{\partial A}{\partial Z} \frac{\partial Z}{\partial W} $$ 其中:
- $\frac{\partial Z}{\partial W}$ 是一个三维张量,但利用矩阵规则,若将 $Z$ 视为 $W$ 的线性函数,则 $\frac{\partial Z}{\partial W}$ 在实践中的效果等同于将上游梯度乘以 $\mathbf{x}^T$。具体地,若上游梯度 $\delta = \frac{\partial L}{\partial Z}$(行向量,与 $Z$ 同形),则 $\frac{\partial L}{\partial W} = \delta^T \mathbf{x}^T$?不,需仔细:设 $Z = W \mathbf{x} + b$,则 $\frac{\partial Z}{\partial W_{ij}} = $ 仅在 $i$ 行有 $\mathbf{x}^T$。实际上,更清晰的推导是:$Z$ 的每个元素 $Z_i = \sum_j W_{ij} x_j + b_i$,因此 $\frac{\partial Z_i}{\partial W_{ij}} = x_j$。于是,$\frac{\partial L}{\partial W_{ij}} = \sum_k \frac{\partial L}{\partial Z_k} \frac{\partial Z_k}{\partial W_{ij}} = \frac{\partial L}{\partial Z_i} x_j$(因为 $\frac{\partial Z_k}{\partial W_{ij}} = \delta_{ik} x_j$)。这表明 $\frac{\partial L}{\partial W}$ 的第 $i$ 行是 $\frac{\partial L}{\partial Z_i} \mathbf{x}^T$。写成矩阵形式:$\frac{\partial L}{\partial W} = \left( \frac{\partial L}{\partial Z} \right)^T \mathbf{x}^T$?注意维度:$\frac{\partial L}{\partial Z}$ 是行向量 $1 \times m$,$\mathbf{x}$ 是列向量 $n \times 1$,则外积为 $m \times n$ 矩阵,正是 $\frac{\partial L}{\partial W}$ 的维度。因此,$\frac{\partial L}{\partial W} = \left( \frac{\partial L}{\partial Z} \right)^T \mathbf{x}^T$。但通常我们使用列向量梯度,若令 $\delta = \left( \frac{\partial L}{\partial Z} \right)^T$(列向量 $m \times 1$),则 $\frac{\partial L}{\partial W} = \delta \mathbf{x}^T$。
类似地,$\frac{\partial L}{\partial \mathbf{x}} = W^T \delta$(因为 $\frac{\partial Z}{\partial \mathbf{x}} = W^T$?实际上:$\frac{\partial L}{\partial x_j} = \sum_i \frac{\partial L}{\partial Z_i} \frac{\partial Z_i}{\partial x_j} = \sum_i \delta_i W_{ij}$,即 $\frac{\partial L}{\partial \mathbf{x}} = W^T \delta$,其中 $\delta$ 是列向量)。
激活函数 $\sigma$ 的导数作用于逐元素:$\frac{\partial A}{\partial Z}$ 是对角矩阵,其对角线为 $\sigma'(Z)$。因此,$\delta_{\text{prev}} = \frac{\partial L}{\partial Z} = \frac{\partial L}{\partial A} \odot \sigma'(Z)$,其中 $\odot$ 表示逐元素乘法(哈达玛积)。这就是反向传播中“误差项”的传递。
NumPy实现示例:手动反向传播
为了巩固理解,我们使用NumPy实现一个包含单隐藏层的前向与反向传播,不依赖自动微分。这有助于揭示梯度计算的内在机制。
```python import numpy as np
def sigmoid(x): return 1 / (1 + np.exp(-x))
def sigmoid_derivative(x):
x 是 sigmoid 的输出 A
return x * (1 - x)
假设一个简单网络:输入维度 n=4,隐藏层 h=5,输出层 o=3
np.random.seed(42) W1 = np.random.randn(5, 4) * 0.01 # 权重矩阵,通常初始化较小 b1 = np.zeros((5, 1)) W2 = np.random.randn(3, 5) * 0.01 b2 = np.zeros((3, 1))
前向传播
X = np.random.randn(4, 1) # 单个样本,列向量 Z1 = W1 @ X + b1 # 线性变换,@ 表示矩阵乘法 A1 = sigmoid(Z1) # 激活 Z2 = W2 @ A1 + b2 A2 = sigmoid(Z2) # 输出层激活(假设二分类或回归用sigmoid,多分类常用softmax,此处简化)
假设真实标签 y (one-hot, 3维)
y = np.array([[0], [1], [0]]) # 列向量
计算损失:均方误差 (MSE) 作为示例
loss = np.mean((A2 - y) ** 2)
反向传播
输出层梯度:dL/dA2
dA2 = 2 * (A2 - y) / y.shape[0] # 均方误差对A2的导数,除以样本数(此处batch=1)
输出层激活导数:dA2/dZ2 = A2 * (1 - A2) 逐元素
dZ2 = dA2 * sigmoid_derivative(A2)
计算 W2 和 b2 的梯度
dW2 = dZ2 @ A1.T # (3,1) @ (1,5) -> (3,5) db2 = dZ2 # (3,1),因为 dZ2/db2 = I
传播到隐藏层
dA1 = W2.T @ dZ2 # (5,3) @ (3,1) -> (5,1)
隐藏层激活导数
dZ1 = dA1 * sigmoid_derivative(A1)
计算 W1 和 b1 的梯度
dW1 = dZ1 @ X.T # (5,1) @ (1,4) -> (5,4) db1 = dZ1 # (5,1)
现在 dW1, db1, dW2, db2 可用于梯度下降更新参数
```
此代码展示了核心链式法则:每一步梯度都是上游梯度与局部导数的逐元素或矩阵乘积。注意维度对齐:矩阵乘法中,左乘上游梯度(列向量)相当于对行求和,这与我们之前的推导一致(若使用行向量梯度,则右乘)。实际框架中,通常将上游梯度表示为与当前层输出同形的张量,然后通过局部 Jacobian 传播。此手动实现揭示了自动微分(如PyTorch的`autograd`)背后的数学本质:它构建计算图,并在反向遍历时应用链式法则。
概率论基础:从贝叶斯到最大似然
深度学习模型常被解释为概率模型。例如,分类网络输出可视为类别的概率分布,损失函数如交叉熵直接源于概率论。理解贝叶斯定理与最大似然估计(MLE)对于把握模型训练的本质至关重要。
贝叶斯定理与模型不确定性
贝叶斯定理表述为: $$ P(\theta \mid D) = \frac{P(D \mid \theta) P(\theta)}{P(D)} $$ 其中 $\theta$ 是模型参数,$D$ 是观测数据。$P(\theta)$ 是先验分布,表示我们对参数的初始信念;$P(D \mid \theta)$ 是似然,表示在参数 $\theta$ 下观测到数据 $D$ 的概率;$P(\theta \mid D)$ 是后验分布,表示结合数据后对参数的更新信念;$P(D)$ 是证据,用于归一化。
在神经网络训练中,我们通常寻找最优参数 $\theta^*$,这等价于最大化后验(MAP)或仅最大化似然(MLE,当先验均匀时)。然而,贝叶斯视角提供了更丰富的解释:Dropout 可视为对模型参数进行贝叶斯近似推断。Gal和Ghahramani (2016) 指出,在训练时随机丢弃神经元,等价于对权重进行变分推断,近似后验分布。测试时使用完整网络但缩放权重(MC Dropout)或多次采样预测并求平均,可得到模型不确定性的估计。这对于安全关键应用(如自动驾驶)至关重要,因为它能识别模型“不知道”的样本。
最大似然估计:训练的目标函数
在监督学习中,我们有一组独立同分布样本 $\{ (x_i, y_i) \}_{i=1}^N$。假设模型 $f_\theta(x)$ 输出概率分布 $p(y \mid x; \theta)$。MLE 通过最大化对数似然来估计 $\theta$: $$ \theta_{\text{MLE}} = \arg\max_\theta \sum_{i=1}^N \log p(y_i \mid x_i; \theta) $$ 这等价于最小化负对数似然(NLL),即许多损失函数的来源。
例如,对于多分类,使用 softmax 输出 $p(y=c \mid x) = \frac{e^{z_c}}{\sum_{k} e^{z_k}}$,其中 $z$ 是 logits。单个样本的交叉熵损失为: $$ \text{CE} = -\log p(y \mid x) = -\sum_{c=1}^C y_c \log p(y=c \mid x) $$ 其中 $y$ 是 one-hot 向量。这正是 MLE 的负对数似然。对于二分类,使用 sigmoid,交叉熵为 $-[y \log \sigma(z) + (1-y) \log (1-\sigma(z))]$。
对于分割任务,输出是像素级分类,损失是对所有像素的交叉熵求和。但交叉熵仅优化类别概率,不直接优化空间重叠指标如 IoU。因此,研究者提出了 IoU Loss 或 Dice Loss,它们源于对区域重叠的似然解释或直接优化目标指标。
示例:逻辑回归的 MLE 推导
考虑二分类逻辑回归:$p(y=1 \mid x) = \sigma(w^T x + b)$,其中 $\sigma$ 是 sigmoid。似然为: $$ P(y \mid x; w,b) = \sigma(w^T x + b)^y (1 - \sigma(w^T x + b))^{1-y} $$ 对数似然: $$ \log P = y \log \sigma(z) + (1-y) \log (1-\sigma(z)), \quad z = w^T x + b $$ 求导: $$ \frac{\partial \log P}{\partial w} = \left( \frac{y}{\sigma(z)} - \frac{1-y}{1-\sigma(z)} \right) \sigma'(z) x = (y - \sigma(z)) x $$ 因为 $\sigma'(z) = \sigma(z)(1-\sigma(z))$,代入化简得。这解释了为何逻辑回归的梯度是预测误差乘以输入。在神经网络中,这一形式推广为 $\delta = (A - Y)$(对于均方误差输出层和线性激活),但交叉熵与 softmax 组合时,$\delta = A - Y$ 也成立(因为 softmax 交叉熵的梯度是预测值减真实值),这是一个优雅的结果,使得深层网络梯度更稳定。
代码示例:MLE 与贝叶斯线性回归
我们实现一个简单的贝叶斯线性回归,使用共轭先验(正态-正态),以展示后验计算。虽然深度学习通常不显式计算后验,但此例有助于理解贝叶斯更新。
```python import numpy as np import matplotlib.pyplot as plt
生成数据:y = 2.5 * x + 1.0 + 噪声
np.random.seed(0) X = np.linspace(0, 1, 20) y = 2.5 * X + 1.0 + np.random.normal(0, 0.1, size=X.shape)
添加偏置项:设计矩阵 Phi = [x, 1]
Phi = np.vstack([X, np.ones_like(X)]).T # (20,2)