《动手学深度学习(第二版)》学习笔记之 12. 计算性能

2025-12-25

在深度学习中,数据集和模型通常都很大,导致计算量也会很大。因此,计算的性能非常重要。本章将集中讨论影响计算性能的主要因素:命令式编程、符号编程、异步计算、自动并行和多 GPU 计算

12.1. 编译器和解释器

12.1.1. 命令式编程(imperative programming)

  • 按顺序执行语句

  • 优点:易于使用和调试,可利用 Python 生态

  • 缺点:可能效率低,Python 解释器可能成为瓶颈

12.1.2. 符号式编程(symbolic programming)

  • 步骤:定义计算流程 → 编译为可执行程序 → 输入数据执行

  • 优点:运行效率高、易于移植,可在编译时优化代码

  • 缺点:灵活性较低

12.1.3. 混合式编程

  • 结合两种模式优点:用命令式编程开发调试,转换为符号式提升性能

  • PyTorch 通过 torchscript 实现:

    • 使用 torch.jit.script 转换模型

    • 不改变模型计算结果,仅优化执行效率

12.1.3.1. 关键操作

  1. 模型定义:用 nn.Sequential 构建网络

  2. 转换优化:net = torch.jit.script(net)

  3. 性能提升:转换后通过符号式编程加速计算

  4. 序列化:net.save('模型名') 保存模型及参数,便于部署

12.2. 异步计算

  • 异步编程(asynchronous programming)模型:深度学习框架将 Python 前端控制与后端执行解耦,前端发出的操作排队到后端执行,无需等待操作完成就返回控制权,提高性能

  • 并行性:允许同时执行多个计算(如 CPU 与 GPU 操作、不同 GPU 间操作),后端管理线程收集并执行排队任务

12.2.1. PyTorch 特性

  • 默认行为:GPU 操作是异步的,调用 GPU 函数时操作会排队到特定设备,不立即执行

  • 依赖跟踪:后端能跟踪计算图中各步骤的依赖关系,无法并行化相互依赖的操作

12.2.2. 性能影响

  • 异步优势:减少总计算时间(假设 10000 次计算,时间从约 $10000 (t_1+ t_2 + t_3)$ 减至 $t_1 + 10000 t_2 + t_3$,$t_1, t_2, t_3$ 分别为前端指令时间,后端计算时间,结果返回时间)

  • 注意事项:过度填充任务队列可能导致内存消耗过多,建议每个小批量进行同步以保持前后端大致同步

12.3. 自动并行

深度学习框架(如 PyTorch)通过构建计算图自动识别任务依赖,并行执行无依赖任务以提升速度

12.3.1. 基于 GPU 的并行计算

  • 多 GPU 上的无依赖任务可自动并行执行

  • 关键操作:

    • torch.cuda.synchronize(device):等待指定 GPU 上所有计算完成,用于准确计时

    • 预热操作:测量前先执行一次任务,避免缓存影响结果

  • 并行执行总时间小于各设备单独执行时间之和

12.3.2. 并行计算与通信

  • 设备间(CPU 与 GPU、GPU 间)需数据传输(如分布式优化中的梯度聚合)

  • 计算与通信可部分并行:计算 y[i] 时可传输 y[i-1]

  • 关键函数:

    • y.to('cpu', non_blocking=True):非阻塞式复制,允许计算与传输并行
  • 总耗时小于计算与通信单独耗时之和

12.4. 硬件

12.4.1. 计算机

  • 关键组件:

    • 处理器(CPU):含 8 个及以上核心,运行操作系统等

    • 内存(RAM):存储权重、激活参数、训练数据等

    • 以太网连接:速度 1GB/s 到 100GB/s,高端服务器有更高级互连

    • 高速扩展总线(PCIe):用于连接 GPU,服务器最多 8 个加速卡,桌面 1-2 个

    • 持久性存储设备:如磁盘驱动器、固态驱动器,提供训练数据和中间检查点存储

12.4.2. 内存

  • CPU 内存:通常为 DDR4 类型,每个模块 20-25Gb/s 带宽,64 位宽总线,2-4 个内存通道,峰值带宽 40GB/s 到 100GB/s

  • 内存访问:发送地址(address)并设置传输约 100ns,后续传输 0.2ns,应避免随机访问,使用突发模式

  • 多物理存储体:可独立读取,随机读操作均匀分布时有效次数可提高,但突发读取(burst read)仍更优,数据结构需与 64 位边界对齐

  • GPU 内存:带宽要求更高,通过加宽内存总线和使用高性能内存实现,容量通常小于 CPU 内存

12.4.3. 存储器

关键特性:带宽(bandwidth)延迟(latency)

  • 硬盘驱动器(hard disk drive,HDD):含旋转盘片,容量可达 16TB(9 个盘片),成本低,有灾难性故障模式,读取延迟高,IOPs 约 100,带宽 100-200MB/s

  • 固态驱动器(solid state drives,SSD):用闪存存储,IOPs 10 万到 50 万,带宽 1-3GB/s,以块(256KB 或更大)存储,写入比读取慢,存储单元易磨损,NVMe 类型通过 PCIe 连接,PCIe4.0 上最高 8GB/s

  • 云存储:性能可配置,延迟高时可增加 IOPs 配置

