以下内容翻译自 Synchronous SGD
利用多个GPU或机器来训练模型的方法有很多。而同步SGD(使用了Caffe2的数据并行模型)是最简单并且最容易理解的:每个GPU以完全相同的代码处理其在mini-batch中分得的数据。在mini-batch之间对每个GPU的梯度求均值,并且每个GPU以完全相同的方式执行参数更新。在任何时间点上,参数在每个GPU上具有相同的值。同步SGD的另一种理解是它允许增加mini-batch大小。使用8个GPU,每卡运行批量为32,相当于一个GPU运行256大小的mini-batch。
编程指南
示例代码:
- data_parallel_model_test.py有一个简单的2-GPU模型。
- 对于更复杂的模型,请参阅 Resnet-50 trainer for ImageNet 示例。
模块caffe2.python.data_parallel_model完成模型的并行。模型必须使用ModelHelper创建,例如 model_helper.ModelHelper。
为单个GPU构建ResNet-50,然后通过Parallelize_GPU
用于多GPU的完整教程可以看这里。以下是Resnet-50 example code的示例:
from caffe2.python import data_parallel_model, model_helper
train_model = model_helper.ModelHelper(name="resnet50")
data_parallel_model.Parallelize_GPU(
train_model,
input_builder_fun=add_image_input,
forward_pass_builder_fun=create_resnet50_model_ops,
param_update_builder_fun=add_parameter_update_ops,
devices=gpus, # list of integers such as [0, 1, 2, 3]
optimize_gradient_memory=False/True,
)
关键是将模型创建代码分成三个函数。这些函数就像不做并行化一样构造操作符。
input_builder_fun
:创建向网络提供输入的操作符。注意:请小心,每个GPU读取唯一的数据(他们不应该读取相同的数据)!通常他们应该共享相同的读取器来防止这种情况发生,或者数据应该按照每个读取器提供唯一数据的方式进行批处理。签名:function(model)
forward_pass_builder_fun
:该函数将操作符、层添加到网络中。它应该返回用于计算损失梯度的loss-blob列表。该函数还传递了一个内部计算的loss_scale参数,用于缩放损失从而和GPU数量相匹配。签名:function(model, loss_scale)
param_update_builder_fun
:该函数添加用于参数梯度更新的运算符。例如,简单的SGD更新、动量参数更新。你还应该在这里实例化学习率和迭代blob。如果不学习而仅做前向,则可以将此功能设置为无。签名:function(model)
optimize_gradient_memory
:如果启用,memonger 模块用于通过尽可能共享blob来优化梯度运算符的内存使用情况。 这可以节省大量的内存,并可以帮助您运行更大的批次。
注意
- 请勿直接访问
model_helper.params
,而是使用model_helper.GetParams()
,它只返回当前GPU的参数。
实现说明
在底层,Caffe2使用DeviceScope
和NameScope
来区分每个GPU的参数。每个参数都以名称范围(例如“gpu_0/”或“gpu_5/”)作为前缀。上述函数创建的每个blob根据DeviceScope
正确分配给GPU,而DeviceScope
通过data_parallel_model.Parallelize_GPU
函数设置。检查模型时,只需调用model.GetParams("gpu_0")
即可获取前缀为“gpu_0/”的参数。我们使用CUDA NCCL-ops来同步机器之间的参数。
性能
性能将取决于型号,但是对于Resnet-50,我们在8颗M40 GPU上实现了约7倍加速。
进一步阅读和示例
Gloo是一个Facebook孵化器项目,可帮助管理多主机、多GPU的机器学习应用程序。
Resnet-50示例代码包含使用 rendezvous
的示例代码。该功能在data_parallel_model module模块中但此同步SGD示例中未明确使用。
Deep Residual Learning for Image Recognition是Resnet-50的研究源头,其中他们在ImageNet数据集上利用残差学习探索了构建更深层、更深层,直至1000多层网络的结果。Resnet-50是他们的残差网络的变体,使用了50层,在物体检测、分类和定位方面表现相当出色。