提交 117e3938 authored 作者: Olivier Delalleau's avatar Olivier Delalleau

Merge pull request #339 from pascanur/sandbox_pinv

Sandbox pseudo-inverse
from pkg_resources import parse_version as V from pkg_resources import parse_version as V
import numpy import numpy
import numpy.linalg
import theano import theano
from theano import tensor, function from theano import tensor, function
...@@ -11,9 +12,10 @@ from theano import config ...@@ -11,9 +12,10 @@ from theano import config
# The one in comment are not tested... # The one in comment are not tested...
from theano.sandbox.linalg.ops import (cholesky, from theano.sandbox.linalg.ops import (cholesky,
Cholesky, # op class Cholesky, # op class
CholeskyGrad, CholeskyGrad,
matrix_inverse, matrix_inverse,
pinv,
#solve, #solve,
diag, diag,
ExtractDiag, ExtractDiag,
...@@ -109,7 +111,7 @@ def test_cholesky_and_cholesky_grad_shape(): ...@@ -109,7 +111,7 @@ def test_cholesky_and_cholesky_grad_shape():
def test_inverse_correctness(): def test_inverse_correctness():
rng = numpy.random.RandomState(utt.fetch_seed()) rng = numpy.random.RandomState(utt.fetch_seed())
r = rng.randn(4,4).astype(theano.config.floatX) r = rng.randn(4, 4).astype(theano.config.floatX)
x = tensor.matrix() x = tensor.matrix()
xi = matrix_inverse(x) xi = matrix_inverse(x)
...@@ -118,13 +120,31 @@ def test_inverse_correctness(): ...@@ -118,13 +120,31 @@ def test_inverse_correctness():
assert ri.shape == r.shape assert ri.shape == r.shape
assert ri.dtype == r.dtype assert ri.dtype == r.dtype
rir = numpy.dot(ri,r) rir = numpy.dot(ri, r)
rri = numpy.dot(r,ri) rri = numpy.dot(r, ri)
assert _allclose(numpy.identity(4), rir), rir assert _allclose(numpy.identity(4), rir), rir
assert _allclose(numpy.identity(4), rri), rri assert _allclose(numpy.identity(4), rri), rri
def test_pseudoinverse_correctness():
rng = numpy.random.RandomState(utt.fetch_seed())
d1 = rng.randint(4) + 2
d2 = rng.randint(4) + 2
r = rng.randn(d1, d2).astype(theano.config.floatX)
x = tensor.matrix()
xi = pinv(x)
ri = function([x], xi)(r)
assert ri.shape[0] == r.shape[1]
assert ri.shape[1] == r.shape[0]
assert ri.dtype == r.dtype
# Note that pseudoinverse can be quite unprecise so I prefer to compare
# the result with what numpy.linalg returns
assert _allclose(ri, numpy.linalg.pinv(r))
def test_matrix_dot(): def test_matrix_dot():
rng = numpy.random.RandomState(utt.fetch_seed()) rng = numpy.random.RandomState(utt.fetch_seed())
n = rng.randint(4) + 2 n = rng.randint(4) + 2
...@@ -162,37 +182,39 @@ def test_inverse_grad(): ...@@ -162,37 +182,39 @@ def test_inverse_grad():
rng = numpy.random.RandomState(utt.fetch_seed()) rng = numpy.random.RandomState(utt.fetch_seed())
r = rng.randn(4,4) r = rng.randn(4, 4)
tensor.verify_grad(matrix_inverse, [r], rng=numpy.random) tensor.verify_grad(matrix_inverse, [r], rng=numpy.random)
def test_rop_lop(): def test_rop_lop():
mx = tensor.matrix('mx') mx = tensor.matrix('mx')
mv = tensor.matrix('mv') mv = tensor.matrix('mv')
v = tensor.vector('v') v = tensor.vector('v')
y = matrix_inverse(mx).sum(axis=0) y = matrix_inverse(mx).sum(axis=0)
yv = tensor.Rop(y, mx, mv) yv = tensor.Rop(y, mx, mv)
rop_f = function([mx, mv], yv) rop_f = function([mx, mv], yv)
sy, _ = theano.scan( lambda i,y,x,v: (tensor.grad(y[i],x)*v).sum(), sy, _ = theano.scan(lambda i, y, x, v: (tensor.grad(y[i], x) * v).sum(),
sequences = tensor.arange(y.shape[0]), sequences=tensor.arange(y.shape[0]),
non_sequences = [y,mx,mv]) non_sequences=[y, mx, mv])
scan_f = function([mx,mv], sy) scan_f = function([mx, mv], sy)
rng = numpy.random.RandomState(utt.fetch_seed()) rng = numpy.random.RandomState(utt.fetch_seed())
vx = numpy.asarray(rng.randn(4,4), theano.config.floatX) vx = numpy.asarray(rng.randn(4, 4), theano.config.floatX)
vv = numpy.asarray(rng.randn(4,4), theano.config.floatX) vv = numpy.asarray(rng.randn(4, 4), theano.config.floatX)
v1 = rop_f(vx,vv) v1 = rop_f(vx, vv)
v2 = scan_f(vx,vv) v2 = scan_f(vx, vv)
assert _allclose(v1, v2), ('ROP mismatch: %s %s' % (v1, v2)) assert _allclose(v1, v2), ('ROP mismatch: %s %s' % (v1, v2))
raised = False raised = False
try: try:
tmp = tensor.Rop(theano.clone(y, tmp = tensor.Rop(
replace={mx:break_op(mx)}), mx, mv) theano.clone(y, replace={mx: break_op(mx)}),
mx,
mv)
except ValueError: except ValueError:
raised = True raised = True
if not raised: if not raised:
...@@ -204,7 +226,7 @@ def test_rop_lop(): ...@@ -204,7 +226,7 @@ def test_rop_lop():
yv = tensor.Lop(y, mx, v) yv = tensor.Lop(y, mx, v)
lop_f = function([mx, v], yv) lop_f = function([mx, v], yv)
sy = tensor.grad((v*y).sum(), mx) sy = tensor.grad((v * y).sum(), mx)
scan_f = function([mx, v], sy) scan_f = function([mx, v], sy)
v1 = lop_f(vx, vv) v1 = lop_f(vx, vv)
...@@ -280,13 +302,15 @@ def test_alloc_diag_grad(): ...@@ -280,13 +302,15 @@ def test_alloc_diag_grad():
def test_diag(): def test_diag():
""" """
Test that linalg.diag has the same behavior as numpy.diag. Test that linalg.diag has the same behavior as numpy.diag.
numpy.diag has two behaviors: numpy.diag has two behaviors:
(1) when given a vector, it returns a matrix with that vector as the diagonal. (1) when given a vector, it returns a matrix with that vector as the
(2) when given a matrix, returns a vector which is the diagonal of the matrix. diagonal.
(2) when given a matrix, returns a vector which is the diagonal of the
(1) and (2) are tested by test_alloc_diag and test_extract_diag respectively. matrix.
This test makes sure that linalg.diag instantiates the right op based on the dimension of
the input. (1) and (2) are tested by test_alloc_diag and test_extract_diag
respectively. This test makes sure that linalg.diag instantiates
the right op based on the dimension of the input.
""" """
# test that it builds a matrix with given diagonal when using vector inputs # test that it builds a matrix with given diagonal when using vector inputs
...@@ -298,7 +322,7 @@ def test_diag(): ...@@ -298,7 +322,7 @@ def test_diag():
x = theano.tensor.matrix() x = theano.tensor.matrix()
y = extract_diag(x) y = extract_diag(x)
assert y.owner.op.__class__ == ExtractDiag assert y.owner.op.__class__ == ExtractDiag
# other types should raise error # other types should raise error
x = theano.tensor.tensor3() x = theano.tensor.tensor3()
ok = False ok = False
...@@ -315,7 +339,7 @@ def test_extract_diag(): ...@@ -315,7 +339,7 @@ def test_extract_diag():
g = extract_diag(x) g = extract_diag(x)
f = theano.function([x], g) f = theano.function([x], g)
for shp in [(2, 3), (3, 2), (3, 3), (1,1), (0,0)]: for shp in [(2, 3), (3, 2), (3, 3), (1, 1), (0, 0)]:
m = rng.rand(*shp).astype(config.floatX) m = rng.rand(*shp).astype(config.floatX)
v = numpy.diag(m) v = numpy.diag(m)
r = f(m) r = f(m)
...@@ -343,7 +367,7 @@ def test_extract_diag(): ...@@ -343,7 +367,7 @@ def test_extract_diag():
def test_extract_diag_grad(): def test_extract_diag_grad():
rng = numpy.random.RandomState(utt.fetch_seed()) rng = numpy.random.RandomState(utt.fetch_seed())
x = rng.rand(5,4) x = rng.rand(5, 4)
tensor.verify_grad(extract_diag, [x], rng=rng) tensor.verify_grad(extract_diag, [x], rng=rng)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论