Dans une certaine tâche, je voulais augmenter les fonctionnalités dans la direction Y tout en réduisant les fonctionnalités dans la direction X. Par exemple, je veux créer une image de taille (100, 100) à (50, 200) en utilisant conv / deconv. Il existe à peu près deux façons de résoudre ce problème.
Je veux éviter la première méthode car elle a une structure à deux couches. Par conséquent, nous avons examiné et mis en œuvre une méthode d'étirement et de convoyage.
Cependant, je ne pouvais pas penser à une bonne méthode d'implémentation et j'ai utilisé functions.deconvolution_2d
.
Je veux l'implémenter plus intelligemment si possible.
En utilisant la convolution, il est possible de mapper sur une plus petite quantité d'entités tout en conservant les informations de position.
x = numpy.random.rand(1, 1, 100, 100).astype(numpy.float32)
shape = chainer.links.Convolution2D(1, 1, ksize=(4, 1), stride=(2, 1), pad=(1, 0))(x).shape
# shape: (1, 1, 50, 100)
En utilisant la déconvolution, il est possible de mapper vers un plus grand nombre d'entités tout en conservant les informations de position.
x = numpy.random.rand(1, 1, 100, 100).astype(numpy.float32)
shape = chainer.links.Deconvolution2D(1, 1, ksize=(1, 4), stride=(1, 2), pad=(0, 1))(x).shape
# shape: (1, 1, 100, 200)
Cependant, il n'y a probablement pas de couche qui mappe à un petit nombre d'entités dans une dimension et à un grand nombre d'entités dans une autre.
conv→deconv/deconv→conv C'est l'implémentation la plus simple, mais je voudrais l'éviter car elle a une structure à deux couches et le dégradé est susceptible de disparaître.
conv->deconv
x = numpy.random.rand(1, 1, 100, 100).astype(numpy.float32)
x = chainer.links.Convolution2D(1, 1, ksize=(4, 1), stride=(2, 1), pad=(1, 0))(x)
x = chainer.links.Deconvolution2D(1, 1, ksize=(1, 4), stride=(1, 2), pad=(0, 1))(x)
# x.shape: (1, 1, 50, 200)
deconv->conv
x = numpy.random.rand(1, 1, 100, 100).astype(numpy.float32)
x = chainer.links.Deconvolution2D(1, 1, ksize=(1, 4), stride=(1, 2), pad=(0, 1))(x)
x = chainer.links.Convolution2D(1, 1, ksize=(4, 1), stride=(2, 1), pad=(1, 0))(x)
# x.shape: (1, 1, 50, 200)
J'ai pensé à deux choses. Tout d'abord, 1.
Après avoir étiré en utilisant functions.unpool_2d
, réduisez-le avec conv.
unpooling->conv
x = numpy.random.rand(1, 1, 100, 100).astype(numpy.float32)
x = chainer.functions.unpooling_2d(x, ksize=(1, 2))
x = chainer.links.Convolution2D(1, 1, ksize=(4, 4), stride=(2, 1), pad=(1, 2))(x)
# x.shape: (1, 1, 50, 200)
Puis ce 2.
Après avoir étiré avec functions.deconvolution_2d
, réduisez-le avec conv.
On a l'impression de faire un masque comme 1010101010 ... et de l'étirer avec deconv.
upsample->conv
x = numpy.random.rand(1, 1, 100, 100).astype(numpy.float32)
x = chainer.functions.deconvolution_2d(x, W=numpy.array([0, 1, 0], numpy.float32).reshape(1, 1, 1, 3), stride=(1, 2))
x = chainer.links.Convolution2D(1, 1, ksize=(4, 4), stride=(2, 1), pad=(1, 1))(x)
# x.shape: (1, 1, 50, 200)
Quel est le meilleur?
En premier lieu, j'ai l'intention de l'appliquer lors de l'exécution de la convocation 3D en utilisant links.ConvolutionND
au lieu de 2D, mais j'ai remarqué qu'il n'y a pas de functions.un Covolution_nd
. Que devrais-je faire.
Recommended Posts