这个月十几号的时候索尼发了篇论文,224 秒跑完了 ImageNet……想想大概去年的这个时候还是 Facebook 和 UCBerkeley 在 ImageNet 的大规模方面你争我赶,不得不感叹时间过得真快。
去年毕业开题大概开的也是这个方向,然后前段时间面试的时候:
面试官:你最近做了什幺?
我:我 follow 了 FB 和 UCB 他们在 ImageNet 上做训练的工作,大概试了下他们论文里面的想法。
面试官:哦,那你最多用到多少卡?
我:e……最多跑到 16 块 V100。
说完这句自己突然感到一阵尴尬,人家工作多少块卡我多少块卡?真好意思说复现……(捂脸)
然而我也没办法啊,实验室资源已经算不少了,我还想拿一块卡假装模拟两块卡用呢。0.0
Anyway,趁着正好要读大法的论文,把之前其他人的东西都理一理。
前面这几段笔记还是去年的时候写的,看了下过了这幺长时间,有的已经正式发了论文了,有的是 arXiv 上有了新版,那就下新的重新看一遍吧。
还是留下 OneDrive 的链接:
2017 Facebook – Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour
Facebook 做的大规模 GPU 集群训练,顺便推一波 Caffe2。
256 块 GPU,1 小时内跑完整个 ImageNet 的数据集训练,想想都可怕。
这篇文章主要是从一个“炼丹师”的角度来写的,主要关注在学习率、minibatch 等等之间的关系,以及它们对训练带来的影响。文章的主要工作是提出了一种根据 minibatch 大小调整学习率的扩放规则,以及一种在训练时预跑的机制。
这些可能大多都是训练中总结出来的一些 tricks 吧。
随着网络模型和数据规模的不断增长,训练时间也跟着增长了,为了保证训练时间能够保持在一个有意义的限度之内,就需要一些额外的工作了。
文章的立足点是通过增大训练时的 batch size 来加快训练速度。例如 ResNet-50 这个网络通常大家采用的 batch 大小是 256,在 8 块 P100 上大约需要 29 个小时才能跑完整个 ImageNet 数据集。
但是如果加大 batch size 呢? 改变 batch size 会影响到最终的收敛和训练结果的正确率 。
说实话,我们网络跑的少,这些问题还真不太懂……
文章接下来的工作就是通过调学习率等等其他的一些方法,把加大 batch size 带来的影响控制在一个可接受的范围内,最终做到 8192 个 batch 训出来的结果跟原本的效果持平。当然最重要的,batch size 增大了 32 倍,总的训练时间也能够降下来, 用 256 块 GPU 在 1 小时内训完了整个 ImageNet!
为了维持训练结果的准确率,他们在过往积累的大量经验上得出了一个令人难以置信地简单却又有效的规则:
Linear Scaling Rule:minibatch 扩大 k 倍,学习率也扩大 k 倍。
其他超参数维持不变就好。
多次测试之后,可以发现应用了上面这个规则时,不同 minibatch 的 SGD 不仅最终准确率非常接近,而且训练的收敛曲线都是非常相似的。
但是在两种情况下,前面讨论的一些假定会有问题:
训练初始的几个 epoch 可能会引起网络参数巨变
在某些网络中,如果一开始设的学习率太大,初始的几个 epoch 会产生过大的梯度,上面这条规则就可能不太适用了。为了解决这个问题,文章于是提出了 预热训练 的阶段。
minibatch 的大小不能无限增长
就拿前面 ResNet-50 为例,这个规则只够保证 minibatch 在增长到 8192 的时候能维持训练效果,再大就保证不了了。
接下来是训练预热的机制:
Gradual warmup:预训练时先用一个比较小的学习率,然后爬坡增长,逐渐增加到目标需要的 k 倍
经过实践调整之后,他们的实现里面是经过 5 个 epoch,学习率逐渐从$\eta$增长到$5\eta$。
分布式 SGD 在具体实现上还有很多细节的地方,可能稍微变动一下就会影响到整个模型的超参数,这里提了几个注意点吧:
- 权重衰减:交叉熵 loss 的扩放并不等价于学习率的扩放(?)
- 动量修正:在改变学习率之后再应用动量修正
- 梯度聚合:用整个 minibatch 的大小 kn 来均一化每个 worker 的 loss,而不是 n
- 数据清洗:先对训练数据做 shuffle 再把他们放到不同的 worker 上
关于我最关心的梯度聚合的实现,他们没有采用 Parameter Server 的形式,而是所有 worker 直接做 allreduce 。
Allreduce 分成 3 个阶段:
- 每个节点的 8 块 GPU 的数据合并到同一个 buffer 上
- 所有节点对数据进行汇总做 allreduce
- 每个节点的梯度更新完之后再广播到各自的 8 块 GPU 上
1、3 两个阶段的操作,如果数据量大于 256 KB 则用 NVIDIA 的 NCCL 库来完成,否则就各自把数据传回 CPU 再做汇总。
阶段 2 用到了 递归二分倍增算法 以及 令牌环算法 ……嗯,基本上也没有什幺特别的,就是想办法高效实现 all_reduce 和 all_gather。
软件栈用的是 Facebook 自家开源的 Gloo ,具体的通信方面都是靠这个通信库来完成,就不涉及到具体的实现了(……)。以及 Caffe2。
硬件是 Facebook 的 Big Basin GPU 集群。每个节点是 8 块 NVLINK 的 P100(!!!DGX-1!!!),50 Gbit 的 InfiniBand 。
预估一下 ResNet-50 的数据量:大约参数量是 100MB 左右,单 P100 跑完一次大约 120ms,也就是峰值带宽大概要在 100MB * 2 / 0.125s = 12.8 Gbit/s 的程度。
后面的 evaluation 先不看了,,2333,,反正效果很好就是了,线性加速等等。
2017 – Extremely Large MinibatchSGD Training ResNet-50 on ImageNet in 15 Minutes
。。。上面 Facebook 用 256 块 P100 做了大 minibatch 的 ImageNet 训练之后,感觉军备竞赛就开始了。
这是日本的一个研究机构,用 1024 块 P100,15分钟跑完 ImageNet!
完成这个任务主要有两方面的挑战:
- 算法层面,使用更大的 BatchSize 之后,要想办法防止精度的损失;
- 系统层面,需要设计一套方案来有效地利用上可用的硬件和软件资源。
这里给了个表,对比了一下目前用 ResNet 跑 ImageNet 的几个工作:
Team | Hardware | Software | Minibatch size | Time | Accuracy |
---|---|---|---|---|---|
MSRA(ResNet作者) | Tesla P100 * 8 | Caffe | 256 | 29 h | 75.3% |
Tesla P100 * 256 | Caffe2 | 8192 | 1 h | 76.3% | |
SURFsara | KNL 7250 * 720 | Intel Caffe | 11520 | 62 m | 75.0% |
UC Berkeley | Xeon 8160 * 1600 | Intel Caffe | 16000 | 31 m | 75.3% |
This work | Tesla P100 * 1024 | Chainer | 32768 | 15 m | 74.9% |
嗯…话说,UCB 最早发的文章也是在 KNL 上跑的,刚刚才发现他们当时最新的工作是用的 8160 跑的???(这 TM 可是通用处理器啊???害怕,下面那篇真得好好看看了)
具体的实现,这里说是参照 Facebook 的工作做的,比较额外的就是加大了 BatchSize,然后软件方面换了他们自己写的 Chainer 框架,因此这块写的比较简略。
NCCL 和 OpenMPI 意味着他们写的这个框架是基于 MPI 做的通信,而且还做了卡间数据传输。主要还是用的同步模型,然后做 Allreduce。
训练用的单精,然后划重点,为了减少通信的数据量,数据传输的时候用的 半精浮点 !!测试之后发现对结果影响不大(666666….)。
硬件方面,双路 E5-2677,8 块 P100 的配置,应该是没有 NVLINK 的,IB 用的 FDR(56 Gbps)。
2017 UC Berkeley – ImageNet Training in Minutes
接下来上台的是 UC Berkeley。
话说他们最早一篇论文写的是 24 分钟跑完,可能被上面那篇 15 分钟的刺激了一下,最近更新了一下把标题里面的 24 去掉了,把这个时间也缩短到了 10 分钟的量级。
文中使用了两种硬件方案:
- Intel Skylake CPU,应该就是前面提到的 Xeon Platinum 8160
- Intel KNL
大致的结果是:
Hardware | Model | Time |
---|---|---|
8160 * 1024 | 100-epoch AlexNet | 11 m |
KNL * 512 | 100-epoch AlexNet | 24 m |
8160 * 1600 | 90-epoch ResNet-50 | 48 m |
KNL * 512 | 90-epoch ResNet-50 | 60 m |
KNL * 2048 | 90-epoch ResNet-50 | 20 m |
有一些前人的工作证明了异步的方式是不稳定的(例如 Revisiting Distributed Synchronous SGD 以及前面 Facebook 的工作等等),所以他们这里用的也是同步方案。通过加大同步 SGD 的 BatchSize 来加速。
在模型的选择上,他们提出了一个扩放率的概念,即计算和通信的比率,对 AlexNet 和 ResNet-50 这两个网络:
Model | Communication # parameters | Computiation # flops per image | Comp/Comm Scaling Ratio |
---|---|---|---|
AlexNet | 61 Million | 1.5 Billion | 24.6 |
ResNet-50 | 25 Million | 7.7 Billion | 308 |
ResNet-50 的扩放率大概是 AlexNet 的 12.5 倍,所以 ResNet-50 的可扩放性更好,能达到更高的弱扩放效率。
然后 BatchSize 的改变是不会影响到网络模型的参数的,也就是说不管 BatchSize 多大,需要通信的量是不会变的,因此 BatchSize 越大,计算量越大,就能够更好地 Overlap 通信的延迟了。
问题在于 BatchSize 不能无限往上加,大到一定程度之后,准确率就降下来了,那幺为了解决这些问题,就要增大学习率以及用上训练预热的机制(这些方法基本上跟前面 Facebook 的做法差不多)。跟进一步的是,这里用了一种叫 LARS(Layer-wise Adaptive Rate Scaling)的算法,达到了 Facebook 他们做不到的 BatchSize。
把一个算法扩大规模到更多的处理器上时,通常通信都会成为最大的 overhead。
这里从两个角度分析了通信比计算慢这一点,首先是硬件运算力(每个 flop 需要花费的时间,例如 P100 的峰值性能是 11TFlops 左右,$\frac{1}{11TFlops}$大约是$0.9*10^{-13}s$左右)会远小于理论传输速度(这里用的是$\frac{1}{Bandwidth}$,例如 56Gb/s 的 FDR,大约是$0.2*10^{-9}s$的水平),然后远小于延迟:
$$Time-Per-Flop << \frac{1}{Bandwidth}<<Latency$$
然后在 45nm 工艺的 CMOS 处理器上,通信消耗的能量也比计算更大:
Operation | Type | Energy(pJ) |
---|---|---|
32-bit Int Add | Computation | 0.1 |
32-bit Float Add | Computation | 0.9 |
32-bit Int Multiply | Computation | 3.1 |
32-bit Float Multiply | Computation | 3.7 |
32-bit Register Access | Communication | 1.0 |
32-bit SRAM Access | Communication | 5.0 |
32-bit DRAM Access | Communication | 640 |
能量这个角度比较神奇,感觉应该体现的不是很明确,因为计算这个过程本身肯定涉及到访存,更多的应该要对比网络传输吧。
设总的 epoch 数为 E,图片数为 n,BatchSize 为 B,网络参数为 |W|。
当 E 不变的时候,总的计算量是固定的,总的迭代次数是 $E*\frac{n}{B}$,通信量是$|W|*E*\frac{n}{B}$。当 BatchSize 增大之后,总迭代次数减少,那幺通信次数也减少了,通信量减少。
因此增大 BatchSize 有利于网络向大规模进行扩展。
To be continued.
Be First to Comment