提交 5726f9ab authored 作者: Vikram's avatar Vikram

Helper function for mode to pad. Other minor changes

上级 1bbe21ba
...@@ -139,9 +139,9 @@ def get_conv_shape_1axis(image_shape, kernel_shape, border_mode, ...@@ -139,9 +139,9 @@ def get_conv_shape_1axis(image_shape, kernel_shape, border_mode,
# In case of symbolic shape, we want to build the smallest graph # In case of symbolic shape, we want to build the smallest graph
# (image_shape + 2 * pad - dil_kernel_shape) // subsample + 1 # (image_shape + 2 * pad - dil_kernel_shape) // subsample + 1
out_shp = (image_shape - dil_kernel_shape) out_shp = (image_shape - dil_kernel_shape)
if pad_l > 0: if pad_l != 0:
out_shp += pad_l out_shp += pad_l
if pad_r > 0: if pad_r != 0:
out_shp += pad_r out_shp += pad_r
if subsample != 1: if subsample != 1:
out_shp = out_shp // subsample out_shp = out_shp // subsample
...@@ -546,6 +546,42 @@ def assert_shape(x, expected_shape, msg='Unexpected shape.'): ...@@ -546,6 +546,42 @@ def assert_shape(x, expected_shape, msg='Unexpected shape.'):
return x return x
def mode_to_pad(mode, convdim, kshp):
if isinstance(mode, tuple):
if len(mode) != convdim:
raise ValueError(
'invalid border_mode {} which must be a '
'tuple of length {}'.format(mode, convdim))
border = ()
for m in mode:
if isinstance(m, integer_types) and m >= 0:
border += ((m, m),)
elif isinstance(m, tuple) and min(m) >= 0 and \
all(isinstance(b, integer_types) for b in m):
if len(m) != 2:
raise NotImplementedError(
'Asymmetric padding not implemented '
'for {}d'.format(len(m)))
border += ((m[0], m[1]),)
else:
raise ValueError(
'invalid border mode {}. The tuple can only contain '
'integers or tuples of length 2'.format(mode))
pad = border
elif mode == 'full':
pad = tuple((kshp[i] - 1,) * 2 for i in range(convdim))
elif mode == 'half':
pad = tuple((kshp[i] // 2,) * 2 for i in range(convdim))
elif mode == 'valid':
pad = ((0, 0),) * convdim
else:
raise ValueError(
'invalid border_mode {}, which must be either '
'"valid", "full", "half", an integer or a tuple '
'of length {}'.format(mode, convdim))
return pad
def conv2d(input, def conv2d(input,
filters, filters,
input_shape=None, input_shape=None,
...@@ -2096,36 +2132,9 @@ class AbstractConv(BaseAbstractConv): ...@@ -2096,36 +2132,9 @@ class AbstractConv(BaseAbstractConv):
% self.convdim) % self.convdim)
o, = out_ o, = out_
mode = self.border_mode mode = self.border_mode
pad = mode_to_pad(mode, self.convdim, dil_kernshp)
if isinstance(mode, tuple): if any(p != (0, 0) for p in pad):
if len(mode) != 2:
raise ValueError(
'invalid border_mode {} which must be a '
'tuple of length {}'.format(mode, self.convdim))
border = ()
for m in mode:
if isinstance(m, integer_types) and m >= 0:
border += ((m, m),)
elif isinstance(m, tuple) and len(m) == 2 and min(m) >= 0 and \
all(isinstance(b, integer_types) for b in m):
border += ((m[0], m[1]),)
else:
raise ValueError(
'invalid border mode {}. The tuple can only contain '
'integers or tuples of length 2'.format(mode))
mode = border
elif mode not in ('valid', 'full', 'half'):
raise ValueError(
'invalid border_mode {}, which must be either '
'"valid", "full", "half", an integer or a tuple '
'of length {}'.format(mode, self.convdim))
if mode == "full":
mode = tuple((dil_kernshp[i] - 1,) * 2 for i in range(self.convdim))
elif mode == "half":
mode = tuple((dil_kernshp[i] // 2,) * 2 for i in range(self.convdim))
if isinstance(mode, tuple):
pad = mode
mode = "valid" mode = "valid"
new_img = np.zeros((img.shape[0], img.shape[1]) + new_img = np.zeros((img.shape[0], img.shape[1]) +
tuple(img.shape[i + 2] + pad[i][0] + pad[i][1] tuple(img.shape[i + 2] + pad[i][0] + pad[i][1]
...@@ -2167,7 +2176,6 @@ class AbstractConv(BaseAbstractConv): ...@@ -2167,7 +2176,6 @@ class AbstractConv(BaseAbstractConv):
conv_out = conv_out[(slice(None), slice(None)) + conv_out = conv_out[(slice(None), slice(None)) +
tuple(slice(None, None, self.subsample[i]) tuple(slice(None, None, self.subsample[i])
for i in range(self.convdim))] for i in range(self.convdim))]
o[0] = node.outputs[0].type.filter(conv_out) o[0] = node.outputs[0].type.filter(conv_out)
def R_op(self, inputs, eval_points): def R_op(self, inputs, eval_points):
...@@ -2383,43 +2391,15 @@ class AbstractConv_gradWeights(BaseAbstractConv): ...@@ -2383,43 +2391,15 @@ class AbstractConv_gradWeights(BaseAbstractConv):
o, = out_ o, = out_
mode = self.border_mode
if isinstance(mode, tuple):
if len(mode) != 2:
raise ValueError(
'invalid border_mode {} which must be a '
'tuple of length {}'.format(mode, self.convdim))
border = ()
for m in mode:
if isinstance(m, integer_types) and m >= 0:
border += ((m, m),)
elif isinstance(m, tuple) and len(m) == 2 and \
min(m) >= 0:
border += ((int(m[0]), int(m[1])),)
else:
raise ValueError(
'invalid border mode {}. The tuple can only contain '
'integers or tuples of length 2'.format(mode))
mode = border
elif mode not in ('valid', 'full', 'half'):
raise ValueError(
'invalid border_mode {}, which must be either '
'"valid", "full", "half", an integer or a tuple '
'of length {}'.format(mode, self.convdim))
if self.unshared and self.convdim != 2: if self.unshared and self.convdim != 2:
raise NotImplementedError('Unshared convolution not implemented for %dD' raise NotImplementedError('Unshared convolution not implemented for %dD'
% self.convdim) % self.convdim)
dil_shape = tuple((shape[i] - 1) * self.filter_dilation[i] + 1 dil_shape = tuple((shape[i] - 1) * self.filter_dilation[i] + 1
for i in range(self.convdim)) for i in range(self.convdim))
if mode == "full": pad = mode_to_pad(self.border_mode, self.convdim, dil_shape)
mode = tuple((dil_shape[i] - 1,) * 2 for i in range(self.convdim))
elif mode == "half": if any(p != (0, 0) for p in pad):
mode = tuple((dil_shape[i] // 2,) * 2 for i in range(self.convdim))
if isinstance(mode, tuple):
pad = mode
mode = "valid"
new_img = np.zeros((img.shape[0], img.shape[1]) + new_img = np.zeros((img.shape[0], img.shape[1]) +
tuple(img.shape[i + 2] + pad[i][0] + pad[i][1] tuple(img.shape[i + 2] + pad[i][0] + pad[i][1]
for i in range(self.convdim)), for i in range(self.convdim)),
...@@ -2713,32 +2693,14 @@ class AbstractConv_gradInputs(BaseAbstractConv): ...@@ -2713,32 +2693,14 @@ class AbstractConv_gradInputs(BaseAbstractConv):
topgrad = np.asarray(topgrad) topgrad = np.asarray(topgrad)
o, = out_ o, = out_
mode = self.border_mode
if isinstance(mode, tuple):
if len(mode) != 2:
raise ValueError(
'invalid border_mode {} which must be a '
'tuple of length {}'.format(mode, self.convdim))
border = ()
for m in mode:
if isinstance(m, integer_types) and m >= 0:
border += ((m, m),)
elif isinstance(m, tuple) and len(m) == 2 and \
min(m) >= 0:
border += ((int(m[0]), int(m[1])),)
else:
raise ValueError(
'invalid border mode {}. The tuple can only contain '
'integers or tuples of length 2'.format(mode))
mode = border
elif mode not in ('valid', 'full', 'half'):
raise ValueError(
'invalid border_mode {}, which must be either '
'"valid", "full", "half", an integer or a tuple '
'of length {}'.format(mode, self.convdim))
if self.unshared and self.convdim != 2: if self.unshared and self.convdim != 2:
raise NotImplementedError('Unshared convolution not implemented for %dD' raise NotImplementedError('Unshared convolution not implemented for %dD'
% self.convdim) % self.convdim)
dil_kernshp = tuple((kern.shape[-self.convdim + i] - 1) * self.filter_dilation[i] + 1
for i in range(self.convdim))
mode = self.border_mode
pad = mode_to_pad(mode, self.convdim, dil_kernshp)
imshp = self.imshp[:] if self.imshp is not None else [None] * (2 + self.convdim) imshp = self.imshp[:] if self.imshp is not None else [None] * (2 + self.convdim)
fallback_imshp = ([topgrad.shape[0], kern.shape[-self.convdim - 1]] + fallback_imshp = ([topgrad.shape[0], kern.shape[-self.convdim - 1]] +
...@@ -2747,24 +2709,13 @@ class AbstractConv_gradInputs(BaseAbstractConv): ...@@ -2747,24 +2709,13 @@ class AbstractConv_gradInputs(BaseAbstractConv):
for i in range(2 + self.convdim)] for i in range(2 + self.convdim)]
expected_topgrad_shape = get_conv_output_shape( expected_topgrad_shape = get_conv_output_shape(
imshp, kern.shape, imshp, kern.shape,
self.border_mode, self.subsample, self.filter_dilation) mode, self.subsample, self.filter_dilation)
if not tuple(expected_topgrad_shape) == tuple(topgrad.shape): if not tuple(expected_topgrad_shape) == tuple(topgrad.shape):
raise ValueError( raise ValueError(
'invalid input_shape for gradInputs: the given input_shape ' 'invalid input_shape for gradInputs: the given input_shape '
'would produce an output of shape {}, but the given topgrad ' 'would produce an output of shape {}, but the given topgrad '
'has shape {}'.format(tuple(expected_topgrad_shape), 'has shape {}'.format(tuple(expected_topgrad_shape),
tuple(topgrad.shape))) tuple(topgrad.shape)))
dil_kernshp = tuple((kern.shape[-self.convdim + i] - 1) * self.filter_dilation[i] + 1
for i in range(self.convdim))
pad = ((0, 0),) * self.convdim
if mode == "full":
pad = tuple((dil_kernshp[i] - 1,) * 2 for i in range(self.convdim))
elif mode == "half":
pad = tuple((dil_kernshp[i] // 2,) * 2 for i in range(self.convdim))
elif isinstance(mode, tuple):
pad = mode
if any(self.subsample[i] > 1 for i in range(self.convdim)): if any(self.subsample[i] > 1 for i in range(self.convdim)):
new_shape = ((topgrad.shape[0], topgrad.shape[1]) + new_shape = ((topgrad.shape[0], topgrad.shape[1]) +
tuple(shape[i] + pad[i][0] + pad[i][1] - dil_kernshp[i] + 1 tuple(shape[i] + pad[i][0] + pad[i][1] - dil_kernshp[i] + 1
...@@ -2823,7 +2774,7 @@ class AbstractConv_gradInputs(BaseAbstractConv): ...@@ -2823,7 +2774,7 @@ class AbstractConv_gradInputs(BaseAbstractConv):
if self.filter_flip: if self.filter_flip:
img = img[flip_filters] img = img[flip_filters]
if any(p != (0, 0) or p != 0 for p in pad): if any(p != (0, 0) for p in pad):
img = img[(slice(None), slice(None)) + img = img[(slice(None), slice(None)) +
tuple(slice(pad[i][0], img.shape[i + 2] - pad[i][1]) tuple(slice(pad[i][0], img.shape[i + 2] - pad[i][1])
for i in range(self.convdim))] for i in range(self.convdim))]
......
...@@ -75,11 +75,11 @@ class BaseCorrMM(gof.OpenMPOp): ...@@ -75,11 +75,11 @@ class BaseCorrMM(gof.OpenMPOp):
'tuple of length 2'.format(border_mode)) 'tuple of length 2'.format(border_mode))
border = () border = ()
for mode in border_mode: for mode in border_mode:
if isinstance(mode, integer_types) and mode >= 0: if isinstance(mode, tuple) and len(mode) == 2 and \
border += ((mode, mode),)
elif isinstance(mode, tuple) and len(mode) == 2 and \
min(mode) >= 0: min(mode) >= 0:
border += ((int(mode[0]), int(mode[1])),) border += ((int(mode[0]), int(mode[1])),)
elif mode >= 0:
border += ((int(mode), int(mode)),)
else: else:
raise ValueError( raise ValueError(
'invalid border mode {}. The tuple can only contain ' 'invalid border mode {}. The tuple can only contain '
...@@ -283,13 +283,13 @@ class BaseCorrMM(gof.OpenMPOp): ...@@ -283,13 +283,13 @@ class BaseCorrMM(gof.OpenMPOp):
if height: if height:
height = '(*(npy_int64 *)(PyArray_DATA(%s)))' % height height = '(*(npy_int64 *)(PyArray_DATA(%s)))' % height
else: else:
if ((self.direction != 0) and (self.dH != 1)) or ((self.direction == 1) and (self.padH_l == -1)): if ((self.direction != 0) and (self.dH != 1)) or ((self.direction == 1) and (self.padH_l == -1 or self.padH_r == -1)):
raise ValueError("height must be given for backprop with vertical sampling or border_mode='half'") raise ValueError("height must be given for backprop with vertical sampling or border_mode='half'")
height = '-1' height = '-1'
if width: if width:
width = '(*(npy_int64 *)(PyArray_DATA(%s)))' % width width = '(*(npy_int64 *)(PyArray_DATA(%s)))' % width
else: else:
if ((self.direction != 0) and (self.dW != 1)) or ((self.direction == 1) and (self.padW_l == -1)): if ((self.direction != 0) and (self.dW != 1)) or ((self.direction == 1) and (self.padW_l == -1 or self.padW_r == -1)):
raise ValueError("width must be given for backprop with horizontal sampling or border_mode='half'") raise ValueError("width must be given for backprop with horizontal sampling or border_mode='half'")
width = '-1' width = '-1'
...@@ -725,7 +725,13 @@ class CorrMM_gradWeights(BaseCorrMM): ...@@ -725,7 +725,13 @@ class CorrMM_gradWeights(BaseCorrMM):
elif self.border_mode == "full": elif self.border_mode == "full":
padH_l = padH_r = padW_l = padW_r = -2 padH_l = padH_r = padW_l = padW_r = -2
elif isinstance(self.border_mode, tuple): elif isinstance(self.border_mode, tuple):
(padH_l, padH_r), (padW_l, padW_r) = self.border_mode border = ()
for mode in self.border_mode:
if isinstance(mode, tuple):
border += ((int(mode[0]), int(mode[1])),)
else:
border += ((int(mode), int(mode)),)
(padH_l, padH_r), (padW_l, padW_r) = border
else: else:
assert self.border_mode == "valid" assert self.border_mode == "valid"
padH_l = padH_r = padW_l = padW_r = 0 padH_l = padH_r = padW_l = padW_r = 0
...@@ -839,7 +845,13 @@ class CorrMM_gradInputs(BaseCorrMM): ...@@ -839,7 +845,13 @@ class CorrMM_gradInputs(BaseCorrMM):
elif self.border_mode == "full": elif self.border_mode == "full":
padH_l = padH_r = padW_l = padW_r = -2 padH_l = padH_r = padW_l = padW_r = -2
elif isinstance(self.border_mode, tuple): elif isinstance(self.border_mode, tuple):
(padH_l, padH_r), (padW_l, padW_r) = self.border_mode border = ()
for mode in self.border_mode:
if isinstance(mode, tuple):
border += ((int(mode[0]), int(mode[1])),)
else:
border += ((int(mode), int(mode)),)
(padH_l, padH_r), (padW_l, padW_r) = border
else: else:
assert self.border_mode == "valid" assert self.border_mode == "valid"
padH_l = padH_r = padW_l = padW_r = 0 padH_l = padH_r = padW_l = padW_r = 0
......
...@@ -24,7 +24,7 @@ from theano.tensor.nnet.abstract_conv import bilinear_kernel_1D ...@@ -24,7 +24,7 @@ from theano.tensor.nnet.abstract_conv import bilinear_kernel_1D
from theano.tensor.nnet.abstract_conv import bilinear_kernel_2D from theano.tensor.nnet.abstract_conv import bilinear_kernel_2D
from theano.tensor.nnet.abstract_conv import bilinear_upsampling from theano.tensor.nnet.abstract_conv import bilinear_upsampling
from theano.tensor.nnet.abstract_conv import separable_conv2d, separable_conv3d from theano.tensor.nnet.abstract_conv import separable_conv2d, separable_conv3d
from theano.tensor.nnet.abstract_conv import dilated_causal_conv from theano.tensor.nnet.abstract_conv import causal_conv
from theano.tensor.nnet.corr import (CorrMM, CorrMM_gradWeights, from theano.tensor.nnet.corr import (CorrMM, CorrMM_gradWeights,
CorrMM_gradInputs) CorrMM_gradInputs)
from theano.tensor.nnet.corr3d import (Corr3dMM, Corr3dMM_gradWeights, from theano.tensor.nnet.corr3d import (Corr3dMM, Corr3dMM_gradWeights,
...@@ -2017,7 +2017,7 @@ class TestAsymmetricPadding(unittest.TestCase): ...@@ -2017,7 +2017,7 @@ class TestAsymmetricPadding(unittest.TestCase):
utt.verify_grad(conv_gradinputs, [kern, top], mode=self.mode, eps=1) utt.verify_grad(conv_gradinputs, [kern, top], mode=self.mode, eps=1)
class TestDilatedCausalConv(unittest.TestCase): class TestCausalConv(unittest.TestCase):
mode = theano.compile.mode.Mode(optimizer='None') mode = theano.compile.mode.Mode(optimizer='None')
imshp = (3, 2, 5) imshp = (3, 2, 5)
...@@ -2031,7 +2031,7 @@ class TestDilatedCausalConv(unittest.TestCase): ...@@ -2031,7 +2031,7 @@ class TestDilatedCausalConv(unittest.TestCase):
img = np.random.random(self.imshp).astype(theano.config.floatX) img = np.random.random(self.imshp).astype(theano.config.floatX)
kern = np.random.random(self.kshp).astype(theano.config.floatX) kern = np.random.random(self.kshp).astype(theano.config.floatX)
sym_out = dilated_causal_conv(img_sym, kern_sym, self.kshp, filter_dilation=1) sym_out = causal_conv(img_sym, kern_sym, self.kshp, filter_dilation=1)
causal_func = theano.function([img_sym, kern_sym], sym_out, mode=self.mode) causal_func = theano.function([img_sym, kern_sym], sym_out, mode=self.mode)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论