web-dev-qa-db-fra.com

Comment * réellement * lire les données CSV dans TensorFlow?

Je suis relativement nouveau dans le monde de TensorFlow et assez déconcerté par la manière dont vous avez réellement lire les données CSV dans un exemple de tenseurs/étiquettes utilisables dans TensorFlow. L'exemple tiré du didacticiel TensorFlow sur la lecture de données CSV est assez fragmenté et ne vous permet qu'une partie du processus de formation sur les données CSV.

Voici le code que j'ai reconstitué à partir de ce tutoriel 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")

Et voici un bref exemple tiré du fichier CSV que je suis en train de charger - données plutôt basiques - 4 colonnes de fonction et une colonne d'étiquette:

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

Tout le code ci-dessus ne fait imprimer chaque exemple à partir du fichier CSV, un par un , ce qui, bien que Nice, est vachement inutile pour la formation.

Ce qui me pose problème ici, c'est comment transformer ces exemples individuels, chargés un par un, en un ensemble de données de formation. Par exemple, voici un cahier je travaillais sur le cours Udacity Deep Learning. Je veux fondamentalement prendre les données CSV que je charge et les insérer dans quelque chose comme train_dataset et 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)

J'ai essayé d'utiliser tf.train.shuffle_batch, comme ceci, mais il se bloque inexplicablement:

  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)

Donc pour résumer, voici mes questions:

  • Que me manque-t-il dans ce processus?
    • Il me semble qu'il me manque une intuition essentielle sur la manière de construire correctement un pipeline d'entrées.
  • Y a-t-il un moyen d'éviter de connaître la longueur du fichier CSV?
    • Il est assez inélégant de connaître le nombre de lignes que vous souhaitez traiter (la ligne de code for i in range(file_length) ci-dessus)

Edit: Dès que Yaroslav a fait remarquer que j’étais probablement en train de mélanger des éléments de construction impérative et graphique, cela a commencé à devenir plus clair. J'ai pu rassembler le code suivant, ce qui, je pense, est plus proche de ce que ferait généralement la formation d'un modèle à partir d'un fichier CSV (à l'exclusion de tout code de formation de modèle):

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) 
79
Rob

Je pense que vous mélangez ici des éléments impératifs et graphiques. L'opération _tf.train.shuffle_batch_ crée un nouveau nœud de file d'attente. Un seul nœud peut être utilisé pour traiter l'ensemble de données. Je pense donc que vous vous attardez parce que vous avez créé un groupe de files d'attente _shuffle_batch_ dans votre boucle for et que vous n'avez pas démarré les coureurs de files d'attente pour elles.

L’utilisation normale du pipeline d’entrée ressemble à ceci:

  1. Ajouter des nœuds comme _shuffle_batch_ au pipeline d'entrée
  2. (facultatif, pour empêcher toute modification involontaire du graphique) finaliser le graphique

--- fin de la construction du graphe, début de la programmation impérative -

  1. _tf.start_queue_runners_
  2. while(True): session.run()

Pour être plus évolutif (pour éviter Python GIL), vous pouvez générer toutes vos données à l'aide du pipeline TensorFlow. Toutefois, si les performances ne sont pas critiques, vous pouvez connecter un tableau numpy à un pipeline d'entrée à l'aide de _slice_input_producer._ Voici un exemple avec quelques nœuds Print pour voir ce qu'il se passe (messages dans Print aller à la sortie standard lorsque le noeud est exécuté)

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

Vous devriez voir quelque chose comme ça

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

Les numéros "8, 9" n'ont pas rempli le lot complet, ils n'ont donc pas été produits. De plus, _tf.Print_ sont imprimés sur sys.stdout, ils apparaissent donc séparément dans Terminal pour moi.

PS: un minimum de connexion de batch à une file d'attente initialisée manuellement est dans numéro 2193 de github

De plus, pour le débogage, vous pouvez définir timeout sur votre session afin que votre bloc-notes IPython ne se bloque pas sur les files d'attente vides. J'utilise cette fonction d'assistance pour mes sessions

_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
_

Notes d'évolutivité:

  1. _tf.constant_ copie en ligne de vos données dans le graphique. Il y a une limite fondamentale de 2 Go sur la taille de la définition de graphique, donc c'est une limite supérieure sur la taille des données
  2. Vous pouvez contourner cette limite en utilisant _v=tf.Variable_ et en y enregistrant les données en exécutant _v.assign_op_ avec un _tf.placeholder_ à droite et en insérant un tableau numpy dans l'espace réservé (_feed_dict_)
  3. Cela crée toujours deux copies de données. Par conséquent, pour économiser de la mémoire, vous pouvez créer votre propre version de _slice_input_producer_ qui fonctionne sur des tableaux numpy et télécharger des lignes une par une à l’aide de _feed_dict_.
23

Vous pouvez également essayer ceci: le code charge le jeu de données Iris dans tensorflow à l'aide de pandas et de numpy, et une sortie simple d'un neurone est imprimée dans la session. J'espère que cela vous aidera pour une compréhension de base .... [Je n'ai pas ajouté la méthode des étiquettes à décodage à chaud].

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)
13
Nagarjun Gururaj

Vous pouvez utiliser la dernière 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
Adarsh Kumar

Si quelqu'un est venu ici à la recherche d'un moyen simple de lire des fichiers CSV absolument volumineux et fragmentés dans l'API tf.estimator, veuillez voir ci-dessous mon 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

Exemple d'utilisation dans 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
Hasan Rafiq