Як * насправді * читати дані CSV у TensorFlow?


83

Я відносно новачок у світі 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 i 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) 

Я випробував ваш код, але не можу змусити його працювати. Ви щось визначили, чого мені не вистачає? Дякую. Я розмістив тут тему, щоб ви могли отримати докладнішу інформацію: stackoverflow.com/questions/40143019/…
Посилання

Відповіді:


24

Я думаю, ви змішуєте тут імперативні та побудови графіків. Операція tf.train.shuffle_batchстворює новий вузол черги, і один вузол може бути використаний для обробки всього набору даних. Тому я думаю, що ви зависаєте, тому що створили купу shuffle_batchчерг у циклі for і не запускали для них бігуни черги.

Звичайне використання вхідного конвеєра виглядає так:

  1. Додайте вузли, подібні shuffle_batchдо вхідного конвеєра
  2. (необов’язково, щоб запобігти ненавмисній модифікації графіка) доопрацювати графік

--- кінець побудови графіка, початок імперативного програмування -

  1. tf.start_queue_runners
  2. while(True): session.run()

Щоб бути більш масштабованим (щоб уникнути Python GIL), ви можете генерувати всі свої дані, використовуючи конвеєр TensorFlow. Однак, якщо продуктивність не є критичною, ви можете підключити масив numpy до вхідного конвеєру, використовуючи slice_input_producer.ось приклад з деякими Printвузлами, щоб побачити, що відбувається (повідомлення в Printgo to stdout при запуску вузла)

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до ініційованої вручну черги міститься у виданні 2193 github

Крім того, для цілей налагодження ви можете встановити 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

Примітки щодо масштабованості:

  1. tf.constantвбудована копія ваших даних на графік. Існує фундаментальна межа 2 ГБ щодо розміру визначення графіків, тож це верхня межа розміру даних
  2. Ви можете обійти це обмеження, використовуючи v=tf.Variableі збереження даних в там працює v.assign_opз tf.placeholderправого боку і підгодівлі Numpy масиву заповнювач ( feed_dict)
  3. Це все одно створює дві копії даних, тому для економії пам’яті ви можете створити власну версію, slice_input_producerяка працює з масивами numpy, і завантажує рядки по одному за допомогоюfeed_dict

2
Ага, так! Ви абсолютно праві - як тільки ви сказали: "Думаю, ви змішуєте тут імперативні та графічні частини", я почав розуміти, де я помилявся. Я опублікував редагування свого запитання, яке включає останній зібраний код, який насправді наближає мене до того, що я хочу, - я можу успішно читати дані CSV і групувати їх таким чином, щоб я міг навчити модель.
Роб

2
Я пропоную оновити цю відповідь, щоб вона працювала з останніми версіями TensorFlow: замінити tf.slice_input_producer()на tf.train.slice_input_producer()(і аналогічно для кількох інших функцій). А також додати sess.run(tf.initialize_local_variables())після sess.run(tf.initialize_all_variables()).
MiniQuark

Ще кілька змін, які слід внести: pack()є зараз stack(), і їх initialize_all_variables()слід замінити на global_variables_initializer()та local_variables_initializer().
MiniQuark

За допомогою tensorflow 1.0.1 вам потрібно ініціалізувати локальні та глобальні змінні як tf.group(tf.global_variables_initializer(), tf.local_variables_initializer()).run(). Вам потрібно буде ініціалізувати локальні змінні, оскільки ви використовуєте num_epochs і згідно з документацією "Примітка: якщо num_epochsні None, ця функція створює локальний лічильник epochs."
Bruno R. Cardoso

13

Або ви можете спробувати це, код завантажує набір даних Iris в tensorflow за допомогою 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)

Це було дуже повчально, але якщо я правильно розумію, це не показує, як використовувати дані для тренувань ...
dividebyzero

так, я їх скоро додаю ... Це повинно бути дріб’язково, чи не так .... обчисліть збиток, запустіть оптимізатор все одно я їх скоро додам
Нагарджун Гурурай

2
Привіт, дідібюзеро, вибачте, я запізнився! Я знайшов інше посилання, яке є цікавим і справді полегшує проблему tensorflow.org/tutorials/tflearn .... Тут ви можете завантажувати файли csv, навчати їх, виконувати класифікацію ...
Nagarjun Gururaj

@NagarjunGururaj Чи можу я використовувати набір даних, побудований contrib_learn, у звичайній процедурі tensorflow?
Джей Вонг,

який набір даних? Ви маєте на увазі Айріс чи будь-яку іншу?
Nagarjun Gururaj

2

Ви можете використовувати найновіший 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])

2

Якщо хтось прийшов сюди, шукаючи простий спосіб прочитати абсолютно великі та заточені файли CSV в API tf.estimator, будь ласка, дивіться нижче мій код

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)

0

2.0 Сумісне рішення : Цю відповідь можуть надати інші в наведеній вище темі, але я надам додаткові посилання, які допоможуть спільноті.

dataset = tf.data.experimental.make_csv_dataset(
      file_path,
      batch_size=5, # Artificially small to make examples easier to show.
      label_name=LABEL_COLUMN,
      na_value="?",
      num_epochs=1,
      ignore_errors=True, 
      **kwargs)

Для отримання додаткової інформації, будь ласка, зверніться до цього підручника Tensorflow .


1
Я вважаю цю відповідь (і підручник та документацію) вкрай неприємним. За словами OP, він все ще отримує лише "частину шляху до можливості тренуватися на даних CSV". Він створює "набір даних" (але якого типу - це навіть невідома документація tf.data.Dataset?), І здається, що набір даних орієнтований на стовпці, а не на рядки. Більшості моделей потрібні партії рядків, передані їм для навчання - як досягти цього кроку? Я поставив це питання, шукаючи наскрізний приклад.
omatai

Будь ласка, надайте наскрізний приклад make_csv_dataset замість того, щоб просто розміщувати документацію абстрактного рівня!
DevLoverUmar
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.