La mise en commun adaptative est une excellente fonction, mais comment fonctionne-t-elle? Il semble être en train d'insérer des pads ou de rétrécir/étendre la taille des noyaux de ce qui semble être une manière patchée mais assez arbitraire. La documentation de Pytorch que je peux trouver n'est pas plus descriptive que "mettez ici la taille de sortie souhaitée". Est-ce que quelqu'un sait comment cela fonctionne ou peut indiquer où cela est expliqué?
Quelques codes de test sur un tenseur 1x1x6, (1,2,3,4,5,6), avec une sortie adaptative de taille 8:
import torch
import torch.nn as nn
class TestNet(nn.Module):
def __init__(self):
super(TestNet, self).__init__()
self.avgpool = nn.AdaptiveAvgPool1d(8)
def forward(self,x):
print(x)
x = self.avgpool(x)
print(x)
return x
def test():
x = torch.Tensor([[[1,2,3,4,5,6]]])
net = TestNet()
y = net(x)
return y
test()
Production:
tensor([[[ 1., 2., 3., 4., 5., 6.]]])
tensor([[[ 1.0000, 1.5000, 2.5000, 3.0000, 4.0000, 4.5000, 5.5000,
6.0000]]])
S'il miroir les pads à gauche et à droite (fonctionnant sur (1,1,2,3,4,5,6,6)), et a un noyau de 2, alors les sorties pour toutes les positions sauf pour 4 et 5 logique, sauf bien sûr que la sortie n'est pas de la bonne taille. Est-ce que cela remplit également les 3 et 4 en interne? Si c'est le cas, il fonctionne (1,1,2,3,3,4,4,5,6,6), qui, si vous utilisez un noyau de taille 2, produit une taille de sortie incorrecte et manquerait également une sortie 3,5. Change-t-il la taille du noyau?
Suis-je en train de manquer quelque chose d'évident sur la façon dont cela fonctionne?
En général, la mise en commun réduit les dimensions. Si vous souhaitez augmenter les dimensions, vous voudrez peut-être regarder interpolation .
Quoi qu'il en soit, parlons de la mise en commun adaptative en général. Vous pouvez regarder le code source ici . Certains ont affirmé que la mise en commun adaptative est la même que la mise en commun standard avec la taille de foulée et du noyau calculée à partir de la taille d'entrée et de sortie. Plus précisément, les paramètres suivants sont utilisés:
(input_size//output_size)
input_size - (output_size-1)*stride
0
Ceux-ci sont inversement travaillés à partir de la mise en commun formule . Bien qu'ils [~ # ~] produisent [~ # ~] produisent une sortie de la taille souhaitée, sa sortie n'est pas nécessairement la même que celle du pooling adaptatif . Voici un extrait de test:
import torch
import torch.nn as nn
in_length = 5
out_length = 3
x = torch.arange(0, in_length).view(1, 1, -1).float()
print(x)
stride = (in_length//out_length)
avg_pool = nn.AvgPool1d(
stride=stride,
kernel_size=(in_length-(out_length-1)*stride),
padding=0,
)
adaptive_pool = nn.AdaptiveAvgPool1d(out_length)
print(avg_pool.stride, avg_pool.kernel_size)
y_avg = avg_pool(x)
y_ada = adaptive_pool(x)
print(y_avg)
print(y_ada)
Production:
tensor([[[0., 1., 2., 3., 4.]]])
(1,) (3,)
tensor([[[1., 2., 3.]]])
tensor([[[0.5000, 2.0000, 3.5000]]])
Error: 1.0
Pools de regroupement moyens des éléments (0, 1, 2), (1, 2, 3) et (2, 3, 4).
Pools de pooling adaptatif à partir des éléments (0, 1), (1, 2, 3) et (3, 4). (Modifiez un peu le code pour voir qu'il n'est pas regroupé à partir de (2) uniquement)
count_include_pad=True
, Mais en général, je ne pense pas qu'ils puissent être exactement les mêmes pour 2D ou plus pour toutes les tailles d'entrée/sortie. J'imagine utiliser différents rembourrages pour gauche/droite. Pour le moment, cela n'est pas pris en charge dans le regroupement des couches.