Skip to content

Commit 45cebd0

Browse files
committed
update post
1 parent 8982485 commit 45cebd0

File tree

1 file changed

+255
-0
lines changed

1 file changed

+255
-0
lines changed
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
---
2+
layout: post
3+
title: "《动手学深度学习(第二版)》学习笔记之 12. 计算性能"
4+
date: 2025-12-25
5+
tags: [AI, notes]
6+
toc: true
7+
comments: true
8+
author: Pianfan
9+
---
10+
11+
在深度学习中,数据集和模型通常都很大,导致计算量也会很大。因此,计算的性能非常重要。本章将集中讨论影响计算性能的主要因素:命令式编程、符号编程、异步计算、自动并行和多 GPU 计算<!-- more -->
12+
13+
## 12.1. 编译器和解释器
14+
15+
### 12.1.1. 命令式编程(imperative programming)
16+
17+
- 按顺序执行语句
18+
19+
- 优点:易于使用和调试,可利用 Python 生态
20+
21+
- 缺点:可能效率低,Python 解释器可能成为瓶颈
22+
23+
### 12.1.2. 符号式编程(symbolic programming)
24+
25+
- 步骤:定义计算流程 → 编译为可执行程序 → 输入数据执行
26+
27+
- 优点:运行效率高、易于移植,可在编译时优化代码
28+
29+
- 缺点:灵活性较低
30+
31+
### 12.1.3. 混合式编程
32+
33+
- 结合两种模式优点:用命令式编程开发调试,转换为符号式提升性能
34+
35+
- PyTorch 通过 torchscript 实现:
36+
37+
- 使用 `torch.jit.script` 转换模型
38+
39+
- 不改变模型计算结果,仅优化执行效率
40+
41+
#### 12.1.3.1. 关键操作
42+
43+
1. 模型定义:用 `nn.Sequential` 构建网络
44+
45+
2. 转换优化:`net = torch.jit.script(net)`
46+
47+
3. 性能提升:转换后通过符号式编程加速计算
48+
49+
4. 序列化:`net.save('模型名')` 保存模型及参数,便于部署
50+
51+
## 12.2. 异步计算
52+
53+
- **异步编程(asynchronous programming)**模型:深度学习框架将 Python 前端控制与后端执行解耦,前端发出的操作排队到后端执行,无需等待操作完成就返回控制权,提高性能
54+
55+
- 并行性:允许同时执行多个计算(如 CPU 与 GPU 操作、不同 GPU 间操作),后端管理线程收集并执行排队任务
56+
57+
### 12.2.1. PyTorch 特性
58+
59+
- 默认行为:GPU 操作是异步的,调用 GPU 函数时操作会排队到特定设备,不立即执行
60+
61+
- 依赖跟踪:后端能跟踪计算图中各步骤的依赖关系,无法并行化相互依赖的操作
62+
63+
### 12.2.2. 性能影响
64+
65+
- 异步优势:减少总计算时间(假设 10000 次计算,时间从约 $10000 (t_1+ t_2 + t_3)$ 减至 $t_1 + 10000 t_2 + t_3$,$t_1, t_2, t_3$ 分别为前端指令时间,后端计算时间,结果返回时间)
66+
67+
- 注意事项:过度填充任务队列可能导致内存消耗过多,建议每个小批量进行同步以保持前后端大致同步
68+
69+
## 12.3. 自动并行
70+
71+
深度学习框架(如 PyTorch)通过构建计算图自动识别任务依赖,并行执行无依赖任务以提升速度
72+
73+
### 12.3.1. 基于 GPU 的并行计算
74+
75+
- 多 GPU 上的无依赖任务可自动并行执行
76+
77+
- 关键操作:
78+
79+
- `torch.cuda.synchronize(device)`:等待指定 GPU 上所有计算完成,用于准确计时
80+
81+
- 预热操作:测量前先执行一次任务,避免缓存影响结果
82+
83+
- 并行执行总时间小于各设备单独执行时间之和
84+
85+
### 12.3.2. 并行计算与通信
86+
87+
- 设备间(CPU 与 GPU、GPU 间)需数据传输(如分布式优化中的梯度聚合)
88+
89+
- 计算与通信可部分并行:计算 `y[i]` 时可传输 `y[i-1]`
90+
91+
- 关键函数:
92+
93+
- `y.to('cpu', non_blocking=True)`:非阻塞式复制,允许计算与传输并行
94+
95+
- 总耗时小于计算与通信单独耗时之和
96+
97+
## 12.4. 硬件
98+
99+
### 12.4.1. 计算机
100+
101+
- 关键组件:
102+
103+
- 处理器(CPU):含 8 个及以上核心,运行操作系统等
104+
105+
- 内存(RAM):存储权重、激活参数、训练数据等
106+
107+
- 以太网连接:速度 1GB/s 到 100GB/s,高端服务器有更高级互连
108+
109+
- 高速扩展总线(PCIe):用于连接 GPU,服务器最多 8 个加速卡,桌面 1-2 个
110+
111+
- 持久性存储设备:如磁盘驱动器、固态驱动器,提供训练数据和中间检查点存储
112+
113+
### 12.4.2. 内存
114+
115+
- CPU 内存:通常为 DDR4 类型,每个模块 20-25Gb/s 带宽,64 位宽总线,2-4 个内存通道,峰值带宽 40GB/s 到 100GB/s
116+
117+
- 内存访问:发送**地址(address)**并设置传输约 100ns,后续传输 0.2ns,应避免随机访问,使用突发模式
118+
119+
- 多物理存储体:可独立读取,随机读操作均匀分布时有效次数可提高,但**突发读取(burst read)**仍更优,数据结构需与 64 位边界对齐
120+
121+
- GPU 内存:带宽要求更高,通过加宽内存总线和使用高性能内存实现,容量通常小于 CPU 内存
122+
123+
### 12.4.3. 存储器
124+
125+
关键特性:**带宽(bandwidth)****延迟(latency)**
126+
127+
- **硬盘驱动器(hard disk drive,HDD)**:含旋转盘片,容量可达 16TB(9 个盘片),成本低,有灾难性故障模式,读取延迟高,IOPs 约 100,带宽 100-200MB/s
128+
129+
- **固态驱动器(solid state drives,SSD)**:用闪存存储,IOPs 10 万到 50 万,带宽 1-3GB/s,以块(256KB 或更大)存储,写入比读取慢,存储单元易磨损,NVMe 类型通过 PCIe 连接,PCIe4.0 上最高 8GB/s
130+
131+
- 云存储:性能可配置,延迟高时可增加 IOPs 配置
132+
133+
### 12.4.4. CPU
134+
135+
组成:处理器核心(执行机器代码)、总线(连接组件)、缓存(提供更高带宽和更低延迟)、向量处理单元(辅助线性代数和卷积运算)
136+
137+
- 微体系结构:前端加载指令并预测路径,解码指令为微指令,执行核心可同时执行多个操作,分支预测单元重要
138+
139+
- 矢量化:通过向量处理单元(ARM 的 NEON、x86 的 AVX2)实现 SIMD 操作,寄存器最长可达 512 位,可组合多对数字
140+
141+
- 缓存:
142+
143+
- 寄存器:非缓存,CPU 可时钟速度访问,数量几十个
144+
145+
- 一级缓存:32-64KB,分数据和指令,访问速度快
146+
147+
- 二级缓存:每个核心 256-512KB,速度慢于一级,需先检查一级缓存
148+
149+
- 三级缓存:多核心共享,可以非常大,常见 4-8MB
150+
151+
缓存未命中代价高,**错误共享(false sharing)**会降低多处理器性能
152+
153+
### 12.4.5. GPU 和其他加速卡
154+
155+
**张量核(tensor core)**:针对小型矩阵运算优化,具体取决于数值精度
156+
157+
局限性:不擅长处理稀疏数据和中断
158+
159+
### 12.4.6. 网络和总线
160+
161+
- PCIe:点到点连接,16 通道 PCIe4.0 上高达 32GB/s,延迟 5μs,通道数量有限制,适合大批量数据传输
162+
163+
- 以太网:连接计算机常用方式,带宽低于 PCIe,低级服务器 1GBit/s,安装成本低、弹性强、距离长
164+
165+
- 交换机:连接多个设备,支持点对点全带宽连接,PCIe 通道也可交换
166+
167+
- NVLink:PCIe 替代品,每条链路高达 300Gbit/s,服务器 GPU(Volta V100)有 6 个链路,消费级(RTX 2080Ti)1 个链路(100Gbit/s)
168+
169+
## 12.5. 多 GPU 训练
170+
171+
单 GPU 计算能力有限,多 GPU 可提升训练速度,支持更大批量和更复杂模型
172+
173+
### 12.5.1. 数据并行
174+
175+
- 原理:将模型复制到多个 GPU,每个 GPU 处理数据的不同子集,计算局部梯度后聚合更新
176+
177+
- $k$ 个 GPU 并行训练过程:
178+
179+
- 在每次训练迭代中,给定随机小批量样本被分成 $k$ 个部分,均匀分配到各 GPU 上
180+
- 每个 GPU 根据分配给它的小批量子集,计算模型参数的损失和梯度
181+
- 将 $k$ 个 GPU 中的局部梯度聚合,获得当前小批量的随机梯度
182+
- 聚合梯度被重新分发到每个 GPU 中
183+
- 每个 GPU 使用这个小批量随机梯度,来更新它所维护的完整模型参数集
184+
185+
## 12.6. 多 GPU 的简洁实现
186+
187+
### 12.6.1. 简单网络
188+
189+
对 ResNet-18 模型稍作修改:更小的卷积核、步长和填充,删除最大汇聚层
190+
191+
- 网络结构:
192+
193+
- 初始卷积层(3x3 卷积、批归一化、ReLU 激活)
194+
- 4 个残差块(分别含 2 个残差单元,通道数 64→128→256→512)
195+
- 全局平均池化层和全连接层
196+
197+
### 12.6.2. 训练
198+
199+
用于训练的代码需要执行几个基本功能才能实现高效并行:
200+
201+
- 在所有设备上初始化网络参数
202+
- 迭代时将小批量数据分配到所有设备
203+
- 跨设备并行计算损失及梯度
204+
- 聚合梯度并更新参数
205+
206+
实现要点:
207+
208+
- 使用 `nn.DataParallel` 实现多 GPU 并行
209+
- 优化器采用 SGD
210+
- 损失函数为交叉熵损失
211+
- 训练过程中记录时间和测试精度
212+
213+
## 12.7. 参数服务器
214+
215+
### 12.7.1. 数据并行训练
216+
217+
数据并行是分布式训练中实现相对简单的方法,在 GPU 显存充足的实际场景(除图深度学习外)值得推荐
218+
219+
核心是梯度聚合后将更新参数广播给所有 GPU,聚合可在特定 GPU、CPU 或分不同部分在不同 GPU 上进行
220+
221+
同步策略影响效率,受硬件总线带宽差异影响,相同参数同步操作时间可能在 15 毫秒到 80 毫秒之间
222+
223+
可在计算部分梯度时同步已准备好的参数以提升性能
224+
225+
### 12.7.2. 环同步(Ring Synchronization)
226+
227+
现代深度学习硬件存在定制网络连接,NVLink 聚合带宽高于 PCIe
228+
229+
最优同步策略是将网络分解为两个环直接同步数据
230+
231+
环同步通过将梯度分为 n 个块,从节点 i 开始同步块 i,使聚合梯度时间不随环大小增加而增长
232+
233+
与其他同步算法本质差异在于同步路径更精细
234+
235+
### 12.7.3. 多机训练
236+
237+
多机训练需处理服务器间低带宽连接及设备同步问题
238+
239+
步骤:读取数据并分配到 GPU 计算梯度→本地 GPU 梯度聚合→梯度发送到本地 CPU→CPU 将梯度发送到中央参数服务器聚合→更新参数并广播回各 CPU→参数发送到本地 GPU→所有 GPU 参数更新完成
240+
241+
单参数服务器会成瓶颈,增加参数服务器数量(每个存储 1/n 参数)可突破瓶颈,实际中机器可同时作为工作节点和服务器
242+
243+
### 12.7.4. 键值存储
244+
245+
为简化分布式多 GPU 训练实现,使用键值存储抽象
246+
247+
梯度计算是**交换归约(commutative reduction)**,运算顺序无关,不同梯度间独立
248+
249+
核心操作:
250+
251+
- push(key,value):工作节点发送梯度值到公共存储并聚合
252+
253+
- pull(key,value):从公共存储获取聚合值
254+
255+
可解耦统计建模人员与系统工程师的关注点

0 commit comments

Comments
 (0)