Поиск…


Вступление

2D-свертка вычисляется аналогичным образом, чтобы вычислить 1D-свертку : вы сдвигаете свое ядро ​​над входом, вычисляете умножения по элементам и суммируете их. Но вместо вашего ядра / ввода, являющегося массивом, здесь они являются матрицами.

Нет отступов, шагов = 1

Это самый простой пример: самые простые вычисления. Предположим, что ваш input и kernel : введите описание изображения здесь

Когда вы получите ядро, вы получите следующий результат: введите описание изображения здесь , который рассчитывается следующим образом:

  • 14 = 4 * 1 + 3 * 0 + 1 * 1 + 2 * 2 + 1 * 1 + 0 * 0 + 1 * 0 + 2 * 0 + 4 * 1
  • 6 = 3 * 1 + 1 * 0 + 0 * 1 + 1 * 2 + 0 * 1 + 1 * 0 + 2 * 0 + 4 * 0 + 1 * 1
  • 6 = 2 * 1 + 1 * 0 + 0 * 1 + 1 * 2 + 2 * 1 + 4 * 0 + 3 * 0 + 1 * 0 + 0 * 1
  • 12 = 1 * 1 + 0 * 0 + 1 * 1 + 2 * 2 + 4 * 1 + 1 * 0 + 1 * 0 + 0 * 0 + 2 * 1

Функция conv2d TF вычисляет свертки в партиях и использует немного другой формат. Для ввода [batch, in_height, in_width, in_channels] для ядра это [filter_height, filter_width, in_channels, out_channels] . Поэтому нам необходимо предоставить данные в правильном формате:

import tensorflow as tf
k = tf.constant([
    [1, 0, 1],
    [2, 1, 0],
    [0, 0, 1]
], dtype=tf.float32, name='k')
i = tf.constant([
    [4, 3, 1, 0],
    [2, 1, 0, 1],
    [1, 2, 4, 1],
    [3, 1, 0, 2]
], dtype=tf.float32, name='i')
kernel = tf.reshape(k, [3, 3, 1, 1], name='kernel')
image  = tf.reshape(i, [1, 4, 4, 1], name='image')

После этого свертка вычисляется с помощью:

res = tf.squeeze(tf.nn.conv2d(image, kernel, [1, 1, 1, 1], "VALID"))
# VALID means no padding
with tf.Session() as sess:
   print sess.run(res)

И будет эквивалентно той, которую мы вычислили вручную.

Некоторые дополнения, шаги = 1

Padding - просто причудливое название: окружайте свою матрицу ввода некоторой константой. В большинстве случаев константа равна нулю, и поэтому люди называют ее нулевым заполнением. Поэтому, если вы хотите использовать дополнение 1 в нашем исходном вводе (проверьте первый пример с padding=0, strides=1 ), матрица будет выглядеть так:

введите описание изображения здесь

Чтобы вычислить значения свертки, вы делаете одно и то же скольжение. Обратите внимание, что в нашем случае многие значения в середине не нужно пересчитывать (они будут такими же, как в предыдущем примере. Я также не буду показывать все вычисления здесь, потому что идея проста: результат:

введите описание изображения здесь

где

  • 5 = 0 * 1 + 0 * 0 + 0 * 1 + 0 * 2 + 4 * 1 + 3 * 0 + 0 * 0 + 0 * 1 + 1 * 1
  • ...
  • 6 = 4 * 1 + 1 * 0 + 0 * 1 + 0 * 2 + 2 * 1 + 0 * 0 + 0 * 0 + 0 * 0 + 0 * 1

TF не поддерживает произвольное заполнение в функции conv2d , поэтому, если вам нужно некоторое дополнение, которое не поддерживается, используйте tf.pad () . К счастью для нашего ввода прокладка «SAME» будет равна padding = 1. Поэтому нам нужно изменить почти ничего в нашем предыдущем примере:

res = tf.squeeze(tf.nn.conv2d(image, kernel, [1, 1, 1, 1], "SAME"))
# 'SAME' makes sure that our output has the same size as input and 
# uses appropriate padding. In our case it is 1.
with tf.Session() as sess:
   print sess.run(res)

Вы можете проверить, что ответ будет таким же, как рассчитывается вручную.

Заполнение и шаг (самый общий случай)

Теперь мы применим свернутую свертку к нашему ранее описанному дополненному примеру и вычислим свертку, где p = 1, s = 2

введите описание изображения здесь

Раньше, когда мы использовали strides = 1 , наше скользящее окно перемещалось на 1 позицию, а strides = s перемещалось по s позициям (вам нужно вычислить s^2 элемента меньше. Но в нашем случае мы можем воспользоваться ярлыком и не выполнять никаких действий вычислений вообще. Поскольку мы уже вычислили значения для s = 1 , в нашем случае мы можем просто захватить каждый второй элемент.

Поэтому, если решение является случаем s = 1 было

введите описание изображения здесь

в случае s = 2 это будет:

введите описание изображения здесь

Проверьте позиции значений 14, 2, 12, 6 в предыдущей матрице. Единственное изменение, которое нам нужно выполнить в нашем коде, - это изменить шаги от 1 до 2 для измерения ширины и высоты (2-й, 3-й).

res = tf.squeeze(tf.nn.conv2d(image, kernel, [1, 2, 2, 1], "SAME"))
with tf.Session() as sess:
   print sess.run(res)

Кстати, нет ничего, что помешало бы нам использовать разные шаги для разных измерений.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow