2015-02-25 1 views
3

Я хочу обучить простой сверточный автокодер, используя Theano, который отлично работает. Однако я не вижу, как можно изменить команду conv2d, когда используется подвыборка (шаг). Есть ли эффективный способ «инвертировать» команду свертки при использовании шага, как на изображении ниже?Theano: Реконструкция сверток с шагом (подвыборкой) в автокодере

Image shamelessly stolen and painted from http:/cs231n.github.io/convolutional-networks.

Например, я хочу, чтобы изменить следующий ...

from theano.tensor.nnet.conv import conv2d 
x = T.tensor4('x') 
y = T.tanh( conv2d(x, W, border_mode='valid', subsample = (1,1)) ) 
z = conv2d(y, Wprime, border_mode='full', subsample = (1,1) ) 

... в ситуацию, когда subsample = (2,2). Первый слой будет работать так же, как и ожидалось. Однако второй слой будет эффективно «делать свертку с шагом 1, а затем выбрасывать половину выходов». Это явно другая операция, чем то, что я ищу - z даже не будет иметь такое же количество нейронов как длина, как x. Какая должна вторая команда conv2d «восстановить» оригинал x?

ответ

5

Я выхожу из этого, что вы намерены иметь привязанные веса, то есть если первая операция была матричным умножением с W, тогда выход будет сгенерирован с помощью W.T, сопряженной матрицы. В вашем случае вы, таким образом, будете искать сопряженный оператор свертки с последующей подвыборкой.

(EDIT: Я ошибочно сделал вывод, что вы можете использовать любой фильтр для «deconvolve», если вы получите правильные формы. Говоря о присоединенном, все еще информативно. .)

Поскольку оператор свертки и подвыборки операторы линейный оператор, позволяет обозначать их C и S соответственно и заметить, что свертка + подвыборки изображение x будет

S C x 

и что операции присоединенной на y (который живет в том же пространстве, S C x) будет

C.T S.T y 

Теперь S.T не что иное, увеличив частоту до исходного размера изображения путем добавления нулей вокруг всех записей y до нужного размера не получается.

С вашего поста, вы, кажется, чтобы быть в курсе сопряженного оператора свертки с шага (1, 1) - это свертка с обратными фильтрами и обратной border_mode, то есть с filters.dimshuffle(1, 0, 2, 3)[:, :, ::-1, ::-1] и переключателем от border_mode='valid' к border_mode='full'.

Конкатенация повышающей дискретизации и свертки с обратным фильтром, и вы получаете сопряженное соединение.

Примечание: могут быть способы использования градиента T.grad или T.jacobian, чтобы получить это автоматически, но я не уверен, как это делается точно.

EDIT: Там, я записал :)

import theano 
import theano.tensor as T 
import numpy as np 

filters = theano.shared(np.random.randn(4, 3, 6, 5).astype('float32')) 

inp1 = T.tensor4(dtype='float32') 

subsampled_convolution = T.nnet.conv2d(inp1, filters, border_mode='valid', subsample=(2, 2)) 

inp2 = T.tensor4(dtype='float32') 
shp = inp2.shape 
upsample = T.zeros((shp[0], shp[1], shp[2] * 2, shp[3] * 2), dtype=inp2.dtype) 
upsample = T.set_subtensor(upsample[:, :, ::2, ::2], inp2) 
upsampled_convolution = T.nnet.conv2d(upsample, 
    filters.dimshuffle(1, 0, 2, 3)[:, :, ::-1, ::-1], border_mode='full') 

f1 = theano.function([inp1], subsampled_convolution) 
f2 = theano.function([inp2], upsampled_convolution) 

x = np.random.randn(1, 3, 10, 10).astype(np.float32) 
f1x = f1(x) 
y = np.random.randn(*f1x.shape).astype(np.float32) 
f2y = f2(y) 

p1 = np.dot(f1x.ravel(), y.ravel()) 
p2 = np.dot(x.ravel(), f2y[:, :, :-1].ravel()) 

print p1 - p2 

p1 равна p2 подкрепляет, что f2 является сопряженным f1

+0

Конечно, вы можете пропустить 'set_subtensor' со всеми нулями если вы решительно рассеиваете фильтр на то, что он видит на четных и нечетных шагах ... (возможно, было бы полезно понять эту градиентную вещь) – eickenberg

+0

Другое примечание: если вы не используете привязанные веса и сопряженность, вы также можете использовать другие значения, кроме нуля, в повышающей дискретизации (например, ближайший сосед). – eickenberg

+0

Спасибо, нулевое заполнение между скрытыми нейронами именно то, что я искал! (Удивительно, насколько просто это на самом деле ...). Я надеялся, что будет какая-то реализация, которая позволит избежать ненужного вычисления сверток (например, те, которые связаны с нашим нулем), я считаю, что эти шаги часто используются для повышения скорости), поэтому я попытаюсь посмотреть на grad/jacobian. – Koen

Смежные вопросы