一直都想把多GPU训练神经网络用起来,但新的框架例如tensorflow和caffe2学习曲线太陡峭,一直没掌握,因此只好先继续基于老的caffe搞一个。
尽管老的caffe多GPU训练也不是很友好,例如无法在训练途中更改学习率,等等,但目前能快速上手的只有它了,毕竟代码已经快烂熟了。
因为对caffe里原有的data layer很不满,所以自己写了一堆data layer,现在搞多gpu训练,也是要基于自己写的data layer,但这里就出状况了,发现用caffe的多GPU训练,无论是基于NCCL还是基于P2PSync,结合我自己的data layer,都似乎有点问题,就是在每个GPU上的批量大小固定的情况下,多GPU训练并没有比单GPU训练更快收敛。
经过仔细检查发现,使用我自己的data layer,多GPU训练时,每个iteration不同GPU接收到的数据总是完全相同的。原因是在不同GPU对应的网络中,data layer底层实际对应于同一个共享的data object。每个GPU的data layer在各自的InternalThreadEntry线程函数里调用这个data object的GetData方法。在GetData方法里会对数据进行随机抽样,问题就在这里,不同的线程中,随机抽样是用CRT的rand函数计算的随机数,但是由于在每个线程开头没有重新给不同的随机种子,因此不同线程里实际上产生了完全相同的一串随机数,不同GPU看到的训练样本序列是完全相同的。
一开始还怀疑是NCCL或P2PSync的问题,花了一天时间,把数据保存到文件里仔细看,最后终于发现是被rand坑了一次。
类似的事情好像以前也发生过,即不同线程里产生相同的随机数的问题。希望不会有下次。