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