提交 940bd5a8 authored 作者: abalkin's avatar abalkin 提交者: Frederic

Implemented linalg.eigh.

上级 7e3caf1e
from ops import (cholesky, matrix_inverse, solve, from ops import (cholesky, matrix_inverse, solve,
diag, extract_diag, alloc_diag, diag, extract_diag, alloc_diag,
det, psd, eig, det, psd, eig, eigh,
trace, spectral_radius_bound) trace, spectral_radius_bound)
...@@ -882,8 +882,8 @@ class Eig(Op): ...@@ -882,8 +882,8 @@ class Eig(Op):
""" """
def __init__(self): def __init__(self, numop):
pass self._numop = numop
def props(self): def props(self):
"""Function exposing different properties of each instance of the """Function exposing different properties of each instance of the
...@@ -907,9 +907,10 @@ class Eig(Op): ...@@ -907,9 +907,10 @@ class Eig(Op):
def perform(self, node, (x,), (w, v)): def perform(self, node, (x,), (w, v)):
try: try:
w[0], v[0] = [z.astype(x.dtype) for z in numpy.linalg.eig(x)] w[0], v[0] = [z.astype(x.dtype) for z in self._numop(x)]
except numpy.linalg.LinAlgError: except numpy.linalg.LinAlgError:
logger.debug('Failed to find eig of %s' % str(node.inputs[0])) logger.debug('Failed to find %s of %s' % (node.inputs[0],
self._numop.__name__))
raise raise
def infer_shape(self, node, shapes): def infer_shape(self, node, shapes):
...@@ -917,7 +918,7 @@ class Eig(Op): ...@@ -917,7 +918,7 @@ class Eig(Op):
return [(n,), (n,n)] return [(n,), (n,n)]
def __str__(self): def __str__(self):
return "Eig" return self._numop.__name__.capitalize()
def grad(self, inputs, g_outputs): def grad(self, inputs, g_outputs):
r"""The gradient function should return r"""The gradient function should return
...@@ -943,7 +944,8 @@ class Eig(Op): ...@@ -943,7 +944,8 @@ class Eig(Op):
gw, gv = g_outputs gw, gv = g_outputs
return [EigGrad()(x, w, v, gw, gv)] return [EigGrad()(x, w, v, gw, gv)]
eig = Eig() eig = Eig(numpy.linalg.eig)
eigh = Eig(numpy.linalg.eigh)
class EigGrad(Op): class EigGrad(Op):
"""Gradient of an eigensystem. """Gradient of an eigensystem.
...@@ -968,6 +970,16 @@ class EigGrad(Op): ...@@ -968,6 +970,16 @@ class EigGrad(Op):
def perform(self, node, inputs, outputs): def perform(self, node, inputs, outputs):
""" """
Implements the "reverse-mode" gradient for the eigensystem of
a square matrix.
Let
.. math:: w, v = \mbox{eig}(x).
By definition of the eigensystem,
.. math:: \sum_j x_{ij}\,v_{jn} = w_n\,v_{in}.
""" """
x, w, v, gw, gv = inputs x, w, v, gw, gv = inputs
N = x.shape[0] N = x.shape[0]
......
...@@ -29,7 +29,7 @@ from theano.sandbox.linalg.ops import (cholesky, ...@@ -29,7 +29,7 @@ from theano.sandbox.linalg.ops import (cholesky,
imported_scipy, imported_scipy,
Eig, Eig,
) )
from theano.sandbox.linalg import eig from theano.sandbox.linalg import eig, eigh
from nose.plugins.skip import SkipTest from nose.plugins.skip import SkipTest
...@@ -471,10 +471,10 @@ class test_Solve(utt.InferShapeTester): ...@@ -471,10 +471,10 @@ class test_Solve(utt.InferShapeTester):
self.op_class) self.op_class)
class test_Eig(utt.InferShapeTester): class test_Eig(utt.InferShapeTester):
op_class = Eig
op = eig
def setUp(self): def setUp(self):
super(test_Eig, self).setUp() super(test_Eig, self).setUp()
self.op_class = Eig
self.op = Eig()
self.rng = numpy.random.RandomState(utt.fetch_seed()) self.rng = numpy.random.RandomState(utt.fetch_seed())
self.A = theano.tensor.matrix() self.A = theano.tensor.matrix()
X = numpy.asarray(self.rng.rand(5, 5), X = numpy.asarray(self.rng.rand(5, 5),
...@@ -494,16 +494,15 @@ class test_Eig(utt.InferShapeTester): ...@@ -494,16 +494,15 @@ class test_Eig(utt.InferShapeTester):
A = theano.tensor.matrix() A = theano.tensor.matrix()
self.assertEquals([e.eval({A: [[1]]}) for e in self.op(A)], self.assertEquals([e.eval({A: [[1]]}) for e in self.op(A)],
[[1.0], [[1.0]]]) [[1.0], [[1.0]]])
x = [[0, 1], [1, 0]]
w, v = [e.eval({A: x}) for e in self.op(A)]
assert_array_almost_equal(numpy.dot(x,v), w * v)
w, v = [e.eval({A: [[0, 1], [1, 0]]}) class test_Eigh(test_Eig):
for e in self.op(A)] op = eigh
assert_array_almost_equal(w, [1, -1])
x = math.sqrt(2)/2
assert_array_almost_equal(v, [[x, -x], [x, x]])
def test_grad(self): def test_grad(self):
S = self.S S = self.S
def fun(x): def fun(x):
w, v = eig(x) w, v = self.op(x)
return w.sum() + v.sum()*0 return w.sum() + v.sum()*0
utt.verify_grad(fun, [S], rng=self.rng) utt.verify_grad(fun, [S], rng=self.rng)
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论