MaxPool1D

Описание

Info

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

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

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

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

out(N_i, C_j, l) = \max\limits_{m=0..k-1}(input(N_i, C_j, stride \times l + m))

где

N - размер батча;
C - количество карт в тензоре;
L - размер последовательности;
stride - шаг пулинга;
k - размер окна пулинга.

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

def __init__(self, size=2, stride=2, pad=0, useMask=False, name=None):

Параметры

Параметр Возможные типы Описание По умолчанию
size int Размер ядра 2
stride int Шаг пулинга 2
pad int Паддинг входных карт 0
useMask bool Сохранять ли тензор с индексами максимумов False
name str Имя слоя None

Пояснения

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

Примеры


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


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

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

Info

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

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

batchsize, maps, insize = 1, 1, 10
data = gpuarray.to_gpu(np.arange(batchsize * maps * insize).reshape((batchsize, maps, insize)).astype(np.float32))
print(data)
[[[0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]]]

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

pool = MaxPool1D()
print(pool(data))
[[[1. 3. 5. 7. 9.]]]


Параметр size


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

pool = MaxPool1D(size=4)
print(pool(data))
[[[3. 5. 7. 9.]]]


Параметр stride


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

pool = MaxPool1D(stride=1)
print(pool(data))
[[[1. 2. 3. 4. 5. 6. 7. 8. 9.]]]

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

pool = MaxPool1D(size=4, stride=4)
print(pool(data))
[[[3. 7.]]]

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


Параметр pad


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

pool = MaxPool1D(size=4, stride=4, pad=1)
print(pool(data))
[[[2. 6. 9.]]]
Обратите внимание, что паддинг в модуле всегда симметричный - по одному новому элементу было добавлено с каждой стороны исходного тензора, т.е. его вид после паддинга:

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

Параметр useMask


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

np.random.seed(123)
data = gpuarray.to_gpu(np.random.randint(low=0, high=9, size=(batchsize, maps, insize)).astype(np.float32))
print(data)
[[[2. 2. 6. 1. 3. 6. 1. 0. 1. 0.]]]
pool = MaxPool1D(useMask=True)
print(pool(data))
[[[2. 6. 6. 1. 1.]]]
print(pool.mask)
[[[[0 2 5 6 8]]]]
Для каждого элемента батча и каждой карты индексы возвращаются отдельно:
maps = 2
data = gpuarray.to_gpu(np.random.randint(low=0, high=9, size=(batchsize, maps, insize)).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.]]]
pool = MaxPool1D(useMask=True)
print(pool(data))
[[[2. 6. 6. 1. 1.]
  [3. 4. 4. 7. 3.]]]
print(pool.mask)
[[[[0 2 5 6 8]]
  [[1 2 5 7 8]]]]
print(pool.mask.shape)
(1, 2, 1, 5)