Как * на самом деле * читать данные CSV в TensorFlow?
Я относительно новичок в мире TensorFlow и довольно озадачен тем, как вы на самом деле читали CSV-данные в пригодный для использования пример тензоров-меток в TensorFlow. Пример из учебника TensorFlow по чтению CSV-данных довольно фрагментирован, и вы получаете только часть возможности тренироваться по CSV-данным.
Здесь мой код, который я собрал вместе, основывался на этом учебнике CSV:
from __future__ import print_function
import tensorflow as tf
def file_len(fname):
with open(fname) as f:
for i, l in enumerate(f):
pass
return i + 1
filename = "csv_test_data.csv"
# setup text reader
file_length = file_len(filename)
filename_queue = tf.train.string_input_producer([filename])
reader = tf.TextLineReader(skip_header_lines=1)
_, csv_row = reader.read(filename_queue)
# setup CSV decoding
record_defaults = [[0],[0],[0],[0],[0]]
col1,col2,col3,col4,col5 = tf.decode_csv(csv_row, record_defaults=record_defaults)
# turn features back into a tensor
features = tf.stack([col1,col2,col3,col4])
print("loading, " + str(file_length) + " line(s)\n")
with tf.Session() as sess:
tf.initialize_all_variables().run()
# start populating filename queue
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord)
for i in range(file_length):
# retrieve a single instance
example, label = sess.run([features, col5])
print(example, label)
coord.request_stop()
coord.join(threads)
print("\ndone loading")
И вот краткий пример из файла CSV, который я загружаю - довольно основные данные - 4 столбца функций и 1 столбец ярлыков:
0,0,0,0,0
0,15,0,0,0
0,30,0,0,0
0,45,0,0,0
Весь вышеприведенный код печатает каждый пример из файла CSV, один за другим, который, хотя и хорош, довольно нищий для обучения.
То, с чем я борюсь, - это то, как вы фактически превращаете эти индивидуальные примеры, загруженные один за другим, в набор учебных материалов. Например, здесь ноутбук, над которым я работал в курсе Udacity Deep Learning. Я в основном хочу взять данные CSV, которые я загружаю, и перевернуть его на что-то вроде train_dataset и train_labels:
def reformat(dataset, labels):
dataset = dataset.reshape((-1, image_size * image_size)).astype(np.float32)
# Map 2 to [0.0, 1.0, 0.0 ...], 3 to [0.0, 0.0, 1.0 ...]
labels = (np.arange(num_labels) == labels[:,None]).astype(np.float32)
return dataset, labels
train_dataset, train_labels = reformat(train_dataset, train_labels)
valid_dataset, valid_labels = reformat(valid_dataset, valid_labels)
test_dataset, test_labels = reformat(test_dataset, test_labels)
print('Training set', train_dataset.shape, train_labels.shape)
print('Validation set', valid_dataset.shape, valid_labels.shape)
print('Test set', test_dataset.shape, test_labels.shape)
Я пробовал использовать tf.train.shuffle_batch
, как это, но это просто необъяснимо зависает:
for i in range(file_length):
# retrieve a single instance
example, label = sess.run([features, colRelevant])
example_batch, label_batch = tf.train.shuffle_batch([example, label], batch_size=file_length, capacity=file_length, min_after_dequeue=10000)
print(example, label)
Итак, чтобы подвести итог, вот мои вопросы:
- Что мне не хватает в этом процессе?
- Похоже, есть какая-то ключевая интуиция, которую я не знаю о том, как правильно построить входной конвейер.
- Есть ли способ избежать необходимости знать длину файла CSV?
- Чувствуется довольно неудобным, чтобы знать количество строк, которые вы хотите обработать (строка
for я in range(file_length)
выше)
Редактировать: Как только Ярослав указал, что я, вероятно, смешивал императивные и графопостроительные детали здесь, он стал становиться яснее. Мне удалось собрать следующий код, который, я думаю, ближе к тому, что обычно делалось при подготовке модели из CSV (за исключением любого кода обучения модели):
from __future__ import print_function
import numpy as np
import tensorflow as tf
import math as math
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('dataset')
args = parser.parse_args()
def file_len(fname):
with open(fname) as f:
for i, l in enumerate(f):
pass
return i + 1
def read_from_csv(filename_queue):
reader = tf.TextLineReader(skip_header_lines=1)
_, csv_row = reader.read(filename_queue)
record_defaults = [[0],[0],[0],[0],[0]]
colHour,colQuarter,colAction,colUser,colLabel = tf.decode_csv(csv_row, record_defaults=record_defaults)
features = tf.stack([colHour,colQuarter,colAction,colUser])
label = tf.stack([colLabel])
return features, label
def input_pipeline(batch_size, num_epochs=None):
filename_queue = tf.train.string_input_producer([args.dataset], num_epochs=num_epochs, shuffle=True)
example, label = read_from_csv(filename_queue)
min_after_dequeue = 10000
capacity = min_after_dequeue + 3 * batch_size
example_batch, label_batch = tf.train.shuffle_batch(
[example, label], batch_size=batch_size, capacity=capacity,
min_after_dequeue=min_after_dequeue)
return example_batch, label_batch
file_length = file_len(args.dataset) - 1
examples, labels = input_pipeline(file_length, 1)
with tf.Session() as sess:
tf.initialize_all_variables().run()
# start populating filename queue
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord)
try:
while not coord.should_stop():
example_batch, label_batch = sess.run([examples, labels])
print(example_batch)
except tf.errors.OutOfRangeError:
print('Done training, epoch reached')
finally:
coord.request_stop()
coord.join(threads)
Ответы
Ответ 1
Я думаю, что вы смешиваете императивные и графические детали. Операция tf.train.shuffle_batch
создает новую очередь node, а один node может использоваться для обработки всего набора данных. Поэтому я думаю, что вы висели, потому что создали цепочку из shuffle_batch
очередей в цикле for и не запускали для них очереди.
Нормальное использование используемого конвейера выглядит следующим образом:
- Добавьте узлы как
shuffle_batch
для ввода конвейера
- (необязательно, чтобы предотвратить непреднамеренное изменение графика) финализировать график
--- конец построения графика, начало императивного программирования -
-
tf.start_queue_runners
-
while(True): session.run()
Чтобы быть более масштабируемым (чтобы избежать Python GIL), вы могли бы сгенерировать все свои данные с помощью конвейера TensorFlow. Однако, если производительность не является критичной, вы можете подключить массив numpy к входному конвейеру с помощью slice_input_producer.
Вот пример с некоторыми узлами Print
, чтобы увидеть, что происходит (сообщения в Print
идут в stdout, когда node выполняется)
tf.reset_default_graph()
num_examples = 5
num_features = 2
data = np.reshape(np.arange(num_examples*num_features), (num_examples, num_features))
print data
(data_node,) = tf.slice_input_producer([tf.constant(data)], num_epochs=1, shuffle=False)
data_node_debug = tf.Print(data_node, [data_node], "Dequeueing from data_node ")
data_batch = tf.batch([data_node_debug], batch_size=2)
data_batch_debug = tf.Print(data_batch, [data_batch], "Dequeueing from data_batch ")
sess = tf.InteractiveSession()
sess.run(tf.initialize_all_variables())
tf.get_default_graph().finalize()
tf.start_queue_runners()
try:
while True:
print sess.run(data_batch_debug)
except tf.errors.OutOfRangeError as e:
print "No more inputs."
Вы должны увидеть что-то вроде этого
[[0 1]
[2 3]
[4 5]
[6 7]
[8 9]]
[[0 1]
[2 3]]
[[4 5]
[6 7]]
No more inputs.
Номера "8, 9" не заполняли полную партию, поэтому они не были получены. Кроме того, tf.Print
печатаются на sys.stdout, поэтому они отображаются отдельно в терминале для меня.
PS: минимальное подключение batch
к инициализированной вручную очереди находится в github issue 2193
Кроме того, для целей отладки вы можете установить timeout
на свой сеанс, чтобы ваш IPython-ноутбук не зависал в пустых очередях очереди. Я использую эту вспомогательную функцию для своих сеансов
def create_session():
config = tf.ConfigProto(log_device_placement=True)
config.gpu_options.per_process_gpu_memory_fraction=0.3 # don't hog all vRAM
config.operation_timeout_in_ms=60000 # terminate on long hangs
# create interactive session to register a default session
sess = tf.InteractiveSession("", config=config)
return sess
Заметки о масштабируемости:
-
tf.constant
вставляет копию ваших данных в график. Существует фундаментальный предел в 2 ГБ по размеру определения Графа, так что верхний предел по размеру данных
- Вы можете обойти это ограничение, используя
v=tf.Variable
и сохранить данные там, запустив v.assign_op
с помощью tf.placeholder
с правой стороны и подав массив numpy в placeholder (feed_dict
)
- Это все еще создает две копии данных, поэтому для экономии памяти вы можете создать собственную версию
slice_input_producer
, которая работает с массивами numpy, и загружает строки по одному с помощью feed_dict
Ответ 2
Или вы можете попробовать это, код загружает набор данных Iris в тензорный поток с использованием pandas и numpy, а в сеансе печатается простой один вывод нейронов. Надеюсь, что это поможет в базовом понимании.... [Я не добавил путь к ярким ярлыкам декодирования].
import tensorflow as tf
import numpy
import pandas as pd
df=pd.read_csv('/home/nagarjun/Desktop/Iris.csv',usecols = [0,1,2,3,4],skiprows = [0],header=None)
d = df.values
l = pd.read_csv('/home/nagarjun/Desktop/Iris.csv',usecols = [5] ,header=None)
labels = l.values
data = numpy.float32(d)
labels = numpy.array(l,'str')
#print data, labels
#tensorflow
x = tf.placeholder(tf.float32,shape=(150,5))
x = data
w = tf.random_normal([100,150],mean=0.0, stddev=1.0, dtype=tf.float32)
y = tf.nn.softmax(tf.matmul(w,x))
with tf.Session() as sess:
print sess.run(y)
Ответ 3
Вы можете использовать новейший API tf.data:
dataset = tf.contrib.data.make_csv_dataset(filepath)
iterator = dataset.make_initializable_iterator()
columns = iterator.get_next()
with tf.Session() as sess:
sess.run([iteator.initializer])
Ответ 4
Если бы кто-нибудь пришел сюда, чтобы найти простой способ прочитать абсолютно большие и осколочные CSV файлы в tf.estimator API, тогда, пожалуйста, см. Ниже мой код
CSV_COLUMNS = ['ID','text','class']
LABEL_COLUMN = 'class'
DEFAULTS = [['x'],['no'],[0]] #Default values
def read_dataset(filename, mode, batch_size = 512):
def _input_fn(v_test=False):
# def decode_csv(value_column):
# columns = tf.decode_csv(value_column, record_defaults = DEFAULTS)
# features = dict(zip(CSV_COLUMNS, columns))
# label = features.pop(LABEL_COLUMN)
# return add_engineered(features), label
# Create list of files that match pattern
file_list = tf.gfile.Glob(filename)
# Create dataset from file list
#dataset = tf.data.TextLineDataset(file_list).map(decode_csv)
dataset = tf.contrib.data.make_csv_dataset(file_list,
batch_size=batch_size,
column_names=CSV_COLUMNS,
column_defaults=DEFAULTS,
label_name=LABEL_COLUMN)
if mode == tf.estimator.ModeKeys.TRAIN:
num_epochs = None # indefinitely
dataset = dataset.shuffle(buffer_size = 10 * batch_size)
else:
num_epochs = 1 # end-of-input after this
batch_features, batch_labels = dataset.make_one_shot_iterator().get_next()
#Begins - Uncomment for testing only -----------------------------------------------------<
if v_test == True:
with tf.Session() as sess:
print(sess.run(batch_features))
#End - Uncomment for testing only -----------------------------------------------------<
return add_engineered(batch_features), batch_labels
return _input_fn
Пример использования в TF.estimator:
train_spec = tf.estimator.TrainSpec(input_fn = read_dataset(
filename = train_file,
mode = tf.estimator.ModeKeys.TRAIN,
batch_size = 128),
max_steps = num_train_steps)