17 向量化逻辑回归的梯度计算(Vectorizing Logistic Regression's Gradient Computation)
一、背景回顾
在上一节中,我们已经学会了如何通过向量化一次性计算整个训练集上的预测值:
对于 $m$ 个训练样本,输入矩阵为:
$$
X = \begin{bmatrix}
| & | & & | \
x^{(1)} & x^{(2)} & \cdots & x^{(m)} \
| & | & & |
\end{bmatrix} \in \mathbb{R}^{n \times m}
$$其中每个 $x^{(i)} \in \mathbb{R}^n$ 是一个样本的特征向量。
参数向量 $w \in \mathbb{R}^n$,偏置标量 $b \in \mathbb{R}$。
线性输出(logits)为:
$$
Z = w^\top X + b \quad \text{(在 NumPy 中自动广播)}
$$注意:这里 $b$ 是标量,但 NumPy 会将其广播到长度为 $m$ 的向量。
激活(预测概率)为:
$$
A = \sigma(Z) = \frac{1}{1 + e^{-Z}} \in \mathbb{R}^{1 \times m}
$$真实标签为:
$$
Y = \begin{bmatrix} y^{(1)} & y^{(2)} & \cdots & y^{(m)} \end{bmatrix} \in \mathbb{R}^{1 \times m}
$$
二、目标:向量化梯度计算
逻辑回归的损失函数是交叉熵损失,对单个样本 $(x^{(i)}, y^{(i)})$ 的梯度为:
$$
\begin{aligned}
dz^{(i)} &= a^{(i)} - y^{(i)} \
dw^{(i)} &= x^{(i)} dz^{(i)} \
db^{(i)} &= dz^{(i)}
\end{aligned}
$$
传统实现需要对 $i = 1$ 到 $m$ 循环累加。现在我们要完全向量化,去掉所有显式 for 循环。
三、关键步骤:定义向量化的中间变量
1. 定义误差向量 $dZ$
将所有样本的 $dz^{(i)}$ 拼成一行向量:
$$
dZ = A - Y = \begin{bmatrix} a^{(1)} - y^{(1)} & a^{(2)} - y^{(2)} & \cdots & a^{(m)} - y^{(m)} \end{bmatrix} \in \mathbb{R}^{1 \times m}
$$
✅ 一行代码实现(NumPy):
dZ = A - Y
2. 向量化计算 $db$
偏置梯度是所有 $dz^{(i)}$ 的平均值:
$$
db = \frac{1}{m} \sum_{i=1}^m dz^{(i)} = \frac{1}{m} \cdot \text{np.sum}(dZ)
$$
✅ 一行代码:
db = (1 / m) * np.sum(dZ)
3. 向量化计算 $dw$
权重梯度为:
$$
dw = \frac{1}{m} \sum_{i=1}^m x^{(i)} dz^{(i)}
$$
注意到 $X \in \mathbb{R}^{n \times m}$,而 $dZ^\top \in \mathbb{R}^{m \times 1}$,因此:
$$
dw = \frac{1}{m} X \cdot dZ^\top \in \mathbb{R}^{n \times 1}
$$
✅ 一行代码:
dw = (1 / m) * np.dot(X, dZ.T)
🔍 为什么成立?
矩阵乘法展开:
$$
X \cdot dZ^\top = x^{(1)} dz^{(1)} + x^{(2)} dz^{(2)} + \cdots + x^{(m)} dz^{(m)}
$$正好是 $dw$ 的累加形式。
四、完整向量化逻辑回归的一次梯度下降迭代
# 前向传播 |
✅ 无任何 for 循环! 仅需矩阵运算即可完成整个训练集的前向+反向传播。
五、注意事项
- 外层循环无法避免:虽然单次梯度下降可完全向量化,但若要运行 $T$ 次迭代(如 1000 次),仍需一个外层 for 循环遍历迭代次数。
- 广播机制(Broadcasting) :在
Z = w.T @ X + b 中,标量b 被自动广播到(1, m)形状,这是 NumPy 的强大特性,将在下一节详细讲解。
六、总结
| 步骤 | 非向量化(低效) | 向量化(高效) |
|---|---|---|
| 前向传播 | 循环计算每个 $a^{(i)}$ | 一次矩阵运算 $A = \sigma(w^\top X + b)$ |
| 梯度 $dZ$ | 循环计算 $a^{(i)} - y^{(i)}$ | 一行:dZ = A - Y |
| 梯度 $dw$ | 循环累加 $x^{(i)} dz^{(i)}$ | 一行:dw = (1/m) * X @ dZ.T |
| 梯度 $db$ | 循环累加 $dz^{(i)}$ | 一行:db = (1/m) * sum(dZ) |
💡 核心思想:用矩阵运算代替 for 循环,大幅提升计算效率,尤其在 GPU 上效果显著。