Wie kann man CSV-Daten in TensorFlow * tatsächlich * lesen?


82

Ich bin relativ neu in der Welt von TensorFlow und ziemlich ratlos darüber, wie Sie CSV-Daten tatsächlich in TensorFlow in verwendbare Beispiel- / Etikettentensoren einlesen würden. Das Beispiel aus dem TensorFlow-Tutorial zum Lesen von CSV-Daten ist ziemlich fragmentiert und gibt Ihnen nur einen Teil des Weges zum Trainieren von CSV-Daten.

Hier ist mein Code, den ich basierend auf diesem CSV-Tutorial zusammengestellt habe:

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")

Und hier ist ein kurzes Beispiel aus der CSV-Datei, die ich lade - ziemlich grundlegende Daten - 4 Feature-Spalten und 1 Beschriftungsspalte:

0,0,0,0,0
0,15,0,0,0
0,30,0,0,0
0,45,0,0,0

Der obige Code druckt lediglich jedes Beispiel einzeln aus der CSV-Datei , was zwar nett, aber für das Training verdammt nutzlos ist.

Ich habe hier Probleme damit, wie Sie diese einzelnen Beispiele, die einzeln geladen werden, tatsächlich in einen Trainingsdatensatz umwandeln. Hier ist zum Beispiel ein Notizbuch, an dem ich im Udacity Deep Learning-Kurs gearbeitet habe. Grundsätzlich möchte ich die CSV-Daten, die ich lade, in etwas wie train_dataset und train_labels kopieren :

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)

Ich habe versucht tf.train.shuffle_batch, so etwas zu verwenden, aber es hängt unerklärlicherweise:

  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)

Zusammenfassend sind hier meine Fragen:

  • Was fehlt mir an diesem Prozess?
    • Es scheint, als ob mir eine wichtige Intuition fehlt, wie man eine Eingabepipeline richtig erstellt.
  • Gibt es eine Möglichkeit, die Länge der CSV-Datei nicht zu kennen?
    • Es fühlt sich ziemlich unelegant an, die Anzahl der zu verarbeitenden Zeilen kennen zu müssen (die for i in range(file_length)Codezeile oben).

Bearbeiten: Sobald Jaroslaw darauf hinwies, dass ich hier wahrscheinlich imperative und grafische Konstruktionsteile verwechseln würde, wurde es klarer. Ich konnte den folgenden Code zusammenstellen, der meiner Meinung nach näher an dem liegt, was normalerweise beim Trainieren eines Modells aus CSV (ohne Modell-Trainingscode) gemacht wird:

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) 

Ich habe Ihren Code ausprobiert, kann ihn aber nicht zum Laufen bringen. Fehlt mir etwas, das Sie festgestellt haben? Vielen Dank. Ich habe hier einen Thread gepostet, damit Sie weitere Details erhalten können: stackoverflow.com/questions/40143019/…
Link

Antworten:


24

Ich denke, Sie verwechseln hier imperative und grafische Konstruktionsteile. Die Operation tf.train.shuffle_batcherstellt einen neuen Warteschlangenknoten, und ein einzelner Knoten kann zum Verarbeiten des gesamten Datensatzes verwendet werden. Ich denke, Sie hängen, weil Sie eine Reihe von shuffle_batchWarteschlangen in Ihrer for-Schleife erstellt und keine Warteschlangenläufer für sie gestartet haben.

Die normale Verwendung der Eingabepipeline sieht folgendermaßen aus:

  1. Fügen Sie Knoten hinzu shuffle_batch, die eine Pipeline eingeben möchten
  2. (Optional, um unbeabsichtigte Änderungen am Diagramm zu verhindern) Schließen Sie das Diagramm ab

--- Ende der Graphkonstruktion, Beginn der imperativen Programmierung -

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

Um skalierbarer zu sein (um Python GIL zu vermeiden), können Sie alle Ihre Daten mithilfe der TensorFlow-Pipeline generieren. Wenn die Leistung jedoch nicht kritisch ist, können Sie ein Numpy-Array an eine Eingabepipeline anschließen. Verwenden Sie slice_input_producer.hier ein Beispiel mit einigen PrintKnoten, um zu sehen, was los ist (Nachrichten in Printgehen an stdout, wenn der Knoten ausgeführt wird).

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."

Sie sollten so etwas sehen

[[0 1]
 [2 3]
 [4 5]
 [6 7]
 [8 9]]
[[0 1]
 [2 3]]
[[4 5]
 [6 7]]
No more inputs.

Die "8, 9" -Nummern füllten nicht die gesamte Charge aus, sodass sie nicht produziert wurden. Sie tf.Printwerden auch in sys.stdout gedruckt, sodass sie für mich separat im Terminal angezeigt werden.

PS: Eine minimale Anzahl von Verbindungen batchzu einer manuell initialisierten Warteschlange befindet sich in Github-Ausgabe 2193

Zu Debugging-Zwecken möchten Sie möglicherweise timeouteine Sitzung festlegen, damit Ihr IPython-Notizbuch nicht an leeren Warteschlangenwarteschlangen hängt. Ich benutze diese Hilfsfunktion für meine Sitzungen

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

