Я просматривал документы по тензорному потоку tf.nn.conv2d
здесь . Но я не могу понять, что он делает или чего пытается достичь. На документах сказано:
# 1: Выравнивает фильтр в 2-D матрицу с формой
[filter_height * filter_width * in_channels, output_channels]
,
Что это делает? Это поэлементное умножение или просто умножение матриц? Я также не мог понять другие два пункта, упомянутые в документах. Я написал их ниже:
# 2: Извлекает патчи изображения из входного тензора для формирования виртуального тензора формы
[batch, out_height, out_width, filter_height * filter_width * in_channels]
,№ 3: Для каждого патча, умножает вправо матрицу фильтра и вектор патча изображения.
Было бы очень полезно, если бы кто-нибудь мог привести пример, фрагмент кода (чрезвычайно полезный), может быть, и объяснить, что там происходит и почему операция такая.
Я попытался написать небольшую часть и распечатать форму операции. Тем не менее, я не могу понять.
Я попробовал что-то вроде этого:
op = tf.shape(tf.nn.conv2d(tf.random_normal([1,10,10,10]),
tf.random_normal([2,10,10,10]),
strides=[1, 2, 2, 1], padding='SAME'))
with tf.Session() as sess:
result = sess.run(op)
print(result)
Я понимаю кусочки сверточных нейронных сетей. Я изучал их здесь . Но реализация тензорного потока - не то, что я ожидал. Так что возник вопрос.
РЕДАКТИРОВАТЬ : Итак, я реализовал гораздо более простой код. Но я не могу понять, что происходит. Я имею в виду, как результаты, как это. Было бы чрезвычайно полезно, если бы кто-нибудь мог сказать мне, какой процесс дает этот вывод.
input = tf.Variable(tf.random_normal([1,2,2,1]))
filter = tf.Variable(tf.random_normal([1,1,1,1]))
op = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='SAME')
init = tf.initialize_all_variables()
with tf.Session() as sess:
sess.run(init)
print("input")
print(input.eval())
print("filter")
print(filter.eval())
print("result")
result = sess.run(op)
print(result)
вывод
input
[[[[ 1.60314465]
[-0.55022103]]
[[ 0.00595062]
[-0.69889867]]]]
filter
[[[[-0.59594476]]]]
result
[[[[-0.95538563]
[ 0.32790133]]
[[-0.00354624]
[ 0.41650501]]]]
источник
tf.nn.conv2d()
, поэтому данный метод вообще не используется, когда мы используем TF с поддержкой GPU, еслиuse_cudnn_on_gpu=False
это не указано явно.Ответы:
2D свертка вычисляется аналогично вычислению 1D свертки : вы скользите ядром по входным данным, вычисляете поэлементное умножение и суммируете их. Но вместо того, чтобы ваше ядро / ввод был массивом, здесь они являются матрицами.
В самом простом примере нет отступов и шага = 1. Давайте предположим, что вы
input
иkernel
есть:Когда вы используете свое ядро, вы получите следующий вывод:, который рассчитывается следующим образом:
Функция conv2d TF рассчитывает свертки в пакетах и использует немного другой формат. Для входа это
[batch, in_height, in_width, in_channels]
для ядра это[filter_height, filter_width, in_channels, out_channels]
. Поэтому нам нужно предоставить данные в правильном формате:После этого свертка рассчитывается по формуле:
И будет эквивалентен тому, который мы рассчитали вручную.
Для примеров с отступами / шагами, посмотрите здесь .
источник
Хорошо, я думаю, что это самый простой способ объяснить все это.
Ваш пример - 1 изображение размером 2х2 с 1 каналом. У вас есть 1 фильтр размером 1x1 и 1 канал (размер - высота x ширина x каналов x количество фильтров).
В этом простом случае результирующее 2x2, 1-канальное изображение (размер 1x2x2x1, количество изображений x высота x ширина xx каналов) является результатом умножения значения фильтра на каждый пиксель изображения.
Теперь давайте попробуем больше каналов:
Здесь изображение 3х3 и фильтр 1х1 имеют по 5 каналов. Результирующее изображение будет 3x3 с 1 каналом (размер 1x3x3x1), где значение каждого пикселя является точечным произведением по каналам фильтра с соответствующим пикселем во входном изображении.
Теперь с фильтром 3х3
Здесь мы получаем изображение 1x1 с 1 каналом (размер 1x1x1x1). Значение является суммой 9,5-элементных точечных произведений. Но вы могли бы просто назвать это 45-элементным точечным произведением.
Теперь с большим изображением
На выходе получается одноканальное изображение 3х3 (размер 1х3х3х1). Каждое из этих значений представляет собой сумму 9, 5-элементных точечных произведений.
Каждый вывод осуществляется путем центрирования фильтра на одном из 9 центральных пикселей входного изображения, чтобы ни один из фильтров не торчал. Приведенные
x
ниже значения представляют центры фильтров для каждого выходного пикселя.Теперь с "ЖЕ" обивка:
Это дает выходное изображение 5x5 (размер 1x5x5x1). Это делается путем центрирования фильтра в каждой позиции на изображении.
Любой из 5-элементных точечных продуктов, в которых фильтр выходит за край изображения, получает значение ноль.
Таким образом, углы являются только суммами 4, 5-элементных точечных произведений.
Теперь с несколькими фильтрами.
Это по-прежнему дает выходное изображение 5x5, но с 7 каналами (размер 1x5x5x7). Где каждый канал производится одним из фильтров в наборе.
Теперь с шагами 2,2:
Теперь результат по-прежнему имеет 7 каналов, но только 3х3 (размер 1х3х3х7).
Это связано с тем, что вместо центрирования фильтров в каждой точке изображения фильтры центрируются в каждой другой точке изображения с шагом (шагом) шириной 2. Ниже
x
приведены центры фильтров для каждого выходного пикселя на входное изображение.И, конечно, первое измерение ввода - это количество изображений, чтобы вы могли применить его к пакету из 10 изображений, например:
Это выполняет ту же операцию для каждого изображения независимо, давая в результате стопку из 10 изображений (размер 10x3x3x7)
источник
Must have strides[0] = strides[3] = 1. For the most common case of the same horizontal and vertices strides, strides = [1, stride, stride, 1].
the 3x3 image and the 1x1 filter each have 5 channels
, я считаю, результат отличается от рассчитанного вручную точечного произведения.Просто чтобы добавить к другим ответам, вы должны думать о параметрах в
как «5», соответствующее количеству каналов в каждом фильтре. Каждый фильтр представляет собой 3d-куб глубиной 5. Глубина фильтра должна соответствовать глубине входного изображения. Последний параметр, 7, следует рассматривать как количество фильтров в пакете. Просто забудьте о том, что это 4D, и вместо этого представьте, что у вас есть набор или партия из 7 фильтров. Что вы делаете, это создать 7 фильтров кубов с размерами (3,3,5).
Намного проще визуализировать в области Фурье, поскольку свертка становится точечным умножением. Для входного изображения размеров (100,100,3) вы можете переписать размеры фильтра как
Чтобы получить одну из 7 выходных карт объектов, мы просто выполняем поточечное умножение куба фильтра с кубом изображения, затем суммируем результаты по измерению каналов / глубины (здесь это 3), сворачивая в 2d (100,100) карта возможностей. Сделайте это с каждым фильтрующим кубом, и вы получите 7 2D карт объектов.
источник
Я пытался реализовать conv2d (для моего изучения). Ну, я написал это:
Надеюсь, я сделал это правильно. Проверено на MNIST, были очень близкие результаты (но эта реализация медленнее). Я надеюсь, это поможет вам.
источник
В дополнение к другим ответам, conv2d работает на c ++ (cpu) или cuda для машин gpu, которые требуют определенного выравнивания и преобразования данных и использования умножения матриц gemmBLAS или cuBLAS (cuda).
источник