Python 使用Tensorflow数据集API读取TFRecords文件时,预处理输入数据会减慢输入管道的速度

Python 使用Tensorflow数据集API读取TFRecords文件时,预处理输入数据会减慢输入管道的速度,python,performance,tensorflow,tensorflow-gpu,tfrecord,Python,Performance,Tensorflow,Tensorflow Gpu,Tfrecord,我使用Tensorflow数据集API读取TFRecords文件,但GPU的使用率仍然很低(10%)。我认为原因是我在将数据送入sess.run()之前对其进行了预处理。下面是我的代码。 1.从3个单独的文件创建数据集 tf.reset_default_graph() # The content of TFRecords files is that each row is an array. Calculate total rows. n_total_row = sum(1 for _ in

我使用Tensorflow数据集API读取TFRecords文件,但GPU的使用率仍然很低(10%)。我认为原因是我在将数据送入
sess.run()
之前对其进行了预处理。下面是我的代码。
1.从3个单独的文件创建数据集

tf.reset_default_graph()

# The content of TFRecords files is that each row is an array. Calculate total rows.
n_total_row = sum(1 for _ in tf.python_io.tf_record_iterator(epd))

def get_epd_dataset(filename):
    dataset = tf.data.TFRecordDataset(filename)
    def _parse_function(example_proto):
        keys_to_features = {'data':tf.VarLenFeature(tf.int64)}
        parsed_features = tf.parse_single_example(example_proto, keys_to_features)
    return tf.sparse_tensor_to_dense(parsed_features['data'])
    # Parse the record into tensors.
    dataset = dataset.map(_parse_function)
    return dataset

# There are 3 essential files comprising input data. It reads 3 seperate
# files "epd", "y_id", "x_feat" into 3 separate dataset respectively, and 
# uses `Dataset.zip()` to combine these 3 separate files into 1 dataset.
epd_ds = get_epd_dataset(epd)
n_lexicon, id_ds = get_id_dataset(y_id)
feat_ds = get_feat_dataset(x_feat)
data_ds = tf.data.Dataset.zip((feat_ds, epd_ds, id_ds))

# Shuffle the dataset
data_ds = data_ds.shuffle(buffer_size=n_total_row, reshuffle_each_iteration=True)
# Repeat the input indefinitly
data_ds = data_ds.repeat(epoch)
# Generate batches
data_ds = data_ds.batch(1)
# Create a one-shot iterator
iterator = data_ds.make_one_shot_iterator()
data_iter = iterator.get_next()
二,。建立一个Tensorflow图

n_input = DIM*(LEFT+1+RIGHT)
n_classes = n_lexicon

mlp = MultiLayerPerceptron.MultiLayerPerceptron(DIM*(LEFT+1+RIGHT), n_lexicon)
# tf Graph input
X = tf.placeholder("float", [None, n_input])
Y = tf.placeholder("float", [None, n_classes])
logits = mlp.multilayer_perceptron(X, dropout_mode)
loss_op = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=Y), name='loss_op')
optimizer = tf.train.AdamOptimizer(learning_rate=lr)
train_op = optimizer.minimize(loss_op, name='train_op')
三,。从
data\u iter
生成数据并运行TF会话

sess = tf.Session()
# Initialization
sess.run(tf.global_variables_initializer())
for e in range(1, epoch+1):
    while True:
        try:
            # Get data from dataset iterator 
            tmp = sess.run([data_iter])[0]
            # a,b,c are a row from 3 serapate files.
            a = tmp[0].flatten()
            b = tmp[1].flatten()
            c = tmp[2].flatten()

            # I believe this step slows down my input pipeline.
            x_train, y_train = _data_generate(mlp, b, d, c)
            _, c = sess.run([train_op, loss_op], feed_dict={X: x_train,
                                                            Y: y_train})
        except tf.errors.OutOfRangeError:
            break
