提交 94a52915 authored 作者: James Bergstra's avatar James Bergstra

Merge branch 'master' of github.com:Theano/Theano

...@@ -294,6 +294,9 @@ class BadOptimization(DebugModeError): ...@@ -294,6 +294,9 @@ class BadOptimization(DebugModeError):
print >> sio, self.old_graph print >> sio, self.old_graph
print >> sio, " New Graph:" print >> sio, " New Graph:"
print >> sio, self.new_graph print >> sio, self.new_graph
print >> sio, ""
print >> sio, "Hint: relax the tolerance by setting tensor.cmp_sloppy=1"
print >> sio, " or even tensor.cmp_sloppy=2 for less-strict comparison"
return sio.getvalue() return sio.getvalue()
class BadDestroyMap(DebugModeError): class BadDestroyMap(DebugModeError):
......
import logging
logger = logging.getLogger(__name__)
import numpy import numpy
from theano.gof import Op, Apply from theano.gof import Op, Apply
...@@ -57,6 +60,7 @@ def hints(variable): ...@@ -57,6 +60,7 @@ def hints(variable):
@local_optimizer([]) @local_optimizer([])
def remove_hint_nodes(node): def remove_hint_nodes(node):
if is_hint_node(node): if is_hint_node(node):
# transfer hints from graph to Feature
try: try:
for k,v in node.op.hints: for k,v in node.op.hints:
node.env.hints_feature.add_hint(node.inputs[0], k, v) node.env.hints_feature.add_hint(node.inputs[0], k, v)
...@@ -95,7 +99,7 @@ class HintsFeature(object): ...@@ -95,7 +99,7 @@ class HintsFeature(object):
""" """
def add_hint(self, r, k, v): def add_hint(self, r, k, v):
print 'adding hint', r, k, v logger.debug('adding hint; %s, %s, %s' % (r, k, v))
self.hints[r][k] = v self.hints[r][k] = v
def ensure_init_r(self, r): def ensure_init_r(self, r):
...@@ -171,9 +175,8 @@ def is_positive(v): ...@@ -171,9 +175,8 @@ def is_positive(v):
return True return True
#TODO: how to handle this - a registry? #TODO: how to handle this - a registry?
# infer_hints on Ops? # infer_hints on Ops?
print 'is_positive', v logger.debug('is_positive: %s' % str(v))
if v.owner and v.owner.op == tensor.pow: if v.owner and v.owner.op == tensor.pow:
print 'try for pow', v, v.owner.inputs
try: try:
exponent = tensor.get_constant_value(v.owner.inputs[1]) exponent = tensor.get_constant_value(v.owner.inputs[1])
except TypeError: except TypeError:
...@@ -250,7 +253,6 @@ def local_log_prod_sqr(node): ...@@ -250,7 +253,6 @@ def local_log_prod_sqr(node):
# we cannot always make this substitution because # we cannot always make this substitution because
# the prod might include negative terms # the prod might include negative terms
p = x.owner.inputs[0] p = x.owner.inputs[0]
print "AAA", p
# p is the matrix we're reducing with prod # p is the matrix we're reducing with prod
if is_positive(p): if is_positive(p):
...@@ -316,7 +318,7 @@ class Cholesky(Op): ...@@ -316,7 +318,7 @@ class Cholesky(Op):
destr = 'destructive' destr = 'destructive'
else: else:
destr = 'non-destructive' destr = 'non-destructive'
return 'Cholesky{%s,%s}'% (lu,destr) return 'Cholesky{%s,%s}' % (lu, destr)
def make_node(self, x): def make_node(self, x):
x = as_tensor_variable(x) x = as_tensor_variable(x)
return Apply(self, [x], [x.type()]) return Apply(self, [x], [x.type()])
...@@ -378,7 +380,10 @@ class Solve(Op): ...@@ -378,7 +380,10 @@ class Solve(Op):
def make_node(self, A, b): def make_node(self, A, b):
A = as_tensor_variable(A) A = as_tensor_variable(A)
b = as_tensor_variable(b) b = as_tensor_variable(b)
return Apply(self, [A,b], [b.type()]) otype = tensor.tensor(
broadcastable=b.broadcastable,
dtype = (A*b).dtype)
return Apply(self, [A,b], [otype])
def perform(self, node, inputs, output_storage): def perform(self, node, inputs, output_storage):
A, b = inputs A, b = inputs
#TODO: use the A_structure to go faster #TODO: use the A_structure to go faster
...@@ -394,40 +399,46 @@ class ExtractDiag(Op): ...@@ -394,40 +399,46 @@ class ExtractDiag(Op):
self.view = view self.view = view
if self.view: if self.view:
self.view_map = {0:[0]} self.view_map = {0:[0]}
self.perform = self.perform_view
else:
self.perform = self.perform_noview
def __eq__(self, other): def __eq__(self, other):
return type(self) == type(other) and self.view == other.view return type(self) == type(other) and self.view == other.view
def __hash__(self): def __hash__(self):
return hash(type(self))^hash(self.view) return hash(type(self))^hash(self.view)
def make_node(self, _x): def make_node(self, _x):
x = as_tensor_variable(_x) x = as_tensor_variable(_x)
if x.type.ndim != 2: if x.type.ndim != 2:
raise TypeError('ExtractDiag only works on matrices', _x) raise TypeError('ExtractDiag only works on matrices', _x)
return Apply(self, [x], [tensor.vector(dtype=x.type.dtype)]) return Apply(self, [x], [tensor.vector(dtype=x.type.dtype)])
def perform_noview(self, node, (x,), (z,)):
def perform(self, node, ins, outs):
x, = ins
z, = outs
#for some reason numpy.diag(x) is really slow #for some reason numpy.diag(x) is really slow
N,M = x.shape N,M = x.shape
assert N==M assert N==M
rval = x[0] rval = x[0]
rval.strides = (x.strides[0]+x.strides[1],) rval.strides = (x.strides[0]+x.strides[1],)
z[0] = rval.copy() if self.view:
def perform_view(self, node, (x,), (z,)):
N,M = x.shape
a,b = x.strides
assert N==M
rval = x[0]
rval.strides = a+b,
z[0] = rval z[0] = rval
else:
z[0] = rval.copy()
def __str__(self): def __str__(self):
return 'ExtractDiag{view=%s}'%self.view return 'ExtractDiag{view=%s}'%self.view
def grad(self, inputs, g_outputs): def grad(self, inputs, g_outputs):
return [alloc_diag(g_outputs[0])] return [alloc_diag(g_outputs[0])]
extract_diag = ExtractDiag()
def infer_shape(self, node, shapes):
x_s, = shapes
return [(x_s[0],)]
extract_diag = ExtractDiag()
#TODO: optimization to insert ExtractDiag with view=True #TODO: optimization to insert ExtractDiag with view=True
class AllocDiag(Op): class AllocDiag(Op):
def __eq__(self, other): def __eq__(self, other):
return type(self) == type(other) return type(self) == type(other)
...@@ -449,7 +460,10 @@ alloc_diag = AllocDiag() ...@@ -449,7 +460,10 @@ alloc_diag = AllocDiag()
def diag(x): def diag(x):
"""Numpy-compatibility method """Numpy-compatibility method
For vector `x`, return a zero matrix except for `x` as diagonal. If `x` is a matrix, return its diagonal.
If `x` is a vector return a matrix with it as its diagonal.
* This method does not support the `k` argument that numpy supports.
""" """
xx = as_tensor_variable(x) xx = as_tensor_variable(x)
if xx.type.ndim == 1: if xx.type.ndim == 1:
...@@ -461,6 +475,7 @@ def diag(x): ...@@ -461,6 +475,7 @@ def diag(x):
class Det(Op): class Det(Op):
"""matrix determinant """matrix determinant
TODO: move this op to another file that request scipy. TODO: move this op to another file that request scipy.
""" """
def make_node(self, x): def make_node(self, x):
...@@ -488,6 +503,7 @@ def trace(X): ...@@ -488,6 +503,7 @@ def trace(X):
""" """
return extract_diag(X).sum() return extract_diag(X).sum()
def spectral_radius_bound(X, log2_exponent): def spectral_radius_bound(X, log2_exponent):
""" """
Returns upper bound on the largest eigenvalue of square symmetrix matrix X. Returns upper bound on the largest eigenvalue of square symmetrix matrix X.
......
from pkg_resources import parse_version as V
import numpy import numpy
import theano import theano
from theano import tensor, function from theano import tensor, function
from theano.tensor.basic import _allclose from theano.tensor.basic import _allclose
from theano.tests import unittest_tools as utt
from theano import config
utt.seed_rng()
try: try:
import scipy import scipy
if scipy.__version__ < '0.7': if V(scipy.__version__) < V('0.7'):
raise ImportError() raise ImportError()
use_scipy = True use_scipy = True
except ImportError: except ImportError:
...@@ -17,11 +23,12 @@ from theano.sandbox.linalg.ops import (cholesky, ...@@ -17,11 +23,12 @@ from theano.sandbox.linalg.ops import (cholesky,
matrix_inverse, matrix_inverse,
#solve, #solve,
#diag, #diag,
#extract_diag, ExtractDiag,
extract_diag,
#alloc_diag, #alloc_diag,
det, det,
#PSD_hint, #PSD_hint,
#trace, trace,
#spectral_radius_bound #spectral_radius_bound
) )
...@@ -88,3 +95,61 @@ def test_det_grad(): ...@@ -88,3 +95,61 @@ def test_det_grad():
r = rng.randn(5,5) r = rng.randn(5,5)
tensor.verify_grad(det, [r], rng=numpy.random) tensor.verify_grad(det, [r], rng=numpy.random)
def test_extract_diag():
rng = numpy.random.RandomState(utt.fetch_seed())
x = theano.tensor.matrix()
g = extract_diag(x)
f = theano.function([x], g)
m = rng.rand(3,3).astype(config.floatX)
v = numpy.diag(m)
r = f(m)
# The right diagonal is extracted
assert (r == v).all()
m = rng.rand(2, 3).astype(config.floatX)
ok = False
try:
r = f(m)
except Exception:
ok = True
assert ok
xx = theano.tensor.vector()
ok = False
try:
extract_diag(xx)
except TypeError:
ok = True
assert ok
f = theano.function([x], g.shape)
topo = f.maker.env.toposort()
assert sum([node.op.__class__ == ExtractDiag for node in topo]) == 0
m = rng.rand(3,3).astype(config.floatX)
assert f(m) == 3
# not testing the view=True case since it is not used anywhere.
def test_trace():
rng = numpy.random.RandomState(utt.fetch_seed())
x = theano.tensor.matrix()
g = trace(x)
f = theano.function([x], g)
m = rng.rand(4, 4).astype(config.floatX)
v = numpy.trace(m)
assert v == f(m)
xx = theano.tensor.vector()
ok = False
try:
trace(xx)
except TypeError:
ok = True
assert ok
from pkg_resources import parse_version as V
import sys import sys
try: try:
import scipy import scipy
enable_sparse = scipy.__version__ >= '0.7' enable_sparse = V(scipy.__version__) >= V('0.7')
if not enable_sparse: if not enable_sparse:
sys.stderr.write("WARNING: scipy version = %s." sys.stderr.write("WARNING: scipy version = %s."
" We request version >=0.7.0 for the sparse code as it has" " We request version >=0.7.0 for the sparse code as it has"
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论