AvgPool2D¶
Описание¶
Этот модуль реализует операцию двумерного усредняющего пулинга (объединения). Подробное теоретическое описание см. в Pool2D.
Для входного тензора с размерами (N, C, H_{in}, W_{in}) и выходного с размерами (N, C, H_{out}, W_{out}) операция проводится следующим образом (рассматриваем i-й элемент батча, j-ую карту выходного тензора):
где
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))
print(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()
print(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)
print(pool(data))
[[[[10.5 12.5]
[22.5 24.5]]]]
Параметр size
можно задавать разным для высоты и ширины карты:
pool = AvgPool2D(size=(4, 2))
print(pool(data))
[[[[ 9.5 11.5 13.5]
[21.5 23.5 25.5]]]]
Параметр stride¶
Установим значение stride
равным 1:
pool = AvgPool2D(stride=1)
print(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))
print(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)
print(pool(data))
[[[[10.5]]]]
В выходном тензоре получился всего один элемент, так как оставшиеся элементы входного тензора не могли образовать субтензоры, которые по размеру были бы не меньше окна пулинга, из-за чего они были проигнорированы.
Параметр pad¶
Чтобы включить проигнорированные элементы из предыдущего примера, инициализируем паддинг:
pool = AvgPool2D(size=4, stride=4, pad=1)
print(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)
print(pool(data))
[[[[ 7. 10.]
[25. 28.]]]]
Как видно, окно пулинга шло с учётом наличия дополнительных элементов, но их наличие никак не учитывалось при подсчёте среднего значения субтензора.