[Навыки разработки] · AdaptivePooling и преобразование Max/AvgPooling
Персональный сайт -->www.yansongsong.cn
1. Описание проблемы
Адаптивный пул Адаптивный пул — это слой пула PyTorch, который можно разделить на шесть форм в соответствии с 1D, 2D, 3D, а также максимальным и средним.
Разница между адаптивным пулом Adaptive Pooling и стандартным Max/AvgPooling заключается в том, что адаптивный пул Adaptive Pooling управляет выходным output_size в соответствии с входными параметрами, в то время как стандартный Max/AvgPooling вычисляет output_size через kernel_size, шаг и отступы:
output_size = ceil ((input_size+2∗padding-kernel_size)/шаг)+1
Адаптивный пул существует только с PyTorch, если вам нужно перенести код, содержащий адаптивный пул, в Keras или TensorFlow, вы столкнетесь с проблемами.
В этой статье будет представлена формула, которая может легко заменить AdaptivePooling на Max/AvgPooling, что удобно для всех.
2. Объяснение принципа
Мы уже знаем, что общая формула Max/AvgPooling:output_size = ceil ((input_size+2∗padding-kernel_size)/шаг)+1
Когда мы используем Adaptive Pooling, эта проблема решается известными величинами input_size, output_sizekernel_size и шаг
Чтобы упростить задачу, мы установили отступ в 0 (позже мы можем обнаружить, что то же самое сделано в исходном коде)Часть исходного кода C++)
stride = floor ( (input_size / (output_size) )
kernel_size = input_size — (output_size-1) * шаг
padding = 0
3. Фактическая демонстрация
Давайте проведем настоящий бой, чтобы проверить правильность формулы.
import torch as t
import math
import numpy as np
alist = t.randn(2,6,7)
inputsz = np.array(alist.shape[1:])
outputsz = np.array([2,3])
stridesz = np.floor(inputsz/outputsz).astype(np.int32)
kernelsz = inputsz-(outputsz-1)*stridesz
adp = t.nn.AdaptiveAvgPool2d(list(outputsz))
avg = t.nn.AvgPool2d(kernel_size=list(kernelsz),stride=list(stridesz))
adplist = adp(alist)
avglist = avg(alist)
print(alist)
print(adplist)
print(avglist)
выходной результат
tensor([[[ 0.9095, 0.8043, 0.4052, 0.3410, 1.8831, 0.8703, -0.0839],
[ 0.3300, -1.2951, -1.8148, -1.1118, -1.1091, 1.5657, 0.7093],
[-0.6788, -1.2790, -0.6456, 1.9085, 0.8627, 1.1711, 0.5614],
[-0.0129, -0.6447, -0.6685, -1.2087, 0.8535, -1.4802, 0.5274],
[ 0.7347, 0.0374, -1.7286, -0.7225, -0.4257, -0.0819, -0.9878],
[-1.2553, -1.0774, -0.1936, -1.4741, -0.9028, -0.1584, -0.6612]],
[[-0.3473, 1.0599, -1.5744, -0.2023, -0.5336, 0.5512, -0.3200],
[-0.2518, 0.1714, 0.6862, 0.3334, -1.2693, -1.3348, -0.0878],
[ 1.0515, 0.1385, 0.4050, 0.8554, 1.0170, -2.6985, 0.3586],
[-0.1977, 0.8298, 1.6110, -0.9102, 0.7129, 0.2088, 0.9553],
[-0.2218, -0.7234, -0.4407, 1.0369, -0.8884, 0.3684, 1.2134],
[ 0.5812, 1.1974, -0.1584, -0.0903, -0.0628, 3.3684, 2.0330]]])
tensor([[[-0.3627, 0.0799, 0.7145],
[-0.5343, -0.7190, -0.3686]],
[[ 0.1488, -0.0314, -0.4797],
[ 0.2753, 0.0900, 0.8788]]])
tensor([[[-0.3627, 0.0799, 0.7145],
[-0.5343, -0.7190, -0.3686]],
[[ 0.1488, -0.0314, -0.4797],
[ 0.2753, 0.0900, 0.8788]]])
Можно обнаружить, что adp = t.nn.AdaptiveAvgPool2d(list(outputsz)) и avg = t.nn.AvgPool2d(kernel_size=list(kernelsz),stride=list(stridesz))Результаты согласуются
Чтобы этого не произошло случайно, измените параметры и поэкспериментируйте с AdaptiveAvgPool1d.
import torch as t
import math
import numpy as np
alist = t.randn(2,3,9)
inputsz = np.array(alist.shape[2:])
outputsz = np.array([4])
stridesz = np.floor(inputsz/outputsz).astype(np.int32)
kernelsz = inputsz-(outputsz-1)*stridesz
adp = t.nn.AdaptiveAvgPool1d(list(outputsz))
avg = t.nn.AvgPool1d(kernel_size=list(kernelsz),stride=list(stridesz))
adplist = adp(alist)
avglist = avg(alist)
print(alist)
print(adplist)
print(avglist)
выходной результат
tensor([[[ 1.3405, 0.3509, -1.5119, -0.1730, 0.6971, 0.3399, -0.0874,
-1.2417, 0.6564],
[ 2.0482, 0.3528, 0.0703, 1.2012, -0.8829, -0.3156, 1.0603,
-0.7722, -0.6086],
[ 1.0470, -0.9374, 0.3594, -0.8068, 0.5126, 1.4135, 0.3538,
-1.0973, 0.3046]],
[[-0.1688, 0.7300, -0.3457, 0.5645, -1.2507, -1.9724, 0.4469,
-0.3362, 0.7910],
[ 0.5676, -0.0614, -0.0243, 0.1529, 0.8276, 0.2452, -0.1783,
0.7460, 0.2577],
[-0.1433, -0.7047, -0.4883, 1.2414, -1.4316, 0.9704, -1.7088,
-0.0094, -0.3739]]])
tensor([[[ 0.0598, -0.3293, 0.3165, -0.2242],
[ 0.8237, 0.1295, -0.0461, -0.1069],
[ 0.1563, 0.0217, 0.7600, -0.1463]],
[[ 0.0718, -0.3440, -0.9254, 0.3006],
[ 0.1606, 0.3187, 0.2982, 0.2751],
[-0.4454, -0.2262, -0.7233, -0.6973]]])
tensor([[[ 0.0598, -0.3293, 0.3165, -0.2242],
[ 0.8237, 0.1295, -0.0461, -0.1069],
[ 0.1563, 0.0217, 0.7600, -0.1463]],
[[ 0.0718, -0.3440, -0.9254, 0.3006],
[ 0.1606, 0.3187, 0.2982, 0.2751],
[-0.4454, -0.2262, -0.7233, -0.6973]]])
Можно обнаружить, что adp = t.nn.AdaptiveAvgPool1d(list(outputsz)) и avg = t.nn.AvgPool1d(kernel_size=list(kernelsz),stride=list(stridesz))Результат тоже тот же.
4. Сводный анализ
В будущем, если вы столкнетесь с чужим кодом, использующим Adaptive Pooling, вы сможете преобразовать эти две формулы в стандартный Max/Avg Pooling и применить их к другим обучающим платформам.
stride = floor ( (input_size / (output_size) )
kernel_size = input_size — (output_size-1) * шаг
padding = 0
Если вы знаете input_size ввода, вы можете определить шаг и kernel_size и заменить их стандартным значением Max/AvgPooling.
Hope this helps