Я просто научился использовать tf.data
API, и я обнаружил, что он значительно замедляет мой код, измеряемый во времени за эпоху. Я думаю, это противоположность тому, что он должен был делать. Я написал простую программу линейной регрессии, чтобы проверить ее.
Tl; Dr: С 100 000 данных обучения tf.data
замедляет время в эпоху примерно на десять раз, если вы используете полное пакетное обучение. Хуже, если вы используете меньшие партии. Противоположно верно 500 данных обучения.
Мой вопрос: что происходит? Является ли моя реализация ошибочной? Другие источники, которые я прочитал, имеют 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.data, с размером данных 500, размером ввода 10 и тренировкой с полной партией, потребовалось в среднем 0,20243382899980134 секунд для запуска 10 эпох.
Не используя tf.data, размер данных 100000, размер ввода 10 и тренировку с полной партией, для выполнения 10 эпох потребовалось в среднем 0.2431719040000644 секунды.
Используя tf.data с размером данных 500 и размером ввода 10 и тренировкой с размером партии 50, для выполнения 10 эпох потребовалось в среднем 0.09512088866661846 секунд.
Используя tf.data, с размером данных 500 и размером ввода 10 и тренировкой с размером партии 500, потребовалось в среднем 0.07286913600000844 секунд для запуска 10 эпох.
Используя tf.data, с размером данных 100000 и размером ввода 10, и тренировкой с размером партии 50, потребовалось в среднем 4,421892363666605 секунд для запуска 10 эпох.
Используя tf.data, с размером данных 100000 и размером ввода 10 и тренировкой с размером партии 100000, потребовалось в среднем 2,2555197536667038 секунд для запуска 10 эпох.
Изменить: Исправлена важная проблема, о которой указал Фред Гут. Однако это не сильно повлияло на результаты.