提交 3805415a authored 作者: botev's avatar botev

Merge remote-tracking branch 'origin/master'

......@@ -23,17 +23,14 @@ class GpuImages2Neibs(GpuKernelBase, Images2Neibs, Op):
"""
def __init__(self, mode='valid'):
if mode not in ['valid', 'ignore_borders', 'wrap_centered', 'half']:
raise NotImplementedError("Only the mode valid, ignore_borders"
", wrap_centered and half"
" have been implemented for the op"
" GpuImages2Neibs")
if mode not in ['valid', 'half', 'full',
'ignore_borders', 'wrap_centered']:
raise NotImplementedError("Only the mode valid, half, full, "
"ignore_borders and wrap_centered have "
"been implemented for GpuImages2Neibs")
self.mode = mode
def make_node(self, ten4, neib_shape, neib_step=None):
# TODO: I don't know why, but without this the tests fail?
neib_shape.eval()
####
ten4 = as_gpuarray_variable(ten4, infer_context_name(ten4))
neib_shape = T.as_tensor_variable(neib_shape)
if neib_step is None:
......@@ -56,7 +53,7 @@ class GpuImages2Neibs(GpuKernelBase, Images2Neibs, Op):
return node.inputs[0].type.context
def c_code_cache_version(self):
return (12, )
return (12,)
def c_headers(self):
return ['<numpy_compat.h>', '<gpuarray/types.h>']
......@@ -124,6 +121,8 @@ class GpuImages2Neibs(GpuKernelBase, Images2Neibs, Op):
ten4_2 -= height;
} else if ("%(mode)s"=="half"){
ten4_2 -= wrap_centered_half_idx_shift_x;
} else if ("%(mode)s"=="full"){
ten4_2 -= c - 1;
}
ga_int j = LID_0; // loop over d
{
......@@ -136,6 +135,8 @@ class GpuImages2Neibs(GpuKernelBase, Images2Neibs, Op):
ten4_3 -= width;
} else if ("%(mode)s"=="half"){
ten4_3 -= wrap_centered_half_idx_shift_y;
} else if ("%(mode)s"=="full"){
ten4_3 -= d - 1;
}
ga_int z_col = j + d * i;
......@@ -219,6 +220,8 @@ class GpuImages2Neibs(GpuKernelBase, Images2Neibs, Op):
ten4_2 -= height;
} else if ("%(mode)s"=="half"){
ten4_2 -= wrap_centered_half_idx_shift_x;
} else if ("%(mode)s"=="full"){
ten4_2 -= c - 1;
}
// loop over d
for (ga_int j = LID_0; j < d; j+=LDIM_0)
......@@ -232,6 +235,8 @@ class GpuImages2Neibs(GpuKernelBase, Images2Neibs, Op):
ten4_3 -= width;
} else if ("%(mode)s"=="half"){
ten4_3 -= wrap_centered_half_idx_shift_y;
} else if ("%(mode)s"=="full"){
ten4_3 -= d - 1;
}
ga_int z_col = j + d * i;
......@@ -333,6 +338,22 @@ class GpuImages2Neibs(GpuKernelBase, Images2Neibs, Op):
const npy_intp step_y = (npy_intp) *(npy_%(dtype_neib_step)s*)
PyArray_GETPTR1(%(neib_step)s, 1);
if (step_x <=0 || step_y <=0)
{
PyErr_Format(PyExc_ValueError,
"neib_step wrong step ; values <= 0. Got %%lld %%lld.",
(long long) step_x, (long long) step_y);
%(fail)s;
}
if (c <=0 || d <=0)
{
PyErr_Format(PyExc_ValueError,
"neib_shape values <= 0. Got %%lld %%lld.",
(long long)c, (long long)d);
%(fail)s;
}
if ( "%(mode)s" == "wrap_centered") {
if (c%%2!=1 || d%%2!=1){
PyErr_Format(PyExc_TypeError,
......@@ -412,6 +433,31 @@ class GpuImages2Neibs(GpuKernelBase, Images2Neibs, Op):
grid_c = 1+(((PyGpuArray_DIMS(%(ten4)s))[2]-(c%%2))/step_x);
//number of patch in width
grid_d = 1+(((PyGpuArray_DIMS(%(ten4)s))[3]-(d%%2))/step_y);
}else if ( "%(mode)s" == "full") {
if ( ((PyGpuArray_DIMS(%(ten4)s))[2] < c) ||
( (((PyGpuArray_DIMS(%(ten4)s))[2]+c-2) %% step_x)!=0))
{
PyErr_Format(PyExc_TypeError,
"neib_shape[0]=%%ld, neib_step[0]=%%ld and"
" ten4.shape[2]=%%ld not consistent",
(long int)c, (long int)step_x,
(long int)(PyGpuArray_DIMS(%(ten4)s)[2]));
%(fail)s;
}
if ( ((PyGpuArray_DIMS(%(ten4)s))[3] < d) ||
( (((PyGpuArray_DIMS(%(ten4)s))[3]+d-2) %% step_y)!=0))
{
PyErr_Format(PyExc_TypeError,
"neib_shape[1]=%%ld, neib_step[1]=%%ld and"
" ten4.shape[3]=%%ld not consistent",
(long int)d, (long int)step_y,
(long int)(PyGpuArray_DIMS(%(ten4)s)[3]));
%(fail)s;
}
//number of patch in height
grid_c = 1+(((PyGpuArray_DIMS(%(ten4)s))[2]+c-2)/step_x);
//number of patch in width
grid_d = 1+(((PyGpuArray_DIMS(%(ten4)s))[3]+d-2)/step_y);
}else{
PyErr_Format(PyExc_TypeError,
"GpuImages2Neibs:: unknown mode '%(mode)s'");
......@@ -530,5 +576,5 @@ class GpuImages2Neibs(GpuKernelBase, Images2Neibs, Op):
@op_lifter([Images2Neibs])
@register_opt2([Images2Neibs], 'fast_compile')
def local_gpua_images2neibs(op, context_name, inputs, outputs):
if op.mode in ['valid', 'ignore_borders', 'wrap_centered', 'half']:
if op.mode in ['valid', 'half', 'full', 'ignore_borders', 'wrap_centered']:
return GpuImages2Neibs(op.mode)
......@@ -24,24 +24,28 @@ class Images2Neibs(Op):
- 'valid' :
Requires an input that is a multiple of the pooling factor
(in each direction).
- 'half' :
Equivalent to 'valid' if we pre-pad with zeros the input on
each side by (neib_shape[0]//2, neib_shape[1]//2)
- 'full' :
Equivalent to 'valid' if we pre-pad with zeros the input on
each side by (neib_shape[0] - 1, neib_shape[1] - 1)
- 'ignore_borders' :
Same as valid, but will ignore the borders if the shape(s)
of the input is not a multiple of the pooling factor(s).
- 'wrap_centered' :
?? TODO comment
- 'half' :
Equivalent to 'valid' if we pre-pad with zeros the input on
each side by (neib_shape[0]//2, neib_shape[1]//2)
"""
__props__ = ("mode",)
def __init__(self, mode='valid'):
if mode not in ['valid', 'wrap_centered', 'ignore_borders', 'half']:
raise NotImplementedError("Only the mode valid, ignore_borders"
",wrap_centered and half have been"
" implemented for the op Images2Neibs")
if mode not in ['valid', 'half', 'full',
'wrap_centered', 'ignore_borders']:
raise NotImplementedError("Only the mode valid, half, full, "
"ignore_borders and wrap_centered have "
"been implemented for Images2Neibs")
self.mode = mode
def __str__(self):
......@@ -155,7 +159,7 @@ class Images2Neibs(Op):
grad_undefined(self, 2, neib_step)]
def c_code_cache_version(self):
return (7,)
return (8,)
def perform(self, node, inp, out_):
ten4, neib_shape, neib_step = inp
......@@ -241,9 +245,28 @@ class Images2Neibs(Op):
grid_c = 1 + ((ten4.shape[2] - (c % 2)) // step_x)
# number of patch in width
grid_d = 1 + ((ten4.shape[3] - (d % 2)) // step_y)
elif mode == "full":
# This is equivalent to 'valid' with padding (c - 1, d - 1) on both sides
# Thus the expanded image will have size (h + 2 * (c - 1), w + 2 * (d - 1))
# Plugging these in the equation for 'valid' we get
# h + 2 * (c - 1) - c = h + c - 2
# w + 2 * (d - 1) - c = w + d - 2
if (ten4.shape[2] < c) or (((ten4.shape[2] + c - 2) % step_x) != 0):
raise TypeError(
"neib_shape[0]=%d, neib_step[0]=%d and"
" ten4.shape[2]=%d not consistent" %
(c, step_x, ten4.shape[2]))
if (ten4.shape[3] < d) or (((ten4.shape[3] + d - 2) % step_y) != 0):
raise TypeError(
"neib_shape[1]=%d, neib_step[1]=%d and"
" ten4.shape[3]=%d not consistent" %
(d, step_y, ten4.shape[3]))
# number of patch in height
grid_c = 1 + ((ten4.shape[2] + c - 2) // step_x)
# number of patch in width
grid_d = 1 + ((ten4.shape[3] + d - 2) // step_y)
else:
raise TypeError("Images2Neibs: unknow mode '%s'" % mode)
z_dim0 = grid_c * grid_d * ten4.shape[1] * ten4.shape[0]
z_dim1 = c * d
z[0] = np.empty((z_dim0, z_dim1), dtype=node.outputs[0].dtype)
......@@ -272,6 +295,8 @@ class Images2Neibs(Op):
ten4_2 -= height
elif mode == "half":
ten4_2 -= wrap_centered_half_idx_shift_x
elif mode == "full":
ten4_2 -= c - 1
if ten4_2 < 0 or ten4_2 >= height:
z[0][z_row, d * i: d * i + d] = 0
else:
......@@ -285,6 +310,8 @@ class Images2Neibs(Op):
ten4_3 -= width
elif mode == "half":
ten4_3 -= wrap_centered_half_idx_shift_y
elif mode == "full":
ten4_3 -= d - 1
z_col = j + d * i
if ten4_3 < 0 or ten4_3 >= width:
z[0][z_row, z_col] = 0
......@@ -307,6 +334,11 @@ class Images2Neibs(Op):
elif self.mode == 'half':
grid_c = 1 + ((in_shape[2] - (c % 2)) // step_x)
grid_d = 1 + ((in_shape[3] - (d % 2)) // step_y)
elif self.mode == 'full':
grid_c = 1 + ((in_shape[2] + c - 2) // step_x)
grid_d = 1 + ((in_shape[3] + d - 2) // step_y)
else:
raise TypeError("Images2Neibs: unknow mode '%s'" % self.mode)
z_dim0 = grid_c * grid_d * in_shape[1] * in_shape[0]
z_dim1 = c * d
return [(z_dim0, z_dim1)]
......@@ -453,7 +485,32 @@ class Images2Neibs(Op):
grid_c = 1+(((PyArray_DIMS(%(ten4)s))[2]-(c%%2))/step_x);
//number of patch in width
grid_d = 1+(((PyArray_DIMS(%(ten4)s))[3]-(d%%2))/step_y);
}else{
}else if ( "%(mode)s" == "full") {
if ( ((PyArray_DIMS(%(ten4)s))[2] < c) ||
( (((PyArray_DIMS(%(ten4)s))[2]+c-2) %% step_x)!=0))
{
PyErr_Format(PyExc_TypeError,
"neib_shape[0]=%%ld, neib_step[0]=%%ld and"
" ten4.shape[2]=%%ld not consistent",
(long int)c, (long int)step_x,
(long int)(PyArray_DIMS(%(ten4)s)[2]));
%(fail)s;
}
if ( ((PyArray_DIMS(%(ten4)s))[3] < d) ||
( (((PyArray_DIMS(%(ten4)s))[3]+d-2) %% step_y)!=0))
{
PyErr_Format(PyExc_TypeError,
"neib_shape[1]=%%ld, neib_step[1]=%%ld and"
" ten4.shape[3]=%%ld not consistent",
(long int)d, (long int)step_y,
(long int)(PyArray_DIMS(%(ten4)s)[3]));
%(fail)s;
}
//number of patch in height
grid_c = 1+(((PyArray_DIMS(%(ten4)s))[2]+c-2)/step_x);
//number of patch in width
grid_d = 1+(((PyArray_DIMS(%(ten4)s))[3]+d-2)/step_y);
}else {
PyErr_Format(PyExc_TypeError,
"Images2Neibs: unknow mode '%(mode)s'");
%(fail)s;
......@@ -521,6 +578,8 @@ class Images2Neibs(Op):
else if (ten4_2 >= height) ten4_2 -= height;
} else if ( "%(mode)s" == "half" ){
ten4_2 -= wrap_centered_half_idx_shift_x;
} else if ( "%(mode)s" == "full" ){
ten4_2 -= c - 1;
}
if (ten4_2 < 0 | ten4_2 >= height) {
dtype_%(z)s* curr_z = (dtype_%(z)s*) PyArray_GETPTR2(%(z)s, z_row, d * i);
......@@ -535,6 +594,8 @@ class Images2Neibs(Op):
else if (ten4_3 >= width) ten4_3 -= width;
} else if ( "%(mode)s" == "half" ){
ten4_3 -= wrap_centered_half_idx_shift_y;
} else if ( "%(mode)s" == "full" ){
ten4_3 -= d - 1;
}
int z_col = j + d * i;
dtype_%(z)s* curr_z = (dtype_%(z)s*) PyArray_GETPTR2(%(z)s, z_row, z_col);
......@@ -583,14 +644,17 @@ def images2neibs(ten4, neib_shape, neib_step=None, mode='valid'):
``valid``
Requires an input that is a multiple of the
pooling factor (in each direction).
``half``
Equivalent to 'valid' if we pre-pad with zeros the input on
each side by (neib_shape[0]//2, neib_shape[1]//2)
``full``
Equivalent to 'valid' if we pre-pad with zeros the input on
each side by (neib_shape[0] - 1, neib_shape[1] - 1)
``ignore_borders``
Same as valid, but will ignore the borders if the shape(s) of
the input is not a multiple of the pooling factor(s).
``wrap_centered``
?? TODO comment
``half``
Equivalent to 'valid' if we pre-pad with zeros the input on
each side by (neib_shape[0]//2, neib_shape[1]//2)
Returns
-------
......
......@@ -94,7 +94,7 @@ class T_Images2Neibs(unittest_tools.InferShapeTester):
shape = (2, 3, 5, 5)
for dtype in self.dtypes:
images = shared(np.asarray(np.arange(np.prod(
shape)).reshape(shape), dtype=dtype))
shape)).reshape(shape), dtype=dtype))
neib_shape = T.as_tensor_variable((3, 3))
neib_step = T.as_tensor_variable((2, 2))
for border in ['valid', 'ignore_borders']:
......@@ -213,7 +213,7 @@ class T_Images2Neibs(unittest_tools.InferShapeTester):
for dtype in self.dtypes:
images = shared(np.asarray(np.arange(np.prod(
shape)).reshape(shape), dtype=dtype))
shape)).reshape(shape), dtype=dtype))
neib_shape = T.as_tensor_variable(neib_shape)
neib_step = T.as_tensor_variable(neib_step)
expected = np.asarray(expected)
......@@ -237,6 +237,7 @@ class T_Images2Neibs(unittest_tools.InferShapeTester):
# assert numpy.allclose(images.get_value(borrow=True), g())
def test_neibs_half_step_by_valid(self):
neib_shapes = ((3, 3), (3, 5), (5, 3))
for shp_idx, (shape, neib_step) in enumerate([
[(7, 8, 5, 5), (1, 1)],
[(7, 8, 5, 5), (2, 2)],
......@@ -248,7 +249,7 @@ class T_Images2Neibs(unittest_tools.InferShapeTester):
[(1, 1, 5, 1037), (2, 4)],
[(1, 1, 1045, 5), (4, 2)]]
):
for neib_shape in [(3, 3), (3, 5), (5, 3)]:
for neib_shape in neib_shapes:
for dtype in self.dtypes:
x = theano.shared(np.random.randn(*shape).astype(dtype))
extra = (neib_shape[0] // 2, neib_shape[1] // 2)
......@@ -261,13 +262,38 @@ class T_Images2Neibs(unittest_tools.InferShapeTester):
f = theano.function([], close, mode=self.mode)
assert f()
def test_neibs_full_step_by_valid(self):
for shp_idx, (shape, neib_step, neib_shapes) in enumerate([
[(7, 8, 5, 5), (1, 1), ((3, 3), (3, 5), (5, 3))],
[(7, 8, 5, 5), (2, 2), ((3, 3), (3, 5), (5, 3))],
[(7, 8, 6, 6), (3, 3), ((2, 2), (2, 5), (5, 2))],
[(7, 8, 6, 6), (1, 3), ((2, 2), (2, 5), (5, 2))],
[(7, 8, 6, 6), (3, 1), ((2, 2), (2, 5), (5, 2))],
[(80, 90, 5, 5), (1, 2), ((3, 3), (3, 5), (5, 3))],
[(1025, 9, 5, 5), (2, 1), ((3, 3), (3, 5), (5, 3))],
[(1, 1, 11, 1037), (2, 3), ((3, 3), (5, 3))],
[(1, 1, 1043, 11), (3, 2), ((3, 3), (3, 5))]]
):
for neib_shape in neib_shapes:
for dtype in self.dtypes:
x = theano.shared(np.random.randn(*shape).astype(dtype))
extra = (neib_shape[0] - 1, neib_shape[1] - 1)
padded_shape = (x.shape[0], x.shape[1], x.shape[2] + 2 * extra[0], x.shape[3] + 2 * extra[1])
padded_x = T.zeros(padded_shape)
padded_x = T.set_subtensor(padded_x[:, :, extra[0]:-extra[0], extra[1]:-extra[1]], x)
x_using_valid = images2neibs(padded_x, neib_shape, neib_step, mode="valid")
x_using_full = images2neibs(x, neib_shape, neib_step, mode="full")
close = T.allclose(x_using_valid, x_using_full)
f = theano.function([], close, mode=self.mode)
assert f()
def test_neibs_bad_shape_wrap_centered(self):
shape = (2, 3, 10, 10)
for dtype in self.dtypes:
images = shared(np.arange(
np.prod(shape), dtype=dtype
).reshape(shape))
).reshape(shape))
for neib_shape in [(3, 2), (2, 3)]:
neib_shape = T.as_tensor_variable(neib_shape)
......@@ -317,6 +343,17 @@ class T_Images2Neibs(unittest_tools.InferShapeTester):
self.assertRaises(TypeError, unittest_tools.verify_grad,
fn, [images_val], mode=self.mode)
def test_grad_full(self):
# It is not implemented for now. So test that we raise an error.
shape = (2, 3, 6, 6)
images_val = np.random.rand(*shape).astype('float32')
def fn(images):
return images2neibs(images, (3, 3), mode='full')
self.assertRaises(TypeError, unittest_tools.verify_grad,
fn, [images_val], mode=self.mode)
def test_grad_valid(self):
shape = (2, 3, 6, 6)
images_val = np.random.rand(*shape).astype('float32')
......@@ -382,6 +419,17 @@ class T_Images2Neibs(unittest_tools.InferShapeTester):
mode=self.mode)
self.assertRaises(TypeError, f, images_val)
def test_neibs_full_with_inconsistent_borders(self):
shape = (2, 3, 5, 5)
images = T.dtensor4()
images_val = np.arange(np.prod(shape),
dtype='float32').reshape(shape)
f = theano.function([images],
T.sqr(images2neibs(images, (2, 2), mode='full')),
mode=self.mode)
self.assertRaises(TypeError, f, images_val)
def test_can_not_infer_nb_dim(self):
# Was reported in gh-5613. Test that we do not crash
# or that we crash in a few other case found while
......@@ -389,8 +437,7 @@ class T_Images2Neibs(unittest_tools.InferShapeTester):
img = T.tensor4('img')
patches = T.nnet.neighbours.images2neibs(img, [16, 16])
extractPatches = theano.function([img], patches,
mode=self.mode)
extractPatches = theano.function([img], patches, mode=self.mode)
patsRecovery = T.matrix('patsRecovery')
original_size = T.ivector('original_size')
......@@ -450,6 +497,19 @@ class T_Images2Neibs(unittest_tools.InferShapeTester):
for i in range(1000):
f()
def speed_neibs_full(self):
shape = (100, 40, 18, 18)
images = shared(np.arange(np.prod(shape),
dtype='float32').reshape(shape))
neib_shape = T.as_tensor_variable((3, 3))
f = function([],
images2neibs(images, neib_shape, mode="full"),
mode=self.mode)
for i in range(1000):
f()
def test_infer_shape(self):
shape = (100, 40, 6, 3)
images = np.ones(shape).astype('float32')
......@@ -498,6 +558,15 @@ class T_Images2Neibs(unittest_tools.InferShapeTester):
self._compile_and_check(
[x], [images2neibs(x, neib_shape=(2, 3), mode='half')],
[images], Images2Neibs)
shape = (100, 40, 6, 5)
images = np.ones(shape).astype('float32')
x = T.ftensor4()
self._compile_and_check(
[x], [images2neibs(x, neib_shape=(2, 1), mode='full')],
[images], Images2Neibs)
self._compile_and_check(
[x], [images2neibs(x, neib_shape=(2, 3), mode='full')],
[images], Images2Neibs)
if __name__ == '__main__':
unittest.main()
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论