问题
为什么将 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)
在我的本地计算机上使用单线程运行比运行多线程产生的结果要差得多。
一次单线程训练运行的结果是:
train_loss: 2.303228187561035 train_accuracy: 10.75%
多线程训练运行的结果是:
train_loss: 0.3670464503765106 train_accuracy: 88.00%
这些结果对我来说没有意义,因为在我看来,无论使用多少线程,运行一定数量的训练周期都应该产生相同的计算量。我的测试结果似乎表明,更多的线程会进行更多的训练,而不仅仅是使用并行性来提高速度。
我浏览了 GitHub 中的 Keras 存储库,但没有找到任何代码让我想到为什么结果会如此不同。
我正在调用 Keras 的
model.fit()
来训练模型,并调用 model.evaluate()
来获取损失和准确性。
以下是我的一些超参数:
loss_function: categorical_crossentropy
optimizer: Adadelta
epochs: 12
mini_batch_size: 128
train_size: 600
validate_size: 400
更新2018年6月26日
我想独立于我自己的代码来测试更多线程的准确性提高,因此我运行了 Keras MNIST CNN,并根据可重现开发的 Keras FAQ 进行了一些更改。我的测试代码可以在这个gist中看到。要点中两个 Python 文件之间的唯一区别是第 80、90 和 91 行。取消注释这些行会强制 TensorFlow 后端在单个线程上运行。
我跑了
mnist_cnn_single_threaded.py
三遍,mnist_cnn_multi_threaded.py
三遍。结果可以在相同的要点中看到。它们与我昨天在本地和 EC2 中运行我自己的模型时发现的结果相符。
测试结果
这是我根据 NPE 评论得出的测试结果。使用显式设置但默认的
tf.ConfigProto()
运行会产生与根本不设置线程值类似的结果。在下面的图表和表格中,“线程”相当于将 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
在准确性和损失方面产生显着差异的唯一情况是将线程显式设置为 1。
更新2018年6月27日
这似乎只是 Keras 的 TensorFlow 后端的问题。我尝试使用 Theano 后端进行测试,使用以下选项强制使用单线程,但我没有注意到准确性/丢失问题。
os.environ['OMP_NUM_THREADS'] = '1'
os.environ['THEANO_FLAGS'] = "device=cpu,force_device=True,openmp=False"
使用并行处理时,神经网络更加高效。当您将线程计数设置为 1 时,需要更长的时间并且无法有效收敛。导致准确性差更多损失等。请参见此处: https://arxiv.org/pdf/1802.09941