我想知道有没有人能够给出关于如何在4个GPU设置中获得tensorflow最佳性能的建议。
作为一个测试,我创建了两个相同的网络(18层残差网络,使用小型滤波器组(范围从16-128)在32x32的输入上。批量大小512,每个GPU 128)。一个在MXNet中,另一个是基于inception示例模拟的。
我的MXNet网络可以以每秒7k个样例进行训练,而tensorflow只能以虚拟数据为基础达到4.2k,真实数据只有3.7k。
(当在1个GPU上运行时,数字分别为每秒1.2k个样例与2.1k)
在我的实验中,我有一些问题希望加快速度。
训练时GPU利用率似乎很低。我注意到在tensorflow白皮书中有支持在同一GPU上运行多个流的功能。这在公共版本中是否可行?
有没有办法在一个执行
session.run()
期间执行多个训练操作?或者有异步执行的方法吗?这将允许权重更新与下一批次的前向传递同时进行。我尝试使用2个线程(系统和QueueRunners
),但结果只会减慢速度。MXNet能够通过在CPU上运行权重更新来提高速度,以便GPU可以用于下一个批次。新的分布式运行时是否能够解决这些问题,使我能够在一台计算机上运行多个工作进程?
还有其他方法吗?
我知道这里在stack overflow上有很多类似的问题,但是我搜索过了,没有找到我已经尝试过的问题的解决方案。
编辑:
我进行了一些CUDA分析,看看哪些内核比较耗时。根据我的运行,21.4%的时间花费在内部:
void Eigen::internal::EigenMetaKernel_NonVectorizable<Eigen::TensorEvaluator
<Eigen::TensorAssignOp<Eigen::TensorMap<Eigen::Tensor<float, int=4, int=1, long>, int=16>,
Eigen::TensorPaddingOp<Eigen::array<std::pair<int, int>,
unsigned long=4> const, Eigen::TensorMap<Eigen::Tensor<float const,
int=4, int=1, long>, int=16> const > const > const, Eigen::GpuDevice>, long>(float, int=4)
20.0%的时间花在了
void Eigen::internal::EigenMetaKernel_NonVectorizable<Eigen::TensorEvaluator
<Eigen::TensorAssignOp<Eigen::TensorMap<Eigen::Tensor<float, int=4, int=1, long>, int=16>,
Eigen::TensorBroadcastingOp<Eigen::array<int, unsigned long=4>
const, Eigen::TensorMap<Eigen::Tensor<float const, int=4, int=1, long>,
int=16> const > const > const, Eigen::GpuDevice>, long>(float, int=4)
关于签名,我不确定这些是在做什么。这些有意义吗?
此外,分析报告显示低内核并发性为0%,这是预期的。计算利用率也很低,只有34.9%(这包括启动时间和训练循环中的一点Python。总共大约32秒,共91秒。在TensorFlow内部大约使用了50%的利用率)。
编辑2:
我附上了一个精简版的源代码。但总体上,我更关心问题1-3,不想占用大家太多时间。
此外,我正在运行来自以下版本构建的TensorFlow:f07234db2f7b316b08f7df25417245274b63342a
编辑3:
已更新至最新版本的TensorFlow(63409bd23facad471973b110df998782c0e19c06),使用默认数据格式(NHWC),这似乎显著加快了速度。在4个GPU上,虚拟数据为6.7k-6.8k(我认为是热依赖关系)每秒例子。1个GPU--每秒2.0k个示例。真实数据的性能约为每秒4.9k个示例(4 GPU)。1个GPU--每秒1.7k个示例。
编辑4:
此外,我尝试切换数据格式为BCHW。我根据Soumith的基准测试的模型进行转换。卷积部分的确更快了,但批量归一化似乎搞砸了所有事情。使用naive实现(修复轴并使权重[1,C,1,1]而不是[C,]),我只能在4个GPU上获得每秒1.2k个示例(虚拟数据)。而使用批量归一化操作前后的转置,则可以获得每秒6.2k个示例(虚拟数据)。仍然比NHWC数据格式慢。
TensorMap
的第二个模板参数是应用的内核吗?您如何知道它是TensorPadding
而不是例如TensorAssign
? - luke