提交 079181cf authored 作者: Pascal Lamblin's avatar Pascal Lamblin

Merge pull request #3275 from abergeron/fix_buildbot

Fix buildbot
...@@ -101,7 +101,8 @@ def rebuild_collect_shared(outputs, ...@@ -101,7 +101,8 @@ def rebuild_collect_shared(outputs,
# Do not use default_update if a "real" update was # Do not use default_update if a "real" update was
# provided # provided
if v not in update_d: if v not in update_d:
v_update = v.type.filter_variable(v.default_update) v_update = v.type.filter_variable(v.default_update,
allow_convert=False)
if v_update.type != v.type: if v_update.type != v.type:
raise TypeError( raise TypeError(
'an update must have the same type as ' 'an update must have the same type as '
...@@ -197,7 +198,8 @@ def rebuild_collect_shared(outputs, ...@@ -197,7 +198,8 @@ def rebuild_collect_shared(outputs,
# filter_variable ensure smooth conversion of cpu/gpu Types # filter_variable ensure smooth conversion of cpu/gpu Types
try: try:
update_val = store_into.type.filter_variable(update_val) update_val = store_into.type.filter_variable(update_val,
allow_convert=False)
except TypeError: except TypeError:
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 (shared_var=%s,' ' original shared variable (shared_var=%s,'
......
...@@ -21,7 +21,7 @@ class NullType(Type): ...@@ -21,7 +21,7 @@ class NullType(Type):
def filter(self, data, strict=False, allow_downcast=None): def filter(self, data, strict=False, allow_downcast=None):
raise ValueError("No values may be assigned to a NullType") raise ValueError("No values may be assigned to a NullType")
def filter_variable(self, other): def filter_variable(self, other, allow_convert=True):
raise ValueError("No values may be assigned to a NullType") raise ValueError("No values may be assigned to a NullType")
def may_share_memory(a, b): def may_share_memory(a, b):
......
...@@ -1288,7 +1288,6 @@ class PatternSub(LocalOptimizer): ...@@ -1288,7 +1288,6 @@ class PatternSub(LocalOptimizer):
return pattern.clone() return pattern.clone()
p = self.out_pattern p = self.out_pattern
new = build(p, u) new = build(p, u)
# print "PatternSub matched:", new
return [new] return [new]
else: else:
return False return False
......
...@@ -263,7 +263,7 @@ class PureType(object): ...@@ -263,7 +263,7 @@ class PureType(object):
# def filter_inplace(value, storage, strict=False, allow_downcast=None) # def filter_inplace(value, storage, strict=False, allow_downcast=None)
def filter_variable(self, other): def filter_variable(self, other, allow_convert=True):
"""Convert a symbolic variable into this Type, if compatible. """Convert a symbolic variable into this Type, if compatible.
For the moment, the only Types compatible with one another are For the moment, the only Types compatible with one another are
...@@ -277,6 +277,11 @@ class PureType(object): ...@@ -277,6 +277,11 @@ class PureType(object):
# a Constant of the appropriate Type. # a Constant of the appropriate Type.
other = self.Constant(type=self, data=other) other = self.Constant(type=self, data=other)
if other.type != self and allow_convert:
other2 = self.convert_variable(other)
if other2 is not None:
return other2
if other.type != self: if other.type != self:
raise TypeError( raise TypeError(
'Cannot convert Type %(othertype)s ' 'Cannot convert Type %(othertype)s '
...@@ -285,6 +290,24 @@ class PureType(object): ...@@ -285,6 +290,24 @@ class PureType(object):
% dict(othertype=other.type, other=other, self=self)) % dict(othertype=other.type, other=other, self=self))
return other return other
def convert_variable(self, var):
"""Patch variable so that its type will match self, if possible.
If the variable can't be converted, this should return None.
The conversion can only happen if the following implication is
true for all possible `val`.
self.is_valid_value(val) => var.type.is_valid_value(val)
For the majority of types this means that you can only have
non-broadcastable dimensions become broadcastable and not the
inverse.
The default is to not convert anything which is always safe.
"""
return None
def is_valid_value(self, a): def is_valid_value(self, a):
"""Required: Return True for any python object `a` that would be a """Required: Return True for any python object `a` that would be a
legal value for a Variable of this Type""" legal value for a Variable of this Type"""
...@@ -404,23 +427,6 @@ class Type(object2, PureType, CLinkerType): ...@@ -404,23 +427,6 @@ class Type(object2, PureType, CLinkerType):
do type-checking in pattern-based optimizations. do type-checking in pattern-based optimizations.
""" """
def convert_variable(self, var):
"""Patch variable so that its type will match self, if possible.
If the variable can't be converted, this should return None.
The conversion can only happen if the following implication is
true for all possible `val`.
self.is_valid_value(val) => var.type.is_valid_value(val)
For the majority of types this means that you can only have
non-broadcastable dimensions become broadcastable and not the
inverse.
The default is to not convert anything which is always safe.
"""
return None
class SingletonType(Type): class SingletonType(Type):
......
...@@ -138,7 +138,7 @@ def test_memory_lazy(): ...@@ -138,7 +138,7 @@ def test_memory_lazy():
# When dtype is float64, only the shared is on the gpu and it is transferd # When dtype is float64, only the shared is on the gpu and it is transferd
# to the cpu for computation. So no extra alloc after compilation. # to the cpu for computation. So no extra alloc after compilation.
# more_alloc1 if after the first compilation, more_alloc2 after the second. # more_alloc1 if after the first compilation, more_alloc2 after the second.
for dtype, more_alloc1 in [("float32", 2), for dtype, more_alloc1 in [("float32", 1),
("float64", 0)]: ("float64", 0)]:
print(dtype) print(dtype)
test_params = np.asarray(np.random.randn(np.prod(shapes)), dtype) test_params = np.asarray(np.random.randn(np.prod(shapes)), dtype)
......
...@@ -119,7 +119,7 @@ class CudaNdarrayType(Type): ...@@ -119,7 +119,7 @@ class CudaNdarrayType(Type):
% (self, self.dtype, data, converted_data, self.dtype), % (self, self.dtype, data, converted_data, self.dtype),
data) data)
def filter_variable(self, other): def filter_variable(self, other, allow_convert=True):
"""Convert a Variable into a CudaNdarrayType, if compatible. """Convert a Variable into a CudaNdarrayType, if compatible.
This Variable should either already be a CudaNdarrayType, or be This Variable should either already be a CudaNdarrayType, or be
...@@ -146,10 +146,17 @@ class CudaNdarrayType(Type): ...@@ -146,10 +146,17 @@ class CudaNdarrayType(Type):
raise TypeError('Incompatible number of dimensions.' raise TypeError('Incompatible number of dimensions.'
' Expected %d, got %d.' % (self.ndim, other.ndim)) ' Expected %d, got %d.' % (self.ndim, other.ndim))
if other.type.broadcastable != self.broadcastable: if other.type.broadcastable != self.broadcastable:
raise TypeError('Incompatible broadcastable dimensions.' if allow_convert:
' Expected %s, got %s.' % type2 = other.type.clone(broadcastable=self.broadcastable)
(str(other.type.broadcastable), other2 = type2.convert_variable(other)
str(self.broadcastable))) else:
other2 = None
if other2 is None:
raise TypeError('Incompatible broadcastable dimensions.'
' Expected %s, got %s.' %
(str(other.type.broadcastable),
str(self.broadcastable)))
other = other2
return theano.sandbox.cuda.basic_ops.GpuFromHost()(other) return theano.sandbox.cuda.basic_ops.GpuFromHost()(other)
......
...@@ -89,7 +89,7 @@ class GpuArrayType(Type): ...@@ -89,7 +89,7 @@ class GpuArrayType(Type):
" dimension.", shp, self.broadcastable) " dimension.", shp, self.broadcastable)
return data return data
def filter_variable(self, other): def filter_variable(self, other, allow_convert=True):
if hasattr(other, '_as_GpuArrayVariable'): if hasattr(other, '_as_GpuArrayVariable'):
other = other._as_GpuArrayVariable() other = other._as_GpuArrayVariable()
...@@ -108,10 +108,17 @@ class GpuArrayType(Type): ...@@ -108,10 +108,17 @@ class GpuArrayType(Type):
raise TypeError('Incompatible number of dimensions.' raise TypeError('Incompatible number of dimensions.'
' Expected %d, got %d.' % (self.ndim, other.ndim)) ' Expected %d, got %d.' % (self.ndim, other.ndim))
if other.type.broadcastable != self.broadcastable: if other.type.broadcastable != self.broadcastable:
raise TypeError('Incompatible broadcastable dimensions.' if allow_convert:
' Expected %s, got %s.' % type2 = other.type.clone(broadcastable=self.broadcastable)
(str(other.type.broadcastable), other2 = type2.convert_variable(other)
str(self.broadcastable))) else:
other2 = None
if other2 is None:
raise TypeError('Incompatible broadcastable dimensions.'
' Expected %s, got %s.' %
(str(other.type.broadcastable),
str(self.broadcastable)))
other = other2
return theano.sandbox.gpuarray.basic_ops.gpu_from_host(other) return theano.sandbox.gpuarray.basic_ops.gpu_from_host(other)
......
...@@ -400,12 +400,7 @@ def expand(tensor_var, size): ...@@ -400,12 +400,7 @@ def expand(tensor_var, size):
shapes = [tensor_var.shape[x] for x in xrange(tensor_var.ndim)] shapes = [tensor_var.shape[x] for x in xrange(tensor_var.ndim)]
zeros_shape = [size + shapes[0]] + shapes[1:] zeros_shape = [size + shapes[0]] + shapes[1:]
empty = tensor.zeros(zeros_shape, empty = tensor.zeros(zeros_shape,
dtype=tensor_var.dtype) dtype=tensor_var.dtype)
# Make sure to reuse the broadcast pattern of the original tensor for
# every dimension but the first one.
broadcastable = (False,) + tensor_var.broadcastable[1:]
empty = tensor.patternbroadcast(empty, broadcastable)
return tensor.set_subtensor(empty[:shapes[0]], tensor_var) return tensor.set_subtensor(empty[:shapes[0]], tensor_var)
......
...@@ -43,6 +43,11 @@ if theano.config.mode == 'FAST_COMPILE': ...@@ -43,6 +43,11 @@ if theano.config.mode == 'FAST_COMPILE':
else: else:
mode_with_opt = theano.compile.mode.get_default_mode() mode_with_opt = theano.compile.mode.get_default_mode()
mode_with_gpu = mode_with_opt.including('gpu', 'scan') mode_with_gpu = mode_with_opt.including('gpu', 'scan')
if theano.config.mode in ('DEBUG_MODE', 'DebugMode'):
mode_nodebug = theano.compile.mode.get_mode('FAST_RUN')
else:
mode_nodebug = mode_with_opt
mode_with_gpu_nodebug = mode_nodebug.including('gpu', 'scan')
type_eps = {'float64': 1e-7, type_eps = {'float64': 1e-7,
...@@ -1772,8 +1777,16 @@ class T_Scan(unittest.TestCase): ...@@ -1772,8 +1777,16 @@ class T_Scan(unittest.TestCase):
analytic_grad = reset_rng_grad_fn(v_u, v_x0, vW_in) analytic_grad = reset_rng_grad_fn(v_u, v_x0, vW_in)
utt.assert_allclose(analytic_grad[0][:2], numpy.zeros((2, 2))) utt.assert_allclose(analytic_grad[0][:2], numpy.zeros((2, 2)))
@attr('slow')
def test_grad_multiple_outs_some_disconnected(self): def test_grad_multiple_outs_some_disconnected(self):
final_cost = self._grad_mout_helper(100, mode_nodebug)
assert final_cost < 0.02
def test_grad_multiple_outs_some_disconnected_2(self):
# This is to try the network in DEBUG_MODE, but not fully
# train it since that would take 3 hours
self._grad_mout_helper(1, None)
def _grad_mout_helper(self, n_iters, mode):
# Created on Tue Oct 07 13:28:51 2014 # Created on Tue Oct 07 13:28:51 2014
# @author: vaneetke # @author: vaneetke
rng = numpy.random.RandomState(utt.fetch_seed()) rng = numpy.random.RandomState(utt.fetch_seed())
...@@ -1815,7 +1828,8 @@ class T_Scan(unittest.TestCase): ...@@ -1815,7 +1828,8 @@ class T_Scan(unittest.TestCase):
sequences=dict(input=x), sequences=dict(input=x),
# corresponds to the return type of one_step # corresponds to the return type of one_step
outputs_info=[dict(initial=h0, taps=[-2, -1]), None], outputs_info=[dict(initial=h0, taps=[-2, -1]), None],
non_sequences=[W_ih, W_hh, b_h, W_ho, b_o]) non_sequences=[W_ih, W_hh, b_h, W_ho, b_o],
mode=mode)
# target values # target values
t = tensor.matrix() t = tensor.matrix()
...@@ -1830,8 +1844,6 @@ class T_Scan(unittest.TestCase): ...@@ -1830,8 +1844,6 @@ class T_Scan(unittest.TestCase):
gparams = theano.grad(cost, params) gparams = theano.grad(cost, params)
updates = [(param, param - gparam * learning_rate) updates = [(param, param - gparam * learning_rate)
for param, gparam in zip(params, gparams)] for param, gparam in zip(params, gparams)]
mode = copy.copy(theano.compile.get_default_mode())
mode.check_py_code = False
learn_rnn_fn = theano.function(inputs=[x, t], learn_rnn_fn = theano.function(inputs=[x, t],
outputs=cost, outputs=cost,
updates=updates, updates=updates,
...@@ -1846,10 +1858,10 @@ class T_Scan(unittest.TestCase): ...@@ -1846,10 +1858,10 @@ class T_Scan(unittest.TestCase):
s_v = numpy.sin(x_v) s_v = numpy.sin(x_v)
t_v = numpy.roll(s_v, -1)[:-1] t_v = numpy.roll(s_v, -1)[:-1]
s_v = s_v[:-1] s_v = s_v[:-1]
for i in xrange(100): for i in xrange(n_iters):
cost = learn_rnn_fn(s_v, t_v) cost = learn_rnn_fn(s_v, t_v)
pred = eval_rnn_fn(s_v) pred = eval_rnn_fn(s_v)
assert cost < 0.02 return cost
def test_draw_as_input_to_scan(self): def test_draw_as_input_to_scan(self):
trng = theano.tensor.shared_randomstreams.RandomStreams(123) trng = theano.tensor.shared_randomstreams.RandomStreams(123)
...@@ -4602,7 +4614,7 @@ class ScanGpuTests: ...@@ -4602,7 +4614,7 @@ class ScanGpuTests:
l1_out, _ = theano.scan(scan_l, sequences=[l1_base], l1_out, _ = theano.scan(scan_l, sequences=[l1_base],
outputs_info=[zero_output], outputs_info=[zero_output],
mode=self.mode_with_gpu) mode=self.mode_with_gpu_nodebug)
l2_out = tensor.dot(l1_out, W) l2_out = tensor.dot(l1_out, W)
...@@ -4613,7 +4625,7 @@ class ScanGpuTests: ...@@ -4613,7 +4625,7 @@ class ScanGpuTests:
# Compile the theano function # Compile the theano function
feval_backprop = theano.function([xin, yout], cost, updates=updates, feval_backprop = theano.function([xin, yout], cost, updates=updates,
mode=self.mode_with_gpu) mode=self.mode_with_gpu_nodebug)
# Validate that the PushOutScanOutput optimization has been applied # Validate that the PushOutScanOutput optimization has been applied
# by checking the number of outputs of the grad Scan node in the # by checking the number of outputs of the grad Scan node in the
...@@ -4676,7 +4688,8 @@ class T_Scan_Cuda(unittest.TestCase, ScanGpuTests): ...@@ -4676,7 +4688,8 @@ class T_Scan_Cuda(unittest.TestCase, ScanGpuTests):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
from theano.sandbox import cuda from theano.sandbox import cuda
self.gpu_backend = cuda self.gpu_backend = cuda
self.mode_with_gpu = mode_with_opt.including('gpu', 'scan') self.mode_with_gpu = mode_with_gpu
self.mode_with_gpu_nodebug = mode_with_gpu_nodebug
super(T_Scan_Cuda, self).__init__(*args, **kwargs) super(T_Scan_Cuda, self).__init__(*args, **kwargs)
def setUp(self): def setUp(self):
...@@ -4737,6 +4750,7 @@ class T_Scan_Gpuarray(unittest.TestCase, ScanGpuTests): ...@@ -4737,6 +4750,7 @@ class T_Scan_Gpuarray(unittest.TestCase, ScanGpuTests):
from theano.sandbox import gpuarray from theano.sandbox import gpuarray
self.gpu_backend = gpuarray self.gpu_backend = gpuarray
self.mode_with_gpu = mode_with_opt.including('gpuarray', 'scan') self.mode_with_gpu = mode_with_opt.including('gpuarray', 'scan')
self.mode_with_gpu_nodebug = mode_nodebug.including('gpuarray', 'scan')
super(T_Scan_Gpuarray, self).__init__(*args, **kwargs) super(T_Scan_Gpuarray, self).__init__(*args, **kwargs)
def setUp(self): def setUp(self):
......
...@@ -712,11 +712,9 @@ def get_scalar_constant_value(orig_v, elemwise=True, ...@@ -712,11 +712,9 @@ def get_scalar_constant_value(orig_v, elemwise=True,
ndim = grandparent.type.ndim ndim = grandparent.type.ndim
if grandparent.owner and isinstance(grandparent.owner.op, if grandparent.owner and isinstance(grandparent.owner.op,
Rebroadcast): Rebroadcast):
l = [] ggp_broadcastable = grandparent.owner.inputs[0].broadcastable
for idx, (b1, b2) in enumerate( l = [b1 or b2 for b1, b2 in zip(ggp_broadcastable,
zip(grandparent.owner.inputs[0].broadcastable, gp_broadcastable)]
gp_broadcastable)):
l.append(b1 or b2)
gp_broadcastable = tuple(l) gp_broadcastable = tuple(l)
assert ndim == len(gp_broadcastable) assert ndim == len(gp_broadcastable)
......
...@@ -1467,6 +1467,8 @@ class CAReduce(Op): ...@@ -1467,6 +1467,8 @@ class CAReduce(Op):
odtype = output.type.dtype_specs()[1] odtype = output.type.dtype_specs()[1]
if hasattr(self, 'acc_dtype') and self.acc_dtype is not None: if hasattr(self, 'acc_dtype') and self.acc_dtype is not None:
if self.acc_dtype == 'float16':
raise theano.gof.utils.MethodNotDefined("no c_code for float16")
acc_type = TensorType( acc_type = TensorType(
broadcastable=node.outputs[0].broadcastable, broadcastable=node.outputs[0].broadcastable,
dtype=self.acc_dtype) dtype=self.acc_dtype)
...@@ -1632,7 +1634,7 @@ for(int i=0;i<PyArray_NDIM(%(iname)s);i++){ ...@@ -1632,7 +1634,7 @@ for(int i=0;i<PyArray_NDIM(%(iname)s);i++){
return ['<vector>', '<algorithm>'] return ['<vector>', '<algorithm>']
def c_code_cache_version_apply(self, node): def c_code_cache_version_apply(self, node):
version = [5] # the version corresponding to the c code in this Op version = (6,) # the version corresponding to the c code in this Op
# now we insert versions for the ops on which we depend... # now we insert versions for the ops on which we depend...
scalar_node = Apply( scalar_node = Apply(
......
...@@ -190,7 +190,7 @@ class TensorType(Type): ...@@ -190,7 +190,7 @@ class TensorType(Type):
raise ValueError("non-finite elements not allowed") raise ValueError("non-finite elements not allowed")
return data return data
def filter_variable(self, other): def filter_variable(self, other, allow_convert=True):
"""Convert a symbolic Variable into a TensorType, if compatible. """Convert a symbolic Variable into a TensorType, if compatible.
For the moment, only a TensorType or CudaNdarrayType will be For the moment, only a TensorType or CudaNdarrayType will be
...@@ -208,6 +208,12 @@ class TensorType(Type): ...@@ -208,6 +208,12 @@ class TensorType(Type):
if other.type == self: if other.type == self:
return other return other
if allow_convert:
# Attempt safe broadcast conversion.
other2 = self.convert_variable(other)
if other2 is not None and other2.type == self:
return other2
raise TypeError( raise TypeError(
'Cannot convert Type %(othertype)s ' 'Cannot convert Type %(othertype)s '
'(of Variable %(other)s) into Type %(self)s. ' '(of Variable %(other)s) into Type %(self)s. '
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论