2016-03-31 14 views
4

私は、一連のイメージを実行し、それらを使用していくつかの統計を計算するモデルを持っています - 単純に、セットからの平均イメージを出力します実際には)。私はイメージを含むいくつかのディレクトリを持っており、各ディレクトリからの出力を取得したい。各ディレクトリには、さまざまな数のイメージがあります。Tensorflow:入力キューを一括してキューソースを変更する

スクリプトのためにグラフ、出力変数、損失関数を一度構築しました。入力はわずかに適合されたcode from hereを使用してバッチ処理されます。私は、可変サイズのプレースホルダを使用して、一連のパスを取得するようにしました。私はそのためのインスピレーションを得たfrom here

ディレクトリかけてIループし、次のように実行します。

  1. は、可変画像のパスを設定し、変数(これは前のディレクトリに計算された結果から、前の出力変数をリセットします)
  2. を初期化します新しいディレクトリから現在のファイルの配列:sess.run(image_paths.initializer, feed_dict={image_paths_initializer: image_paths})
  3. キューが実行を開始:エポックの数のqueue_threads = tf.train.start_queue_runners(sess=sess, coord=coord)
  4. 実行して結果を得るために
  5. の閉じるスレッドcoord.request_stop(); coord.join(queue_threads); coord.clear_stop()
  6. 戻り結果、結果を保存するには、次のディレクトリに移動...

問題は、それが2番目のディレクトリに来るとき、キューランナースレッドが(私はこれを見ることができますを開始することを拒否していることです変数queue_threadsをデバッグします)。私はスレッドを閉じない(とそれらをもう一度起動しない)場合は

Compute status: Aborted: FIFOQueue '_1_input_producer' is closed. 
Compute status: Aborted: RandomShuffleQueue '_0_shuffle_batch/random_shuffle_queue' is closed. 

その後、彼らは新しいディレクトリからファイルを生成しない - 彼らは変数代入OPを無視する:これは、のようなエラーが発生します(2)。このようなキューを再起動することはできませんか?

私はキューを別々のセッションで設定しようとしましたが、それらからバッチを引き出すことができましたが、それはさまざまなCUDA /メモリエラーをもたらします。私がこれを行い、デバッグの停止を追加すると、これに当たる前に実行することができますが、ディスジョイントセッション/グラフ間でコントロールの依存関係を追加することが可能かどうかはわかりません。

新しいディレクトリごとに最初から開始することは可能ですが、それは回避しようとしているプロセスに多くのオーバーヘッドを追加します。私はこれと同様のことをしました(すなわち、変数をリセットし、異なる入力で再実行する)、キューを使わずに済むので、時間が大幅に節約できます。

あなたのいずれか素晴らしいSO人はこれの方法を考えることができますか?

答えて

6

string_input_producerは、FIFOQueue + QueueRunnerである。 FIFOQueueを使用して手作業でエンキューすると、より多くの制御が得られます。この上で正しい方向に私を指しているため、@のヤロスラフ・bulatovにこの

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) 
+0

ありがとうございました!私はあなたが言うようにそれを稼働させようとしましたが、バッチを取得しようとすると吊り下がります。このようなサウンドは、 'filename_queue'が' shuffle_batch'キューに入っているので、別のキューに入ってくるキューによって引き起こされますか? – lopsided

+0

フル・キューにエンキューしようとしているとき、または空のキューからデキューしようとしているときにハングします。既にキュー内にある要素の数を確認するには "sess.run([filename_queue.size()])"を試してください –

+0

また、tf.batchもキューであるためキューランナーを起動する必要があります –

4

ビッグ感謝のようなもの。

私の最大の問題は、キューのランナーだったようです。ファイル名のキューを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) 

これはresult_0 ouputs - 黒四角、result_1 - 白四角及びresult_2 - (ほとんど)灰色正方形。

0

あなた自身の答えを見ると、tf.train.match_filenames_onceをご覧になることをお勧めします。ファイルのパターンを指定してstring_input_producerに渡すことができます。

q = tf.train.string_input_producer(
    tf.train.match_filenames_once('/path/to/datasets/*.png') 
) 

さらにcomprehensive exampleです。これを行うだけでなく、問題を修正するだけでなく、すべてのディレクトリを繰り返し処理する必要はありません。

関連する問題