Theano:在自动编码器中用步幅(子采样)重建卷积
Theano: Reconstructing convolutions with stride (subsampling) in an autoencoder
我想使用 Theano 训练一个简单的卷积自动编码器,它运行良好。但是,我看不出在使用子采样(步幅)时如何反转 conv2d
命令。有没有一种有效的方法来 "invert" 使用 stride 时的卷积命令,如下图所示?
例如,我想更改以下...
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)
的情况。第一层将按预期工作。但是,第二层将有效 "do a convolution with stride 1, then throw away half of the outputs"。这显然与我正在寻找的操作不同 - z
的神经元数量甚至不会与 x
的长度相同。第二个 conv2d
命令对 "reconstruct" 原来的 x
应该是什么?
我由此推断您打算绑定权重,即如果第一个运算是与 W
的矩阵乘法,那么输出将由 W.T
伴随矩阵生成。在你的情况下,你会因此寻找卷积运算符的伴随,然后是子采样。
(编辑:我推断错误,你可以使用任何过滤器来 'deconvolve',只要你的形状正确。不过,谈论伴随仍然是有益的。你将能够放松之后的假设。)
由于卷积运算符和二次采样运算符是线性运算符,让我们分别用 C
和 S
表示它们并观察卷积 + 二次采样图像 x
将是
S C x
并且 y
上的伴随运算(与 S C x
位于相同的 space)将是
C.T S.T y
现在,S.T 只不过是通过在 y
的所有条目周围添加零直到获得正确的大小,对原始图像大小进行上采样。
从你的 post 来看,你似乎知道步长 (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
的伴随
我想使用 Theano 训练一个简单的卷积自动编码器,它运行良好。但是,我看不出在使用子采样(步幅)时如何反转 conv2d
命令。有没有一种有效的方法来 "invert" 使用 stride 时的卷积命令,如下图所示?
例如,我想更改以下...
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)
的情况。第一层将按预期工作。但是,第二层将有效 "do a convolution with stride 1, then throw away half of the outputs"。这显然与我正在寻找的操作不同 - z
的神经元数量甚至不会与 x
的长度相同。第二个 conv2d
命令对 "reconstruct" 原来的 x
应该是什么?
我由此推断您打算绑定权重,即如果第一个运算是与 W
的矩阵乘法,那么输出将由 W.T
伴随矩阵生成。在你的情况下,你会因此寻找卷积运算符的伴随,然后是子采样。
(编辑:我推断错误,你可以使用任何过滤器来 'deconvolve',只要你的形状正确。不过,谈论伴随仍然是有益的。你将能够放松之后的假设。)
由于卷积运算符和二次采样运算符是线性运算符,让我们分别用 C
和 S
表示它们并观察卷积 + 二次采样图像 x
将是
S C x
并且 y
上的伴随运算(与 S C x
位于相同的 space)将是
C.T S.T y
现在,S.T 只不过是通过在 y
的所有条目周围添加零直到获得正确的大小,对原始图像大小进行上采样。
从你的 post 来看,你似乎知道步长 (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