Gluon实现跨卡同步Batch Normlization


#1

在实践中,我发现,跨卡同步的BN对于performance相当有用。
尤其是对于detection,segmentation任务,本来Batch size较小。如果Batch Norm能跨卡同步的话,就相当于增大了Batch Norm的batch size 这样能估计更加准确的mean和variance,所以这个操作能提升performance。
所以,我想知道这个跨卡BN的跨卡通信同步,在gluon中可以怎么实现?


#2

@zhreshold @piiswrong


#3

可以把batch norm拆分计算,手动算mean variance,然后拷回每个gpu就行


#4

你的意思是指,其他层并行处理,batch norm单独抽出来计算?我在pytorch上实现过类似想法,这样的话,效率比较慢而且比较吃显存。所以,我觉得比较好的方法,还是在batch norm这儿多卡之间进行通信同步,你觉得呢?


#5

in operator的通信需要考虑到计算的依赖,其实和分拆了以后是一样的。你觉得效率低应该和实现的问题和多卡通信的带宽也有关


#6

拆分后,bn相当于不并行,在某一张卡上跑,这样它会gather它上一层所有卡的输出,这样会比较耗显存吧。而bn内部进行通信的话,显存方面应该会好很多。


#7

之前和同事(基本是同事搞的)在pytorch上面hack出来的基本上是每个显卡自己算mean var, 然后把mean var reduce到一个gpu求个平均再传回去。内存方面基本没什么变化但是在有gpu p2p 的情况下大概要慢30%(implementation其实并不是很efficient,我么每个layer都要wait其他gpu,其实只要bn的时候wait就好了),没有p2p就是慢的不行(其实可以做tree reduce不过我们没空)。具体到gluon这边不知道直接写一个新batchnorm layer然后传一个kvstore 进去用kvstore sync效率会不会更高。我们在pytorch上本来想用nccl写的但是不知道是有bug还是啥的每次都deadlock 另外要注意的事项就是mean和var也要对x求gradient。。然后这个gradient也要做 reduce 和broadcast我们一开始把这个忽略了debug了半天,各种不converge


#8

谢谢~大概思路是这样的,你们的代码开源了吗?求repo。不过,你们在各个显卡自己算 mean, var,然后再平均。这个做法应该有点问题,你们可以推一下公式计算一下。正确做法,我觉得应该是各个卡的bn,wait,然后同步上一层的输出,再进行计算。我准备试试用NCCL进行通信。


#9

我说的不是很准确,mean是求平均不过var不是平均而是整个batch的var。基本就是把所有x square给传到一个gpu上面算var。 我们是写了一个自己bn而不是用framework自己的。暂时还不打算开源,可能过一段时间吧:)


#10

OK.谢谢~


#11

我有一个解释、一点建议。
解释是:现有的各个卡各自算mean和var再做平均其实也不影响精度的,本身训练过程中的moving_mean和moving_var的更新就是一种近似,用了很不完美的滑动平均。而且BN完全就是个辅助,接在conv后面完全可看作是conv的一个factorization,网络训练好之后完全可以合并到带bias的conv的计算里面去,BN出发点就是要保证较深的网络能快速稳定的收敛,如果这个目的达到了就行了,并不是用来提高精度的。

建议是:检测任务一般是finetune吧,finetune时一般把bn的lr_mult设到很小甚至关闭,其二是由于模型已经在finetune之前已经通过分类训练收敛好所以bn在此无需再做过多学习,所以bn的影响十分有限。还有个很重要的,检测训练过程中的Batch根本就不是BN的那个Batch,而是经过OHEM之后的,所以进一步证明bn对检测影响不大。另外,detection和segmentation方面,不带BN的VGG16在工业应用中已经完全足够,Resnet优势十分微弱。


#12

说实话,在实际中,跨卡BN是真的能涨点的,而且能涨不少。至于计算问题,这样做平均是不科学的,虽然原本就是近似,但是也不能这样啊,毕竟BN在网络中用的比较多。还有虽然是finetune,但是针对新任务的transfer也是需要重新训练的,至少我们用的时候不会直接就把BN锁住。Seg方面,deeplab v3和PSPNet已经证明的跨卡BN对performance有提高。而且在我接触到的工业界的话,基本上都用上了跨卡BN。


#13

分割时batch的大小可以看作[图像数量]x[图像宽]x[图像高],而且单卡所能容纳的[图像数量]少且图像间区别较大,导致每个卡运算出的mean和var差距较大,所以应该会有一些影响。
PSPNet论文我看了,他也没说用了提升了多少,他只是说他这样做了;DeeplabV3论文说他训练时BN是冻结的。目前https://github.com/DrSleep/tensorflow-deeplab-resnet这个实现在VOC上比PSPNet的mAP要高,而且训练也可以用,PSPNet没有完全开源,而且商汤的东东一贯坑多,建议别跟。


#14

我在非开源的库上用过跨卡BN,差不多两三个点吧,所以才会希望开源的框架能实现或者自己实现一下。另外,Deeplab v3的BN是在训练后期才冻结的,并不是一开始就冻结。
还有,VOC的图片尺寸正常,所以每张卡还能放比较多的图。但是,像ADE这样的数据集,图片尺寸普遍较大,有的甚至超过1024*1024,这时候如果输入图片的尺寸设置较大的话,每张卡就放不了多少图了。这时候不用跨卡BN,可能就直接train不出来。
所以,我是希望官方或者自己能实现这个东西,并不是论证这个是否有效。


#15

CUHK官方未被Test的方案,可以试试。也可以看看里面的人怎么说。


#16

OK.多谢


#17

其实deeplabv3之所以要冻结基本就是没有跨卡bn然后要hack fasterRCNN也是差不多 DeeplabV3拿一个resnet101 比人家resnet50不太公平啊。。。psp上101/152基本秒杀deeplabv3。PSP的pyramid pooling里面有一个pool是只有1x1的spaitial resolution所以没bn基本gg


#18

貌似还有个Resnet-38,MXNet实现的,和PSPNet跑分差别很小


#19

ResNet-38那个是从base model上不同,然后PSPNet和Deeplab v3这些base model基本一致,所以这是两条思路,不太有可比性。


#20

Deeplab v3讨论了Cascade 和 ASPP两种形式,在ASPP中Deeplab v3也加入了Global Pooling的。还有Deeplab v3并不是从一开始就冻结BN的,是训练到后期,为了保证训练和测试尽量一致,所以冻结的。