Python Tensorflow:批处理输入队列,然后更改队列源

Python Tensorflow:批处理输入队列,然后更改队列源,python,multithreading,queue,tensorflow,Python,Multithreading,Queue,Tensorflow,我有一个模型,它运行在一组图像上,并使用计算它们的一些统计数据——为简单起见,它只输出该组图像的平均值(实际上它做的更多)。我有许多包含图像的目录,我想从每个目录中获取输出。每个目录中都有数量可变的图像 我已经为我的脚本构建了一次图形、输出变量和损失函数。使用略微调整的方法对输入进行批处理。我对它进行了调整,以获取一组路径,并使用大小可变的占位符输入这些路径。我从中得到了灵感 然后我在目录上循环并运行以下操作: 初始化变量(这将根据在上一个目录上计算的结果重置上一个输出变量) 将image pa

我有一个模型,它运行在一组图像上,并使用计算它们的一些统计数据——为简单起见,它只输出该组图像的平均值(实际上它做的更多)。我有许多包含图像的目录,我想从每个目录中获取输出。每个目录中都有数量可变的图像

我已经为我的脚本构建了一次图形、输出变量和损失函数。使用略微调整的方法对输入进行批处理。我对它进行了调整,以获取一组路径,并使用大小可变的占位符输入这些路径。我从中得到了灵感

