首页 > 解决方案 > Python vs Mathematica 下令人费解的 mxnet 性能

问题描述

我比较了 Mathematica 和 Python 之间的 mxnet 性能,观察到超过一个数量级的性能差异,并希望就如何在 Python 下提高性能提出建议。

我的 NN 是一个用于回归的 MLP,具有 3 个浮点输入,8、16、24、8 个神经元全连接层和 2 个浮点输出,除了输入和输出神经元外,Sigmoid 无处不在。Mathematica 中使用的优化器是 Adam,所以我在 Python 中也使用了相同的参数。训练数据集包含 4215 条记录,将 xyY 颜色映射到 Munsell Hue 和 Chroma。

Mathematica 是 2017 年发布的 11.2 版,Mathematica 在底层使用 mxnet 进行深度学习任务。在 Python 方面,我使用最新版本的 mxnet-mkl 并检查了 MKLDNN 是否已启用。

Mathematica 许可证在装有 Windows 10、i7-7660U、2.5Ghz、2 核、4 超线程、AVX2 的 MS Surface Pro 笔记本电脑上运行。我在这台计算机上运行 Python 进行比较。

这是 32768 个 epoch 的学习循环的时间和

Batch Sizes:   128,   256,   512,  1024, 2048,  4096
Mathematica: 8m12s, 5m14s, 3m34s, 2m57s, 3m4s, 3m48s
PythonMxNet:  286m,  163m,   93m,   65m,  49m,   47m

我尝试了英特尔建议的 mxnet 环境变量优化技巧,但速度只慢了 120%。

我还将所有数组从 float64 切换到 float32,假设 MKL 可以使用 SIMD 寄存器在相同的时间内(当然不包括开销)处理 2 倍的操作,但发现甚至没有轻微的改进。

我将 NN 工作从 Mathematica 切换到 Python 的原因是我想在不同且更强大的计算机上训练 NN。而且我也不喜欢把我的笔记本绑在神经网络学习任务上。

我应该如何解释这些结果?

这些性能差异的原因可能是什么?

我可以做些什么来在 Python 下获得一些性能吗?

或者这仅仅是 Python 解释器强加的不可避免的开销?

编辑:

生成NN的脚本:

def get_MunsellNet( Layers, NbInputs ):
   net = nn.HybridSequential()
   for l in range( len( Layers ) ):
      if l == 0:
         net.add( nn.Dense( Layers[ l ], activation = 'sigmoid', dtype = mu.DType, in_units = NbInputs ) )
      else:
         net.add( nn.Dense( Layers[ l ], activation = 'sigmoid', dtype = mu.DType ) )
   net.add( nn.Dense( 2, dtype = mu.DType ) )
   net.hybridize()
   net.initialize( mx.init.Uniform(), ctx = ctx )
   return net

NN 是这样创建的:

mu.DType = 'f8'
NbInputs = 3
Norm = 'None'   # Possible normalizer are: 'None', 'Unit', 'RMS', 'RRMS', 'Std'
Train_Dataset = mnr.Build_HCTrainData( NbInputs, Norm, Datasets = [ 'all.dat', 'fill.dat' ] )
Test_Dataset1 = mnr.Build_HCTestData( 'real.dat', NbInputs )
Test_Dataset2 = mnr.Build_HCTestData( 'test.dat', NbInputs )
Layers = [ 8, 16, 24, 8 ]
Net = mnn.get_MunsellNet( Layers, NbInputs )
Loss_Fn = mx.gluon.loss.L2Loss()
Learning_Rate = 0.0005
Optimizer = 'Adam'
Batch_Size = 4096
Epochs = 500000

并接受了以下培训:

if __name__ == '__main__':
   global Train_Data_Loader
   Train_Data_Loader = mx.gluon.data.DataLoader( Train_Dataset, batch_size = Batch_Size, shuffle = True, num_workers = mnn.NbWorkers )
   Trainer = mx.gluon.Trainer( Net.collect_params(), Optimizer, {'learning_rate': Learning_Rate} )
   Estimator = estimator.Estimator( net = Net,
                                   loss = Loss_Fn,
                                trainer = Trainer,
                                context = mnn.ctx )
   LossRecordHandler = mnu.ProgressRecorder( Epochs, Test_Dataset1, Test_Dataset2, NbInputs, Net_Name, Epochs / 10 * 8 )
   for n in range( 10 ):
      LossRecordHandler.ResetStates()
      Train_Metric = Estimator.prepare_loss_and_metrics()
      Net.initialize( force_reinit = True )
      # ignore warnings for nightly test on CI only
      with warnings.catch_warnings():
         warnings.simplefilter( "ignore" )
         Estimator.fit( train_data = Train_Data_Loader,
                            epochs = Epochs,
                    event_handlers = [ LossRecordHandler ] )

如果您需要更多代码片段,请告诉我。

标签: pythonwolfram-mathematicamxnet

解决方案


通常,Python 开销可能很大,尤其是在使用少量输入频繁启动计算内核时。从上面的基准中有一些证据表明其中很大一部分是由于开销造成的。我们看到,虽然批量大小从 128 增加到 4096 (32x),但 mxnet 与数学的时间比率从 ~35.75 下降到 ~12.37,这可以看作是由于调用开销减少而加速。一旦有更多关于这个问题的细节,我会更新答案。


推荐阅读