Python 3.x Tensorflow:使用带有自定义估计器的CSV文件队列和;输入“fn”;作用

Python 3.x Tensorflow:使用带有自定义估计器的CSV文件队列和;输入“fn”;作用,python-3.x,csv,machine-learning,tensorflow,Python 3.x,Csv,Machine Learning,Tensorflow,我花了很长时间(很多小时)寻找问题的正确答案,但没有结果,所以我来了。我想我遗漏了一些明显的东西,但我不知道 问题:使用队列读取CSV文件,并使用输入对估计器进行训练,而每次都不重新加载图形(这非常慢) 我创建了一个自定义模型,该模型为我提供了一个模型函数,用于创建我自己的估计器: tf.estimator.Estimator(model_fn=model_fn, params=model_params) batch_size = 4 shuffle_size = 10000 feature

我花了很长时间(很多小时)寻找问题的正确答案,但没有结果,所以我来了。我想我遗漏了一些明显的东西,但我不知道

问题:使用队列读取CSV文件,并使用输入对估计器进行训练,而每次都不重新加载图形(这非常慢)


我创建了一个自定义模型,该模型为我提供了一个模型函数,用于创建我自己的估计器:

tf.estimator.Estimator(model_fn=model_fn, params=model_params)
batch_size = 4
shuffle_size = 10000
features, labels = input_fn()
with tf.Session() as sess:
    f_data, l_data = sess.run([features, labels])
print(f_data, l_data)
之后,我需要读取一个非常大的CSV文件(无法在内存中加载),因此我决定使用队列(似乎是最好的解决方案):

我认为这个代码是可以的


然后,主代码:

with tf.Session() as sess:
    tf.logging.set_verbosity(tf.logging.INFO)
    sess.run(tf.global_variables_initializer())

    coord = tf.train.Coordinator()
    threads = tf.train.start_queue_runners(coord=coord)

    # Return a Tensor of 1000 features/labels
    def get_inputs():
        print("input call !")
        xs = []
        ys = []
        for i in range(1000):
            x, y = sess.run([features, label])
            xs.append(x)
            ys.append(y)
        return tf.constant(np.asarray(xs), dtype=tf.float32), tf.constant(np.asarray(ys))

    estimator.train(input_fn=get_inputs,
                   steps=100)

    coord.request_stop()
    coord.join(threads)

正如你所看到的,这里有很多丑陋的东西

我想要的:我想要训练功能在每个步骤中使用新的一批功能。但在这里,它在100个步骤中使用了同一批1000个特性,因为get_inputs函数只是在我们开始训练时调用的。有没有一个简单的方法可以做到这一点

我尝试使用step=1循环estimator.train,但每次都会重新加载图形,速度会非常慢

我不知道现在该怎么办,也不知道这是否可能


谢谢你帮助我

简短版本:将CSV文件转换为
tfrecords
,然后使用
tf.contrib.data.TFRecordDataset
。长版:见代码见问题/公认答案(为方便起见,复制如下)


查看API。我想您最好将CSV转换为TfRecord文件并使用TfRecordDataset。这里有一个完整的教程

步骤1:将csv数据转换为tfrecords数据。下面是示例代码

import tensorflow as tf


def read_csv(filename):
    with open(filename, 'r') as f:
        out = [line.rstrip().split(',') for line in f.readlines()]
    return out


csv = read_csv('data.csv')
with tf.python_io.TFRecordWriter("data.tfrecords") as writer:
    for row in csv:
        features, label = row[:-1], row[-1]
        features = [float(f) for f in features]
        label = int(label)
        example = tf.train.Example()
        example.features.feature[
            "features"].float_list.value.extend(features)
        example.features.feature[
            "label"].int64_list.value.append(label)
        writer.write(example.SerializeToString())
这假设最后一列中的标签是整数,前面的列中有浮点特征。这只需要运行一次

第2步:编写数据集并解码这些记录文件

def parse_function(example_proto):
    features = {
        'features': tf.FixedLenFeature((n_features,), tf.float32),
        'label': tf.FixedLenFeature((), tf.int64)
    }
    parsed_features = tf.parse_single_example(example_proto, features)
    return parsed_features['features'], parsed_features['label']


def input_fn():
    dataset = tf.contrib.data.TFRecordDataset(['data.tfrecords'])
    dataset = dataset.map(parse_function)
    dataset = dataset.shuffle(shuffle_size)
    dataset = dataset.repeat()  # repeat indefinitely
    dataset = dataset.batch(batch_size)
    print(dataset.output_shapes)
    features, label = dataset.make_one_shot_iterator().get_next()
    return features, label
测试(独立于估计器):

用于tf.estimator.estimator:

estimator.train(input_fn, max_steps=1e7)

如果您担心没有调用
tf.train.start\u queue\u runner
,请尝试以下操作:

class ThreadStartHook(tf.train.SessionRunHook):
    def after_create_session(self, session, coord):
        self.coord = coord
        self.threads = tf.train.start_queue_runners(coord=coord, sess=session)

    def end(self, session):
        self.coord.request_stop()
        self.coord.join(self.threads)


estimator.train(input_fn, [ThreadStartHook()])

刚开始的时候我也有类似的想法,但我觉得没必要这样做。

嗨,谢谢你的回答。我已经看到了你的帖子,但是这个解决方案需要将CSV转换为TFRecord,我想知道我们是否不能避免使用队列和批处理功能。你可以。。。但我相当肯定这就是数据集在幕后所做的一切。您可以在训练时直接从csv读取并解析字符串数据,但速度会慢一些。据我所知,TFR记录的唯一缺点是它们会占用额外的空间。这真的令人担忧吗?如果你正在加载图像,你可以将路径保存在tfrecords中,然后像平常一样从文件中读取。不,在TFrecord中复制并不重要,这只是为了我个人的知识(因为我在这个问题上浪费了很多时间哈哈)。你有没有想过不用转换就从CSV开始呢?对于您的解决方案,所有数据集都不会加载到内存中?只是当前批次,对吗?我明天会试试这个。这肯定是个办法,但我很怀疑这是不是最好的办法。我花了很长时间尝试制作一个数据管道,它以我想要的方式工作,直到我意识到在更大的团队中有更聪明的人做得更好,并考虑具有更多通用性的边缘案例:)。此外,还有比数据更有趣的问题。看,你赢了。我也很厌倦这个。再次感谢:)好的!我认为这个代码解决了这个问题。但是另一个出现了。。。(否则就不好玩了是的)。“传递的张量(“稀疏\软最大\交叉\熵\损失/值:0”,shape=(),dtype=float32)应具有与当前图形相等的图形属性”。我现在会调查这个错误。好的,我更了解。。。事实上,我们需要在tf.train.batch之后调用“start\u queue\u runners”,实习生队列将不会启动!(已测试并批准)
class ThreadStartHook(tf.train.SessionRunHook):
    def after_create_session(self, session, coord):
        self.coord = coord
        self.threads = tf.train.start_queue_runners(coord=coord, sess=session)

    def end(self, session):
        self.coord.request_stop()
        self.coord.join(self.threads)


estimator.train(input_fn, [ThreadStartHook()])