提交 563bdb57 authored 作者: fsavard's avatar fsavard

Added ImagesFromNeighbourhoods and two basic tests... but the tests are…

Added ImagesFromNeighbourhoods and two basic tests... but the tests are commented out for the moment
上级 cf46082b
...@@ -7,7 +7,8 @@ import numpy ...@@ -7,7 +7,8 @@ import numpy
import __builtin__ import __builtin__
class NeighbourhoodsFromImages(Op): class NeighbourhoodsFromImages(Op):
def __init__(self, n_dims_before, dims_neighbourhoods, strides=None, ignore_border=False): def __init__(self, n_dims_before, dims_neighbourhoods,
strides=None, ignore_border=False, inverse=False):
""" """
This extracts neighbourhoods from "images", but in a This extracts neighbourhoods from "images", but in a
dimension-generic manner. dimension-generic manner.
...@@ -58,13 +59,18 @@ class NeighbourhoodsFromImages(Op): ...@@ -58,13 +59,18 @@ class NeighbourhoodsFromImages(Op):
If the dimensions of the neighbourhoods don't exactly divide the If the dimensions of the neighbourhoods don't exactly divide the
dimensions of the "images", you can either fill the last dimensions of the "images", you can either fill the last
neighbourhood with zeros (False) or drop it entirely (True). neighbourhood with zeros (False) or drop it entirely (True).
inverse : bool
You shouldn't have to use this. Only used by child class
ImagesFromNeighbourhoods which simply reverses the assignment.
""" """
self.n_dims_before = n_dims_before self.n_dims_before = n_dims_before
self.dims_neighbourhoods = dims_neighbourhoods self.dims_neighbourhoods = dims_neighbourhoods
self.strides = strides if not strides is None else dims_neighbourhoods self.strides = strides if not strides is None else dims_neighbourhoods
self.ignore_border = ignore_border self.ignore_border = ignore_border
self.code = self.make_py_code() self.inverse = inverse
self.code_string, self.code = self.make_py_code()
def _compute_neigh_strides(self): def _compute_neigh_strides(self):
neigh_strides = [1 for i in range(len(self.strides))] neigh_strides = [1 for i in range(len(self.strides))]
...@@ -114,23 +120,78 @@ class NeighbourhoodsFromImages(Op): ...@@ -114,23 +120,78 @@ class NeighbourhoodsFromImages(Op):
return dims, num_strides return dims, num_strides
# for inverse mode
# "output" here actually referes to the Op's input shape (but it's inverse mode)
def in_shape(self, output_shape):
out_dims = list(output_shape[:self.n_dims_before])
num_strides = []
# in the inverse case we don't worry about borders:
# they either have been filled with zeros, or have been cropped
for i, ds in enumerate(self.dims_neighbourhoods):
# the number of strides performed by NeighFromImg is
# directly given by this shape
num_strides.append(output_shape[self.n_dims_before + i])
# our Op's output image must be at least this wide
at_least_width = num_strides[i] * self.strides[i]
# ... which gives us this number of neighbourhoods
num_neigh = at_least_width // ds
if at_least_width % ds != 0:
num_neigh += 1
# making the final Op's output dimension this wide
out_dims.append(num_neigh * ds)
return out_dims, num_strides
def make_node(self, x): def make_node(self, x):
if x.type.ndim != (self.n_dims_before + \ if self.inverse:
len(self.dims_neighbourhoods)): # +1 in the inverse case
raise TypeError() if x.type.ndim != (self.n_dims_before + \
len(self.dims_neighbourhoods) + 1):
raise TypeError()
else:
if x.type.ndim != (self.n_dims_before + \
len(self.dims_neighbourhoods)):
raise TypeError()
return gof.Apply(self, [x], [x.type()]) return gof.Apply(self, [x], [x.type()])
def perform(self, node, (x,), (z,)): def perform(self, node, (x,), (z,)):
if self.inverse:
# +1 in the inverse case
if len(x.shape) != (self.n_dims_before + \
len(self.dims_neighbourhoods) + 1):
raise ValueError("Images passed as input don't match the "+\
"dimensions passed when this (inversed) Apply node was created")
prod = 1
for dim in self.dims_neighbourhoods:
prod *= dim
if x.shape[-1] != prod:
raise ValueError(("Last dimension of neighbourhoods (%s) is not "+\
"the product of the neighbourhoods dimensions (%s)") % \
(str(x.shape[-1]), str(prod)))
else:
if len(x.shape) != (self.n_dims_before + \
len(self.dims_neighbourhoods)):
raise ValueError("Images passed as input don't match the "+\
"dimensions passed when this Apply node was created")
if self.inverse:
input_shape, num_strides = self.in_shape(x.shape)
out_shape, dummy = self.out_shape(input_shape)
else:
input_shape = x.shape
out_shape, num_strides = self.out_shape(input_shape)
if len(x.shape) != (self.n_dims_before + len(self.dims_neighbourhoods)):
raise ValueError("Images passed as input don't match the dimensions passed when this Apply node was created")
out_shape, num_strides = self.out_shape(x.shape)
neigh_strides = self._compute_neigh_strides() neigh_strides = self._compute_neigh_strides()
input_shape = x.shape
if z[0] is None: if z[0] is None:
z[0] = numpy.zeros(out_shape) if self.inverse:
z[0] = numpy.zeros(input_shape)
else:
z[0] = numpy.zeros(out_shape)
z[0] = theano._asarray(z[0], dtype=x.dtype) z[0] = theano._asarray(z[0], dtype=x.dtype)
exec(self.code) exec(self.code)
...@@ -140,7 +201,7 @@ class NeighbourhoodsFromImages(Op): ...@@ -140,7 +201,7 @@ class NeighbourhoodsFromImages(Op):
for i in xrange(len(self.strides)): for i in xrange(len(self.strides)):
code += self._py_innerloop(i) code += self._py_innerloop(i)
code += self._py_assignment() code += self._py_assignment()
return __builtin__.compile(code, '<string>', 'exec') return code, __builtin__.compile(code, '<string>', 'exec')
def _py_outerloops(self): def _py_outerloops(self):
code_before = "" code_before = ""
...@@ -185,8 +246,27 @@ class NeighbourhoodsFromImages(Op): ...@@ -185,8 +246,27 @@ class NeighbourhoodsFromImages(Op):
["stride_idx_%d," % (i,) for i in \ ["stride_idx_%d," % (i,) for i in \
range(len(self.strides))]) range(len(self.strides))])
out_idx += self._py_flattened_idx() out_idx += self._py_flattened_idx()
return '\t' * (self.n_dims_before + len(self.strides)*2) + \
"z[0][%s] = x[%s]\n" % (out_idx, input_idx)
#return_val = '\t' * (self.n_dims_before + len(self.strides)*2)
#return_val += "print "+input_idx+"'\\n',"+out_idx+"\n"
return_val = '\t' * (self.n_dims_before + len(self.strides)*2)
if self.inverse:
# remember z and x are inversed:
# z is the Op's output, but has input_shape
# x is the Op's input, but has out_shape
return_val += "z[0][%s] = x[%s]\n" % (input_idx, out_idx)
else:
return_val += "z[0][%s] = x[%s]\n" % (out_idx, input_idx)
return return_val
class ImagesFromNeighbourhoods(NeighbourhoodsFromImages):
def __init__(self, n_dims_before, dims_neighbourhoods,
strides=None, ignore_border=False):
NeighbourhoodsFromImages.__init__(self,n_dims_before, dims_neighbourhoods,
strides=strides, ignore_border=ignore_border,
inverse=True)
# and that's all there is to it
...@@ -8,6 +8,57 @@ import theano.tensor as T ...@@ -8,6 +8,57 @@ import theano.tensor as T
from theano.sandbox.neighbourhoods import * from theano.sandbox.neighbourhoods import *
''' '''
def test_imgFromNeigh_noborder_1d():
x = T.dtensor3()
a = numpy.arange(2*2*6).reshape((2,2,6))
neighs = NeighbourhoodsFromImages(2, (3,))(x)
f = theano.function([x], neighs)
z = f(a)
cmp = numpy.asarray([[[[ 0., 1., 2.],
[ 3., 4., 5.]],
[[ 6., 7., 8.],
[ 9., 10., 11.]]],
[[[ 12., 13., 14.],
[ 15., 16., 17.]],
[[ 18., 19., 20.],
[ 21., 22., 23.]]]])
assert numpy.allclose(z, cmp)
x2 = T.dtensor4()
imgs = ImagesFromNeighbourhoods(2, (3,))(x2)
f2 = theano.function([x2], imgs)
z2 = f2(cmp)
assert numpy.allclose(z2, a)
def test_imgFromNeigh_1d_stridesmaller():
x = T.dtensor3()
a = numpy.arange(2*4).reshape((2,4))
#neighs = NeighbourhoodsFromImages(1, (3,), strides=(1,), ignore_border=False)(x)
cmp = numpy.asarray([[[0.,1.,2.],[1.,2.,3.],[2.,3.,0.],[3.,0.,0.]],\
[[4.,5.,6.],[5.,6.,7.],[6.,7.,0.],[7.,0.,0.]]])
images = ImagesFromNeighbourhoods(1, (3,), strides=(1,), ignore_border=False)(x)
f = theano.function([x], images)
aprime = f(cmp)
should_be = [[0., 1., 2., 3., 0., 0.], [ 4., 5., 6., 7., 0., 0.]]
assert numpy.allclose(aprime, should_be)
def test_neighFromImg_1d(): def test_neighFromImg_1d():
x = T.dtensor3() x = T.dtensor3()
...@@ -116,6 +167,7 @@ if __name__ == '__main__': ...@@ -116,6 +167,7 @@ if __name__ == '__main__':
test_neighFromImg_1d_stridesmaller() test_neighFromImg_1d_stridesmaller()
test_neighFromImg_1d_stridesbigger() test_neighFromImg_1d_stridesbigger()
test_neighFromImg_2d() test_neighFromImg_2d()
test_imgFromNeigh_noborder_1d()
test_imgFromNeigh_1d_stridesmaller()
''' '''
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论