TensorFlowでCSVデータを*実際に*読み取る方法は?


83

私はTensorFlowの世界に比較的慣れていないので、CSVデータをTensorFlowで使用可能なサンプル/ラベルテンソルに実際に読み込む方法にかなり戸惑っています。CSVデータの読み取りに関するTensorFlowチュートリアルの例はかなり断片化されており、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ファイルから各例を1つずつ印刷するだけです。これは、すばらしいとはいえ、トレーニングにはまったく役に立ちません。

ここで私が苦労しているのは、1つずつ読み込まれた個々の例を実際にトレーニングデータセットに変換する方法です。たとえば、これは私がUdacityディープラーニングコースで取り組んでいたノートブックです。基本的に、ロードしているCSVデータを取得して、train_datasettrain_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)上記のコード行)を知らなければならないのはかなりエレガントではないと感じます

編集: Yaroslavが、ここで命令型とグラフ構築の部分を混同している可能性があると指摘するとすぐに、それはより明確になり始めました。次のコードをまとめることができました。これは、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ノードを使用した例を使用して、何が起こっているかを確認します(Printノードの実行時にメッセージが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手動で初期化されたキューへの接続の最小限はgithubの問題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

スケーラビリティに関する注意:

  1. tf.constantデータのインラインコピーをグラフに挿入します。グラフ定義のサイズには基本的に2GBの制限があるため、データのサイズには上限があります。
  2. 右側でv=tf.Variable実行v.assign_opし、tf.placeholdernumpy配列をプレースホルダーにフィードすることで、データを使用してそこに保存することで、この制限を回避できます(feed_dict
  3. それでもデータのコピーが2つ作成されるため、メモリを節約するためにslice_input_producer、numpy配列で動作する独自のバージョンを作成し、を使用して一度に1つずつ行をアップロードできます。feed_dict

2
ああ、そうだ!あなたは完全に正しいです-「ここで命令型とグラフ構築の部分を混同していると思います」と言うとすぐに、私はどこが間違っているのかがわかり始めました。私がまとめた最新のコードを含む編集を質問に投稿しました。これにより、実際に必要なものに近づくことができます。CSVデータを正常に読み取り、トレーニングできるようにバッチ処理することができます。モデル。
ロブ

2
この回答を更新して、最近のバージョンのTensorFlowで機能するようにすることをお勧めします:replace tf.slice_input_producer()with tf.train.slice_input_producer()(および他のいくつかの関数についても同様)。また、sess.run(tf.initialize_local_variables())後に追加しsess.run(tf.initialize_all_variables())ます。
miniQuark 2016

行うべきいくつかの変更:pack()は現在stack()、であり、およびinitialize_all_variables()に置き換える必要がglobal_variables_initializer()ありlocal_variables_initializer()ます。
miniQuark 2017

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

または、これを試すこともできます。コードは、パンダとnumpyを使用してIrisデータセットをテンソルフローにロードし、セッションで単純な1つのニューロン出力が出力されます。それが基本的な理解に役立つことを願っています.... [私は1つのホットデコードラベルの方法を追加していません]。

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

はい、すぐに追加します...些細なことですよね....損失を計算し、オプティマイザをすぐに実行します。すぐに追加します
Nagarjun Gururaj 2017年

2
こんにちはdividebyzero、遅れてすみません!興味深く、問題を本当に緩和する別のリンクを見つけましたtensorflow.org/tutorials/tflearn ....ここで、csvファイルをロードし、トレーニングし、分類を実行できます...
Nagarjun Gururaj 2017

@NagarjunGururaj通常のテンソルフロールーチンでcontrib_learnによって構築されたデータセットを使用できますか?
ジェイウォン

どのデータセット?アイリスか他のことですか?
Nagarjun Gururaj 2017

2

最新のtf.dataAPIを使用できます。

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

tf.estimator APIで絶対に大きくシャーディングされたCSVファイルを読み取る簡単な方法を探している人がここに来た場合は、以下の私のコードを参照してください

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.