Tensorflow 训练期间 GPU 使用率非常低
Very low GPU usage during training in Tensorflow
我正在尝试为 10-class 图像 class 化任务训练一个简单的多层感知器,这是 Udacity 深度学习课程作业的一部分。更准确地说,任务是 class 验证从各种字体渲染的字母(数据集称为 notMNIST)。
我最终得到的代码看起来相当简单,但无论如何我在训练期间总是得到非常低的 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
这是我到目前为止尝试过的:
我将输入管道从简单的 feed_dict
更改为 tensorflow.contrib.data.Dataset
。据我了解,它应该负责输入的效率,例如在单独的线程中加载数据。所以不应该有任何与输入相关的瓶颈。
我按照此处的建议收集了痕迹:https://github.com/tensorflow/tensorflow/issues/1824#issuecomment-225754659
然而,这些痕迹并没有真正显示出任何有趣的东西。 >90% 的训练步骤是 matmul 操作。
更改了批量大小。当我将它从 128 更改为 512 时,负载从 ~30% 增加到 ~38%,当我将它进一步增加到 2048 时,负载增加到 ~45%。我有 6Gb GPU 内存,数据集是单通道 28x28 图像。我真的应该使用这么大的批量吗?我应该进一步增加吗?
一般来说,我应该担心低负荷吗,这真的是我训练效率低下的标志吗?
这是 GPU-Z 屏幕截图,批次中有 128 张图像。当我在每个纪元后测量整个数据集的准确性时,您可以看到低负载偶尔会达到 100%。
MNIST 大小的网络很小,很难为它们实现高 GPU(或 CPU)效率,我认为 30% 对于您的应用程序来说并不罕见。您将获得更高的计算效率和更大的批量大小,这意味着您每秒可以处理更多的示例,但您也会获得更低的统计效率,这意味着您需要处理更多的示例才能达到目标准确性。所以这是一个权衡。对于像您这样的小角色模型,统计效率在 100 后下降得非常快,因此可能不值得尝试增加批处理大小来进行训练。对于推理,您应该使用最大的批量大小。
在我的 nVidia GTX 1080 上,如果我在 MNIST 数据库上使用卷积神经网络,GPU 负载约为 68%。
如果我切换到简单的非卷积网络,则 GPU 负载约为 20%。
您可以通过在教程中依次构建更高级的模型来复制这些结果 Building Autoencoders in Keras by Francis Chollet。
我正在尝试为 10-class 图像 class 化任务训练一个简单的多层感知器,这是 Udacity 深度学习课程作业的一部分。更准确地说,任务是 class 验证从各种字体渲染的字母(数据集称为 notMNIST)。
我最终得到的代码看起来相当简单,但无论如何我在训练期间总是得到非常低的 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
这是我到目前为止尝试过的:
我将输入管道从简单的
feed_dict
更改为tensorflow.contrib.data.Dataset
。据我了解,它应该负责输入的效率,例如在单独的线程中加载数据。所以不应该有任何与输入相关的瓶颈。我按照此处的建议收集了痕迹:https://github.com/tensorflow/tensorflow/issues/1824#issuecomment-225754659 然而,这些痕迹并没有真正显示出任何有趣的东西。 >90% 的训练步骤是 matmul 操作。
更改了批量大小。当我将它从 128 更改为 512 时,负载从 ~30% 增加到 ~38%,当我将它进一步增加到 2048 时,负载增加到 ~45%。我有 6Gb GPU 内存,数据集是单通道 28x28 图像。我真的应该使用这么大的批量吗?我应该进一步增加吗?
一般来说,我应该担心低负荷吗,这真的是我训练效率低下的标志吗?
这是 GPU-Z 屏幕截图,批次中有 128 张图像。当我在每个纪元后测量整个数据集的准确性时,您可以看到低负载偶尔会达到 100%。
MNIST 大小的网络很小,很难为它们实现高 GPU(或 CPU)效率,我认为 30% 对于您的应用程序来说并不罕见。您将获得更高的计算效率和更大的批量大小,这意味着您每秒可以处理更多的示例,但您也会获得更低的统计效率,这意味着您需要处理更多的示例才能达到目标准确性。所以这是一个权衡。对于像您这样的小角色模型,统计效率在 100 后下降得非常快,因此可能不值得尝试增加批处理大小来进行训练。对于推理,您应该使用最大的批量大小。
在我的 nVidia GTX 1080 上,如果我在 MNIST 数据库上使用卷积神经网络,GPU 负载约为 68%。
如果我切换到简单的非卷积网络,则 GPU 负载约为 20%。
您可以通过在教程中依次构建更高级的模型来复制这些结果 Building Autoencoders in Keras by Francis Chollet。