提交 d1ac0913 authored 作者: lamblin's avatar lamblin

Merge pull request #830 from nouiz/update_broadcast

Update broadcast
...@@ -2,8 +2,7 @@ global-include *.txt ...@@ -2,8 +2,7 @@ global-include *.txt
global-include *.cu global-include *.cu
global-include *.cuh global-include *.cuh
global-include *.sh global-include *.sh
recursive-include docs *.png *.gp recursive-include docs
include distribute_setup.py
include bin/theano-cache include bin/theano-cache
include bin/theano-nose include bin/theano-nose
include bin/theano-test include bin/theano-test
...@@ -131,7 +131,7 @@ to your machine, you can install to an alternate prefix using ...@@ -131,7 +131,7 @@ to your machine, you can install to an alternate prefix using
.. code-block:: bash .. code-block:: bash
pip install Theano --install-option='--prefix=~/.local pip install Theano --install-option='--prefix=~/.local'
e.g. using ``--install-option='--prefix=~/.local'`` on Python 2.4 would e.g. using ``--install-option='--prefix=~/.local'`` on Python 2.4 would
install Theano into ``.local/lib/python2.4/site-packages`` inside your home install Theano into ``.local/lib/python2.4/site-packages`` inside your home
......
...@@ -198,17 +198,25 @@ def rebuild_collect_shared(outputs, ...@@ -198,17 +198,25 @@ def rebuild_collect_shared(outputs,
(store_into, update_d[store_into])) (store_into, update_d[store_into]))
# filter_variable ensure smooth conversion of cpu/gpu Types # filter_variable ensure smooth conversion of cpu/gpu Types
try:
update_val = store_into.type.filter_variable(update_val) update_val = store_into.type.filter_variable(update_val)
if update_val.type != store_into.type: except TypeError, e:
err_msg = ('an update must have the same type as the ' err_msg = ('An update must have the same type as the'
'original shared variable(dest, dest.type, ' ' original shared variable (shared_var=%s,'
'update_val, update_val.type)') ' shared_var.type=%s,'
err_arg = (store_into, ' update_val=%s, update_val.type=%s).' % (
store_into,
store_into.type, store_into.type,
update_val, update_val,
update_val.type) update_val.type))
err_sug = ('If the difference is related to the broadcast pattern,'
' you can call the'
' tensor.unbroadcast(var, axis_to_unbroadcast[, ...])'
' function to remove broadcastable dimensions.')
raise TypeError(err_msg, err_sug)
assert update_val.type == store_into.type
raise TypeError(err_msg, err_arg)
update_d[store_into] = update_val update_d[store_into] = update_val
update_expr.append((store_into, update_val)) update_expr.append((store_into, update_val))
......
...@@ -335,6 +335,16 @@ class Test_pfunc(unittest.TestCase): ...@@ -335,6 +335,16 @@ class Test_pfunc(unittest.TestCase):
inc_by_y() inc_by_y()
self.assertTrue(x.get_value() == 1) self.assertTrue(x.get_value() == 1)
def test_update_err_broadcast(self):
# Test that broadcastable dimensions raise error
data = numpy.random.rand(10, 10).astype('float32')
output_var = shared(name="output", value=data)
# the update_var has type matrix, and the update expression
# is a broadcasted scalar, and that should be allowed.
self.assertRaises(TypeError, theano.function, inputs=[], outputs=[],
updates={output_var: output_var.sum().dimshuffle('x', 'x')})
def test_duplicate_updates(self): def test_duplicate_updates(self):
x, y = dmatrices('x', 'y') x, y = dmatrices('x', 'y')
z = shared(numpy.ones((2, 3))) z = shared(numpy.ones((2, 3)))
......
...@@ -88,8 +88,9 @@ def run_mercurial_command(hg_command): ...@@ -88,8 +88,9 @@ def run_mercurial_command(hg_command):
hg_command_tuple.insert(0, hg_executable) hg_command_tuple.insert(0, hg_executable)
try: try:
hg_subprocess = Popen(hg_command_tuple, stdout=PIPE, stderr=PIPE) hg_subprocess = Popen(hg_command_tuple, stdout=PIPE, stderr=PIPE)
except OSError: except OSError, e:
print >> sys.stderr, "Can't find the hg executable!" print >> sys.stderr, "Can't find the hg executable!"
print e
sys.exit(1) sys.exit(1)
hg_out, hg_err = hg_subprocess.communicate() hg_out, hg_err = hg_subprocess.communicate()
......
...@@ -58,7 +58,7 @@ def setup(): ...@@ -58,7 +58,7 @@ def setup():
try: try:
os.mkdir(basedir) os.mkdir(basedir)
except OSError as e: except OSError, e:
if e.errno != errno.EEXIST: if e.errno != errno.EEXIST:
raise raise
os.chdir(basedir) os.chdir(basedir)
......
...@@ -5,12 +5,9 @@ from nose.plugins.skip import SkipTest ...@@ -5,12 +5,9 @@ from nose.plugins.skip import SkipTest
import theano import theano
from theano import tensor from theano import tensor
from theano import sparse
from theano.tensor import TensorType
from theano.tests import unittest_tools as utt
from theano.sandbox.cuda.var import float32_shared_constructor as f32sc from theano.sandbox.cuda.var import float32_shared_constructor as f32sc
from theano.sandbox.cuda import CudaNdarrayType, cuda_available from theano.sandbox.cuda import CudaNdarrayType, cuda_available
import theano.sandbox.cuda as cuda
# Skip test if cuda_ndarray is not available. # Skip test if cuda_ndarray is not available.
if cuda_available == False: if cuda_available == False:
raise SkipTest('Optional package cuda disabled') raise SkipTest('Optional package cuda disabled')
...@@ -66,6 +63,10 @@ class T_updates(unittest.TestCase): ...@@ -66,6 +63,10 @@ class T_updates(unittest.TestCase):
f = theano.function([], y, updates={x: x + 1}) f = theano.function([], y, updates={x: x + 1})
f() f()
# Test that we can update with a CudaVariable
f = theano.function([], y, updates={x: cuda.gpu_from_host(x + 1)})
f()
def test_2(self): def test_2(self):
# This test case uses code mentionned in #698 # This test case uses code mentionned in #698
data = numpy.random.rand(10, 10).astype('float32') data = numpy.random.rand(10, 10).astype('float32')
...@@ -79,14 +80,42 @@ class T_updates(unittest.TestCase): ...@@ -79,14 +80,42 @@ class T_updates(unittest.TestCase):
updates=output_updates, givens=output_givens) updates=output_updates, givens=output_givens)
output_func() output_func()
def test_3(self): def test_err_ndim(self):
# Test that broadcastable dimensions don't screw up # Test that we raise a good error message when we don't
# update expressions. # same the same number of dimensions.
data = numpy.random.rand(10, 10).astype('float32')
output_var = f32sc(name="output", value=data)
# the update_var has type matrix, and the update expression
# is a broadcasted scalar, and that should be allowed.
self.assertRaises(TypeError, theano.function, inputs=[], outputs=[],
updates={output_var:
output_var.sum()})
def test_err_broadcast(self):
# Test that we raise a good error message when we don't
# same the same number of dimensions.
data = numpy.random.rand(10, 10).astype('float32') data = numpy.random.rand(10, 10).astype('float32')
output_var = f32sc(name="output", value=data) output_var = f32sc(name="output", value=data)
# the update_var has type matrix, and the update expression # the update_var has type matrix, and the update expression
# is a broadcasted scalar, and that should be allowed. # is a broadcasted scalar, and that should be allowed.
self.assertRaises(TypeError, theano.function, inputs=[], outputs=[],
updates={output_var:
output_var.sum().dimshuffle('x', 'x')})
def test_broadcast(self):
# Test that we can rebroadcast
data = numpy.random.rand(10, 10).astype('float32')
output_var = f32sc(name="output", value=data)
up = tensor.unbroadcast(output_var.sum().dimshuffle('x', 'x'), 0, 1)
output_func = theano.function(inputs=[], outputs=[],
updates={output_var: up})
output_func()
up = tensor.patternbroadcast(output_var.sum().dimshuffle('x', 'x'),
output_var.type.broadcastable)
output_func = theano.function(inputs=[], outputs=[], output_func = theano.function(inputs=[], outputs=[],
updates={output_var: output_var.sum().dimshuffle('x', 'x')}) updates={output_var: up})
output_func() output_func()
...@@ -130,20 +130,20 @@ class CudaNdarrayType(Type): ...@@ -130,20 +130,20 @@ class CudaNdarrayType(Type):
if other.type == self: if other.type == self:
return other return other
if not isinstance(other.type, tensor.TensorType): if not isinstance(other.type, (tensor.TensorType, CudaNdarrayType)):
raise TypeError('Incompatible type', (self, other.type)) raise TypeError('Incompatible type', (self, other.type))
if (other.type.dtype != self.dtype): if (other.type.dtype != self.dtype):
raise TypeError('Incompatible dtype', (self.dtype, raise TypeError('Incompatible dtype', (self.dtype,
other.type.dtype)) other.type.dtype))
if numpy.any([bi and not obi if other.type.ndim != self.ndim:
for obi, bi in zip( raise TypeError('Incompatible number of dimensions.'
other.type.broadcastable, ' Expected %d, got %d.' % (self.ndim, other.ndim))
self.broadcastable)]):
raise TypeError('Incompatible broadcastable', (self.broadcastable,
other.type.broadcastable))
if other.type.broadcastable != self.broadcastable: if other.type.broadcastable != self.broadcastable:
rebroadcast = tensor.Rebroadcast(*enumerate(self.broadcastable)) raise TypeError('Incompatible broadcastable dimensions.'
other = rebroadcast(other) ' Expected %s, got %s.' %
(str(other.type.broadcastable),
str(self.broadcastable)))
return theano.sandbox.cuda.basic_ops.GpuFromHost()(other) return theano.sandbox.cuda.basic_ops.GpuFromHost()(other)
@staticmethod @staticmethod
......
from nose.plugins.skip import SkipTest
import numpy import numpy
from theano import tensor, function from theano import tensor, function
from theano.tests import unittest_tools as utt from theano.tests import unittest_tools as utt
from theano.sandbox.linalg.kron import Kron, kron from theano.sandbox.linalg.kron import Kron, kron
...@@ -9,6 +11,9 @@ try: ...@@ -9,6 +11,9 @@ try:
except ImportError: except ImportError:
imported_scipy = False imported_scipy = False
if not imported_scipy:
raise SkipTest('Kron Op need the scipy package to be installed')
class TestKron(utt.InferShapeTester): class TestKron(utt.InferShapeTester):
...@@ -20,8 +25,6 @@ class TestKron(utt.InferShapeTester): ...@@ -20,8 +25,6 @@ class TestKron(utt.InferShapeTester):
self.op = kron self.op = kron
def test_perform(self): def test_perform(self):
assert imported_scipy, (
"Scipy not available. Scipy is needed for TestKron")
x = tensor.dmatrix() x = tensor.dmatrix()
y = tensor.dmatrix() y = tensor.dmatrix()
f = function([x, y], kron(x, y)) f = function([x, y], kron(x, y))
......
from nose.plugins.skip import SkipTest
import numpy import numpy
try: try:
import scipy.sparse as sp import scipy.sparse as sp
......
from nose.plugins.skip import SkipTest
import numpy import numpy
import theano.sparse import theano.sparse
......
...@@ -4655,6 +4655,9 @@ class Rebroadcast(Op): ...@@ -4655,6 +4655,9 @@ class Rebroadcast(Op):
def __init__(self, *axis): def __init__(self, *axis):
self.axis = dict(axis) self.axis = dict(axis)
for axis, broad in self.axis.iteritems():
assert isinstance(axis, (numpy.integer, int)), (
"Rebroadcast need integers axis. Got ", axis)
def __eq__(self, other): def __eq__(self, other):
return type(self) == type(other) and self.axis == other.axis return type(self) == type(other) and self.axis == other.axis
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论