Skip to content

MaxPool2D

Описание

Info

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

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

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

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

out(N_i, C_j, h, w) = \max\limits_{m=0..k_h-1}\max\limits_{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, useMask=False, name=None):

Параметры

Параметр Возможные типы Описание По умолчанию
size Union[int, tuple] Размер ядра 2
stride Union[int, tuple] Шаг пулинга 2
pad Union[int, tuple] Паддинг входных карт 0
useMask bool Сохранять ли тензор с индексами максимумов False
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.

Примеры


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


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

import numpy as np
from PuzzleLib.Backend import gpuarray
from PuzzleLib.Modules import MaxPool2D

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, useMask=False):

pool = MaxPool2D()
print(avgpool(data))
[[[[ 7.  9. 11.]
   [19. 21. 23.]
   [31. 33. 35.]]]]

Параметр size


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

pool = MaxPool2D(size=4)
print(pool(data))
[[[[21. 23.]
   [33. 35.]]]]

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

pool = MaxPool2D(size=(4, 2))
print(pool(data))

[[[[19. 21. 23.]
   [31. 33. 35.]]]]

Параметр stride


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

pool = MaxPool2D(stride=1)
print(pool(data))

[[[[ 7.  8.  9. 10. 11.]
   [13. 14. 15. 16. 17.]
   [19. 20. 21. 22. 23.]
   [25. 26. 27. 28. 29.]
   [31. 32. 33. 34. 35.]]]]

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

pool = MaxPool2D(stride=(1, 3))
print(pool(data))
[[[[ 7. 10.]
   [13. 16.]
   [19. 22.]
   [25. 28.]
   [31. 34.]]]]

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

pool = MaxPool2D(size=4, stride=4)
print(pool(data))
[[[[21.]]]]

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


Параметр pad


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

pool = MaxPool2D(size=4, stride=4, pad=1)
print(pool(data))

[[[[14. 17.]
   [32. 35.]]]]

Обратите внимание, что паддинг в модуле всегда симметричный - по одному новому элементу (строка или столбец) было добавлено с каждой стороны исходного тензора, т.е. его вид после паддинга:

[[[[ 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.]]]]

Параметр useMask


Параметр useMask отвечает за то, будет ли сохранён тензор индексов максимальных элементов. Чтобы продемонстрировать его работу, переинициализируем тензор данных:

np.random.seed(123)
data = gpuarray.to_gpu(np.random.randint(low=0, high=9, size=(batchsize, maps, h, w)).astype(np.float32))
print(data)
[[[[2. 2. 6. 1. 3. 6.]
   [1. 0. 1. 0. 0. 3.]
   [4. 0. 0. 4. 1. 7.]
   [3. 2. 4. 7. 2. 4.]
   [8. 0. 7. 3. 4. 6.]
   [1. 5. 6. 2. 1. 8.]]]]
pool = MaxPool2D(useMask=True)
print(pool(data))
[[[[2. 6. 6.]
   [4. 7. 7.]
   [8. 7. 8.]]]]
print(pool.mask)
[[[[ 6  3 10]
   [19 20 17]
   [30 27 34]]]]

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

maps = 2
data = gpuarray.to_gpu(np.random.randint(low=0, high=9, size=(batchsize, maps, h, w)).astype(np.float32))
print(data)

[[[[2. 2. 6. 1. 3. 6.]
   [1. 0. 1. 0. 0. 3.]
   [4. 0. 0. 4. 1. 7.]
   [3. 2. 4. 7. 2. 4.]
   [8. 0. 7. 3. 4. 6.]
   [1. 5. 6. 2. 1. 8.]]

  [[3. 5. 0. 2. 6. 2.]
   [4. 4. 6. 3. 0. 6.]
   [4. 7. 6. 7. 1. 5.]
   [7. 2. 4. 8. 1. 2.]
   [1. 1. 3. 5. 0. 8.]
   [1. 6. 3. 3. 5. 7.]]]]
pool = MaxPool2D(useMask=True)
print(pool(data))
[[[[2. 6. 6.]
   [4. 7. 7.]
   [8. 7. 8.]]

  [[5. 6. 6.]
   [7. 8. 5.]
   [6. 5. 8.]]]]
print(pool.mask)
[[[[ 0  2  5]
   [12 21 17]
   [24 26 35]]

  [[ 1  8  4]
   [13 21 17]
   [31 27 29]]]]
print(pool.mask.shape)
(1, 2, 3, 3)