Реализация im2col в TensorFlow
Я хочу реализовать операцию, подобную 2D-свертке в TensorFlow. Согласно моему пониманию, наиболее распространенный подход к реализации свертки - это первое применение im2col
операция с изображением (см. здесь - п. "реализация как умножение матриц") - операция, преобразующая изображение в 2D-матрицу с отдельными "кусками" изображения, к которым ядро применяется в виде сплющенных столбцов.
в других словами, этот отрывок из вышеупомянутого связанного ресурса объясняет, что im2col
не красиво:
[... Например, если вход [227x227x3] (в формате Высота x Ширина x n_channels) и он должен быть свернут с фильтрами 11x11x3 на шаге 4, тогда мы возьмем [11x11x3] блоки пикселей на входе и растянем каждый блок в вектор столбца размера 11*11*3 = 363. Итерация этого процесса на входе при шаге 4 дает (227-11)/4+1 = 55 местоположений по ширине и высоте, что приводит к выходной матрице
X_col
ofim2col
размера [363 x 3025], где каждый столбец представляет собой растянутое рецептивное поле, и всего их 55*55 = 3025. Обратите внимание, что, поскольку поля восприятия перекрываются, каждое число во входном томе может дублироваться в несколько отдельных столбцов.
как я понял из TensorFlow docs, это то, что делается внутри tf.nn.conv2d
как хорошо.
теперь, я бы хотелось бы реализовать сказанное im2col
операция в TensorFlow отдельно (так как я хочу иметь доступ к этому промежуточному результату). Поскольку это включает копирование значений нетривиальным способом, как я сам построю относительно эффективный вычислительный граф для этой операции? Аналогично, как можно было бы реализовать обратную операцию?
1 ответов
вы можете легко сделать это с помощью extract_image_patches
.
эта функция ставит каждого filter_size x filter_size
патч изображения в глубину, дающую [batch_size, height, width, 9]
тензор.
Для сравнения tf.nn.conv2d
вы можете реализовать оператор Sobel для изображений
import tensorflow as tf
import numpy as np
image = np.arange(10 * 10 * 1).reshape(1, 10, 10, 1)
images = tf.convert_to_tensor(image.astype(np.float32))
filter_size = 3
sobel_x = tf.constant([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], tf.float32)
sobel_x_filter = tf.reshape(sobel_x, [3, 3, 1, 1])
image_patches = tf.extract_image_patches(images,
[1, filter_size, filter_size, 1],
[1, 1, 1, 1], [1, 1, 1, 1],
padding='SAME')
actual = tf.reduce_sum(tf.multiply(image_patches, tf.reshape(sobel_x_filter, [9])), 3, keep_dims=True)
expected = tf.nn.conv2d(images, sobel_x_filter, strides=[1, 1, 1, 1], padding='SAME')
with tf.Session() as sess:
print sess.run(tf.reduce_sum(expected - actual))
это дает вам 0.0
как они эквивалентны. Для этого не нужна обратная функция.
редактировать:
как я понял из TensorFlow docs, это то, что сделано внутренне с ТФ.НН.conv2d, а также.
нет, не совсем. TF на GPU, например, полагается на CuDNN, который является более сложный зверь (winograd, ptx,...). Только в некоторых случаях он использует im2col
подход здесь на CPU и квантованной версии здесь.