2017-07-05 1 views
1

J'utilise des couches convolutives sur des échantillons de données constitués d'images 2D. Une option pour la forme du filtre est 1x2, qui agit sur un bloc contigu de 1x2 de deux pixels voisins. Que faire si je veux avoir un filtre qui agit également sur 2 pixels, mais les pixels sont séparés par un autre entre eux? Est-il possible de coder un tel filtre pour les convolutions dans le réseau de neurones?Filtres arbitraires pour conv2d (par opposition à rectangulaires)

+1

Vous pouvez créer un « masque » des zéros et des uns et appliquer ensuite aux poids et faire une convolution normale? –

Répondre

0

Non ce n'est pas possible. Convolution fonctionne sur hypercube n-dim donc tout ce que vous suggérez n'est pas une convolution, mais une sorte d'opérateur de pedro-ponte. Vous êtes libre de write it on your own (basé sur l'opérateur tf conv) mais ce ne sera pas facile et très probablement n'obtiendra pas de meilleurs résultats que la convolution.

4

Code pour le faire fonctionner

Voici quelques exemples de code qui définit un noyau pour Conv2d et un masque de 5x5 qui permet seulement le centre et les valeurs à l'extérieur passent par.

import tensorflow as tf 
import numpy as np 

image = np.array(range(25)).reshape([1,5,5,1]).astype(float) 
image = tf.stop_gradient(tf.constant(image , dtype=tf.float32)) 


kern = tf.Variable(tf.ones([5,5,1,1] , dtype=tf.float32)) 

mask = np.array([[ 1., 1., 1., 1., 1.], 
       [ 1., 0., 0., 0., 1.], 
       [ 1., 0., 1., 0., 1.], 
       [ 1., 0., 0., 0., 1.], 
       [ 1., 1., 1., 1., 1.]]).reshape([5,5,1,1]) 
mask_variable = tf.Variable(mask , dtype=tf.float32) 
mask = tf.stop_gradient(mask_variable) 

output   = tf.nn.conv2d(image , kern  , strides=[1,1,1,1] , padding="VALID") 
output_with_mask = tf.nn.conv2d(image , kern * mask , strides=[1,1,1,1] , padding="VALID") 

sess = tf.Session() 
sess.run(tf.global_variables_initializer()) 

print "Using whole kernal :",sess.run(output) 

print "Using kernal with a mask :",sess.run(output_with_mask) 

Et la sortie

Using whole kernal : [[[[ 300.]]]] 
Using kernal with a mask : [[[[ 204.]]]] 

En outre, backprop ne changera pas le masque parce que le masque est enveloppé dans tf.stop_gradient.

Résumé

Oui il est possible de le faire comme @ m-vijay déclaré, et Non vous ne voulez probablement pas faire ce que @ Salvador-Dali a déclaré. Bien sûr, il y a des raisons académiques pour lesquelles vous voudriez pouvoir faire ceci.

acclamations

+1

J'expérimente des réseaux convolutifs pour un jeu sur une grille hexagonale. Cela semble être une application valide de cette technique. – Marc

+0

C'est une application cool et totalement appropriée! Je n'avais pas pensé à ça. – Wontonimo

+0

Pourquoi les opérations stop_gradient() sont-elles nécessaires lorsqu'elles agissent uniquement sur des constantes? – Marc

0

filtres arbitraires (avec des poids placés partout) ne sont pas disponibles, mais il existe un nombre limité par la version utile appelée convolution Atrous qui place des poids sur une grille de rechange, qui peut gérer votre exemple précis.

Par exemple, dans votre cas, vous pouvez essayer

W = tf.Variable(tf.random_uniform((1, 2, n_in, n_out)) 
tf.nn.atrous_conv2d(value, W, (1, 2), 'SAME')