1. 背景
近几年,随着'大模型'概念的提出,深度学习模型越来越大,如何训练这些大模型成为一个亟待解决的工程问题。最初的视觉模型只有几百兆的参数量,而现在的语言模型中,动则百亿、千亿的参数量,甚至万亿的大模型也是见怪不怪。如此巨大的参数量将会消耗巨大的存储空间。如下表所示为当前大模型的参数量(以 Float32 计算)以及对应的存储空间。

而当前最好的 NVIDIA GPU 显卡也只有 40G 的显存容量,显然将大模型塞进一张显卡是不现实的。本质上,所有大模型的训练都使用了分布式的方式。当前分布式训练中,常用的有数据并行、模型并行和流水线并行,从计算效率上来说,数据并行要远远优于模型并行和流水线并行。但是数据并行对显存的占用是最高的,因为它需要将整个网络都运行在一张 GPU 上面。而在模型训练过程中,除了参数以外,还有很多地方需要占用存储空间,这就使得训练大模型时候的显存消耗进一步提升。因此你是否好奇,如何训练如此庞大的深度学习模型呢?
2. 深度学习中的显存占用
在探讨如何进行大规模训练之前,我们先来详细看看网络中的显存占用。通常在深度学习训练过程中,涉及到的显存占用包括:网络的参数、梯度、激活值、激活值的梯度、优化器的状态信息,如果使用了混合精度训练,那么还有备份参数 (master_weight) 等。这里需要指出的是,激活值的梯度在古老的 Caffe 框架中是没有做过优化的,其占用空间和激活值相同。但是在 TensorFlow、PyTorch 等框架中,已经做了很好的优化,因此激活值的梯度实际上并没有占据很大的显存空间。另外,可能很多朋友对前面几种类型的显存占用(网络的参数、梯度、激活值、激活值的梯度)比较清楚,但是对于优化器的状态信息以及混合精度训练的备份参数 (master_weight) 不是很清楚,这里稍加说明。
2.1 SGD 优化器
在简单的 SGD 优化器中,更新参数使用如下公式:

2.2 Moment SGD 优化器
但是通常我们不会直接使用 SGD 来更新参数,而会对梯度进行滑动平均后,再进行更新,即使用 Moment SGD 优化器,其计算公式如下:

由于计算需要用到,因此需要一直保存在显存中。就是优化器的状态信息,其大小和梯度一致,因此和参数大小一致。例如参数规模是 100 亿,那么优化器缓存信息也是 100 亿的规模。
2.3 ADAM 优化器
在很多时候,我们也会使用 ADAM 优化器进行参数更新,而 ADAM 会用到梯度的一阶矩估计和二阶矩估计,公式如下:

同理,由于计算需要用到,因此和两个变量也需要一直保存在显存中,他们大小也和梯度一致,因此也和参数一致。例如参数规模是 100 亿,那么 m 和 v 一共就是需要 200 亿的规模。
2.4 混合精度训练
有时候我们为了提升效率,会使用混合精度进行训练,而混合精度训练为了抵消 float16 在参数更新时候的舍入误差,会额外保存一份 FP32 的参数用于参数更新,称作 master-weights,因此会多出一份显存占用空间。











