提交 086a2092 authored 作者: ChienliMa's avatar ChienliMa

delete test_fill_diagonal.py, modify test in to ignore input offset. Test passed

上级 6421f7e7
...@@ -665,8 +665,8 @@ class FillDiagonal(gof.Op): ...@@ -665,8 +665,8 @@ class FillDiagonal(gof.Op):
% self.__class__.__name__) % self.__class__.__name__)
val = tensor.cast(val, dtype=scalar.upcast(a.dtype, val.dtype)) val = tensor.cast(val, dtype=scalar.upcast(a.dtype, val.dtype))
if val.dtype != a.dtype: if val.dtype != a.dtype:
raise TypeError('%s: type of second parameter must be compatible' raise TypeError('%s: type of second parameter must be the same as'
' with first\'s' % self.__class__.__name__) ' the first\'s' % self.__class__.__name__)
return gof.Apply(self, [a, val], [a.type()]) return gof.Apply(self, [a, val], [a.type()])
def perform(self, node, inputs, output_storage): def perform(self, node, inputs, output_storage):
...@@ -729,7 +729,6 @@ def fill_diagonal(a, val): ...@@ -729,7 +729,6 @@ def fill_diagonal(a, val):
# Offset version of fill_diagonal
class FillDiagonalOffset(gof.Op): class FillDiagonalOffset(gof.Op):
# See function fill_diagonal_offset for docstring # See function fill_diagonal_offset for docstring
def __eq__(self, other): def __eq__(self, other):
...@@ -759,8 +758,8 @@ class FillDiagonalOffset(gof.Op): ...@@ -759,8 +758,8 @@ class FillDiagonalOffset(gof.Op):
% self.__class__.__name__) % self.__class__.__name__)
val = tensor.cast(val, dtype=scalar.upcast(a.dtype, val.dtype)) val = tensor.cast(val, dtype=scalar.upcast(a.dtype, val.dtype))
if val.dtype != a.dtype: if val.dtype != a.dtype:
raise TypeError('%s: type of second parameter must be compatible' raise TypeError('%s: type of second parameter must be the same'
' with first\'s' % self.__class__.__name__) ' as the first\'s' % self.__class__.__name__)
return gof.Apply(self, [a, val, offset], [a.type()]) return gof.Apply(self, [a, val, offset], [a.type()])
...@@ -776,9 +775,15 @@ class FillDiagonalOffset(gof.Op): ...@@ -776,9 +775,15 @@ class FillDiagonalOffset(gof.Op):
raise ValueError('%s: third parameter must be an integer'\ raise ValueError('%s: third parameter must be an integer'\
% self.__class__.__name__) % self.__class__.__name__)
# numpy.fill_diagonal up to date(including 1.6.2) have a """
# bug for tall matrix. Note: The fill_diagonal only support rectangular matrix. The output
# the offset function is only implemented for matrices of tall matrix is "wrapped", which is an option in numpy 1.9.0
but was regarded as a bug in numpy 1.6.2. Here I implement the
fill_diagonal_offset with unwrapped output, so fill_diagonal_offset
supports tall matrix.(This make a little difference between the output
of fill_diagonal and fill_diagonal_offset only in the case of tall
matrix)
"""
if offset >= 0: if offset >= 0:
start = offset start = offset
num_of_step = min( min(width,height), width - offset) num_of_step = min( min(width,height), width - offset)
...@@ -800,13 +805,34 @@ class FillDiagonalOffset(gof.Op): ...@@ -800,13 +805,34 @@ class FillDiagonalOffset(gof.Op):
""" """
a, val, offset = inp a, val, offset = inp
grad = cost_grad[0] grad = cost_grad[0]
height, width = grad.shape
if (a.dtype.startswith('complex')): if (a.dtype.startswith('complex')):
return [None, None] return [None, None]
# only valid for matrices # only valid for matrices
wr_a = fill_diagonal_offset(grad, 0, offset) wr_a = fill_diagonal_offset(grad, 0, offset)
import theano.sandbox.linalg
wr_val = theano.sandbox.linalg.ops.diag(grad).sum() import theano.tensor as T
offset_abs = T.abs_( offset )
pos_offset_flag = T.ge( offset, 0 )
start = offset * pos_offset_flag + offset_abs * width \
* (1-pos_offset_flag)
min_wh = T.minimum(width,height)
num_of_step = T.minimum( min_wh, width * pos_offset_flag
+ height * ( 1 - pos_offset_flag ) - offset_abs )
step = grad.shape[1] + 1
end = start + step * num_of_step
# input of slide should be integer
start = T.cast(start,'int32')
step = T.cast(step,'int32')
end = T.cast(end,'int32')
wr_val = grad.flatten()[start:end:step].sum()
wr_offset = axis_grad = theano.gradient.grad_undefined( wr_offset = axis_grad = theano.gradient.grad_undefined(
self, 2, offset, self, 2, offset,
"offset is not defined for non-integer offset so" "offset is not defined for non-integer offset so"
...@@ -831,6 +857,5 @@ def fill_diagonal_offset(a, val, offset): ...@@ -831,6 +857,5 @@ def fill_diagonal_offset(a, val, offset):
:return: An array identical to 'a' except that its offset diagonal :return: An array identical to 'a' except that its offset diagonal
is filled with scalar 'val'. is filled with scalar 'val'.
Only support rectangular matrix
""" """
return fill_diagonal_offset_(a, val, offset) return fill_diagonal_offset_(a, val, offset)
...@@ -8,7 +8,8 @@ from theano.tests import unittest_tools as utt ...@@ -8,7 +8,8 @@ from theano.tests import unittest_tools as utt
from theano.tensor.extra_ops import (CumsumOp, cumsum, CumprodOp, cumprod, from theano.tensor.extra_ops import (CumsumOp, cumsum, CumprodOp, cumprod,
BinCountOp, bincount, DiffOp, diff, BinCountOp, bincount, DiffOp, diff,
squeeze, RepeatOp, repeat, Bartlett, bartlett, squeeze, RepeatOp, repeat, Bartlett, bartlett,
FillDiagonal, fill_diagonal) FillDiagonal, fill_diagonal, FillDiagonalOffset,
fill_diagonal_offset)
from theano import tensor as T from theano import tensor as T
from theano import config, tensor, function from theano import config, tensor, function
...@@ -408,63 +409,6 @@ class TestBartlett(utt.InferShapeTester): ...@@ -408,63 +409,6 @@ class TestBartlett(utt.InferShapeTester):
self._compile_and_check([x], [self.op(x)], [1], self.op_class) self._compile_and_check([x], [self.op(x)], [1], self.op_class)
class TestFillDiagonal(utt.InferShapeTester):
rng = numpy.random.RandomState(43)
def setUp(self):
super(TestFillDiagonal, self).setUp()
self.op_class = FillDiagonal
self.op = fill_diagonal
def test_perform(self):
x = tensor.matrix()
y = tensor.scalar()
f = function([x, y], fill_diagonal(x, y))
for shp in [(8, 8), (5, 8), (8, 5)]:
a = numpy.random.rand(*shp).astype(config.floatX)
val = numpy.cast[config.floatX](numpy.random.rand())
out = f(a, val)
# We can't use numpy.fill_diagonal as it is bugged.
assert numpy.allclose(numpy.diag(out), val)
assert (out == val).sum() == min(a.shape)
# test for 3d tensor
a = numpy.random.rand(3, 3, 3).astype(config.floatX)
x = tensor.tensor3()
y = tensor.scalar()
f = function([x, y], fill_diagonal(x, y))
val = numpy.cast[config.floatX](numpy.random.rand() + 10)
out = f(a, val)
# We can't use numpy.fill_diagonal as it is bugged.
assert out[0, 0, 0] == val
assert out[1, 1, 1] == val
assert out[2, 2, 2] == val
assert (out == val).sum() == min(a.shape)
def test_gradient(self):
utt.verify_grad(fill_diagonal, [numpy.random.rand(5, 8),
numpy.random.rand()],
n_tests=1, rng=TestFillDiagonal.rng)
utt.verify_grad(fill_diagonal, [numpy.random.rand(8, 5),
numpy.random.rand()],
n_tests=1, rng=TestFillDiagonal.rng)
def test_infer_shape(self):
z = tensor.dtensor3()
x = tensor.dmatrix()
y = tensor.dscalar()
self._compile_and_check([x, y], [self.op(x, y)],
[numpy.random.rand(8, 5),
numpy.random.rand()],
self.op_class)
self._compile_and_check([z, y], [self.op(z, y)],
#must be square when nd>2
[numpy.random.rand(8, 8, 8),
numpy.random.rand()],
self.op_class,
warn=False)
class TestFillDiagonalOffset(utt.InferShapeTester): class TestFillDiagonalOffset(utt.InferShapeTester):
rng = numpy.random.RandomState(43) rng = numpy.random.RandomState(43)
...@@ -501,13 +445,15 @@ class TestFillDiagonalOffset(utt.InferShapeTester): ...@@ -501,13 +445,15 @@ class TestFillDiagonalOffset(utt.InferShapeTester):
def test_gradient(self): def test_gradient(self):
test_offset = numpy.array(numpy.random.randint(-5,5), test_offset = numpy.array(numpy.random.randint(-5,5),
dtype = config.floatX) dtype = config.floatX)
utt.verify_grad(fill_diagonal_offset, [numpy.random.rand(5, 8), # input 'offset' will not be tested
numpy.random.rand(), def fill_diagonal_with_fix_offset( a, val):
test_offset], return fill_diagonal_offset( a, val, test_offset)
utt.verify_grad(fill_diagonal_with_fix_offset,
[numpy.random.rand(5, 8), numpy.random.rand()],
n_tests=1, rng=TestFillDiagonalOffset.rng) n_tests=1, rng=TestFillDiagonalOffset.rng)
utt.verify_grad(fill_diagonal_offset, [numpy.random.rand(8, 5), utt.verify_grad(fill_diagonal_with_fix_offset,
numpy.random.rand(), [numpy.random.rand(8, 5), numpy.random.rand()],
test_offset],
n_tests=1, rng=TestFillDiagonalOffset.rng) n_tests=1, rng=TestFillDiagonalOffset.rng)
def test_infer_shape(self): def test_infer_shape(self):
...@@ -521,4 +467,3 @@ class TestFillDiagonalOffset(utt.InferShapeTester): ...@@ -521,4 +467,3 @@ class TestFillDiagonalOffset(utt.InferShapeTester):
numpy.random.rand(), numpy.random.rand(),
test_offset], test_offset],
self.op_class) self.op_class)
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论