简介

Tensorflow CNN Benchmark提供了基于CNN的多个图像分类模型用于图像数据的分类,其运行模式分为单机多GPU及分布式多GPU模式,这两种模式又根据参数更新方式的不同各分两种类型,一共四种运行方式。本测试中使用的数据集为ImageNet图像数据。

参数更新方式

replicated

单机多GPU模式。在该模式下,每个GPU拥有变量各自的副本,通过nccl 或cross-device aggregation的方式把计算完梯度后的参数值拷贝到各GPU。

parameter_server

支持多Worker多Parameter Server的分布式模式,变量存储在ps中,每个worker的各个GPU在每执行每个step时直接从ps获取参数值,然后把计算出的梯度汇总得出新的参数值并传回ps。

distributed_replicated

支持多Worker多Parameter Server的分布式模式,每个GPU拥有自己的local副本,在各GPU执行完一个step后,以同步的方式先将得到的梯度计算均值并更新到ps,然后再将更新后的参数从ps拷贝到各副本,相比于ps方式,该方式消耗更多的存储空间以节省网络开销。

independent

单机多GPU模式,每个GPU拥有自己的变量拷贝,各GPU间数据不相互交互(一般用来单纯做性能测试),在总结中就不再讨论了

测试脚本

测试是基于 源码tf-cnn-benchmarks.tar.gzImageNet 2012 数据集。

测试结果

  • TFoS集群为 2 * 4GPU(K40)集群。运行200 step后统计每秒处理的 images 数。 Variable update 类型分别有replicated、parameterserver 和 distributedreplicated。Worker * GPUS + PS 表示 任务使用几个 worker,每个 worker 所带的 GPU 个数和 几个 PS,例如:4 * 2 + 1 表示为4个 带2GPU的 worker 和 一个 PS,这里所有PS皆没有带GPU,内存都是每个 PS 和 Worker 为32G。 模型:Inception-V3
Variable updateBatch sizeWorker * GPUS + PSImages/Sec加速比
replicated321 * 1 27.211
replicated321 * 2 39.241.44
replicated321 * 4 70.922.6
     
parameter_server321 * 1 + 123.580.87
parameter_server321 * 2 + 142.051.55
parameter_server321 * 4 + 186.513.18
parameter_server322 * 1 + 147.71.76
parameter_server324 * 1 + 186.053.16
parameter_server322 * 2 + 193.13.42
parameter_server328 * 1 + 1113.934.19
parameter_server322 * 4 + 1140.385.16
parameter_server324 * 2 + 1196.967.24
     
distributed_replicated321 * 1 + 125.70.94
distributed_replicated321 * 2 + 148.781.79
distributed_replicated321 * 4 + 194.483.47
distributed_replicated322 * 1 + 152.671.94
distributed_replicated324 * 1 + 164.112.36
distributed_replicated322 * 2 + 192.523.4
distributed_replicated328 * 1 + 1125.554.61
distributed_replicated322 * 4 + 1184.86.7
distributed_replicated324 * 2 + 1152.35.6
     
replicated641 * 1 29.391.08
replicated641 * 2 40.641.49
replicated641 * 4 82.683.04
     
parameter_server641 * 1 + 127.351.005
parameter_server641 * 2 + 152.011.91
parameter_server641 * 4 + 191.043.45
parameter_server642 * 1 + 153.41.96
parameter_server644 * 1 + 1101.753.74
parameter_server642 * 2 + 1104.83.85
parameter_server648 * 1 + 1180.156.62
parameter_server642 * 4 + 1195.617.19
parameter_server644 * 2 + 1188.656.93
     
distributed_replicated641 * 1 + 128.411.044
distributed_replicated641 * 2 + 153.571.97
distributed_replicated641 * 4 + 1103.013.79
distributed_replicated642 * 1 + 153.221.96
distributed_replicated644 * 1 + 185.83.15
distributed_replicated642 * 2 + 1108.53.99
distributed_replicated648 * 1 + 1200.027.35
distributed_replicated642 * 4 + 1195.457.18
distributed_replicated644 * 2 + 1206.37.58

  • TFoS集群为 8 * 4GPU(P40)集群。运行200 step后统计每秒处理的 images 数 (TBD)

参数更新详解

逻辑结构

图片名称
图1 逻辑结构

参数更新流程

