提交 68adb874 authored 作者: Pascal Lamblin's avatar Pascal Lamblin 提交者: GitHub

Merge pull request #4824 from gvtulder/f-conv3d2d-full

Full 3D convolution for conv3d2d
...@@ -288,7 +288,32 @@ def conv3d(signals, filters, ...@@ -288,7 +288,32 @@ def conv3d(signals, filters,
_signals_shape_5d[3] - _filters_shape_5d[3] + 1, _signals_shape_5d[3] - _filters_shape_5d[3] + 1,
_signals_shape_5d[4] - _filters_shape_5d[4] + 1, _signals_shape_5d[4] - _filters_shape_5d[4] + 1,
)) ))
elif border_mode[0] in ('full', 'same'): elif border_mode[0] == 'full':
if _filters_shape_5d[1] != 1:
# pad out_tmp with zeros to have full convolution
out_tmp_padded = tensor.zeros(dtype=out_tmp.dtype, shape=(
_signals_shape_5d[0], # Ns
_signals_shape_5d[1] + 2 * (_filters_shape_5d[1] - 1), # Ts
_filters_shape_5d[0], # Nf
_filters_shape_5d[1], # Tf
_signals_shape_5d[3] + _filters_shape_5d[3] - 1,
_signals_shape_5d[4] + _filters_shape_5d[4] - 1,
))
out_tmp_padded = tensor.set_subtensor(
out_tmp_padded[:,
(_filters_shape_5d[1] - 1):(_signals_shape_5d[1] + _filters_shape_5d[1] - 1),
:, :, :, :],
out_tmp)
out_5d = diagonal_subtensor(out_tmp_padded, 1, 3).sum(axis=3)
else: # for tf==1, no sum along tf, the ts-axis of the output is unchanged!
out_5d = out_tmp.reshape((
_signals_shape_5d[0],
_signals_shape_5d[1],
_filters_shape_5d[0],
_signals_shape_5d[3] + _filters_shape_5d[3] - 1,
_signals_shape_5d[4] + _filters_shape_5d[4] - 1,
))
elif border_mode[0] == 'same':
raise NotImplementedError('sequence border mode', border_mode[0]) raise NotImplementedError('sequence border mode', border_mode[0])
else: else:
raise ValueError('invalid border mode', border_mode[1]) raise ValueError('invalid border mode', border_mode[1])
......
...@@ -2,6 +2,7 @@ from __future__ import absolute_import, print_function, division ...@@ -2,6 +2,7 @@ from __future__ import absolute_import, print_function, division
import time import time
from nose.plugins.skip import SkipTest from nose.plugins.skip import SkipTest
from nose_parameterized import parameterized
import numpy import numpy
try: try:
from scipy import ndimage from scipy import ndimage
...@@ -53,7 +54,17 @@ def test_get_diagonal_subtensor_view(wrap=lambda a: a): ...@@ -53,7 +54,17 @@ def test_get_diagonal_subtensor_view(wrap=lambda a: a):
assert numpy.all(xvi == get_diagonal_subtensor_view(xi, 0, 1)) assert numpy.all(xvi == get_diagonal_subtensor_view(xi, 0, 1))
def pyconv3d(signals, filters): def pyconv3d(signals, filters, border_mode='valid'):
if border_mode == 'full':
# zero-pad signals for full convolution
Ns, Ts, C, Hs, Ws = signals.shape
Nf, Tf, C, Hf, Wf = filters.shape
signals_padded = numpy.zeros((Ns, Ts + 2 * (Tf - 1), C,
Hs + 2 * (Hf - 1), Ws + 2 * (Wf - 1)), 'float32')
signals_padded[:, (Tf - 1):(Ts + Tf - 1), :, (Hf - 1):(Hs + Hf - 1),
(Wf - 1):(Ws + Wf - 1)] = signals
signals = signals_padded
Ns, Ts, C, Hs, Ws = signals.shape Ns, Ts, C, Hs, Ws = signals.shape
Nf, Tf, C, Hf, Wf = filters.shape Nf, Tf, C, Hf, Wf = filters.shape
...@@ -80,7 +91,8 @@ def check_diagonal_subtensor_view_traces(fn): ...@@ -80,7 +91,8 @@ def check_diagonal_subtensor_view_traces(fn):
fn, ops_to_check=(DiagonalSubtensor, IncDiagonalSubtensor)) fn, ops_to_check=(DiagonalSubtensor, IncDiagonalSubtensor))
def test_conv3d(mode=mode_without_gpu, shared=theano.tensor._shared): @parameterized.expand(('valid', 'full'), utt.custom_name_func)
def test_conv3d(border_mode, mode=mode_without_gpu, shared=theano.tensor._shared):
if ndimage is None: if ndimage is None:
raise SkipTest("conv3d2d tests need SciPy") raise SkipTest("conv3d2d tests need SciPy")
...@@ -91,7 +103,7 @@ def test_conv3d(mode=mode_without_gpu, shared=theano.tensor._shared): ...@@ -91,7 +103,7 @@ def test_conv3d(mode=mode_without_gpu, shared=theano.tensor._shared):
filters = numpy.arange(Nf * Tf * C * Hf * Wf).reshape(Nf, Tf, C, Hf, Wf).astype('float32') filters = numpy.arange(Nf * Tf * C * Hf * Wf).reshape(Nf, Tf, C, Hf, Wf).astype('float32')
t0 = time.time() t0 = time.time()
pyres = pyconv3d(signals, filters) pyres = pyconv3d(signals, filters, border_mode)
print(time.time() - t0) print(time.time() - t0)
s_signals = shared(signals) s_signals = shared(signals)
...@@ -100,7 +112,8 @@ def test_conv3d(mode=mode_without_gpu, shared=theano.tensor._shared): ...@@ -100,7 +112,8 @@ def test_conv3d(mode=mode_without_gpu, shared=theano.tensor._shared):
out = conv3d(s_signals, s_filters, out = conv3d(s_signals, s_filters,
signals_shape=signals.shape, signals_shape=signals.shape,
filters_shape=filters.shape) filters_shape=filters.shape,
border_mode=border_mode)
newconv3d = theano.function([], [], newconv3d = theano.function([], [],
updates={s_output: out}, updates={s_output: out},
...@@ -128,7 +141,8 @@ def test_conv3d(mode=mode_without_gpu, shared=theano.tensor._shared): ...@@ -128,7 +141,8 @@ def test_conv3d(mode=mode_without_gpu, shared=theano.tensor._shared):
signals = numpy.random.rand(Ns, Ts, C, Hs, Ws).astype('float32') signals = numpy.random.rand(Ns, Ts, C, Hs, Ws).astype('float32')
filters = numpy.random.rand(Nf, Tf, C, Hf, Wf).astype('float32') filters = numpy.random.rand(Nf, Tf, C, Hf, Wf).astype('float32')
utt.verify_grad(conv3d, [signals, filters], eps=1e-1, mode=mode) utt.verify_grad(lambda s, f: conv3d(s, f, border_mode=border_mode),
[signals, filters], eps=1e-1, mode=mode)
# Additional Test that covers the case of patched implementation for filter with Tf=1 # Additional Test that covers the case of patched implementation for filter with Tf=1
Ns, Ts, C, Hs, Ws = 3, 10, 3, 32, 32 Ns, Ts, C, Hs, Ws = 3, 10, 3, 32, 32
...@@ -138,7 +152,7 @@ def test_conv3d(mode=mode_without_gpu, shared=theano.tensor._shared): ...@@ -138,7 +152,7 @@ def test_conv3d(mode=mode_without_gpu, shared=theano.tensor._shared):
filters = numpy.arange(Nf * Tf * C * Hf * Wf).reshape(Nf, Tf, C, Hf, Wf).astype('float32') filters = numpy.arange(Nf * Tf * C * Hf * Wf).reshape(Nf, Tf, C, Hf, Wf).astype('float32')
t0 = time.time() t0 = time.time()
pyres = pyconv3d(signals, filters) pyres = pyconv3d(signals, filters, border_mode)
print(time.time() - t0) print(time.time() - t0)
s_signals = shared(signals) s_signals = shared(signals)
...@@ -147,7 +161,8 @@ def test_conv3d(mode=mode_without_gpu, shared=theano.tensor._shared): ...@@ -147,7 +161,8 @@ def test_conv3d(mode=mode_without_gpu, shared=theano.tensor._shared):
out = conv3d(s_signals, s_filters, out = conv3d(s_signals, s_filters,
signals_shape=signals.shape, signals_shape=signals.shape,
filters_shape=filters.shape) filters_shape=filters.shape,
border_mode=border_mode)
newconv3d = theano.function([], [], newconv3d = theano.function([], [],
updates={s_output: out}, updates={s_output: out},
...@@ -173,4 +188,5 @@ def test_conv3d(mode=mode_without_gpu, shared=theano.tensor._shared): ...@@ -173,4 +188,5 @@ def test_conv3d(mode=mode_without_gpu, shared=theano.tensor._shared):
signals = numpy.random.rand(Ns, Ts, C, Hs, Ws).astype('float32') signals = numpy.random.rand(Ns, Ts, C, Hs, Ws).astype('float32')
filters = numpy.random.rand(Nf, Tf, C, Hf, Wf).astype('float32') filters = numpy.random.rand(Nf, Tf, C, Hf, Wf).astype('float32')
utt.verify_grad(conv3d, [signals, filters], eps=1e-1, mode=mode) utt.verify_grad(lambda s, f: conv3d(s, f, border_mode=border_mode),
[signals, filters], eps=1e-1, mode=mode)
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论