我由此推断您打算绑定权重,即如果第一个操作是与 的矩阵乘法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.grad
或T.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 的伴随