提交 bb899b3e authored 作者: abergeron's avatar abergeron

Merge pull request #2140 from nouiz/mixed

[ENH] Add SliceConstant, better stack trace, fast_compile_gpu
...@@ -93,7 +93,13 @@ OPT_NONE = gof.Query(include=[], exclude=exclude) ...@@ -93,7 +93,13 @@ OPT_NONE = gof.Query(include=[], exclude=exclude)
OPT_MERGE = gof.Query(include=['merge'], exclude=exclude) OPT_MERGE = gof.Query(include=['merge'], exclude=exclude)
OPT_FAST_RUN = gof.Query(include=['fast_run'], exclude=exclude) OPT_FAST_RUN = gof.Query(include=['fast_run'], exclude=exclude)
OPT_FAST_RUN_STABLE = OPT_FAST_RUN.requiring('stable') OPT_FAST_RUN_STABLE = OPT_FAST_RUN.requiring('stable')
OPT_FAST_COMPILE = gof.Query(include=['fast_compile'], exclude=exclude) # We need fast_compile_gpu here. As on the GPU, we don't have all
# operation that exist in fast_compile, but have some that get
# introduced in fast_run, we want those optimization to also run in
# fast_compile+gpu. We can't tag them just as 'gpu', as this would
# exclude them if we exclude 'gpu'.
OPT_FAST_COMPILE = gof.Query(include=['fast_compile', 'fast_compile_gpu'],
exclude=exclude)
OPT_STABILIZE = gof.Query(include=['fast_run'], exclude=exclude) OPT_STABILIZE = gof.Query(include=['fast_run'], exclude=exclude)
OPT_STABILIZE.position_cutoff = 1.5000001 OPT_STABILIZE.position_cutoff = 1.5000001
OPT_NONE.name = 'OPT_NONE' OPT_NONE.name = 'OPT_NONE'
...@@ -191,7 +197,7 @@ optdb.register('Print1.51', PrintCurrentFunctionGraph('Post-stabilize'), ...@@ -191,7 +197,7 @@ optdb.register('Print1.51', PrintCurrentFunctionGraph('Post-stabilize'),
# misc special cases for speed # misc special cases for speed
optdb.register('specialize', gof.EquilibriumDB(), optdb.register('specialize', gof.EquilibriumDB(),
2, 'fast_run') 2, 'fast_run', 'fast_compile_gpu')
# misc special cases for speed that break canonicalization # misc special cases for speed that break canonicalization
optdb.register('uncanonicalize', gof.EquilibriumDB(), optdb.register('uncanonicalize', gof.EquilibriumDB(),
......
...@@ -8,6 +8,7 @@ import logging ...@@ -8,6 +8,7 @@ import logging
import pdb import pdb
import sys import sys
import time import time
import warnings
import numpy import numpy
...@@ -731,7 +732,8 @@ def pre_constant_merge(vars): ...@@ -731,7 +732,8 @@ def pre_constant_merge(vars):
seen_var = set() seen_var = set()
# signature -> variable (for constants) # signature -> variable (for constants)
const_sig_inv = {} const_sig_inv = {}
if isinstance(vars, graph.Variable):
vars = [vars]
def recursive_merge(var): def recursive_merge(var):
if var in seen_var: if var in seen_var:
return var return var
...@@ -747,6 +749,10 @@ def pre_constant_merge(vars): ...@@ -747,6 +749,10 @@ def pre_constant_merge(vars):
return const_sig_inv[sig] return const_sig_inv[sig]
const_sig_inv[sig] = var const_sig_inv[sig] = var
except TypeError: # unhashable type except TypeError: # unhashable type
warnings.warn(
"We work around a problem, the following variable"
" signature isn't hashable. Please, report this to"
" theano-dev so that the better fix is done. %s" % var)
# Some python object like slice aren't hashable. So # Some python object like slice aren't hashable. So
# don't merge them here. # don't merge them here.
pass pass
......
...@@ -409,3 +409,20 @@ class TestEquilibrium(object): ...@@ -409,3 +409,20 @@ class TestEquilibrium(object):
_logger.setLevel(oldlevel) _logger.setLevel(oldlevel)
#print 'after', g #print 'after', g
assert str(g) == '[Op1(x, y)]' assert str(g) == '[Op1(x, y)]'
def test_pre_constant_merge_slice():
ms = theano.tensor.type_other.MakeSlice()(1)
pre_constant_merge([ms])
const_slice = theano.tensor.type_other.SliceConstant(
type=theano.tensor.type_other.slicetype,
data=slice(1, None, 2))
adv = theano.tensor.subtensor.AdvancedSubtensor()(theano.tensor.matrix(),
[2, 3], const_slice)
pre_constant_merge(adv)
cst = pre_greedy_local_optimizer([theano.tensor.opt.constant_folding], ms)
assert isinstance(cst, theano.tensor.type_other.SliceConstant)
# Make sure constant of slice signature is hashable.
hash(cst.signature())
...@@ -18,6 +18,18 @@ def add_tag_trace(thing): ...@@ -18,6 +18,18 @@ def add_tag_trace(thing):
# rid of it. We also want to get rid of the add_tag_trace call. # rid of it. We also want to get rid of the add_tag_trace call.
if tr and "add_tag_trace" in tr[-1][-1]: if tr and "add_tag_trace" in tr[-1][-1]:
tr = tr[:-1] tr = tr[:-1]
while tr:
file_path = tr[-1][0]
rm = False
for p in ["theano/tensor/",
"theano/gof/"]:
if p in file_path:
tr = tr[:-1]
rm = True
break
if not rm:
break
thing.tag.trace = tr thing.tag.trace = tr
return thing return thing
......
...@@ -577,7 +577,7 @@ class Softmax(gof.Op): ...@@ -577,7 +577,7 @@ class Softmax(gof.Op):
softmax = Softmax() softmax = Softmax()
@opt.register_specialize('gpu') @opt.register_specialize('fast_compile_gpu')
@gof.local_optimizer([softmax]) @gof.local_optimizer([softmax])
def local_softmax_with_bias(node): def local_softmax_with_bias(node):
"""Try to turn softmax(sum_of_stuff) -> softmax_w_bias(matrix, bias) """Try to turn softmax(sum_of_stuff) -> softmax_w_bias(matrix, bias)
...@@ -1330,8 +1330,8 @@ class CrossentropyCategorical1Hot(gof.Op): ...@@ -1330,8 +1330,8 @@ class CrossentropyCategorical1Hot(gof.Op):
crossentropy_categorical_1hot = CrossentropyCategorical1Hot() crossentropy_categorical_1hot = CrossentropyCategorical1Hot()
@opt.register_stabilize('gpu') @opt.register_stabilize('fast_compile_gpu')
@opt.register_specialize('gpu') @opt.register_specialize('fast_compile_gpu')
@gof.optimizer @gof.optimizer
def crossentropy_to_crossentropy_with_softmax_with_bias(fgraph): def crossentropy_to_crossentropy_with_softmax_with_bias(fgraph):
"""This is a stabilization optimization """This is a stabilization optimization
...@@ -1404,10 +1404,10 @@ def crossentropy_to_crossentropy_with_softmax(fgraph): ...@@ -1404,10 +1404,10 @@ def crossentropy_to_crossentropy_with_softmax(fgraph):
optdb.register('crossentropy_to_crossentropy_with_softmax', optdb.register('crossentropy_to_crossentropy_with_softmax',
crossentropy_to_crossentropy_with_softmax, 2.01, crossentropy_to_crossentropy_with_softmax, 2.01,
'fast_run', 'xent', 'gpu') 'fast_run', 'xent', 'fast_compile_gpu')
@opt.register_specialize('gpu') @opt.register_specialize('fast_compile_gpu')
@gof.local_optimizer([softmax_grad]) @gof.local_optimizer([softmax_grad])
def local_crossentropy_to_crossentropy_with_softmax_grad(node): def local_crossentropy_to_crossentropy_with_softmax_grad(node):
if node.op == softmax_grad: if node.op == softmax_grad:
...@@ -1420,7 +1420,7 @@ def local_crossentropy_to_crossentropy_with_softmax_grad(node): ...@@ -1420,7 +1420,7 @@ def local_crossentropy_to_crossentropy_with_softmax_grad(node):
return [dx] return [dx]
@opt.register_specialize('gpu') @opt.register_specialize('fast_compile_gpu')
@gof.local_optimizer([tensor._max_and_argmax]) @gof.local_optimizer([tensor._max_and_argmax])
def local_argmax_pushdown(node): def local_argmax_pushdown(node):
if node.op == tensor._max_and_argmax and node.inputs[0].owner and \ if node.op == tensor._max_and_argmax and node.inputs[0].owner and \
...@@ -1506,7 +1506,7 @@ def _is_const(z, val, approx=False): ...@@ -1506,7 +1506,7 @@ def _is_const(z, val, approx=False):
return numpy.all(maybe == val) return numpy.all(maybe == val)
@opt.register_specialize('gpu') @opt.register_specialize('fast_compile_gpu')
@gof.local_optimizer([subtensor.AdvancedSubtensor, tensor.log]) @gof.local_optimizer([subtensor.AdvancedSubtensor, tensor.log])
def local_advanced_indexing_crossentropy_onehot(node): def local_advanced_indexing_crossentropy_onehot(node):
log = None log = None
...@@ -1547,7 +1547,7 @@ def local_advanced_indexing_crossentropy_onehot(node): ...@@ -1547,7 +1547,7 @@ def local_advanced_indexing_crossentropy_onehot(node):
labels)[0]] labels)[0]]
@opt.register_specialize('gpu') @opt.register_specialize('fast_compile_gpu')
@gof.local_optimizer([softmax_grad]) @gof.local_optimizer([softmax_grad])
def local_advanced_indexing_crossentropy_onehot_grad(node): def local_advanced_indexing_crossentropy_onehot_grad(node):
if not (node.op == softmax_grad): if not (node.op == softmax_grad):
...@@ -1770,7 +1770,7 @@ def local_advanced_indexing_crossentropy_onehot_grad(node): ...@@ -1770,7 +1770,7 @@ def local_advanced_indexing_crossentropy_onehot_grad(node):
return return
@opt.register_specialize('gpu') @opt.register_specialize('fast_compile_gpu')
@gof.local_optimizer([softmax_with_bias]) @gof.local_optimizer([softmax_with_bias])
def graph_merge_softmax_with_crossentropy_softmax(node): def graph_merge_softmax_with_crossentropy_softmax(node):
if node.op == softmax_with_bias: if node.op == softmax_with_bias:
...@@ -1976,4 +1976,4 @@ local_log_softmax = gof.PatternSub(in_pattern=(tensor.log, (softmax, 'x')), ...@@ -1976,4 +1976,4 @@ local_log_softmax = gof.PatternSub(in_pattern=(tensor.log, (softmax, 'x')),
#don't do register_stabilize, this is to make local_log_softmax run #don't do register_stabilize, this is to make local_log_softmax run
#only after another more specific optimization that stabilizes cross entropy #only after another more specific optimization that stabilizes cross entropy
#opt.register_stabilize(local_log_softmax, name = 'local_log_softmax') #opt.register_stabilize(local_log_softmax, name = 'local_log_softmax')
opt.register_specialize(local_log_softmax, 'gpu', name='local_log_softmax') opt.register_specialize(local_log_softmax, 'fast_compile_gpu', name='local_log_softmax')
...@@ -338,7 +338,8 @@ def register_specialize(lopt, *tags, **kwargs): ...@@ -338,7 +338,8 @@ def register_specialize(lopt, *tags, **kwargs):
return register return register
else: else:
name = (kwargs and kwargs.pop('name')) or lopt.__name__ name = (kwargs and kwargs.pop('name')) or lopt.__name__
compile.optdb['specialize'].register(name, lopt, 'fast_run', *tags) compile.optdb['specialize'].register(name, lopt, 'fast_run',
'fast_compile_gpu', *tags)
return lopt return lopt
...@@ -1319,7 +1320,7 @@ def local_track_shape_i(node): ...@@ -1319,7 +1320,7 @@ def local_track_shape_i(node):
@register_specialize @register_specialize
@register_canonicalize('gpu') @register_canonicalize('fast_compile_gpu')
@gof.local_optimizer([Subtensor]) @gof.local_optimizer([Subtensor])
def local_subtensor_make_vector(node): def local_subtensor_make_vector(node):
# replace all subtensor(make_vector) like: # replace all subtensor(make_vector) like:
......
...@@ -1807,6 +1807,8 @@ def as_index_variable(idx): ...@@ -1807,6 +1807,8 @@ def as_index_variable(idx):
return NoneConst.clone() return NoneConst.clone()
if isinstance(idx, slice): if isinstance(idx, slice):
return make_slice(idx) return make_slice(idx)
if isinstance(idx, gof.Variable) and isinstance(idx.type, SliceType):
return idx
idx = theano.tensor.as_tensor_variable(idx) idx = theano.tensor.as_tensor_variable(idx)
if idx.type.dtype[:3] not in ('int', 'uin'): if idx.type.dtype[:3] not in ('int', 'uin'):
raise TypeError('index must be integers') raise TypeError('index must be integers')
......
# #
# Slice type and Op. None Type and NoneConst. # Slice type and Op. None Type and NoneConst.
# #
import numpy
import theano import theano
from theano.gof import Apply, Constant, Generic, Op, Type, hashtype from theano.gof import Apply, Constant, Generic, Op, Type, hashtype
from theano.gradient import DisconnectedType from theano.gradient import DisconnectedType
...@@ -76,6 +79,35 @@ class SliceType(Type): ...@@ -76,6 +79,35 @@ class SliceType(Type):
slicetype = SliceType() slicetype = SliceType()
class SliceConstant(Constant):
def __init__(self, type, data, name=None):
assert isinstance(data, slice)
# Numpy ndarray aren't hashable, so get rid of them.
if isinstance(data.start, numpy.ndarray):
assert data.start.ndim == 0
assert "int" in str(data.start.dtype)
data = slice(int(data.start), data.stop, data.step)
elif isinstance(data.stop, numpy.ndarray):
assert data.stop.ndim == 0
assert "int" in str(data.stop.dtype)
data = slice(data.start, int(data.stop), data.step)
elif isinstance(data.step, numpy.ndarray):
assert data.step.ndim == 0
assert "int" in str(data.step.dtype)
data = slice(data.start, int(data.stop), data.step)
Constant.__init__(self, type, data, name)
def signature(self):
return (SliceConstant, self.data.start, self.data.stop, self.data.step)
def __str__(self):
return "%s{%s, %s, %s}" % (self.__class__.__name__,
self.data.start,
self.data.stop,
self.data.step)
SliceType.Constant = SliceConstant
class NoneTypeT(Generic): class NoneTypeT(Generic):
""" """
Inherit from Generic to have c code working. Inherit from Generic to have c code working.
......
...@@ -600,6 +600,7 @@ class TensorVariable(_tensor_py_operators, Variable): ...@@ -600,6 +600,7 @@ class TensorVariable(_tensor_py_operators, Variable):
x = x[:-1] x = x[:-1]
nb_rm += 1 nb_rm += 1
rm = True rm = True
break
if not rm: if not rm:
break break
warnings.warn(msg, stacklevel=1 + nb_rm) warnings.warn(msg, stacklevel=1 + nb_rm)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论