我正在学习使用TensorFlow的tf.data API,我发现它大大降低了我的代码速度,以每个历元的时间来衡量.我想,这与它应该做的正好相反.我写了一个简单的线性回归程序来测试它.

Tl;Dr:如果你使用的是整批训练,那么使用tf.data000个训练数据,tf.data个历元的时间会减少大约10倍.如果使用较小的批次,情况会更糟.500个训练数据的情况正好相反.

My question:发生了什么事?我的实现有缺陷吗?我读过的其他资料有tf.data种,速度提高了约30%.

import tensorflow as tf 
import numpy as np
import timeit

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
tf.logging.set_verbosity(tf.logging.ERROR)

n_epochs = 10
input_dimensions_list = [10]

def function_to_approximate(x):
    return np.dot(x, random_covector).astype(np.float32) + np.float32(.01) * np.random.randn(1,1).astype(np.float32)

def regress_without_tfData(n_epochs, input_dimension, training_inputs, training_labels):
    tf.reset_default_graph()
    weights = tf.get_variable("weights", initializer=np.random.randn(input_dimension, 1).astype(np.float32))

    X = tf.placeholder(tf.float32, shape=(None, input_dimension), name='X')
    Y = tf.placeholder(tf.float32, shape=(None, 1), name='Y')
    prediction = tf.matmul(X,weights)
    loss = tf.reduce_mean(tf.square(tf.subtract(prediction, Y)))
    loss_op = tf.train.AdamOptimizer(.01).minimize(loss)

    init = tf.global_variables_initializer()

    with tf.Session() as sess:
        sess.run(init)
        for _ in range(n_epochs):
            sess.run(loss_op, feed_dict={X: training_inputs, Y:training_labels})

def regress_with_tfData(n_epochs, input_dimension, training_inputs, training_labels, batch_size):
    tf.reset_default_graph()
    weights = tf.get_variable("weights", initializer=np.random.randn(input_dimension, 1).astype(np.float32))

    X,Y = data_set.make_one_shot_iterator().get_next()

    prediction = tf.matmul(X, weights)
    loss = tf.reduce_mean(tf.square(tf.subtract(prediction, Y)))
    loss_op = tf.train.AdamOptimizer(.01).minimize(loss)

    init = tf.global_variables_initializer()

    with tf.Session() as sess:
        sess.run(init)
        while True:
            try: 
                sess.run(loss_op)
            except tf.errors.OutOfRangeError:
                break

for input_dimension in input_dimensions_list:
    for data_size in [500, 100000]:

        training_inputs = np.random.randn(data_size, input_dimension).astype(np.float32)
        random_covector = np.random.randint(-5, 5, size=(input_dimension, 1))
        training_labels = function_to_approximate(training_inputs)

        print("Not using tf.data, with data size "
        "{}, input dimension {} and training with "
        "a full batch, it took an average of "
        "{} seconds to run {} epochs.\n".
            format(
                data_size,
                input_dimension,
                timeit.timeit(
                    lambda: regress_without_tfData(
                        n_epochs, input_dimension, 
                        training_inputs, training_labels
                    ), 
                    number=3
                ),
                n_epochs))

for input_dimension in input_dimensions_list:
    for data_size, batch_size in [(500, 50), (500, 500), (100000, 50), (100000, 100000)]:

        training_inputs = np.random.randn(data_size, input_dimension).astype(np.float32)
        random_covector = np.random.randint(-5, 5, size=(input_dimension, 1))
        training_labels = function_to_approximate(training_inputs)

        data_set = tf.data.Dataset.from_tensor_slices((training_inputs, training_labels))
        data_set = data_set.repeat(n_epochs)
        data_set = data_set.batch(batch_size)

        print("Using tf.data, with data size "
        "{}, and input dimension {}, and training with "
        "batch size {}, it took an average of {} seconds "
        "to run {} epochs.\n".
            format(
                data_size,
                input_dimension,
                batch_size,
                timeit.timeit(
                    lambda: regress_with_tfData(
                        n_epochs, input_dimension, 
                        training_inputs, training_labels, 
                        batch_size
                    ),
                    number=3
                )/3,
                n_epochs
            ))

这对我来说是:

不使用tf.数据,数据大小为500,输入维度10和培训

不使用tf.数据,数据大小为100000,输入维度10和

使用tf.数据,数据大小为500,输入维度为10,以及

使用tf.数据,数据大小为500,输入维度为10,以及

使用tf.数据,数据大小为100000,输入维度为10,以及

使用tf.数据,数据大小为100000,输入维度为10,以及

弗雷德·古思指出了一个重要的问题.不过,这对结果影响不大.

推荐答案

那是因为你在比较苹果和香蕉.

一方面,当使用占位符时,您提供的是一个整体张量.另一方面,当使用Dataset时,将张量切片为单个样本.这是非常不同的.

Dataset管道提供单岩石占位符张量的等效方法是使用tf.data.Dataset.from_tensors.When I use 102 in your example, I get similar (actually smaller) computation times than with placeholders.

如果要使用from_tensor_slices来比较更复杂的管道,应该使用占位符进行公平比较.例如,洗牌你的数据.在切片上添加一些预处理.我毫不怀疑,你会观察到让人们转向这条管道的性能提升.

Python-3.x相关问答推荐

使用Python装载. iso文件

这是重命名极地df列的最好方式吗?

无法使用Python slack 螺栓SDK读取在 slack 通道中收到的消息

将数据帧扩展为矩阵索引

如何使用TensorFlow Keras子类化来构建和训练模型

Pandas -我们如何在一行中应用多个要求

将列表转换为 pandas 数据框,其中列表包含字典

隐藏Cartopy中高纬度非矩形投影的右侧轴(纬度)标签

删除给定数组中所有元素为True的所有子数组

过滤阈值大小数据以使用 Pyspark 或 Python 读取

Python.在循环中填充字典的问题

pip 找不到最新的软件包版本

活动屏幕上的 PyQt4 中心窗口

运行 PyCharm 测试时如何解决django.core.exceptions.ImproperlyConfigured:找不到 GDAL 库?

基本 Flask 应用程序未运行(TypeError:模块中缺少必填字段type_ignores)

virtualenv virtualenvwrapper virtualenv:错误:无法识别的参数:--no-site-packages

发送Electron邮件时的 MIMEText UTF-8 编码问题

为什么 2to3 将 mydict.keys() 更改为 list(mydict.keys())?

ImportError:无法在 PyQt5 中导入名称QStringList

为现有项目创建virtualenv