提交 081f64c8 authored 作者: Pascal Lamblin's avatar Pascal Lamblin

Merge pull request #2029 from abergeron/fix_gpuadvsub1

Remove the restriction on indexing a broadcastable dimension.
...@@ -2439,7 +2439,10 @@ class GpuAdvancedSubtensor1(tensor.AdvancedSubtensor1, GpuOp): ...@@ -2439,7 +2439,10 @@ class GpuAdvancedSubtensor1(tensor.AdvancedSubtensor1, GpuOp):
if x_.type.ndim == 0: if x_.type.ndim == 0:
raise TypeError('cannot index into a scalar') raise TypeError('cannot index into a scalar')
return Apply(self, [x_, ilist_], [x_.type()]) bcast = (ilist_.broadcastable[0],) + x_.broadcastable[1:]
return Apply(self, [x_, ilist_],
[CudaNdarrayType(dtype=x.dtype,
broadcastable=bcast)()])
def perform(self, node, inp, out_): def perform(self, node, inp, out_):
# This don't work as CudaNdarray_Subscript() don't support it. # This don't work as CudaNdarray_Subscript() don't support it.
...@@ -2509,15 +2512,15 @@ class GpuAdvancedIncSubtensor1(tensor.AdvancedIncSubtensor1, GpuOp): ...@@ -2509,15 +2512,15 @@ class GpuAdvancedIncSubtensor1(tensor.AdvancedIncSubtensor1, GpuOp):
if ilist_.type.dtype[:3] not in ('int', 'uin'): if ilist_.type.dtype[:3] not in ('int', 'uin'):
raise TypeError('index must be integers') raise TypeError('index must be integers')
if ilist_.type.broadcastable != (False,): if ilist_.type.ndim != 1:
raise TypeError('index must be vector') raise TypeError('index must be vector')
if x_.type.ndim == 0: if x_.type.ndim == 0:
raise TypeError('cannot index into a scalar') raise TypeError('cannot index into a scalar')
if x_.type.broadcastable[0]:
# the caller should have made a copy of x len(ilist) times
raise TypeError('cannot index into a broadcastable dimension')
return Apply(self, [x_, y_, ilist_], [x_.type()]) bcast = (ilist_.broadcastable[0],) + x_.broadcastable[1:]
return Apply(self, [x_, y_, ilist_],
[CudaNdarrayType(dtype=x_.dtype,
broadcastable=bcast)()])
# CudaNdarray_Subscript() doesn't support Advanced slicing. # CudaNdarray_Subscript() doesn't support Advanced slicing.
# But we can't use the parent version that loops on each index # But we can't use the parent version that loops on each index
...@@ -2678,15 +2681,15 @@ class GpuAdvancedIncSubtensor1_dev20(GpuAdvancedIncSubtensor1): ...@@ -2678,15 +2681,15 @@ class GpuAdvancedIncSubtensor1_dev20(GpuAdvancedIncSubtensor1):
if ilist_.type.dtype[:3] not in ('int', 'uin'): if ilist_.type.dtype[:3] not in ('int', 'uin'):
raise TypeError('index must be integers') raise TypeError('index must be integers')
if ilist_.type.broadcastable != (False,): if ilist_.type.ndim != 1:
raise TypeError('index must be vector') raise TypeError('index must be vector')
if x_.type.ndim == 0: if x_.type.ndim == 0:
raise TypeError('cannot index into a scalar') raise TypeError('cannot index into a scalar')
if x_.type.broadcastable[0]:
# the caller should have made a copy of x len(ilist) times
raise TypeError('cannot index into a broadcastable dimension')
return Apply(self, [x_, y_, ilist_], [x_.type()]) bcast = (ilist_.broadcastable[0],) + x_.broadcastable[1:]
return Apply(self, [x_, y_, ilist_],
[CudaNdarrayType(dtype=x_.dtype,
broadcastable=bcast)()])
def c_code_cache_version(self): def c_code_cache_version(self):
return (2,) return (2,)
......
...@@ -986,6 +986,7 @@ class T_subtensor(theano.tensor.tests.test_subtensor.T_subtensor): ...@@ -986,6 +986,7 @@ class T_subtensor(theano.tensor.tests.test_subtensor.T_subtensor):
# optimized for that case. # optimized for that case.
((4, 4, 2, 3), [3, 3, 1, 1, 2, 2, 0, 0, ((4, 4, 2, 3), [3, 3, 1, 1, 2, 2, 0, 0,
-1, -2, -3, -4], False), -1, -2, -3, -4], False),
((1, 10), [0, 0], True),
]: ]:
# If there is not enough memory on the GPU, skip the test # If there is not enough memory on the GPU, skip the test
size_needed = numpy.prod(shape) * (4 + 1) size_needed = numpy.prod(shape) * (4 + 1)
......
...@@ -450,22 +450,6 @@ class TestConstructSparseFromList(unittest.TestCase): ...@@ -450,22 +450,6 @@ class TestConstructSparseFromList(unittest.TestCase):
g = theano.grad(sub.sum(), m) g = theano.grad(sub.sum(), m)
assert isinstance(g.owner.op, tensor.AdvancedIncSubtensor1) assert isinstance(g.owner.op, tensor.AdvancedIncSubtensor1)
# Test that we create a sparse grad when asked
# OLD INTERFACE
m = theano.tensor.matrix()
sub = m[v]
m.type.sparse_grad = True
g = theano.grad(sub.sum(), m)
assert isinstance(g.owner.op, ConstructSparseFromList)
# Test that we create a sparse grad when asked
# OLD INTERFACE CONSEQUENCE
m = theano.tensor.matrix()
sub = m[v]
sub.type.sparse_grad = True
g = theano.grad(sub.sum(), m)
assert isinstance(g.owner.op, ConstructSparseFromList)
# Test that we create a sparse grad when asked # Test that we create a sparse grad when asked
# USER INTERFACE # USER INTERFACE
m = theano.tensor.matrix() m = theano.tensor.matrix()
......
...@@ -1523,7 +1523,9 @@ class AdvancedSubtensor1(Op): ...@@ -1523,7 +1523,9 @@ class AdvancedSubtensor1(Op):
raise TypeError('index must be vector') raise TypeError('index must be vector')
if x_.type.ndim == 0: if x_.type.ndim == 0:
raise TypeError('cannot index into a scalar') raise TypeError('cannot index into a scalar')
return Apply(self, [x_, ilist_], [x_.type()]) bcast = (ilist_.broadcastable[0],) + x_.broadcastable[1:]
return Apply(self, [x_, ilist_], [TensorType(dtype=x.dtype,
broadcastable=bcast)()])
def perform(self, node, inp, out_): def perform(self, node, inp, out_):
x, i = inp x, i = inp
...@@ -1565,14 +1567,7 @@ class AdvancedSubtensor1(Op): ...@@ -1565,14 +1567,7 @@ class AdvancedSubtensor1(Op):
x, ilist = inputs x, ilist = inputs
gz, = grads gz, = grads
assert len(inputs) == 2 assert len(inputs) == 2
sparse = False if self.sparse_grad:
if getattr(x.type, 'sparse_grad', False):
sparse = True
warnings.warn(
"DEPRECATION WARNING: AdvancedSubtensor1, you are using"
" an old interface to the sparse grad. You should use"
" theano.sparse_grad(a_tensor[an_int_vector]). ")
if sparse or self.sparse_grad:
if x.type.ndim != 2: if x.type.ndim != 2:
raise TypeError( raise TypeError(
"AdvancedSubtensor1: you can't take the sparse grad" "AdvancedSubtensor1: you can't take the sparse grad"
...@@ -1742,8 +1737,9 @@ class AdvancedIncSubtensor1(Op): ...@@ -1742,8 +1737,9 @@ class AdvancedIncSubtensor1(Op):
'cannot %s x subtensor with ndim=%s' 'cannot %s x subtensor with ndim=%s'
' by y with ndim=%s to x subtensor with ndim=%s ' % ( ' by y with ndim=%s to x subtensor with ndim=%s ' % (
opname, x_.type.ndim, y_.type.ndim)) opname, x_.type.ndim, y_.type.ndim))
bcast = (ilist_.broadcastable[0],) + x_.broadcastable[1:]
return Apply(self, [x_, y_, ilist_], [x_.type()]) return Apply(self, [x_, y_, ilist_], [TensorType(dtype=x.dtype,
broadcastable=bcast)()])
def perform(self, node, inp, out_): def perform(self, node, inp, out_):
# TODO opt to make this inplace # TODO opt to make this inplace
......
...@@ -500,9 +500,25 @@ class T_subtensor(unittest.TestCase, utt.TestOptimizationMixin): ...@@ -500,9 +500,25 @@ class T_subtensor(unittest.TestCase, utt.TestOptimizationMixin):
self.ignore_topo)] self.ignore_topo)]
assert len(topo_) == 1 assert len(topo_) == 1
self.assertTrue(isinstance(topo_[0].op, self.adv_sub1)) self.assertTrue(isinstance(topo_[0].op, self.adv_sub1))
self.assertTrue(numpy.allclose(f([0]), ones[0] * 5)) f_0 = f([0])
self.assertTrue(f_0.shape == (1, 3))
self.assertTrue(numpy.allclose(f_0, ones[0] * 5))
f_00 = f([0, 0])
self.assertTrue(f_00.shape == (2, 3))
self.assertTrue(numpy.allclose(f_00, 5))
self.assertRaises(IndexError, f, [0, 1]) self.assertRaises(IndexError, f, [0, 1])
# Test the gradient
c = t.sum()
gn = theano.grad(c, n)
g = self.function([idx], gn, op=self.adv_incsub1)
g_0 = g([0])
self.assertTrue(g_0.shape == (1, 3))
self.assertTrue(numpy.allclose(g_0, 1))
g_00 = g([0, 0])
self.assertTrue(g_00.shape == (1, 3))
self.assertTrue(numpy.allclose(g_00, 2))
def test_adv_sub1_idx_broadcast(self): def test_adv_sub1_idx_broadcast(self):
# The idx can be a broadcastable vector. # The idx can be a broadcastable vector.
ones = numpy.ones((4, 3), dtype=self.dtype) ones = numpy.ones((4, 3), dtype=self.dtype)
...@@ -518,7 +534,18 @@ class T_subtensor(unittest.TestCase, utt.TestOptimizationMixin): ...@@ -518,7 +534,18 @@ class T_subtensor(unittest.TestCase, utt.TestOptimizationMixin):
self.ignore_topo)] self.ignore_topo)]
assert len(topo_) == 1 assert len(topo_) == 1
self.assertTrue(isinstance(topo_[0].op, self.adv_sub1)) self.assertTrue(isinstance(topo_[0].op, self.adv_sub1))
self.assertTrue(numpy.allclose(f([0]), ones[0] * 5)) f_0 = f([0])
self.assertTrue(f_0.shape == (1, 3))
self.assertTrue(numpy.allclose(f_0, 5))
# Test the gradient
c = t.sum()
gn = theano.grad(c, n)
g = self.function([idx], gn, op=self.adv_incsub1)
g_0 = g([0])
self.assertTrue(g_0.shape == (4, 3))
self.assertTrue(numpy.allclose(g_0[0], 1))
self.assertTrue(numpy.allclose(g_0[1:], 0))
@attr('slow') @attr('slow')
def test_shape_i_const(self): def test_shape_i_const(self):
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论