然后我在目录上循环并运行以下操作:

  • 初始化变量(这将根据在上一个目录上计算的结果重置上一个输出变量)
  • 将image path变量从新目录设置为当前文件数组:
    sess.run(image\u paths.initializer,feed\u dict={image\u paths\u initializer:image\u paths})
  • 开始队列运行:
    queue\u threads=tf.train.Start\u queue\u runner(sess=sess,coord=coord)
  • 运行多个历元以获得结果
  • 关闭线程
    coord.request_stop();协作连接(队列线程);协调。清除停止()
  • 返回结果,保存结果,移动到下一个目录
  • 问题是,当涉及到第二个目录时,队列运行程序线程拒绝启动(我可以通过调试
    queue\u threads
    变量看到这一点)。这会产生如下错误:

    Compute status: Aborted: FIFOQueue '_1_input_producer' is closed.
    Compute status: Aborted: RandomShuffleQueue '_0_shuffle_batch/random_shuffle_queue' is closed.
    
    如果我不关闭线程(并且不再启动它们),那么它们就不会从新目录生成文件——它们会忽略(2)中的变量赋值op。难道不能像这样重新启动队列吗

    我曾尝试在单独的会话中设置队列并从中提取批,但这会导致各种CUDA/内存错误。如果我这样做,并添加调试停止,我可以让它在遇到这个问题之前运行很久——但我不知道是否有可能在不相交的会话/图之间添加控件依赖项

    每个新目录都可以从头开始,但这会给我试图避免的过程增加很多开销。我在没有队列的情况下做过类似的事情(即重置变量和使用不同的输入重新运行),这节省了很多时间,所以我知道bit是有效的


    你们当中有谁能想出一个解决办法吗?

    string\u input\u producer
    是一个
    FIFOQueue
    +
    QueueRunner
    。如果您使用
    FIFOQueue
    并手动排队,您将获得更多的控制权。像这样的

    filename_queue = tf.FIFOQueue(100, tf.string)
    enqueue_placeholder = tf.placeholder(dtype=tf.string)
    enqueue_op = filename_queue.enqueue(enqueue_placeholder)
    
    config = tf.ConfigProto()
    config.operation_timeout_in_ms=2000  # for debugging queue hangs
    sess = tf.InteractiveSession(config=config)
    coord = tf.train.Coordinator()
    threads = tf.train.start_queue_runners(coord=coord)
    
    sess.run([enqueue_op], feed_dict={enqueue_placeholder:"/temp/dir1/0"})
    sess.run([enqueue_op], feed_dict={enqueue_placeholder:"/temp/dir1/1"})
    
    # do stats for /temp/dir1
    
    sess.run([enqueue_op], feed_dict={enqueue_placeholder:"/temp/dir2/0"})
    sess.run([enqueue_op], feed_dict={enqueue_placeholder:"/temp/dir2/1"})
    
    # do stats for /temp/dir2
    
    coord.request_stop()
    coord.join(threads)
    

    非常感谢@yaroslav bulatov为我指明了正确的方向

    看来我最大的问题是排队的人。当我将文件名队列替换为
    FIFOQueue
    并手动将文件名排入队列时,效果很好,但由于我也使用了
    shuffle_batch
    队列,因此当我尝试清空下一个目录的文件名队列时,这一情况变得不正常。我不能清空这个队列,因为它会导致锁定或中断队列,所以我能管理的最好方法是让它填满新的图像,同时保留以前目录中的剩余内容-显然不好!最后,我用一个
    RandomShuffleQueue
    替换了它,并再次以与文件名相同的方式手动将项目排队。我认为这是给足够好的图像混合,并不是过分的问题。没有线程,但一旦我取消了,事情就变得简单多了

    我已经包括我的最终解决方案如下。欢迎任何建议

    import os
    import tensorflow as tf
    import numpy as np
    from itertools import cycle
    
    output_dir = '/my/output/dir'
    
    my_dirs = [
        [
            '/path/to/datasets/blacksquares/black_square_100x100.png',
            '/path/to/datasets/blacksquares/black_square_200x200.png',
            '/path/to/datasets/blacksquares/black_square_300x300.png'
        ],
        [
            '/path/to/datasets/whitesquares/white_square_100x100.png',
            '/path/to/datasets/whitesquares/white_square_200x200.png',
            '/path/to/datasets/whitesquares/white_square_300x300.png',
            '/path/to/datasets/whitesquares/white_square_400x400.png'
        ],
        [
            '/path/to/datasets/mixedsquares/black_square_200x200.png',
            '/path/to/datasets/mixedsquares/white_square_200x200.png'
        ]
    ]
    
    # set vars
    patch_size = (100, 100, 1)
    batch_size = 20
    queue_capacity = 1000
    
    # setup filename queue
    filename_queue = tf.FIFOQueue(
        capacity=queue_capacity,
        dtypes=tf.string,
        shapes=[[]]
    )
    filenames_placeholder = tf.placeholder(dtype='string', shape=(None))
    filenames_enqueue_op = filename_queue.enqueue_many(filenames_placeholder)
    
    # read file and preprocess
    image_reader = tf.WholeFileReader()
    key, file = image_reader.read(filename_queue)
    uint8image = tf.image.decode_png(file)
    cropped_image = tf.random_crop(uint8image, patch_size) # take a random 100x100 crop
    float_image = tf.div(tf.cast(cropped_image, tf.float32), 255) # put pixels in the [0,1] range
    
    # setup shuffle batch queue for training images
    images_queue = tf.RandomShuffleQueue(
        capacity=queue_capacity,
        min_after_dequeue=0,  # allow queue to become completely empty (as we need to empty it)
        dtypes=tf.float32,
        shapes=patch_size
    )
    images_enqueue_op = images_queue.enqueue(float_image)
    
    # setup simple computation - calculate an average image patch
    input = tf.placeholder(shape=(None,) + patch_size, dtype=tf.float32)
    avg_image = tf.Variable(np.random.normal(loc=0.5, scale=0.5, size=patch_size).astype(np.float32))
    loss = tf.nn.l2_loss(tf.sub(avg_image, input))
    train_op = tf.train.AdamOptimizer(2.).minimize(loss)
    
    # start session and initialize variables
    sess = tf.InteractiveSession()
    sess.run(tf.initialize_all_variables())
    
    # note - no need to start any queue runners as I've done away with them
    
    for dir_index, image_paths in enumerate(my_dirs):
        image_paths_cycle = cycle(image_paths)
    
        # reset the optimisation and training vars
        sess.run(tf.initialize_all_variables())
    
        num_epochs = 1000
        for i in range(num_epochs):
            # keep the filename queue at capacity
            size = sess.run(filename_queue.size())
            image_paths = []
            while size < queue_capacity:
                image_paths.append(next(image_paths_cycle))
                size += 1
            sess.run(filenames_enqueue_op, feed_dict={filenames_placeholder: image_paths})
    
            # keep the shuffle batch queue at capacity
            size = sess.run(images_queue.size())
            while size < queue_capacity:
                sess.run([images_enqueue_op])
                size += 1
    
            # get next (random) batch of training images
            batch = images_queue.dequeue_many(batch_size).eval()
    
            # run train op
            _, result, loss_i = sess.run([train_op, avg_image, loss], feed_dict={input: batch})
            print('Iteration {:d}. Loss: {:.2f}'.format(i, loss_i))
    
            # early stopping :)
            if loss_i < 0.05:
                break
    
        # empty filename queue and verify empty
        size = sess.run(filename_queue.size())
        sess.run(filename_queue.dequeue_many(size))
        size = sess.run(filename_queue.size())
        assert size == 0
    
        # empty batch queue and verify empty
        size = sess.run(images_queue.size())
        sess.run(images_queue.dequeue_many(size))
        size = sess.run(filename_queue.size())
        assert size == 0
    
        # save the average image output
        result_image = np.clip(result * 255, 0, 255).astype(np.uint8)
        with open(os.path.join(output_dir, 'result_' + str(dir_index)), 'wb') as result_file:
            result_file.write(tf.image.encode_png(result_image).eval())
    
    print('Happy days!')
    exit(0)
    
    导入操作系统
    导入tensorflow作为tf
    将numpy作为np导入
    从itertools导入周期
    output_dir='/my/output/dir'
    我的_dirs=[
    [
    “/path/to/dataset/blacksquares/black_squares_100x100.png”,
    “/path/to/dataset/blacksquares/black_square_200x200.png”,
    “/path/to/dataset/blacksquares/black_squares_300x300.png”
    ],
    [
    “/path/to/datasets/whitesquares/white_square_100x100.png”,
    “/path/to/datasets/whitesquares/white_square_200x200.png”,
    “/path/to/datasets/whitesquares/white_square_300x300.png”,
    “/path/to/datasets/whitesquares/white_square_400x400.png”
    ],
    [
    “/path/to/dataset/mixedsquares/black_square_200x200.png”,
    “/path/to/dataset/mixedsquares/white_square_200x200.png”
    ]
    ]
    #设置变量
    补丁大小=(1001001)
    批量大小=20
    队列容量=1000
    #设置文件名队列
    filename_queue=tf.FIFOQueue(
    容量=队列容量,
    dtypes=tf.string,
    形状=[]]
    )
    filenames\u placeholder=tf.placeholder(dtype='string',shape=(无))
    filenames\u enqueue\u op=filename\u queue.enqueue\u many(filenames\u占位符)
    #读取文件并进行预处理
    image\u reader=tf.WholeFileReader()
    key,file=image\u reader.read(文件名\u队列)
    uint8image=tf.image.decode\u png(文件)
    裁剪图像=tf.随机裁剪(uint8image,补丁大小)#随机进行100x100次裁剪
    float_image=tf.div(tf.cast(裁剪的_image,tf.float32),255)#将像素置于[0,1]范围内
    #为训练图像设置洗牌批处理队列
    images\u queue=tf.RandomShuffleQueue(
    容量=队列容量,
    min_在_dequeue=0之后,#允许队列完全变空(因为我们需要清空它)
    数据类型=tf.float32,
    形状=面片大小
    )
    images\u enqueue\u op=images\u queue.enqueue(float\u image)
    #设置简单计算-计算平均图像面片
    input=tf.placeholder(shape=(None,)+patch_size,dtype=tf.float32)
    平均图像=tf.变量(np.随机.正常(loc=0.5,比例=0.5,大小=面片大小).aType(np.浮动32))
    损耗=tf.nn.l2_损耗(tf.sub(平均图像,输入))
    列op=tf.列AdamOptimizer(2.)最小化(损失)
    #启动会话并初始化变量
    sess=tf.InteractiveSession()
    sess.run(tf.initialize\u all\u variables())
    #注-无需启动任何queu
    
    q = tf.train.string_input_producer(
      tf.train.match_filenames_once('/path/to/datasets/*.png')
    )