Theano:在自动编码器中用步幅(子采样)重建卷积

时间:2015-02-25 10:28:45

标签: neural-network convolution theano conv-neural-network

我想使用Theano训练一个简单的卷积自动编码器,它一直很好用。但是,在使用子采样(stride)时,我不知道如何反转conv2d命令。是否有一种有效的方式来反转"使用步幅时的卷积命令,如下图所示?

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

1 个答案:

答案 0 :(得分:5)

我从中推断出你打算使用绑定权重,即如果第一个操作是W的矩阵乘法,则输出将使用伴随矩阵W.T生成。在您的情况下,您将寻找卷积运算符的伴随,然后进行子采样。

(编辑:我错误地推断出,你可以使用任何过滤器进行'去卷积',只要你得到正确的形状。然而,谈论伴随仍然提供信息。你将能够放松这个假设。 )

由于卷积运算符和子采样运算符是线性运算符,我们分别用CS表示它们并观察卷积+子采样图像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.gradT.jacobian来自动获取,但我无法确定这是如何完成的。

编辑:在那里,我把它写下来了:)

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的伴随