提交 c1124b59 authored 作者: Nicholas Leonard's avatar Nicholas Leonard

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

...@@ -607,6 +607,27 @@ dimensions, see :meth:`_tensor_py_operators.dimshuffle`. ...@@ -607,6 +607,27 @@ dimensions, see :meth:`_tensor_py_operators.dimshuffle`.
have shape (2, 60). have shape (2, 60).
.. function:: tile(x, reps, ndim=None)
Construct an array by repeating the input `x` according to `reps`
pattern.
Tiles its input according to `reps`. The length of `reps` is the
number of dimension of `x` and contains the number of times to
tile `x` in each dimension.
:see: `numpy.tile
<http://docs.scipy.org/doc/numpy/reference/generated/numpy.tile.html>`_
documentation for examples.
:see: :func:`theano.tensor.extra_ops.repeat
<theano.tensor.extra_ops.repeat>`
:note: Currently, `reps` must be a constant, `x.ndim` and
`len(reps)` must be equal and, if specified, `ndim` must be
equal to both.
Creating Tensor Creating Tensor
=============== ===============
......
...@@ -57,7 +57,10 @@ from theano.gof.link import \ ...@@ -57,7 +57,10 @@ from theano.gof.link import \
from theano.gof.op import \ from theano.gof.op import \
Op, OpenMPOp, PureOp, ops_with_inner_function Op, OpenMPOp, PureOp, ops_with_inner_function
from theano.gof.opt import (Optimizer, optimizer, SeqOptimizer, from theano.gof.opt import (
Optimizer,
optimizer, inplace_optimizer,
SeqOptimizer,
MergeOptimizer, MergeOptMerge, MergeOptimizer, MergeOptMerge,
LocalOptimizer, local_optimizer, LocalOptGroup, LocalOptimizer, local_optimizer, LocalOptGroup,
OpSub, OpRemove, PatternSub, OpSub, OpRemove, PatternSub,
......
...@@ -114,13 +114,13 @@ class Optimizer(object): ...@@ -114,13 +114,13 @@ class Optimizer(object):
class FromFunctionOptimizer(Optimizer): class FromFunctionOptimizer(Optimizer):
"""WRITEME""" """WRITEME"""
def __init__(self, fn): def __init__(self, fn, requirements=()):
self.apply = fn self.apply = fn
self.requirements = requirements
def add_requirements(self, fgraph): def add_requirements(self, fgraph):
# Added by default for req in self.requirements:
#fgraph.attach_feature(toolbox.ReplaceValidate()) req(fgraph)
pass
def print_summary(self, stream=sys.stdout, level=0, depth=-1): def print_summary(self, stream=sys.stdout, level=0, depth=-1):
print >> stream, "%s%s id=%i" % ( print >> stream, "%s%s id=%i" % (
...@@ -142,6 +142,16 @@ def optimizer(f): ...@@ -142,6 +142,16 @@ def optimizer(f):
return rval return rval
def inplace_optimizer(f):
"""decorator for FromFunctionOptimizer"""
dh_handler = dh.DestroyHandler
requirements = (lambda fgraph:
fgraph.attach_feature(dh_handler()),)
rval = FromFunctionOptimizer(f, requirements)
rval.__name__ = f.__name__
return rval
class SeqOptimizer(Optimizer, list): class SeqOptimizer(Optimizer, list):
#inherit from Optimizer first to get Optimizer.__hash__ #inherit from Optimizer first to get Optimizer.__hash__
"""WRITEME """WRITEME
...@@ -790,9 +800,14 @@ class LocalOptimizer(object): ...@@ -790,9 +800,14 @@ class LocalOptimizer(object):
class FromFunctionLocalOptimizer(LocalOptimizer): class FromFunctionLocalOptimizer(LocalOptimizer):
"""WRITEME""" """WRITEME"""
def __init__(self, fn, tracks=None): def __init__(self, fn, tracks=None, requirements=()):
self.transform = fn self.transform = fn
self._tracks = tracks self._tracks = tracks
self.requirements = requirements
def add_requirements(self, fgraph):
for req in self.requirements:
req(fgraph)
def tracks(self): def tracks(self):
return self._tracks return self._tracks
...@@ -808,7 +823,7 @@ class FromFunctionLocalOptimizer(LocalOptimizer): ...@@ -808,7 +823,7 @@ class FromFunctionLocalOptimizer(LocalOptimizer):
id(self)) id(self))
def local_optimizer(tracks): def local_optimizer(tracks, inplace=False):
def decorator(f): def decorator(f):
"""WRITEME""" """WRITEME"""
if tracks is not None: if tracks is not None:
...@@ -817,7 +832,12 @@ def local_optimizer(tracks): ...@@ -817,7 +832,12 @@ def local_optimizer(tracks):
for t in tracks: for t in tracks:
if not (isinstance(t, op.Op) or issubclass(t, op.PureOp)): if not (isinstance(t, op.Op) or issubclass(t, op.PureOp)):
raise ValueError, ("Tracks are op classes or instances", f.__module__, f.__name__) raise ValueError, ("Tracks are op classes or instances", f.__module__, f.__name__)
rval = FromFunctionLocalOptimizer(f, tracks) requirements = ()
if inplace:
dh_handler = dh.DestroyHandler
requirements = (lambda fgraph:
fgraph.attach_feature(dh_handler()),)
rval = FromFunctionLocalOptimizer(f, tracks, requirements)
rval.__name__ = f.__name__ rval.__name__ = f.__name__
return rval return rval
return decorator return decorator
...@@ -852,6 +872,10 @@ class LocalOptGroup(LocalOptimizer): ...@@ -852,6 +872,10 @@ class LocalOptGroup(LocalOptimizer):
for lopt in self.opts: for lopt in self.opts:
lopt.print_summary(stream, level=(level + 2), depth=depth) lopt.print_summary(stream, level=(level + 2), depth=depth)
def add_requirements(self, fgraph):
for opt in self.opts:
opt.add_requirements(fgraph)
class _LocalOpKeyOptGroup(LocalOptGroup): class _LocalOpKeyOptGroup(LocalOptGroup):
"""WRITEME""" """WRITEME"""
......
...@@ -1611,7 +1611,7 @@ class GpuCAReduce(GpuOp): ...@@ -1611,7 +1611,7 @@ class GpuCAReduce(GpuOp):
""" % locals() """ % locals()
def c_code_cache_version_apply(self, node): def c_code_cache_version_apply(self, node):
version = [8] # the version corresponding to the c code in this Op version = [9] # 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(self.scalar_op, scalar_node = Apply(self.scalar_op,
......
...@@ -1214,19 +1214,19 @@ def local_gpujoin_1(node): ...@@ -1214,19 +1214,19 @@ def local_gpujoin_1(node):
# shared = dimshuffle(gemm_inplace(dimshuffle(shared))) # shared = dimshuffle(gemm_inplace(dimshuffle(shared)))
# which causes memory leaks (long term fix is to make the above not leak # which causes memory leaks (long term fix is to make the above not leak
# memory) # memory)
@local_optimizer([gpu_gemm_no_inplace]) @local_optimizer([gpu_gemm_no_inplace], inplace=True)
def local_inplace_gemm(node): def local_inplace_gemm(node):
if node.op == gpu_gemm_no_inplace: if node.op == gpu_gemm_no_inplace:
return [gpu_gemm_inplace(*node.inputs)] return [gpu_gemm_inplace(*node.inputs)]
@local_optimizer([gpu_gemv_no_inplace]) @local_optimizer([gpu_gemv_no_inplace], inplace=True)
def local_inplace_gemv(node): def local_inplace_gemv(node):
if node.op == gpu_gemv_no_inplace: if node.op == gpu_gemv_no_inplace:
return [gpu_gemv_inplace(*node.inputs)] return [gpu_gemv_inplace(*node.inputs)]
@local_optimizer([gpu_ger_no_inplace]) @local_optimizer([gpu_ger_no_inplace], inplace=True)
def local_inplace_ger(node): def local_inplace_ger(node):
if node.op == gpu_ger_no_inplace: if node.op == gpu_ger_no_inplace:
return [gpu_ger_inplace(*node.inputs)] return [gpu_ger_inplace(*node.inputs)]
......
...@@ -1702,7 +1702,7 @@ class GpuCAReduceCuda(HideC, CAReduce): ...@@ -1702,7 +1702,7 @@ class GpuCAReduceCuda(HideC, CAReduce):
""" % locals() """ % locals()
def c_code_cache_version_apply(self, node): def c_code_cache_version_apply(self, node):
version = [8] # the version corresponding to the c code in this Op version = [9] # 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(self.scalar_op, scalar_node = Apply(self.scalar_op,
......
...@@ -341,17 +341,20 @@ def local_gpua_crossentropysoftmaxargmax1hotwithbias(node): ...@@ -341,17 +341,20 @@ def local_gpua_crossentropysoftmaxargmax1hotwithbias(node):
@op_lifter([tensor.nnet.CrossentropySoftmax1HotWithBiasDx]) @op_lifter([tensor.nnet.CrossentropySoftmax1HotWithBiasDx])
def local_gpua_crossentropysoftmax1hotwithbiasdx(node): def local_gpua_crossentropysoftmax1hotwithbiasdx(node):
return GpuCrossentropySoftmax1HotWithBiasDx() return GpuCrossentropySoftmax1HotWithBiasDx()
@register_opt() @register_opt()
@op_lifter([tensor.nnet.Softmax]) @op_lifter([tensor.nnet.Softmax])
def local_gpua_softmax(node): def local_gpua_softmax(node):
return GpuSoftmax() return GpuSoftmax()
@register_opt() @register_opt()
@op_lifter([tensor.nnet.SoftmaxWithBias]) @op_lifter([tensor.nnet.SoftmaxWithBias])
def local_gpua_softmaxwithbias(node): def local_gpua_softmaxwithbias(node):
return GpuSoftmaxWithBias() return GpuSoftmaxWithBias()
@register_opt() @register_opt()
@op_lifter([gpu_from_host, ConvOp]) @op_lifter([gpu_from_host, ConvOp])
def local_gpu_conv(node): def local_gpu_conv(node):
......
...@@ -1715,20 +1715,19 @@ def local_dot_to_dot22(node): ...@@ -1715,20 +1715,19 @@ def local_dot_to_dot22(node):
_logger.info('Not optimizing dot with inputs %s %s %s %s', _logger.info('Not optimizing dot with inputs %s %s %s %s',
x, y, x.type, y.type) x, y, x.type, y.type)
@local_optimizer([gemm_no_inplace], inplace=True)
@local_optimizer([gemm_no_inplace])
def local_inplace_gemm(node): def local_inplace_gemm(node):
if node.op == gemm_no_inplace: if node.op == gemm_no_inplace:
return [gemm_inplace(*node.inputs)] return [gemm_inplace(*node.inputs)]
@local_optimizer([gemv_no_inplace]) @local_optimizer([gemv_no_inplace], inplace=True)
def local_inplace_gemv(node): def local_inplace_gemv(node):
if node.op == gemv_no_inplace: if node.op == gemv_no_inplace:
return [gemv_inplace(*node.inputs)] return [gemv_inplace(*node.inputs)]
@local_optimizer([ger]) @local_optimizer([ger], inplace=True)
def local_inplace_ger(node): def local_inplace_ger(node):
if node.op == ger: if node.op == ger:
return [ger_destructive(*node.inputs)] return [ger_destructive(*node.inputs)]
......
...@@ -571,6 +571,8 @@ def repeat(x, repeats, axis=None): ...@@ -571,6 +571,8 @@ def repeat(x, repeats, axis=None):
:param axis: int, optional. :param axis: int, optional.
:see: :func:`tensor.tile <tensor.tile>`
.. versionadded:: 0.6 .. versionadded:: 0.6
""" """
return RepeatOp(axis=axis)(x, repeats) return RepeatOp(axis=axis)(x, repeats)
......
...@@ -174,7 +174,7 @@ def inplace_elemwise_optimizer_op(OP): ...@@ -174,7 +174,7 @@ def inplace_elemwise_optimizer_op(OP):
""" """
We parametrise it to make it work for Elemwise and GpuElemwise op. We parametrise it to make it work for Elemwise and GpuElemwise op.
""" """
@gof.optimizer @gof.inplace_optimizer
def inplace_elemwise_optimizer(fgraph): def inplace_elemwise_optimizer(fgraph):
""" """
Usage: inplace_elemwise_optimizer.optimize(fgraph) Usage: inplace_elemwise_optimizer.optimize(fgraph)
...@@ -2110,7 +2110,7 @@ compile.optdb.register('pre_local_IncSubtensor_serialize', ...@@ -2110,7 +2110,7 @@ compile.optdb.register('pre_local_IncSubtensor_serialize',
#after priority 50 Destructive inplace operations #after priority 50 Destructive inplace operations
#gemm is the first one now, at priority 70 #gemm is the first one now, at priority 70
@gof.local_optimizer([IncSubtensor]) # XXX: GPU @gof.local_optimizer([IncSubtensor], inplace=True)
def local_inplace_setsubtensor(node): def local_inplace_setsubtensor(node):
""" """
Also work for GpuIncSubtensor Also work for GpuIncSubtensor
...@@ -2129,7 +2129,7 @@ compile.optdb.register('local_inplace_setsubtensor', ...@@ -2129,7 +2129,7 @@ compile.optdb.register('local_inplace_setsubtensor',
'fast_run', 'inplace') # DEBUG 'fast_run', 'inplace') # DEBUG
@gof.local_optimizer([AdvancedIncSubtensor1]) # XXX: GPU @gof.local_optimizer([AdvancedIncSubtensor1], inplace=True)
def local_inplace_incsubtensor1(node): def local_inplace_incsubtensor1(node):
""" also work for GpuAdvancedIncSubtensor1 """ """ also work for GpuAdvancedIncSubtensor1 """
if isinstance(node.op, AdvancedIncSubtensor1) and not node.op.inplace: if isinstance(node.op, AdvancedIncSubtensor1) and not node.op.inplace:
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论