sess.close() 
我的代码达到了GPU使用量的10~15%。我认为原因是
\u data\u generate()
在处理numpy数组上花费了太多时间。 但我不知道如何改进我的管道。以下是我的问题

  • 根据和,我认为使用Dataset API和TFRecords文件是解决这个GPU使用率低的问题的最佳选择。或者我应该首先使用python多线程将数据馈送到缓冲区,然后将数据馈送到
    sess.run()
    。我没有选择后一种解决方案,因为我提到了这一点
  • 我们发现,使用tf.FIFOQueue和tf.train.queue_runner在使用大输入和每秒更高采样率的处理时,无法使多个当前代GPU饱和

  • 我认为将
    \u data\u generate()
    放入
    \u parse\u function()
    可以解决这个问题,bucause Tensorflow处理的是数据部分的预处理,而不是python。但是我不知道怎么做,因为
    \u data\u generate()
    需要从3个单独的文件中提取3行。有人知道怎么做吗

  • 有没有其他方法可以解决我的GPU使用率低的问题


  • 谢谢。

    您能分享
    \u data\u generate
    功能的代码吗? 我看不出它有什么作用

    正如您所指出的,性能可能会因为RAM GPU而损失 内存交换和tensorflow操作与Python操作的混合

    与其通过
    sess.run()
    自己运行迭代器
    data\u iter
    ,执行numpy操作,然后执行训练步骤,不如将
    data\u iter
    作为输入传递到神经网络图中-它应该替换占位符。 (只需制作一个函数,使用
    data\u iter
    作为参数来构造图形)

    我认为将_data _generate()放入_parse _function()可以解决这个问题 他的问题是,bucause Tensorflow处理预处理数据部分,但不处理>python。但是我不知道怎么做,因为_data_generate()需要3个不同文件中的3>行。有人知道怎么做吗

    正确的方法是从文件中创建3个数据集,对它们进行解码、压缩,然后将迭代器作为处理图的输入传递给压缩后的数据集。你几乎要这么做了

    还有,; 只要可能/需要,就尝试执行多线程。 在这里:

    你应使用:

    dataset.map(_parse_function, num_threads=<MORE THAN ONE>)
    
    dataset.map(\u parse\u函数,num\u threads=)
    
    其中,
    是大于1的整数。 在您的情况下,我将从8个线程开始(看看GPU是否为100%)


    检查dis并告诉我它是否正常

    我假设您的示例使用了您模型的简化版本,否则GPU几乎总是在下一批准备就绪之前终止其工作

    每个数据集和transofrmation管道都有自己的特殊性,很难提供明确的答案,但这里可能有一些值得研究的问题:

    • 您不应该明确地计算数据的值,也不应该再使用占位符和提要。.make_one_shot_iterator().get_next()返回的值已经是模型的输入节点,而不是占位符变量。这将把输入管道与模型粘在一起,避免在tensorflow CPU、python和tensorflow GPU内存区域之间来回发送数据。在您的session.run()调用中,您不需要指定任何输入值,模型将根据需要自动在数据集上输入自己
    • 我不认为TFRecord文件在随机访问时应该很快,因为元素大小未知。在您的案例中,您似乎还使用了三次随机访问:epd、feats和元数据
    • 你有没有指示tensorflow在什么地方使用?否则,tensorflow可能会在加载和处理下一批之前等待处理当前批次
    • 您可能需要检查map函数的多个工作进程是否正在等待某些资源(磁盘IO、CPU时间、锁定对象?)
    • data API很难调试,而且不太实用(说真的,它怎么可能不知道关于张量的任何信息?),您可能想看看tensorpack库或旧的tensorflow队列数据加载API

    不幸的是,增加线程数并没有增加GPU实用程序。我仍然认为从CPU到GPU的数据传输是造成瓶颈的原因。我遇到了一个问题,CPU无法快速获取大量数据。但是,在我应用@Xyz的建议后,来自CPU的瓶颈显著减少:)
    dataset.map(_parse_function, num_threads=<MORE THAN ONE>)