TensorFlow: как применить одно и то же искажение изображения к нескольким изображениям

Начиная с примера Tensorflow CNN, я пытаюсь изменить модель так, чтобы в качестве входных данных использовалось несколько изображений (чтобы на входе было не только 3 входных канала, но и 3 на несколько изображений). Чтобы увеличить ввод, я пытаюсь использовать случайные операции с изображениями, такие как переворачивание, контрастность и яркость, предоставленные в TensorFlow. Мое текущее решение применить одно и то же случайное искажение ко всем входным изображениям состоит в том, чтобы использовать фиксированное начальное значение для этих операций:

def distort_image(image):
  flipped_image = tf.image.random_flip_left_right(image, seed=42)
  contrast_image = tf.image.random_contrast(flipped_image, lower=0.2, upper=1.8, seed=43)
  brightness_image = tf.image.random_brightness(contrast_image, max_delta=0.2, seed=44)
  return brightness_image

Этот метод вызывается несколько раз для каждого изображения во время построения графика, поэтому я подумал, что для каждого изображения будет использоваться одна и та же последовательность случайных чисел, и, следовательно, он приведет к тому, что будут применены одинаковые операции с изображениями для моей последовательности ввода изображений.

# ...

# distort images
distorted_prediction = distort_image(seq_record.prediction)
distorted_input = []
for i in xrange(INPUT_SEQ_LENGTH):
    distorted_input.append(distort_image(seq_record.input[i,:,:,:]))
stacked_distorted_input = tf.concat(2, distorted_input)

# Ensure that the random shuffling has good mixing properties.
min_queue_examples = int(num_examples_per_epoch *
                         MIN_FRACTION_EXAMPLES_IN_QUEUE)

# Generate a batch of sequences and prediction by building up a queue of examples.
return generate_sequence_batch(stacked_distorted_input, distorted_prediction, min_queue_examples, 
                               batch_size, shuffle=True)

В теории это работает нормально. И после нескольких тестовых прогонов это, похоже, решило мою проблему. Но через некоторое время я обнаружил, что у меня гоночное условие, потому что я использую входной конвейер кода примера CNN с несколькими потоками (что является предложенным методом в TensorFlow для повышения производительности и уменьшения потребления памяти во время выполнения):

def generate_sequence_batch(sequence_in, prediction, min_queue_examples,
                        batch_size):
    num_preprocess_threads = 8 # <-- !!!
    sequence_batch, prediction_batch = tf.train.shuffle_batch(
        [sequence_in, prediction],
        batch_size=batch_size,
        num_threads=num_preprocess_threads,
        capacity=min_queue_examples + 3 * batch_size,
        min_after_dequeue=min_queue_examples)
return sequence_batch, prediction_batch

Поскольку несколько потоков создают мои примеры, больше не гарантируется, что все операции с изображениями выполняются в правильном порядке (в смысле правильного порядка случайных операций).

Здесь я пришел к тому, что застрял полностью. Кто-нибудь знает, как решить эту проблему, чтобы применить одно и то же искажение изображения к нескольким изображениям?

Некоторые мои мысли:

  • Я думал о том, чтобы сделать некоторые синхронизации вокруг этих методов искажения изображения, но я мог найти что-нибудь, предоставленное TensorFlow
  • Я попытался сгенерировать случайное число, например, для случайной дельты яркости, используя tf.random_uniform (), и использовал это значение для tf.image.adjust_contrast(). Но результатом случайного генератора TensorFlow всегда является тензор, и я не нашел способа использовать этот тензор в качестве параметра для tf.image.adjust_contrast(), который ожидает простой float32 для своего параметра контрастного фактора.
  • Решение, которое (частично) сработало бы, - объединить все изображения в огромное изображение с помощью tf.concat(), применить случайные операции для изменения контрастности и яркости, а затем разделить изображение. Но это не будет работать для случайного переключения, потому что это (по крайней мере, в моем случае) изменит порядок изображений, и нет никакого способа определить, выполнил ли tf.image.random_flip_left_right() переворот или нет, что при необходимости исправить неправильный порядок изображений.

1 ответ

Решение

Вот что я придумал, посмотрев код random_flip_up_down и random_flip_left_right в тензорном потоке:

def image_distortions(image, distortions):
    distort_left_right_random = distortions[0]
    mirror = tf.less(tf.pack([1.0, distort_left_right_random, 1.0]), 0.5)
    image = tf.reverse(image, mirror)
    distort_up_down_random = distortions[1]
    mirror = tf.less(tf.pack([distort_up_down_random, 1.0, 1.0]), 0.5)
    image = tf.reverse(image, mirror)
    return image


distortions = tf.random_uniform([2], 0, 1.0, dtype=tf.float32)
image = image_distortions(image, distortions)
label = image_distortions(label, distortions)

Я бы сделал что-то подобное, используя tf.case, Это позволяет вам указать, что возвращать, если выполняется определенное условие https://www.tensorflow.org/api_docs/python/tf/case

import tensorflow as tf

def distort(image, x):
    # flip vertically, horizontally, both, or do nothing
    image = tf.case({
        tf.equal(x,0): lambda: tf.reverse(image,[0]),
        tf.equal(x,1): lambda: tf.reverse(image,[1]),
        tf.equal(x,2): lambda: tf.reverse(image,[0,1]),
    }, default=lambda: image, exclusive=True)

    return image

def random_distortion(image):
    x = tf.random_uniform([1], 0, 4, dtype=tf.int32)
    return distort(image, x[0])

Чтобы проверить, работает ли это.

import numpy as np
import matplotlib.pyplot as plt

# create image
image = np.zeros((25,25))
image[:10,5:10] = 1.
# create subplots
fig, axes = plt.subplots(2,2)
for i in axes.flatten(): i.axis('off')

with tf.Session() as sess:
    for i in range(4):
        distorted_img = sess.run(distort(image, i))
        axes[i % 2][i // 2].imshow(distorted_img, cmap='gray')

    plt.show()
Другие вопросы по тегам