Hinweise zur Skalierbarkeit:

  1. tf.constantInline-Kopie Ihrer Daten in das Diagramm. Es gibt eine grundlegende Grenze von 2 GB für die Größe der Diagrammdefinition, sodass dies eine Obergrenze für die Datengröße ist
  2. Sie können diese Grenze umgehen, indem Sie v=tf.Variabledie Daten verwenden und dort speichern, indem Sie v.assign_opmit einem tf.placeholderauf der rechten Seite ausführen und dem Platzhalter ein numpy-Array zuweisen ( feed_dict).
  3. Dadurch werden immer noch zwei Kopien von Daten erstellt. Um Speicherplatz zu sparen, können Sie eine eigene Version slice_input_producererstellen, die auf Numpy-Arrays ausgeführt wird, und Zeilen einzeln mit hochladenfeed_dict

2
Ahh, ja! Sie haben vollkommen recht - sobald Sie sagten: "Ich glaube, Sie verwechseln hier imperative und grafische Konstruktionsteile", begann ich zu sehen, wo ich falsch lag. Ich habe eine Bearbeitung meiner Frage veröffentlicht, die den neuesten Code enthält, den ich zusammengestellt habe. Dadurch komme ich dem, was ich möchte, näher. Ich kann CSV-Daten erfolgreich einlesen und so stapeln, dass ich a trainieren kann Modell.
Rob

2
Ich schlage vor, diese Antwort zu aktualisieren, damit sie mit neueren Versionen von TensorFlow funktioniert : Ersetzen tf.slice_input_producer()durch tf.train.slice_input_producer()(und ähnlich für mehrere andere Funktionen). Und auch sess.run(tf.initialize_local_variables())nachher hinzufügen sess.run(tf.initialize_all_variables()).
MiniQuark

Einige weitere Änderungen müssen vorgenommen werden: pack()ist jetzt stack()und initialize_all_variables()sollte durch global_variables_initializer()und ersetzt werden local_variables_initializer().
MiniQuark

Mit Tensorflow 1.0.1 müssen Sie lokale und globale Variablen als initialisieren tf.group(tf.global_variables_initializer(), tf.local_variables_initializer()).run(). Sie müssen lokale Variablen initialisieren, da Sie num_epochs verwenden und gemäß Dokumentation "Hinweis: Wenn dies num_epochsnicht derNoneepochs
Bruno R. Cardoso

13

Oder Sie könnten dies versuchen, der Code lädt den Iris-Datensatz mithilfe von Pandas und Numpy in den Tensorflow und eine einfache Ausgabe mit einem Neuron wird in der Sitzung gedruckt. Hoffe, es hilft für ein grundlegendes Verständnis .... [Ich habe nicht den Weg eines heißen Dekodierungsetiketts hinzugefügt].

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)

Das war sehr lehrreich, aber wenn ich es richtig verstehe, zeigt es nicht, wie man die Daten für das Training verwendet ...
Dividebyzero

Ja, ich werde sie bald hinzufügen ... Es sollte trivial sein, nicht wahr ... Berechnen Sie den Verlust, führen Sie den Optimierer aus, ich werde sie bald hinzufügen
Nagarjun Gururaj

2
Hallo dividbyzero, sorry ich bin spät dran! Ich habe einen anderen Link gefunden, der interessant ist und das Problem wirklich lindert . Tensorflow.org/tutorials/tflearn .... Hier können Sie die CSV-Dateien laden, trainieren, klassifizieren ...
Nagarjun Gururaj

@NagarjunGururaj Kann ich den von Contrib_Learn erstellten Datensatz in der normalen Tensorflow-Routine verwenden?
Jay Wong

welcher Datensatz? Du meinst Iris oder eine andere?
Nagarjun Gururaj

2

Sie können die neueste tf.data-API verwenden:

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

Wenn jemand hierher gekommen ist, um nach einer einfachen Möglichkeit zu suchen, absolut große und gesplittete CSV-Dateien in der tf.estimator-API zu lesen, siehe unten meinen Code

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

Beispiel für die Verwendung in 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)

2

2.0-kompatible Lösung : Diese Antwort wird möglicherweise von anderen im obigen Thread bereitgestellt, aber ich werde zusätzliche Links bereitstellen, die der Community helfen.

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)

Weitere Informationen finden Sie in diesem Tensorflow-Tutorial .


Ich finde diese Antwort (und das Tutorial und die Dokumentation) äußerst frustrierend. Es wird immer noch nur "ein Teil des Weges, um in der Lage zu sein, auf CSV-Daten zu trainieren", so die Worte des OP. Es wird ein "Datensatz" erstellt (aber welcher Typ - ist es überhaupt eine tf.data.Dataset? Dokumentation unklar) und es scheint, dass der Datensatz spaltenorientiert und nicht zeilenorientiert ist. Die meisten Modelle benötigen Stapel von Zeilen, die für das Training an sie übergeben werden. Wie kann dieser Schritt erreicht werden? Ich habe diese Frage gestellt, um ein durchgängiges Beispiel zu finden.
Omatai
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.