提交 6a231fea authored 作者: lamblin's avatar lamblin

Merge pull request #1369 from nouiz/neibs

Image2Neibs.perform
"""
TODO: implement Images2Neibs.{perform,infer_shape}() methods
TODO: implement Images2Neibs.infer_shape() methods
"""
from theano import Op, Apply
......@@ -7,16 +7,23 @@ import theano.tensor as T
from theano.gradient import grad_not_implemented
from theano.gradient import grad_undefined
import numpy
class Images2Neibs(Op):
def __init__(self, mode='valid'):
"""
Modes:
valid : Reshapes the input as a a 2D tensor where each row is a pooling example.
Requires an input that is a multiple of the pooling factor (in each direction)
ignore_borders : Same as valid, but will ignore the borders if the shape(s) of the input
:type mode: str
:param mode: Possible values:
'valid': Requires an input that is a multiple of the
pooling factor (in each direction)
'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
'wrap_centered' : ?? TODO comment
:return:
Reshapes the input as a 2D tensor where each row is an
pooling example
"""
if mode not in ['valid', 'wrap_centered', 'ignore_borders']:
raise NotImplementedError("Only the mode valid, ignore_borders"
......@@ -63,7 +70,8 @@ class Images2Neibs(Op):
= flattened version of ten4[i,j,l:l+r,k:k+c]
idx += 1
(note: the op isn't necessarily implemented internally with these
for loops, they're just the easiest way to describe the output pattern)
for loops, they're just the easiest way to describe the output
pattern)
"""
ten4 = T.as_tensor_variable(ten4)
neib_shape = T.as_tensor_variable(neib_shape)
......@@ -100,6 +108,103 @@ class Images2Neibs(Op):
def c_code_cache_version(self):
return (5,)
def perform(self, node, inp, out_):
ten4, neib_shape, neib_step = inp
z, = out_
def CEIL_INTDIV(a, b):
if a % b:
return (a // b) + 1
else:
return a // b
grid_c = -1 # number of patch in height
grid_d = -1 # number of patch in width
assert ten4.ndim == 4
assert neib_shape.ndim == 1
assert neib_shape.shape[0] == 2
assert neib_step.ndim == 1
assert neib_step.shape[0] == 2
c, d = neib_shape
step_x, step_y = neib_step
mode = self.mode
if mode == "wrap_centered":
if (c % 2 != 1) or (d % 2 != 1):
raise TypeError(
"Images2Neibs:"
" in mode wrap_centered need patch with odd shapes")
if (ten4.shape[2] < c) or (ten4.shape[3] < d):
raise TypeError(
"Images2Neibs: in wrap_centered mode, don't support"
" image shapes smaller then the patch shapes:"
" neib_shape=(%d,%d), ten4[2:]=[%d,%d]" %
(c, d, ten4.shape[2], ten4.shape[3]))
grid_c = CEIL_INTDIV(ten4.shape[2], step_x)
grid_d = CEIL_INTDIV(ten4.shape[3], step_y)
elif mode == "valid":
if (ten4.shape[2] < c) or (((ten4.shape[2] - c) % 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) % 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) // step_x)
# number of patch in width
grid_d = 1 + ((ten4.shape[3] - d) // step_y)
elif mode == "ignore_borders":
# number of patch in height
grid_c = 1 + ((ten4.shape[2] - c) // step_x)
# number of patch in width
grid_d = 1 + ((ten4.shape[3] - d) // 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] = numpy.empty((z_dim0, z_dim1), dtype=node.outputs[0].dtype)
nb_batch = ten4.shape[0]
nb_stack = ten4.shape[1]
height = ten4.shape[2]
width = ten4.shape[3]
wrap_centered_idx_shift_x = c // 2
wrap_centered_idx_shift_y = d // 2
for n in range(nb_batch):
for s in range(nb_stack):
# loop over the number of patch in height
for a in range(grid_c):
# loop over the number of patch in width
for b in range(grid_d):
z_row = b + grid_d * (a + grid_c * (s + nb_stack * n))
for i in range(c):
ten4_2 = i + a * step_x
if mode == "wrap_centered":
ten4_2 -= wrap_centered_idx_shift_x
if ten4_2 < 0:
ten4_2 += height
elif ten4_2 >= height:
ten4_2 -= height
for j in range(d):
ten4_3 = j + b * step_y
if mode == "wrap_centered":
ten4_3 -= wrap_centered_idx_shift_y
if ten4_3 < 0:
ten4_3 += width
elif ten4_3 >= width:
ten4_3 -= width
z_col = j + d * i
z[0][z_row, z_col] = ten4[n, s, ten4_2, ten4_3]
def c_code(self, node, name, inp, out, sub):
ten4, neib_shape, neib_step = inp
z, = out
......@@ -151,38 +256,59 @@ class Images2Neibs(Op):
if ( "%(mode)s" == "wrap_centered") {
if (c%%2!=1 || d%%2!=1){
PyErr_Format(PyExc_TypeError, "Images2Neibs: in mode wrap_centered need patch with odd shapes");
PyErr_Format(PyExc_TypeError,
"Images2Neibs: in mode wrap_centered"
" need patch with odd shapes");
%(fail)s;
}
if ( (PyArray_DIMS(%(ten4)s))[2] < c || (PyArray_DIMS(%(ten4)s))[3] < d)
if ( (PyArray_DIMS(%(ten4)s))[2] < c ||
(PyArray_DIMS(%(ten4)s))[3] < d)
{
PyErr_Format(PyExc_TypeError, "Images2Neibs: in wrap_centered mode, don't support image shapes smaller then the patch shapes: neib_shape=(%%ld,%%ld), ten4[2:]=[%%ld,%%ld]",
(long int)c, (long int)d, (long int)(PyArray_DIMS(%(ten4)s)[2]), (long int)(PyArray_DIMS(%(ten4)s)[3]));
PyErr_Format(PyExc_TypeError,
"Images2Neibs: in wrap_centered mode, don't support image"
" shapes smaller then the patch shapes:"
" neib_shape=(%%ld,%%ld), ten4[2:]=[%%ld,%%ld]",
(long int)c, (long int)d,
(long int)(PyArray_DIMS(%(ten4)s)[2]),
(long int)(PyArray_DIMS(%(ten4)s)[3]));
%(fail)s;
}
grid_c = CEIL_INTDIV(((PyArray_DIMS(%(ten4)s))[2]),step_x);
grid_d = CEIL_INTDIV(((PyArray_DIMS(%(ten4)s))[3]),step_y);
}else if ( "%(mode)s" == "valid") {
if ( ((PyArray_DIMS(%(ten4)s))[2] < c) ||( (((PyArray_DIMS(%(ten4)s))[2]-c) %% step_x)!=0))
if ( ((PyArray_DIMS(%(ten4)s))[2] < c) ||
( (((PyArray_DIMS(%(ten4)s))[2]-c) %% 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]));
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) %% step_y)!=0))
if ( ((PyArray_DIMS(%(ten4)s))[3] < d) ||
( (((PyArray_DIMS(%(ten4)s))[3]-d) %% 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]));
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;
}
grid_c = 1+(((PyArray_DIMS(%(ten4)s))[2]-c)/step_x); //number of patch in height
grid_d = 1+(((PyArray_DIMS(%(ten4)s))[3]-d)/step_y); //number of patch in width
//number of patch in height
grid_c = 1+(((PyArray_DIMS(%(ten4)s))[2]-c)/step_x);
//number of patch in width
grid_d = 1+(((PyArray_DIMS(%(ten4)s))[3]-d)/step_y);
}else if ( "%(mode)s" == "ignore_borders") {
grid_c = 1+(((PyArray_DIMS(%(ten4)s))[2]-c)/step_x); //number of patch in height
grid_d = 1+(((PyArray_DIMS(%(ten4)s))[3]-d)/step_y); //number of patch in width
//number of patch in height
grid_c = 1+(((PyArray_DIMS(%(ten4)s))[2]-c)/step_x);
//number of patch in width
grid_d = 1+(((PyArray_DIMS(%(ten4)s))[3]-d)/step_y);
}else{
PyErr_Format(PyExc_TypeError, "Images2Neibs: unknow mode '%(mode)s'");
PyErr_Format(PyExc_TypeError,
"Images2Neibs: unknow mode '%(mode)s'");
%(fail)s;
}
......@@ -261,7 +387,8 @@ class Images2Neibs(Op):
dtype_%(z)s* curr_z = (dtype_%(z)s*) PyArray_GETPTR2(%(z)s, z_row, z_col);
*curr_z = *( (dtype_%(ten4)s*) PyArray_GETPTR4(%(ten4)s, n, s, ten4_2, ten4_3));
//printf("\\n(%%i,%%i,%%i,%%i) --> (%%i,%%i)",n,s, ten4_2, ten4_3, z_row, z_col);
//printf("\\n(%%i,%%i,%%i,%%i) --> (%%i,%%i)",
// n, s, ten4_2, ten4_3, z_row, z_col);
//printf("%%f ", *curr_z);
}
}
......
from nose.plugins.skip import SkipTest
import numpy
import unittest
import theano
from theano import shared, function
......@@ -9,14 +10,7 @@ from neighbours import images2neibs, neibs2images, Images2Neibs
from theano.tests import unittest_tools
if theano.config.mode == 'FAST_COMPILE':
mode_without_gpu = theano.compile.mode.get_mode(
'FAST_RUN').excluding('gpu')
else:
mode_without_gpu = theano.compile.mode.get_default_mode().excluding('gpu')
if not theano.config.cxx:
raise SkipTest("G++ not available, so we need to skip this test.")
mode_without_gpu = theano.compile.mode.get_default_mode().excluding('gpu')
class T_Images2Neibs(unittest_tools.InferShapeTester):
......@@ -25,10 +19,10 @@ class T_Images2Neibs(unittest_tools.InferShapeTester):
dtypes = ['int64', 'float32', 'float64']
def test_neibs(self):
for shape, pshape in [((100, 40, 18, 18), (2, 2)),
((100, 40, 6, 18), (3, 2)),
((10, 40, 66, 66), (33, 33)),
((10, 40, 68, 66), (34, 33))
for shape, pshape in [((10, 7, 18, 18), (2, 2)),
((10, 7, 6, 18), (3, 2)),
((5, 7, 66, 66), (33, 33)),
((5, 7, 68, 66), (34, 33))
]:
for border in ['valid', 'ignore_borders']:
for dtype in self.dtypes:
......@@ -69,7 +63,8 @@ class T_Images2Neibs(unittest_tools.InferShapeTester):
#print images.get_value(borrow=True)
neibs = f()
#print neibs
assert numpy.allclose(neibs,[[ 0, 1, 4, 5],
assert numpy.allclose(neibs,
[[ 0, 1, 4, 5],
[ 2, 3, 6, 7],
[ 8, 9, 12, 13],
[10, 11, 14, 15],
......@@ -274,7 +269,8 @@ class T_Images2Neibs(unittest_tools.InferShapeTester):
images = shared(numpy.arange(numpy.prod(shape)).reshape(shape))
neib_shape = T.as_tensor_variable((3, 3))
f = function([], images2neibs(images, neib_shape, mode="wrap_centered"),
f = function([],
images2neibs(images, neib_shape, mode="wrap_centered"),
mode=self.mode)
f()
......@@ -289,7 +285,6 @@ class T_Images2Neibs(unittest_tools.InferShapeTester):
self.assertRaises(TypeError, unittest_tools.verify_grad,
fn, [images_val], mode=self.mode)
def test_grad_valid(self):
shape = (2, 3, 4, 4)
images_val = numpy.random.rand(*shape).astype('float32')
......@@ -310,7 +305,6 @@ class T_Images2Neibs(unittest_tools.InferShapeTester):
def test_grad_ignore_border(self):
shape = (2, 3, 5, 5)
images = T.dtensor4()
images_val = numpy.random.rand(*shape).astype('float32')
def fn(images):
......@@ -321,13 +315,12 @@ class T_Images2Neibs(unittest_tools.InferShapeTester):
eps=0.1)
def test_neibs2images_grad(self):
# say we had images of size (2, 3, 20, 20)
# then we extracted 2x2 neighbors on this, we get (2 * 3 * 10 * 10, 4)
neibs = T.dmatrix()
neibs_val = numpy.random.rand(600, 4)
# say we had images of size (2, 3, 10, 10)
# then we extracted 2x2 neighbors on this, we get (2 * 3 * 5 * 5, 4)
neibs_val = numpy.random.rand(150, 4)
def fn(neibs):
return neibs2images(neibs, (2, 2), (2, 3, 20, 20))
return neibs2images(neibs, (2, 2), (2, 3, 10, 10))
unittest_tools.verify_grad(fn, [neibs_val], mode=self.mode,
eps=0.1)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论