提交 a7a21dc4 authored 作者: fsavard's avatar fsavard

merge

...@@ -46,6 +46,9 @@ class Images2Neibs(Op): ...@@ -46,6 +46,9 @@ class Images2Neibs(Op):
return Apply(self, [ten4, neib_shape,neib_step], [T.matrix(dtype=ten4.type.dtype)]) return Apply(self, [ten4, neib_shape,neib_step], [T.matrix(dtype=ten4.type.dtype)])
def grad(self, (x, neib_shape, neib_step), (gz,)):
return [neibs2images(gz, neib_shape, x.shape), None, None]
def c_code_cache_version(self): def c_code_cache_version(self):
return (3,) return (3,)
...@@ -211,36 +214,16 @@ class Images2Neibs(Op): ...@@ -211,36 +214,16 @@ class Images2Neibs(Op):
def images2neibs(ten4, neib_shape, neib_step=None, mode='valid'): def images2neibs(ten4, neib_shape, neib_step=None, mode='valid'):
return Images2Neibs(mode)(ten4, neib_shape, neib_step) return Images2Neibs(mode)(ten4, neib_shape, neib_step)
def neibs2images(neibs, neib_shape, original_shape, neib_step=None, mode='valid'): def neibs2images(neibs, neib_shape, original_shape):
""" """
Inverse of images2neib. Don't implement neib_step and mode. Inverse of images2neib.
:type neibs: Theano variable
:param neibs: matrix like the one obtained by images2neib
:type neib_shape: Theano variable
:param neib_shape: neib_shape that was used in images2neib
:type original_shape: Theano variable
:param original_shape: original shape of the 4d tensor given to images2neib.
:type neib_step: Theano variable or None
:param neib_step: neib_step that was used in images2neib Implement only None.
None is non overlapping patches and not-adjacent patches.
:type mode: str neibs : matrix like the one obtained by images2neib
:param mode: The mode that was used in images2neib. Implement only valid. neib_shape : neib_shape that was used in images2neib
original_shape : original shape of the 4d tensor given to images2neib
Return a 4d tensor of shape `original_shape`. Return a 4d tensor of shape `original_shape`.
""" """
# TODO: handle the case where patches either overlap
# TODO: handle the case where patches are not directly adjacent
# TODO: at least separate these cases so that the following code does not incorrectly
# handle them by accident.
if neib_step != None:
raise NotImplementedError('neibs2images do not implement overlapping patches or non-adjacent patches.')
if mode != 'valid':
raise NotImplementedError('neibs2images do not implement the mode %s. It currently only implement `valid`.'%mode)
neibs = T.as_tensor_variable(neibs) neibs = T.as_tensor_variable(neibs)
neib_shape = T.as_tensor_variable(neib_shape) neib_shape = T.as_tensor_variable(neib_shape)
original_shape = T.as_tensor_variable(original_shape) original_shape = T.as_tensor_variable(original_shape)
......
...@@ -7,6 +7,8 @@ from neighbours import images2neibs, neibs2images, Images2Neibs, GpuImages2Neibs ...@@ -7,6 +7,8 @@ from neighbours import images2neibs, neibs2images, Images2Neibs, GpuImages2Neibs
from nose.plugins.skip import SkipTest from nose.plugins.skip import SkipTest
import theano.sandbox.cuda as cuda import theano.sandbox.cuda as cuda
from theano.tests import unittest_tools
if theano.config.mode=='FAST_COMPILE': if theano.config.mode=='FAST_COMPILE':
mode_with_gpu = theano.compile.mode.get_mode('FAST_RUN').including('gpu') mode_with_gpu = theano.compile.mode.get_mode('FAST_RUN').including('gpu')
mode_without_gpu = theano.compile.mode.get_mode('FAST_RUN').excluding('gpu') mode_without_gpu = theano.compile.mode.get_mode('FAST_RUN').excluding('gpu')
...@@ -328,8 +330,65 @@ def speed_neibs_wrap_centered(): ...@@ -328,8 +330,65 @@ def speed_neibs_wrap_centered():
for i in range(1000): for i in range(1000):
f() f()
def test_neibs_grad():
shape = (2,3,4,4)
images = T.shared(numpy.arange(numpy.prod(shape), dtype='float32').reshape(shape))
cost = T.sum(T.sqr(images2neibs(images, (2,2))), axis=[0,1])
grad = T.grad(cost, images)
f = theano.function([], [cost, grad], mode=mode_without_gpu)
got = f()
should_get = [numpy.asarray(290320.0, dtype=numpy.float32),
numpy.asarray([[[[ 0., 2., 4., 6.],
[ 8., 10., 12., 14.],
[ 16., 18., 20., 22.],
[ 24., 26., 28., 30.]],
[[ 32., 34., 36., 38.],
[ 40., 42., 44., 46.],
[ 48., 50., 52., 54.],
[ 56., 58., 60., 62.]],
[[ 64., 66., 68., 70.],
[ 72., 74., 76., 78.],
[ 80., 82., 84., 86.],
[ 88., 90., 92., 94.]]],
[[[ 96., 98., 100., 102.],
[ 104., 106., 108., 110.],
[ 112., 114., 116., 118.],
[ 120., 122., 124., 126.]],
[[ 128., 130., 132., 134.],
[ 136., 138., 140., 142.],
[ 144., 146., 148., 150.],
[ 152., 154., 156., 158.]],
[[ 160., 162., 164., 166.],
[ 168., 170., 172., 174.],
[ 176., 178., 180., 182.],
[ 184., 186., 188., 190.]]]], dtype=numpy.float32)]
assert numpy.allclose(got[0], should_get[0])
assert numpy.allclose(got[1], should_get[1])
def test_neibs_grad_verify_grad():
shape = (2,3,4,4)
images = T.dtensor4()
images_val = numpy.arange(numpy.prod(shape), dtype='float32').reshape(shape)
def fn(images):
return T.sum(T.sqr(images2neibs(images, (2,2))), axis=[0,1])
unittest_tools.verify_grad(fn, [images_val])
if __name__ == '__main__': if __name__ == '__main__':
test_neibs_gpu() #test_neibs_gpu()
test_neibs() #test_neibs()
test_neibs_grad_verify_grad()
...@@ -1155,8 +1155,40 @@ class Prod(CAReduce): ...@@ -1155,8 +1155,40 @@ class Prod(CAReduce):
def grad(self, (x, ), (gz, )): def grad(self, (x, ), (gz, )):
if x.dtype[0:3] in ('int','uin'): if x.dtype[0:3] in ('int','uin'):
return [None] return [None]
prod_out = self(x)
gz = as_tensor_variable(gz)
axis = self.axis
if axis is None:
axis = range(x.type.ndim)
if axis == ():
return gz,
new_dims = []
i = 0
for j, _ in enumerate(x.type.broadcastable):
if j in axis:
new_dims.append('x')
else: else:
raise NotImplementedError('Will be implemented shortly') new_dims.append(i)
i += 1
# fill a matrix with the same shape as x by broadcasting
# values taken from gz, which has the same shape as the output
# of prod().
gz_filled_x = Elemwise(scalar.second)(x,
DimShuffle(gz.type.broadcastable, new_dims)(gz))
# do the same with the output of prod, by broadcasting along
# axises where the product was taken
prod_out_filled_x = Elemwise(scalar.second)(x,
DimShuffle(prod_out.type.broadcastable,
new_dims)(prod_out))
return [theano.tensor.mul(gz_filled_x,
theano.tensor.true_div(prod_out_filled_x, x))]
#else:
# raise NotImplementedError('Will be implemented shortly')
def __str__(self): def __str__(self):
if self.axis is None: if self.axis is None:
......
...@@ -254,5 +254,52 @@ class test_CAReduce(unittest.TestCase): ...@@ -254,5 +254,52 @@ class test_CAReduce(unittest.TestCase):
#self.with_linker(gof.CLinker(), and_) #self.with_linker(gof.CLinker(), and_)
class test_Prod(unittest.TestCase):
def setUp(self):
unittest_tools.seed_rng()
def test_prod_grad(self):
x_val = numpy.asarray([[1,2,3],[4,5,6],[7,8,9]], dtype='float32')
x = theano.tensor.dmatrix()
p = Prod(axis=0)(x)
# sanity check
fn = theano.function([x], [p])
assert numpy.allclose(fn(x_val), numpy.array([ 28., 80., 162.]))
# very basic case for the product; no broadcasting in x
g = theano.tensor.grad(p.sum(), x)
g_fn = theano.function([x], g)
assert numpy.allclose(g_fn(x_val),
numpy.asarray([[28.,40.,54.],[7.,16.,27.],[4.,10.,18.]]))
# now with some tranposition in input
x_bc = x.dimshuffle(1, 0)
p_bc = Prod(axis=0)(x_bc)
p_bc_sum = p_bc.sum()
g_bc = theano.tensor.grad(p_bc_sum, x)
g_fn_bc = theano.function([x], [p_bc,g_bc])
p_bc_ret, g_bc_ret = g_fn_bc(x_val)
assert numpy.allclose(p_bc_ret, numpy.array([ 6., 120., 504.]))
assert numpy.allclose(g_bc_ret,
numpy.asarray([[6.,3.,2.],[30.,24.,20.],[72.,63.,56.]]))
def test_verify_grad(self):
x_val = numpy.asarray([[1,2,3],[4,5,6],[7,8,9]], dtype='float32')
x = theano.tensor.dmatrix()
# now with verify_grad
unittest_tools.verify_grad(Prod(axis=0), [x_val])
# second time, with some added complexity
# verify_grad takes the sum of the matrices anyway
def fn(x2):
return theano.tensor.sqr(Prod(axis=0)(x2))
unittest_tools.verify_grad(fn, [x_val])
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
#suite = unittest.TestSuite([test_Prod('test_prod_grad')])
#unittest.TextTestRunner().run(suite)
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论