3

我想使用 Theano 训练一个简单的卷积自动编码器,效果很好。但是,我看不出conv2d在使用二次采样(步幅)时如何反转命令。当使用 stride 时,是否有一种有效的方法来“反转”卷积命令,如下图所示?

图片无耻地从 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

4

1 回答 1

5

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

(编辑:我推错了,只要你得到正确的形状,你可以使用任何过滤器来“反卷积”。不过,谈论伴随物仍然是有益的。之后你将能够放松假设。)

由于卷积算子和子采样算子是线性算子,让我们分别用C和表示它们,S并观察卷积+子采样图像x将是

S C x

y并且(与 位于同一空间中)的伴随操作S C x将是

C.T S.T y

现在,ST 只不过是通过在所有条目周围添加零来对原始图像大小进行上采样,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 的伴随

于 2015-02-26T20:24:33.360 回答