如何*实际*读取TensorFlow中的CSV数据?


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深度学习课程中正在使用的笔记本。我基本上想获取正在加载的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/…–
链接

Answers:


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管道生成所有数据。但是,如果性能不是很关键,则可以使用slice_input_producer.以下示例将一个numpy数组连接到输入管道:这是一个带有一些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,因此它们对我来说分别显示在Terminal中。

PS:连接batch到手动初始化的队列的最低要求在github问题2193中

另外,出于调试目的,您可能需要timeout在会话上进行设置,以使IPython Notebook不挂在空队列出队中。我在会话中使用此帮助器功能

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将数据的副本内联到Graph中。Graph定义的大小有2GB的基本限制,因此这是数据大小的上限
  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'4

使用tensorflow 1.0.1,您需要将局部和全局变量初始化为tf.group(tf.global_variables_initializer(), tf.local_variables_initializer()).run()。您将需要初始化局部变量,因为您正在使用num_epochs并按照文档 “注意:如果num_epochs不是None,此函数将创建局部计数器 epochs。”
布鲁诺·R·卡多佐

13

或者您可以尝试这样做,代码使用pandas和numpy将Iris数据集加载到tensorflow中,并在会话中打印一个简单的神经元输出。希望它有助于基本理解。...[我还没有添加一个热解码标签的方法]。

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)

这非常有启发性,但是如果我理解正确,它并不会显示如何使用数据进行训练...
Divybyzero

是的,我会尽快添加它们...应该没什么大不了的....计算损失,不运行优化程序我会尽快添加它们
Nagarjun Gururaj

2
嗨,dividbyzero,对不起,我来晚了!我发现了另一个有趣的链接,它确实缓解了tensorflow.org/tutorials/tflearn ....在这里,您可以加载csv文件,对其进行训练,进行分类...
Nagarjun Gururaj

@NagarjunGururaj我可以在普通的tensorflow例程中使用由contrib_learn构造的数据集吗?
周杰伦(Jay Wong)

哪个数据集?你是说鸢尾花还是其他?
Nagarjun Gururaj

2

您可以使用最新的tf.data API:

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.