12.4.4. CPU

组成:处理器核心(执行机器代码)、总线(连接组件)、缓存(提供更高带宽和更低延迟)、向量处理单元(辅助线性代数和卷积运算)

  • 微体系结构:前端加载指令并预测路径,解码指令为微指令,执行核心可同时执行多个操作,分支预测单元重要

  • 矢量化:通过向量处理单元(ARM 的 NEON、x86 的 AVX2)实现 SIMD 操作,寄存器最长可达 512 位,可组合多对数字

  • 缓存:

    • 寄存器:非缓存,CPU 可时钟速度访问,数量几十个

    • 一级缓存:32-64KB,分数据和指令,访问速度快

    • 二级缓存:每个核心 256-512KB,速度慢于一级,需先检查一级缓存

    • 三级缓存:多核心共享,可以非常大,常见 4-8MB

    缓存未命中代价高,错误共享(false sharing)会降低多处理器性能

12.4.5. GPU 和其他加速卡

张量核(tensor core):针对小型矩阵运算优化,具体取决于数值精度

局限性:不擅长处理稀疏数据和中断

12.4.6. 网络和总线

  • PCIe:点到点连接,16 通道 PCIe4.0 上高达 32GB/s,延迟 5μs,通道数量有限制,适合大批量数据传输

  • 以太网:连接计算机常用方式,带宽低于 PCIe,低级服务器 1GBit/s,安装成本低、弹性强、距离长

  • 交换机:连接多个设备,支持点对点全带宽连接,PCIe 通道也可交换

  • NVLink:PCIe 替代品,每条链路高达 300Gbit/s,服务器 GPU(Volta V100)有 6 个链路,消费级(RTX 2080Ti)1 个链路(100Gbit/s)

12.5. 多 GPU 训练

单 GPU 计算能力有限,多 GPU 可提升训练速度,支持更大批量和更复杂模型

12.5.1. 数据并行

  • 原理:将模型复制到多个 GPU,每个 GPU 处理数据的不同子集,计算局部梯度后聚合更新

  • $k$ 个 GPU 并行训练过程:

    • 在每次训练迭代中,给定随机小批量样本被分成 $k$ 个部分,均匀分配到各 GPU 上
    • 每个 GPU 根据分配给它的小批量子集,计算模型参数的损失和梯度
    • 将 $k$ 个 GPU 中的局部梯度聚合,获得当前小批量的随机梯度
    • 聚合梯度被重新分发到每个 GPU 中
    • 每个 GPU 使用这个小批量随机梯度,来更新它所维护的完整模型参数集

12.6. 多 GPU 的简洁实现

12.6.1. 简单网络

对 ResNet-18 模型稍作修改:更小的卷积核、步长和填充,删除最大汇聚层

  • 网络结构:

    • 初始卷积层(3x3 卷积、批归一化、ReLU 激活)
    • 4 个残差块(分别含 2 个残差单元,通道数 64→128→256→512)
    • 全局平均池化层和全连接层

12.6.2. 训练

用于训练的代码需要执行几个基本功能才能实现高效并行:

  • 在所有设备上初始化网络参数
  • 迭代时将小批量数据分配到所有设备
  • 跨设备并行计算损失及梯度
  • 聚合梯度并更新参数

实现要点:

  • 使用 nn.DataParallel 实现多 GPU 并行
  • 优化器采用 SGD
  • 损失函数为交叉熵损失
  • 训练过程中记录时间和测试精度

12.7. 参数服务器

12.7.1. 数据并行训练

数据并行是分布式训练中实现相对简单的方法,在 GPU 显存充足的实际场景(除图深度学习外)值得推荐

核心是梯度聚合后将更新参数广播给所有 GPU,聚合可在特定 GPU、CPU 或分不同部分在不同 GPU 上进行

同步策略影响效率,受硬件总线带宽差异影响,相同参数同步操作时间可能在 15 毫秒到 80 毫秒之间

可在计算部分梯度时同步已准备好的参数以提升性能

12.7.2. 环同步(Ring Synchronization)

现代深度学习硬件存在定制网络连接,NVLink 聚合带宽高于 PCIe

最优同步策略是将网络分解为两个环直接同步数据

环同步通过将梯度分为 n 个块,从节点 i 开始同步块 i,使聚合梯度时间不随环大小增加而增长

与其他同步算法本质差异在于同步路径更精细

12.7.3. 多机训练

多机训练需处理服务器间低带宽连接及设备同步问题

步骤:读取数据并分配到 GPU 计算梯度→本地 GPU 梯度聚合→梯度发送到本地 CPU→CPU 将梯度发送到中央参数服务器聚合→更新参数并广播回各 CPU→参数发送到本地 GPU→所有 GPU 参数更新完成

单参数服务器会成瓶颈,增加参数服务器数量(每个存储 1/n 参数)可突破瓶颈,实际中机器可同时作为工作节点和服务器

12.7.4. 键值存储

为简化分布式多 GPU 训练实现,使用键值存储抽象

梯度计算是交换归约(commutative reduction),运算顺序无关,不同梯度间独立

核心操作:

  • push(key,value):工作节点发送梯度值到公共存储并聚合

  • pull(key,value):从公共存储获取聚合值

可解耦统计建模人员与系统工程师的关注点