2017-09-11 93 views
2

我想为10级图像分类任务训练一个简单的多层感知器,这是Udacity深度学习课程任务的一部分。更确切地说,任务是对各种字体所呈现的字母进行分类(数据集称为notMNIST)。在Tensorflow培训中非常低的GPU使用率

我最终得到的代码看起来相当简单,但无论我在训练期间总是获得非常低的GPU使用率。我用GPU-Z测量负载,并显示只有25-30%。

这里是我当前的代码:

graph = tf.Graph() 
with graph.as_default(): 
    tf.set_random_seed(52) 

    # dataset definition 
    dataset = Dataset.from_tensor_slices({'x': train_data, 'y': train_labels}) 
    dataset = dataset.shuffle(buffer_size=20000) 
    dataset = dataset.batch(128) 
    iterator = dataset.make_initializable_iterator() 
    sample = iterator.get_next() 
    x = sample['x'] 
    y = sample['y'] 

    # actual computation graph 
    keep_prob = tf.placeholder(tf.float32) 
    is_training = tf.placeholder(tf.bool, name='is_training') 

    fc1 = dense_batch_relu_dropout(x, 1024, is_training, keep_prob, 'fc1') 
    fc2 = dense_batch_relu_dropout(fc1, 300, is_training, keep_prob, 'fc2') 
    fc3 = dense_batch_relu_dropout(fc2, 50, is_training, keep_prob, 'fc3') 
    logits = dense(fc3, NUM_CLASSES, 'logits') 

    with tf.name_scope('accuracy'): 
     accuracy = tf.reduce_mean(
      tf.cast(tf.equal(tf.argmax(y, 1), tf.argmax(logits, 1)), tf.float32), 
     ) 
     accuracy_percent = 100 * accuracy 

    with tf.name_scope('loss'): 
     loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y)) 

    update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS) 
    with tf.control_dependencies(update_ops): 
     # ensures that we execute the update_ops before performing the train_op 
     # needed for batch normalization (apparently) 
     train_op = tf.train.AdamOptimizer(learning_rate=1e-3, epsilon=1e-3).minimize(loss) 

with tf.Session(graph=graph) as sess: 
    tf.global_variables_initializer().run() 
    step = 0 
    epoch = 0 
    while True: 
     sess.run(iterator.initializer, feed_dict={}) 
     while True: 
      step += 1 
      try: 
       sess.run(train_op, feed_dict={keep_prob: 0.5, is_training: True}) 
      except tf.errors.OutOfRangeError: 
       logger.info('End of epoch #%d', epoch) 
       break 

     # end of epoch 
     train_l, train_ac = sess.run(
      [loss, accuracy_percent], 
      feed_dict={x: train_data, y: train_labels, keep_prob: 1, is_training: False}, 
     ) 
     test_l, test_ac = sess.run(
      [loss, accuracy_percent], 
      feed_dict={x: test_data, y: test_labels, keep_prob: 1, is_training: False}, 
     ) 
     logger.info('Train loss: %f, train accuracy: %.2f%%', train_l, train_ac) 
     logger.info('Test loss: %f, test accuracy: %.2f%%', test_l, test_ac) 

     epoch += 1 

这里是我试过到目前为止:

  1. 我改变了输入管道从简单到feed_dicttensorflow.contrib.data.Dataset。据我所知,它应该考虑输入的效率,例如将数据加载到单独的线程中。所以不应该有任何与输入有关的瓶颈。

  2. 我收集了这里建议的痕迹:https://github.com/tensorflow/tensorflow/issues/1824#issuecomment-225754659 但是,这些痕迹并没有真正显示任何有趣的东西。 > 90%的列车步骤是matmul操作。

  3. 更改批量大小。当我将它从128更改为512时,负载从〜30%增加到〜38%,当我进一步增加到2048时,负载降至〜45%。我有6Gb GPU内存,数据集是单通道28x28图像。我真的应该使用这么大的批量?我应该进一步增加它吗?

一般来说,我应该担心低负荷,是否真的表明我训练效率低下?

下面是批量处理128张图像的GPU-Z屏幕截图。当我在每个纪元后测量整个数据集的准确度时,您可以看到偶尔出现的尖峰到100%的低负载。

GPU load

回答

4

MNIST规模的网络是微小的,很难实现高GPU(或CPU)的效率对他们来说,我认为30%是不寻常的应用程序。在批量更大的情况下,您可以获得更高的计算效率,这意味着您可以每秒处理更多示例,但是您也将获得更低的统计效率,这意味着您需要处理更多示例才能达到目标准确度。所以这是一个折衷。对于像你这样的小型角色模型,统计效率在100之后会很快下降,所以可能不值得尝试增加批量来训练。为了推断,你应该使用最大的批量大小。

+0

谢谢你的快速回复!雅罗斯拉夫,你能提供一个暗示为什么会发生这种情况吗?我的假设如下:只要当时只有一个训练步骤完成,就没有足够的计算来饱和所有的GPU核心?所以,当我提供128个图像批次时,它已经尽可能并行运行,但它可以做更多。 –

+1

是的,没有足够的计算来饱和内核。另外,如果计算量相对于所需的内存带宽或者内核启动的开销很小,那么效率会很低。更重要的是要关注整体效率而不是GPU占用率。 TitanX大型matmul可以获得10T /秒,但在许多应用中,网络运行速度低于1Top /秒,因此不到峰值效率的10% –

0

在我的nVidia GTX 1080上,如果我在MNIST数据库上使用卷积神经网络,GPU负载约为68%。

如果我切换到一个简单的非卷积网络,那么GPU负载约为20%。

您可以通过在教程Building Autoencoders in Keras by Francis Chollet中继续构建更高级的模型来复制这些结果。