14 向量化(Vectorization)
1. 什么是向量化?
向量化 是指避免在代码中使用显式的 for 循环,转而使用高度优化的矩阵/向量运算(如 NumPy 中的内置函数),从而大幅提升计算效率。
在深度学习中,我们经常处理大规模数据集(例如百万级特征或样本)。如果使用非向量化实现,程序运行会极其缓慢;而向量化能充分利用 CPU/GPU 的并行计算能力(SIMD 指令),使代码快数百倍甚至上千倍。
2. 为什么需要向量化?—— 以逻辑回归为例
在逻辑回归中,我们需要计算:
$$
z = \mathbf{w}^\top \mathbf{x} + b
$$
其中:
- $\mathbf{w} \in \mathbb{R}^{n_x}$ 是权重向量,
- $\mathbf{x} \in \mathbb{R}^{n_x}$ 是输入特征向量,
- $b$ 是偏置项,
- $n_x$ 是特征数量(可能非常大)。
❌ 非向量化实现(显式 for 循环):
z = 0 |
- 时间复杂度:$O(n_x)$
- 实际运行慢,无法利用硬件并行性。
✅ 向量化实现(使用 NumPy):
z = np.dot(w, x) + b |
- 一行代码完成相同计算。
- 底层由 C/Fortran 优化,自动并行化。
- 速度提升可达 300 倍以上(见下文实验)。
3. 实验演示:向量化 vs 非向量化
实验设置:
- 创建两个长度为 $10^6$ 的随机向量 $\mathbf{a}, \mathbf{b} \in \mathbb{R}^{1,000,000}$
- 计算点积:$\mathbf{a}^\top \mathbf{b} = \sum_{i=1}^{10^6} a_i b_i$
✅ 向量化版本(NumPy):
c = np.dot(a, b) |
- 耗时:约 1.5 毫秒
❌ 非向量化版本(for 循环):
c = 0 |
- 耗时:约 480 毫秒
- 慢了约 300 倍!
💡 结果验证:两种方法计算出的
c 值完全一致(如 250699.123…),说明向量化不仅快,而且数值正确。
4. 为什么向量化更快?
现代 CPU 和 GPU 都支持 SIMD(Single Instruction, Multiple Data) 指令。
- 即:一条指令同时处理多个数据。
NumPy 等库底层使用高度优化的 C/C++/BLAS 库(如 OpenBLAS、Intel MKL),能自动利用 SIMD 并行。
显式 for 循环由 Python 解释器逐行执行,解释开销大 + 无并行 → 极慢。
⚠️ 注意:即使没有 GPU,仅在 CPU 上,向量化也能带来巨大加速!
5. 核心原则(Rule of Thumb)
“尽可能避免显式 for 循环!”
在深度学习中,以下操作都应向量化:
- 矩阵乘法(如 $\mathbf{W} \mathbf{X}$)
- 激活函数(如
np.sigmoid(Z)作用于整个矩阵) - 损失函数计算
- 梯度更新
6. 后续内容预告
本节是向量化的入门。接下来课程将:
展示如何向量化整个逻辑回归模型(包括前向传播、损失计算、反向传播)
扩展到多样本批量(batch)处理,即对 $m$ 个样本同时计算:
$$
\mathbf{Z} = \mathbf{W}^\top \mathbf{X} + b
$$其中 $\mathbf{X} \in \mathbb{R}^{n_x \times m}$ 是所有样本组成的矩阵。
✅ 总结要点
| 项目 | 非向量化 | 向量化 |
|---|---|---|
| 代码风格 | 显式 for 循环 | 使用 np.dot, np.sum 等 |
| 速度 | 慢(毫秒 → 秒级) | 快(微秒 → 毫秒级) |
| 可读性 | 冗长 | 简洁、数学直观 |
| 并行性 | 无 | 自动利用 CPU/GPU 并行 |
| 推荐程度 | ❌ 避免 | ✅ 必须掌握 |
掌握向量化是高效深度学习编程的基石。它不仅让代码跑得更快,还能让你更专注于算法本身,而非低效的循环细节。