[PYTHON] Conv en direction x et déconv en direction y avec chainer

Aperçu

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.

  1. conv → déconv ou déconv → conv
  2. Étirer → conv

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.

Contexte

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.

Etude de méthode

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)

Étirer → conv

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)

Considération

Quel est le meilleur?

à partir de maintenant

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

Conv en direction x et déconv en direction y avec chainer
Installez Python 2.7.9 et Python 3.4.x avec pip.
[Parfum x STAR WARS] Conversion de style avec Chainer à partir d'une minute
Mettez OpenCV dans OS X avec Homebrew et vidéo d'entrée / sortie avec python
Apprenez les données distribuées avec TensorFlow Y = 2X
Gérer les "années et mois" en Python
Connectez Scratch X et Digispark avec bouteille
Chargez le modèle caffe avec Chainer et classez les images
Traitement Y / n avec bash, Python et Go
Mettez Scipy + Matplotlib dans Ubuntu sur Vagrant et affichez le graphique avec X11 Forwarding