使用TensorFlow Keras后端的单线程影响模型精度和损耗

ms.*_*.js 9 python keras tensorflow

为什么将Keras的TensorFlow后端(intra_op_parallelism_threads和inter_op_parallelism_threads)中的线程数设置为1会对模型的准确性和丢失产生负面影响?

背景

我使用Keras(2.1.6)训练MNIST CNN,TensorFlow(1.7.0)作为后端.我在AWS EC2实例中运行了一些培训,并注意到从t2.medium实例切换到t2.small后,我的准确性大大降低.发生这种情况时,两个实例类型之间根本没有更改代码.

鉴于CPU核心数量从t2.medium(2核心)变为t2.small(1核心),我假设精度的降低与线程有关.为了测试这个,我强迫TensorFlow使用单个线程并在本地运行训练.

from keras import backend as K
config = tf.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1)

sess = tf.Session(graph=tf.get_default_graph(),config=config)
K.set_session(sess)
Run Code Online (Sandbox Code Playgroud)

使用单个线程运行在本地计算机上产生比运行多线程更糟糕的结果.

一次单线程培训导致:

train_loss: 2.303228187561035 train_accuracy: 10.75%
Run Code Online (Sandbox Code Playgroud)

而多线程培训运行导致:

train_loss: 0.3670464503765106 train_accuracy: 88.00%
Run Code Online (Sandbox Code Playgroud)

这些结果对我来说没有意义,因为在我看来,运行一定数量的训练时期应该导致相同数量的计算工作量,而不管使用的线程数量.我的测试结果似乎表明,有更多的线程进行了更多的训练,而不仅仅是使用并行性来提高速度.

我在GitHub中浏览了Keras存储库,但我没有找到任何代码跳出来,为什么结果会如此不同.

我叫Keras的model.fit()来训练模型和模型.估计()以获得损失和准确性.

以下是我的一些超参数:

loss_function: categorical_crossentropy
optimizer: Adadelta
epochs: 12
mini_batch_size: 128
train_size: 600
validate_size: 400
Run Code Online (Sandbox Code Playgroud)

更新于6/26/2018

我想用更多的线程独立于我自己的代码来测试准确度的提高,所以我根据Keras 常见问题解答在可重现的开发上运行了Keras MNIST CNN.我的测试代码可以在这个要点中看到.gist中两个Python文件之间的唯一区别是80,90和91行.取消注释这些行会强制TensorFlow后端在单个线程上运行.

我跑mnist_cnn_single_threaded.py三次,mnist_cnn_multi_threaded.py三次.结果可以在同一个要点中看到.它们符合我昨天在本地和EC2中运行我自己模型的结果.

测试结果

以下是我根据NPE评论的测试结果.使用显式设置运行,但默认tf.ConfigProto()产生类似的结果,根本不设置线程值.在下面的图表和表格中,"threads"等同于将intra_op_parallelism_threads和inter_op_parallelism_threads都设置为指定值.

                  损失和准确性与线程

Threads   Test Loss     Test Accuracy
1         2.300546171   0.1141
2         0.060040779   0.9806
4         0.060651763   0.9805
6         0.06015457    0.9808
8         0.057530957   0.9819
Run Code Online (Sandbox Code Playgroud)

唯一能够在准确性和损失方面产生显着差异的情况是将线程明确地设置为1.

更新于6/27/2018

这似乎只是TensorFlow后端到Keras的一个问题.我使用Theano后端尝试了测试,下面的选项强制单个线程,我没有注意到准确/丢失问题.

os.environ['OMP_NUM_THREADS'] = '1'
os.environ['THEANO_FLAGS'] = "device=cpu,force_device=True,openmp=False"
Run Code Online (Sandbox Code Playgroud)