Tensorflow CNN 图像增强管道

iva*_*van 0 python machine-learning deep-learning tensorflow

我正在尝试学习新的 Tensorflow API,但我对在哪里获得输入批处理张量的句柄有点迷茫,这样我就可以使用例如 tf.image 来操作和增强它们。

这是我当前的网络和管道:

trainX, testX, trainY, testY = read_data()
# trainX [num_image, height, width, channels], these are numpy arrays

#...
train_dataset = tf.data.Dataset.from_tensor_slices((trainX, trainY))
test_dataset = tf.data.Dataset.from_tensor_slices((testX, testY))

#...
iterator = tf.data.Iterator.from_structure(train_dataset.output_types, 
                 train_dataset.output_shapes)
features, labels = iterator.get_next()
train_init_op = iterator.make_initializer(train_dataset)
test_init_op = iterator.make_initializer(test_dataset)

#...defining cnn architecture...

# In the train loop
TrainLoop {
   sess.run(train_init_op)  # switching to train data
   sess.run(train_step, ...) # running a train step

   #... 
   sess.run(test_init_op)  # switching to test data
   test_loss = sess.run(loss, ...) # printing test loss after epoch
}
Run Code Online (Sandbox Code Playgroud)

我正在使用 Dataset API 创建 2 个数据集,以便在 trainloop 中我可以计算训练和测试损失并记录它们。

我将在此管道中的何处操作和扭曲我的输入批次图像?我没有为我的 trainX 输入批次创建任何 tf.placeholders,所以我不能用 tf.image 操作它们,因为例如tf.image.flip_up_down需要一个 3-D 或 4-D 张量。

  • 使用新 API 实现此管道的自然方法是什么?
  • 是否有模块或简单的方法来增加输入批次的图像以适合该管道进行训练?

Dom*_*ack 5

最近发布了一篇非常好的文章演讲,它比我在这里的回复更详细地介绍了 API。下面是一个简短的例子:

import tensorflow as tf
import numpy as np


def read_data():
    n_train = 100
    n_test = 50
    height = 20
    width = 30
    channels = 3
    trainX = (np.random.random(
        size=(n_train, height, width, channels)) * 255).astype(np.uint8)
    testX = (np.random.random(
            size=(n_test, height, width, channels))*255).astype(np.uint8)
    trainY = (np.random.random(size=(n_train,))*10).astype(np.int32)
    testY = (np.random.random(size=(n_test,))*10).astype(np.int32)
    return trainX, testX, trainY, testY


trainX, testX, trainY, testY = read_data()
# trainX [num_image, height, width, channels], these are numpy arrays


train_dataset = tf.data.Dataset.from_tensor_slices((trainX, trainY))
test_dataset = tf.data.Dataset.from_tensor_slices((testX, testY))


def map_single(x, y):
    print('Map single:')
    print('x shape: %s' % str(x.shape))
    print('y shape: %s' % str(y.shape))
    x = tf.image.per_image_standardization(x)
    # Consider: x = tf.image.random_flip_left_right(x)
    return x, y


def map_batch(x, y):
    print('Map batch:')
    print('x shape: %s' % str(x.shape))
    print('y shape: %s' % str(y.shape))
    # Note: this flips ALL images left to right. Not sure this is what you want
    # UPDATE: looks like tf documentation is wrong and you need a 3D tensor?
    # return tf.image.flip_left_right(x), y
    return x, y


batch_size = 32
train_dataset = train_dataset.repeat().shuffle(100)
train_dataset = train_dataset.map(map_single, num_parallel_calls=8)
train_dataset = train_dataset.batch(batch_size)
train_dataset = train_dataset.map(map_batch)
train_dataset = train_dataset.prefetch(2)

test_dataset = test_dataset.map(
        map_single, num_parallel_calls=8).batch(batch_size).map(map_batch)
test_dataset = test_dataset.prefetch(2)


iterator = tf.data.Iterator.from_structure(train_dataset.output_types, 
                 train_dataset.output_shapes)
features, labels = iterator.get_next()
train_init_op = iterator.make_initializer(train_dataset)
test_init_op = iterator.make_initializer(test_dataset)


with tf.Session() as sess:
    sess.run(train_init_op)
    feat, lab = sess.run((features, labels))

    print(feat.shape)
    print(lab.shape)

    sess.run(test_init_op)
    feat, lab = sess.run((features, labels))

    print(feat.shape)
    print(lab.shape)    
Run Code Online (Sandbox Code Playgroud)

一些注意事项:

  1. 这种方法依赖于能够将整个数据集加载到内存中。如果不能,请考虑使用tf.data.Dataset.from_generator. 如果您的 shuffle 缓冲区很大,这可能会导致 shuffle 时间变慢。我的首选方法是将一些keys张量完全加载到内存中 - 它可能只是每个示例的索引 - 然后map使用tf.py_func. 这比转换为 效率稍低tfrecords,但prefetching它可能不会影响性能。由于混洗是在映射之前完成的,因此您只需将shuffle_buffer键加载到内存中,而不是shuffle_buffer示例。
  2. 要扩充您的数据集,请tf.data.Dataset.map在批处理操作之前或之后使用,具体取决于您是要应用批处理操作(适用于 4D 图像张量的操作)还是逐元素操作(3D 图像张量)。请注意,它的文档似乎tf.image.flip_left_right已过时,因为当我尝试使用 4D 张量时出现错误。如果您想随机增加数据,请使用tf.image.random_flip_left_right而不是tf.image.flip_left_right
  3. 如果您正在使用tf.estimator.Estimator(或者不介意将您的代码转换为使用它),那么请查看tf.estimator.train_and_evaluate在数据集之间切换的内置方式。
  4. 考虑使用shuffle/repeat方法改组/重复您的数据集。有关效率的说明,请参阅文章。特别是,repeat -> shuffle -> map -> batch -> batch-wise map -> prefetch 似乎是大多数应用程序的最佳操作顺序。