图片名称
图2 每个step的执行流程

整体执行流程

图片名称
图3 运行流程图
运行流程分这么几步骤:

1. 图像预处理

定义每个batch图像数据的shape,将数据按GPU个数进行切分成image_split数组 ,这里会根据eval flag 来区分到底使用train还是eval的数据集。

2. 定义变量域

这里根据不同的variable_update方式执行不同的操作

  • replicated:为每个gpu分配一个变量域 'v%s' %gpu_number ,如v0 v1 v2,域变量定义在global_variables中
  • parameter_server: 仅当gpu_number =0 时在global域分配 ‘v’变量域,域变量定义在global_variables中
  • distributed_replicated:为每个gpu分配一个变量域 'v%s' %gpu_number ,域变量定义在local_variables中,此外还创建了一个ps_var变量域用于管理同步的训练参数,这个域的变量定义在global_variables中。

3. 定义向前传播过程

  • 定义训练需要的参数。
  • 通过模型定义cnn各层的执行过程,生成一个cnn实例。
  • 需要训练的参数会被加到train_variables中。
  • 如果mode=eval,定义评估的过程。

4.如果mode=train,定义反向传播的过程。

  • 在反向传播时会提取train_variables集合中定义的参数并执行训练,这个集合根据对参数设置trainable=True得到。
  • 定义apply gradient过程(也就是同步参数的过程)。在各worker的各gpu下计算完参数的梯度后,不同的variable_update模式apply gradient方式不同。
  • replicated:通过gpu的nccl模式同步每个GPU的参数副本。
  • parameter_server/distributed_replicated: 在benchmark中使用Between-graph模式,每个worker持有相同的图的副本,通过随机数据读取的方式为每个worker供给不同的数据,因此各worker之间需要定期把计算出的梯度通过同步或异步的方式进行汇总,默认情况下通过cross_replica_sync=true设定采用同步方式更新参数(比起异步更新会有性能上的损失,但精度上有所提升),在每个worker汇总完自身GPU的梯度后向ps apply梯度,随后已经完成的worker阻塞至barrier处等待其他worker执行完毕然后统一进入下一个step。distributed_replicated还需要执行一个额外的操作,就是在本次汇总完成后把ps_var变量域中的更新后的参数拷贝到local的副本中。

5.执行训练/评估过程

  • 对参数进行初始化

定义global_step_watcher累计global_step
循环num_batches次 ,执行3和4步中定义的操作,如果是评估过程,只执行3中定义的操作 如果是训练过程,定期保存checkpoint和summary

  • 代码细节

variable_mgr.py中提供了不同运行模式下各自的执行细节

replicated: VariableMgrLocalReplicated
parameter_server: VariableMgrDistributedFetchFromPS
distributed_replicated: VariableMgrDistributedReplicated
  • 方法
  • each_tower_has_variables:每个GPU是否含有变量副本,ps方式为False,其余为True ,该状态决定在apply gradient后是否更新各GPU的参数副本

  • create_outer_variable_scope:创建变量域的细节

  • replicated:为每个gpu分配一个变量域 'v%s' %gpu_number

  • parameter_server:仅为gpu0分配 变量域v,提供custom_getter=OverrideCachingDevice,告知数据缓存保存在哪个设备(一些ops只在cpu中执行,因此ops需要的参数也会被保存到内存而不是GPU显存)

  • distributed_replicated:为每个gpu分配一个变量域 'v%s' %gpu_number ,提供custom_getter=OverrideToLocalVariableIfNotPsVar,使得除了ps_var域以外的域全部在在local_variable中保存和使用。

  • get_devices: 获取执行复杂计算用的设备,在replicated/distributed_replicated下默认为所有GPU设备(cnn.raw_devices),在ps中为被tf.train.replica_device_setter封装的所有GPU设备, 在该封装下定义的所有参数(变量保存的位置跟global、local、trainable等域无关,只跟执行的操作有关)都保存在ps中,replicated在global_variables中定义的变量被保存在各worker的GPU中, 而distributed_replicated的local_variables也保存在worker的GPU中,存储在global_variables集合中的ps_var域的变量在保存时也使用了tf.train.replica_device_setter,因此也是被保存在ps中。

  • get_gradients_to_apply: 将各gpu计算得到的梯度进行汇总,默认是采用均值的方式获得最终梯度。