AvgPool2D

Описание

Info

Родительский класс: Pool2D

Производные классы: -

Этот модуль реализует операцию двумерного усредняющего пулинга (двумерного усредняющего объединения). Подробное теоретическое описание см. в Pool2D.

Для входного тензора с размерами (N, C, H_{in}, W_{in}) и выходного с размерами (N, C, H_{out}, W_{out}) операция проводится следующим образом (рассматриваем i-й элемент батча, j-ую карту выходного тензора):

out(N_i, C_j, h, w) = \frac{1}{k_hk_w}\sum_{m=0}^{k_h-1}\sum_{n=0}^{k_w-1}(input(N_i, C_j, stride_h \times h + m, stride_w \times w + n))

где

N - размер батча;
C - количество карт в тензоре;
H - размер карт по высоте;
W - размер карт по ширине;
stride_h, stride_w - шаг пулинга вдоль высоты и ширины карт соответственно;
k_h, k_w - размер окна пулинга по высоте и ширине соответственно.

Инициализация

def __init__(self, size=2, stride=2, pad=0, includePad=True, name=None):
Параметр Возможные типы Описание По умолчанию
size Union[int, tuple] Размер ядра. 2
stride Union[int, tuple] Шаг пулинга. 2
pad Union[int, tuple] Паддинг входных карт. 0
includePad bool Флаг учета значений заполнения краёв при подсчете среднего значения. True
name str Имя слоя. None

Пояснения

size - возможна передача как единого размера окна пулинга, в таком случае оно будет квадратным, так и tuple вида (size_h, size_w), где size_h - высота окна пулинга, а size_w - его ширина;


stride - возможна передача как единой величины шага пулинга по высоте и ширине карт, так и tuple вида (stride_h, stride_w), где stride_h - величина шага пулинга вдоль высоты карты, а stride_w - вдоль ширины;


pad - возможна передача как единой величины отступа для всех сторон карт, так и tuple вида (pad_h, pad_w), где pad_h - величина отступа с каждой стороны вдоль высоты картинки, а pad_w - вдоль ширины. Возможности создания асимметричного паддинга (заполнение дополнительными элементами только с одной стороны тензора) для данного модуля не предусмотрено, используйте Pad2D;


includePad - если параметр pad был задан ненулевым и к исходному тензору по краям были добавлены новые элементы, то при поднятом includePad их значения также будут оказывать влияние на результат операции пулинга.

Примеры


Базовый пример пулинга


Необходимые импорты.

>>> import numpy as np
>>> from PuzzleLib.Backend import gpuarray
>>> from PuzzleLib.Modules import AvgPool2D

Info

gpuarray необходим для правильного размещения тензора на GPU

Зададим параметры тензора, чтобы можно было наглядно продемонстрировать работу модуля.

>>> batchsize, maps, h, w = 1, 1, 6, 6
>>> data = gpuarray.to_gpu(np.arange(batchsize * maps * h * w).reshape((batchsize, maps, h, w)).astype(np.float32))
>>> data
[[[[ 0.  1.  2.  3.  4.  5.]
   [ 6.  7.  8.  9. 10. 11.]
   [12. 13. 14. 15. 16. 17.]
   [18. 19. 20. 21. 22. 23.]
   [24. 25. 26. 27. 28. 29.]
   [30. 31. 32. 33. 34. 35.]]]]

Инициализируем модуль со стандартными параметрами (size=2, stride=2, pad=0, includePad=True):

>>> pool = AvgPool2D()
>>> pool(data)
[[[[ 3.5  5.5  7.5]
   [15.5 17.5 19.5]
   [27.5 29.5 31.5]]]]

Параметр size


Оставим все параметры такими же, кроме size:

>>> pool = AvgPool2D(size=4)
>>> pool(data)
[[[[10.5 12.5]
   [22.5 24.5]]]]
Параметр size можно задавать разным для высоты и ширины карты:
>>> pool = AvgPool2D(size=(4, 2))
>>> pool(data)
[[[[ 9.5 11.5 13.5]
   [21.5 23.5 25.5]]]]


Параметр stride


Установим значение stride равным 1:

>>> pool = AvgPool2D(stride=1)
>>> pool(data)
[[[[ 3.5  4.5  5.5  6.5  7.5]
   [ 9.5 10.5 11.5 12.5 13.5]
   [15.5 16.5 17.5 18.5 19.5]
   [21.5 22.5 23.5 24.5 25.5]
   [27.5 28.5 29.5 30.5 31.5]]]]

Параметр stride также можно задавать разным для высоты и ширины карты:

>>> pool = AvgPool2D(stride=(1, 3))
>>> pool(data)
[[[[ 3.5  6.5]
   [ 9.5 12.5]
   [15.5 18.5]
   [21.5 24.5]
   [27.5 30.5]]]]

Изменим теперь и stride, и size:

>>> pool = AvgPool2D(size=4, stride=4)
>>> pool(data)

[[[[10.5]]]]

В выходном тензоре получился всего один элемент, так как оставшиеся элементы входного тензора не могли образовать субтензоры, которые по размеру были бы не меньше окна пулинга, из-за чего они были проигнорированы.


Параметр pad


Чтобы включить проигнорированные элементы из предыдущего примера, инициализируем паддинг:

>>> pool = AvgPool2D(size=4, stride=4, pad=1)
>>> pool(data)
[[[[ 3.9375  5.625 ]
   [14.0625 15.75  ]]]]
Обратите внимание, что паддинг в модуле всегда симметричный - по одному новому элементу (строка или столбец) было добавлено с каждой стороны исходного тензора, т.е. его вид после паддинга:
[[[[ 0.  0.  0.  0.  0.  0.  0.  0.]
   [ 0.  0.  1.  2.  3.  4.  5.  0.]
   [ 0.  6.  7.  8.  9. 10. 11.  0.]
   [ 0. 12. 13. 14. 15. 16. 17.  0.]
   [ 0. 18. 19. 20. 21. 22. 23.  0.]
   [ 0. 24. 25. 26. 27. 28. 29.  0.]
   [ 0. 30. 31. 32. 33. 34. 35.  0.]
   [ 0.  0.  0.  0.  0.  0.  0.  0.]]]]

Параметр pad также можно задавать разным для высоты и ширины карты. Например pad=(0, 2), тогда:

[[[[ 0.  0.  0.  1.  2.  3.  4.  5.  0.  0.]
   [ 0.  0.  6.  7.  8.  9. 10. 11.  0.  0.]
   [ 0.  0. 12. 13. 14. 15. 16. 17.  0.  0.]
   [ 0.  0. 18. 19. 20. 21. 22. 23.  0.  0.]
   [ 0.  0. 24. 25. 26. 27. 28. 29.  0.  0.]
   [ 0.  0. 30. 31. 32. 33. 34. 35.  0.  0.]]]]


Параметр includePad


В предыдущих примерах параметр includePad оставался тем же, что и по умолчанию, т.е. периферийные элементы паддинга включались в расчёты. Теперь посмотрим, что будет, если отключить этот флаг для последнего примера:

>>> pool = AvgPool2D(size=4, stride=4, pad=1, includePad=False)
>>> pool(data)
[[[[ 7. 10.]
   [25. 28.]]]]
Как видно, окно пулинга шло с учётом наличия дополнительных элементов, но их наличие никак не учитывалось при подсчёте среднего значения субтензора.