Операции объединения и свертки перемещают «окно» по входному тензору. Использование tf.nn.conv2d
в качестве примера: Если входной тензор имеет 4 измерения:, [batch, height, width, channels]
то свертка работает с 2D-окном в height, width
измерениях.
strides
определяет, насколько окно сдвигается в каждом из измерений. При обычном использовании первый (партия) и последний (глубина) шаг устанавливаются равными 1.
Давайте возьмем очень конкретный пример: выполнение двумерной свертки над входным изображением в оттенках серого 32x32. Я говорю оттенки серого, потому что тогда входное изображение имеет глубину = 1, что помогает упростить его. Пусть это изображение будет выглядеть так:
00 01 02 03 04 ...
10 11 12 13 14 ...
20 21 22 23 24 ...
30 31 32 33 34 ...
...
Давайте запустим окно свертки 2x2 на одном примере (размер пакета = 1). Мы дадим свертке глубину выходного канала 8.
Вход в свертку имеет shape=[1, 32, 32, 1]
.
Если вы укажете strides=[1,1,1,1]
с padding=SAME
, тогда вывод фильтра будет [1, 32, 32, 8].
Фильтр сначала создаст вывод для:
F(00 01
10 11)
А затем для:
F(01 02
11 12)
и так далее. Затем он переместится во вторую строку, вычисляя:
F(10, 11
20, 21)
затем
F(11, 12
21, 22)
Если вы укажете шаг [1, 2, 2, 1], он не будет перекрывать окна. Он вычислит:
F(00, 01
10, 11)
а потом
F(02, 03
12, 13)
Шаг действует аналогично для операторов объединения.
Вопрос 2: почему шаги [1, x, y, 1] для сверток
Первый 1 - это пакет: обычно вы не хотите пропускать примеры в своем пакете, иначе вы не должны были включать их в первую очередь. :)
Последний 1 - это глубина свертки: обычно вы не хотите пропускать ввод по той же причине.
Оператор conv2d является более общим, поэтому вы можете создавать свертки, которые перемещают окно по другим измерениям, но это не типичное использование в свертках. Типичное использование - использовать их в пространстве.
Зачем менять форму на -1 -1 - это заполнитель, который говорит: «При необходимости отрегулируйте, чтобы соответствовать размеру, необходимому для полного тензора». Это способ сделать код независимым от размера входного пакета, чтобы вы могли изменить свой конвейер и не настраивать размер пакета повсюду в коде.