提交 626104a8 authored 作者: Frédéric Bastien's avatar Frédéric Bastien

Merge pull request #2744 from mohammadpz/pep8

Pep8
...@@ -24,7 +24,7 @@ def floatX_convert(s): ...@@ -24,7 +24,7 @@ def floatX_convert(s):
AddConfigVar('floatX', AddConfigVar('floatX',
"Default floating-point precision for python casts", "Default floating-point precision for python casts",
EnumStr('float64', 'float32', convert=floatX_convert,), EnumStr('float64', 'float32', convert=floatX_convert,),
) )
AddConfigVar('warn_float64', AddConfigVar('warn_float64',
"Do an action when a tensor variable with float64 dtype is" "Do an action when a tensor variable with float64 dtype is"
...@@ -32,20 +32,20 @@ AddConfigVar('warn_float64', ...@@ -32,20 +32,20 @@ AddConfigVar('warn_float64',
" gpu back-end and are slow with gamer GPUs.", " gpu back-end and are slow with gamer GPUs.",
EnumStr('ignore', 'warn', 'raise', 'pdb'), EnumStr('ignore', 'warn', 'raise', 'pdb'),
in_c_key=False, in_c_key=False,
) )
AddConfigVar('cast_policy', AddConfigVar('cast_policy',
"Rules for implicit type casting", 'Rules for implicit type casting',
EnumStr('custom', 'numpy+floatX', EnumStr('custom', 'numpy+floatX',
# The 'numpy' policy was originally planned to provide a smooth # The 'numpy' policy was originally planned to provide a
# transition from numpy. It was meant to behave the same as # smooth transition from numpy. It was meant to behave the
# numpy+floatX, but keeping float64 when numpy would. However # same asnumpy+floatX, but keeping float64 when numpy
# the current implementation of some cast mechanisms makes it # would. However the current implementation of some cast
# a bit more complex to add than what was expected, so it is # mechanisms makes it a bit more complex to add than what
# currently not available. # was expected, so it is currently not available.
# numpy, # numpy,
), ),
) )
# python 2.* define int / int to return int and int // int to return int. # python 2.* define int / int to return int and int // int to return int.
# python 3* define int / int to return float and int // int to return int. # python 3* define int / int to return float and int // int to return int.
...@@ -53,10 +53,10 @@ AddConfigVar('cast_policy', ...@@ -53,10 +53,10 @@ AddConfigVar('cast_policy',
# than numpy. When we will do the transition, we should create an int_warn # than numpy. When we will do the transition, we should create an int_warn
# and floatX_warn option. # and floatX_warn option.
AddConfigVar('int_division', AddConfigVar('int_division',
"What to do when one computes x / y, where both x and y are of " "What to do when one computes x / y, where both x and y are of "
"integer types", "integer types",
EnumStr('int', 'raise', 'floatX'), EnumStr('int', 'raise', 'floatX'),
in_c_key=False) in_c_key=False)
# gpu means let the driver select the gpu. Needed in case of gpu in # gpu means let the driver select the gpu. Needed in case of gpu in
# exclusive mode. # exclusive mode.
...@@ -82,14 +82,14 @@ class DeviceParam(ConfigParam): ...@@ -82,14 +82,14 @@ class DeviceParam(ConfigParam):
def __str__(self): def __str__(self):
return '%s (cpu, gpu*, opencl*, cuda*) ' % (self.fullname,) return '%s (cpu, gpu*, opencl*, cuda*) ' % (self.fullname,)
AddConfigVar('device', AddConfigVar(
("Default device for computations. If gpu*, change the default to try " 'device',
"to move computation to it and to put shared variable of float32 " ("Default device for computations. If gpu*, change the default to try "
"on it. Do not use upper case letters, only lower case even if " "to move computation to it and to put shared variable of float32 "
"NVIDIA use capital letters."), "on it. Do not use upper case letters, only lower case even if "
DeviceParam('cpu', allow_override=False), "NVIDIA use capital letters."),
in_c_key=False, DeviceParam('cpu', allow_override=False),
) in_c_key=False,)
AddConfigVar('gpuarray.init_device', AddConfigVar('gpuarray.init_device',
""" """
...@@ -99,28 +99,31 @@ AddConfigVar('gpuarray.init_device', ...@@ -99,28 +99,31 @@ AddConfigVar('gpuarray.init_device',
StrParam(''), StrParam(''),
in_c_key=False) in_c_key=False)
AddConfigVar('init_gpu_device', AddConfigVar(
("Initialize the gpu device to use, works only if device=cpu. " 'init_gpu_device',
"Unlike 'device', setting this option will NOT move computations, " ("Initialize the gpu device to use, works only if device=cpu. "
"nor shared variables, to the specified GPU. " "Unlike 'device', setting this option will NOT move computations, "
"It can be used to run GPU-specific tests on a particular GPU."), "nor shared variables, to the specified GPU. "
EnumStr('', 'gpu', "It can be used to run GPU-specific tests on a particular GPU."),
EnumStr('', 'gpu',
'gpu0', 'gpu1', 'gpu2', 'gpu3', 'gpu0', 'gpu1', 'gpu2', 'gpu3',
'gpu4', 'gpu5', 'gpu6', 'gpu7', 'gpu4', 'gpu5', 'gpu6', 'gpu7',
'gpu8', 'gpu9', 'gpu10', 'gpu11', 'gpu8', 'gpu9', 'gpu10', 'gpu11',
'gpu12', 'gpu13', 'gpu14', 'gpu15', 'gpu12', 'gpu13', 'gpu14', 'gpu15',
allow_override=False), allow_override=False),
in_c_key=False) in_c_key=False)
AddConfigVar('force_device', AddConfigVar(
"Raise an error if we can't use the specified device", 'force_device',
BoolParam(False, allow_override=False), "Raise an error if we can't use the specified device",
in_c_key=False) BoolParam(False, allow_override=False),
in_c_key=False)
AddConfigVar('print_active_device', AddConfigVar(
"Print active device at when the GPU device is initialized.", 'print_active_device',
BoolParam(True, allow_override=False), "Print active device at when the GPU device is initialized.",
in_c_key=False) BoolParam(True, allow_override=False),
in_c_key=False)
# Do not add FAST_RUN_NOGC to this list (nor any other ALL CAPS shortcut). # Do not add FAST_RUN_NOGC to this list (nor any other ALL CAPS shortcut).
...@@ -129,11 +132,12 @@ AddConfigVar('print_active_device', ...@@ -129,11 +132,12 @@ AddConfigVar('print_active_device',
# scalable. # scalable.
# Also, please be careful not to modify the first item in the enum when adding # Also, please be careful not to modify the first item in the enum when adding
# new modes, since it is the default mode. # new modes, since it is the default mode.
AddConfigVar('mode', AddConfigVar(
"Default compilation mode", 'mode',
EnumStr('Mode', 'ProfileMode', 'DebugMode', 'FAST_RUN', "Default compilation mode",
'FAST_COMPILE', 'PROFILE_MODE', 'DEBUG_MODE'), EnumStr('Mode', 'ProfileMode', 'DebugMode', 'FAST_RUN',
in_c_key=False) 'FAST_COMPILE', 'PROFILE_MODE', 'DEBUG_MODE'),
in_c_key=False)
param = "g++" param = "g++"
...@@ -209,22 +213,24 @@ AddConfigVar('allow_gc', ...@@ -209,22 +213,24 @@ AddConfigVar('allow_gc',
in_c_key=False) in_c_key=False)
# Keep the default optimizer the same as the one for the mode FAST_RUN # Keep the default optimizer the same as the one for the mode FAST_RUN
AddConfigVar('optimizer', AddConfigVar(
("Default optimizer. If not None, will use this linker with the Mode " 'optimizer',
"object (not ProfileMode(deprecated) or DebugMode)"), ("Default optimizer. If not None, will use this linker with the Mode "
EnumStr('fast_run', 'merge', 'fast_compile', 'None'), "object (not ProfileMode(deprecated) or DebugMode)"),
in_c_key=False) EnumStr('fast_run', 'merge', 'fast_compile', 'None'),
in_c_key=False)
AddConfigVar('optimizer_verbose', AddConfigVar('optimizer_verbose',
"If True, we print all optimization being applied", "If True, we print all optimization being applied",
BoolParam(False), BoolParam(False),
in_c_key=False) in_c_key=False)
AddConfigVar('on_opt_error', AddConfigVar(
("What to do when an optimization crashes: warn and skip it, raise " 'on_opt_error',
"the exception, or fall into the pdb debugger."), ("What to do when an optimization crashes: warn and skip it, raise "
EnumStr('warn', 'raise', 'pdb'), "the exception, or fall into the pdb debugger."),
in_c_key=False) EnumStr('warn', 'raise', 'pdb'),
in_c_key=False)
def safe_no_home(home): def safe_no_home(home):
...@@ -239,23 +245,25 @@ def safe_no_home(home): ...@@ -239,23 +245,25 @@ def safe_no_home(home):
""" """
if home: if home:
raise RuntimeError( raise RuntimeError(
'The `config.home` option has been removed and should not be ' 'The `config.home` option has been removed and should not be '
'used anymore. Please set the `config.base_compiledir` option ' 'used anymore. Please set the `config.base_compiledir` option '
'instead (for instance to: %s)' % 'instead (for instance to: %s)' %
os.path.join(home, '.theano')) os.path.join(home, '.theano'))
return True return True
AddConfigVar('home', AddConfigVar(
"This config option was removed in 0.5: do not use it!", 'home',
ConfigParam('', allow_override=False, filter=safe_no_home), "This config option was removed in 0.5: do not use it!",
in_c_key=False) ConfigParam('', allow_override=False, filter=safe_no_home),
in_c_key=False)
AddConfigVar('nocleanup', AddConfigVar(
"Suppress the deletion of code files that did not compile cleanly", 'nocleanup',
BoolParam(False), "Suppress the deletion of code files that did not compile cleanly",
in_c_key=False) BoolParam(False),
in_c_key=False)
AddConfigVar('on_unused_input', AddConfigVar('on_unused_input',
"What to do if a variable in the 'inputs' list of " "What to do if a variable in the 'inputs' list of "
...@@ -267,40 +275,46 @@ AddConfigVar('on_unused_input', ...@@ -267,40 +275,46 @@ AddConfigVar('on_unused_input',
# So changing it after import will not modify these global variables. # So changing it after import will not modify these global variables.
# This could be done differently... but for now we simply prevent it from being # This could be done differently... but for now we simply prevent it from being
# changed at runtime. # changed at runtime.
AddConfigVar('tensor.cmp_sloppy', AddConfigVar(
"Relax tensor._allclose (0) not at all, (1) a bit, (2) more", 'tensor.cmp_sloppy',
IntParam(0, lambda i: i in (0, 1, 2), allow_override=False), "Relax tensor._allclose (0) not at all, (1) a bit, (2) more",
in_c_key=False) IntParam(0, lambda i: i in (0, 1, 2), allow_override=False),
in_c_key=False)
AddConfigVar('tensor.local_elemwise_fusion',
("Enable or not in fast_run mode(fast_run optimization) the elemwise " AddConfigVar(
"fusion optimization"), 'tensor.local_elemwise_fusion',
BoolParam(True), ("Enable or not in fast_run mode(fast_run optimization) the elemwise "
in_c_key=False) "fusion optimization"),
BoolParam(True),
AddConfigVar('gpu.local_elemwise_fusion', in_c_key=False)
("Enable or not in fast_run mode(fast_run optimization) the gpu "
"elemwise fusion optimization"), AddConfigVar(
BoolParam(True), 'gpu.local_elemwise_fusion',
in_c_key=False) ("Enable or not in fast_run mode(fast_run optimization) the gpu "
"elemwise fusion optimization"),
BoolParam(True),
in_c_key=False)
# http://developer.amd.com/CPU/LIBRARIES/LIBM/Pages/default.aspx # http://developer.amd.com/CPU/LIBRARIES/LIBM/Pages/default.aspx
AddConfigVar('lib.amdlibm', AddConfigVar(
"Use amd's amdlibm numerical library", 'lib.amdlibm',
BoolParam(False)) "Use amd's amdlibm numerical library",
BoolParam(False))
AddConfigVar('gpuelemwise.sync',
"when true, wait that the gpu fct finished and check it error code.", AddConfigVar(
BoolParam(True), 'gpuelemwise.sync',
in_c_key=False) "when true, wait that the gpu fct finished and check it error code.",
BoolParam(True),
AddConfigVar('traceback.limit', in_c_key=False)
"The number of stack to trace. -1 mean all.",
# We default to 6 to be able to know where v1 + v2 is created in the AddConfigVar(
# user script. The bigger this number is, the more run time it takes. 'traceback.limit',
# We need to default to 7 to support theano.tensor.tensor(...). "The number of stack to trace. -1 mean all.",
IntParam(7), # We default to 6 to be able to know where v1 + v2 is created in the
in_c_key=False) # user script. The bigger this number is, the more run time it takes.
# We need to default to 7 to support theano.tensor.tensor(...).
IntParam(7),
in_c_key=False)
AddConfigVar('experimental.mrg', AddConfigVar('experimental.mrg',
"Another random number generator that work on the gpu", "Another random number generator that work on the gpu",
...@@ -329,14 +343,14 @@ AddConfigVar('numpy.seterr_all', ...@@ -329,14 +343,14 @@ AddConfigVar('numpy.seterr_all',
"by the following flags: seterr_divide, seterr_over, " "by the following flags: seterr_divide, seterr_over, "
"seterr_under and seterr_invalid."), "seterr_under and seterr_invalid."),
EnumStr('ignore', 'warn', 'raise', 'call', 'print', 'log', 'None', EnumStr('ignore', 'warn', 'raise', 'call', 'print', 'log', 'None',
allow_override=False), allow_override=False),
in_c_key=False) in_c_key=False)
AddConfigVar('numpy.seterr_divide', AddConfigVar('numpy.seterr_divide',
("Sets numpy's behavior for division by zero, see numpy.seterr. " ("Sets numpy's behavior for division by zero, see numpy.seterr. "
"'None' means using the default, defined by numpy.seterr_all."), "'None' means using the default, defined by numpy.seterr_all."),
EnumStr('None', 'ignore', 'warn', 'raise', 'call', 'print', 'log', EnumStr('None', 'ignore', 'warn', 'raise', 'call', 'print', 'log',
allow_override=False), allow_override=False),
in_c_key=False) in_c_key=False)
AddConfigVar('numpy.seterr_over', AddConfigVar('numpy.seterr_over',
...@@ -344,7 +358,7 @@ AddConfigVar('numpy.seterr_over', ...@@ -344,7 +358,7 @@ AddConfigVar('numpy.seterr_over',
"see numpy.seterr. " "see numpy.seterr. "
"'None' means using the default, defined by numpy.seterr_all."), "'None' means using the default, defined by numpy.seterr_all."),
EnumStr('None', 'ignore', 'warn', 'raise', 'call', 'print', 'log', EnumStr('None', 'ignore', 'warn', 'raise', 'call', 'print', 'log',
allow_override=False), allow_override=False),
in_c_key=False) in_c_key=False)
AddConfigVar('numpy.seterr_under', AddConfigVar('numpy.seterr_under',
...@@ -352,7 +366,7 @@ AddConfigVar('numpy.seterr_under', ...@@ -352,7 +366,7 @@ AddConfigVar('numpy.seterr_under',
"see numpy.seterr. " "see numpy.seterr. "
"'None' means using the default, defined by numpy.seterr_all."), "'None' means using the default, defined by numpy.seterr_all."),
EnumStr('None', 'ignore', 'warn', 'raise', 'call', 'print', 'log', EnumStr('None', 'ignore', 'warn', 'raise', 'call', 'print', 'log',
allow_override=False), allow_override=False),
in_c_key=False) in_c_key=False)
AddConfigVar('numpy.seterr_invalid', AddConfigVar('numpy.seterr_invalid',
...@@ -360,7 +374,7 @@ AddConfigVar('numpy.seterr_invalid', ...@@ -360,7 +374,7 @@ AddConfigVar('numpy.seterr_invalid',
"see numpy.seterr. " "see numpy.seterr. "
"'None' means using the default, defined by numpy.seterr_all."), "'None' means using the default, defined by numpy.seterr_all."),
EnumStr('None', 'ignore', 'warn', 'raise', 'call', 'print', 'log', EnumStr('None', 'ignore', 'warn', 'raise', 'call', 'print', 'log',
allow_override=False), allow_override=False),
in_c_key=False) in_c_key=False)
### ###
...@@ -422,30 +436,33 @@ AddConfigVar('warn.sum_div_dimshuffle_bug', ...@@ -422,30 +436,33 @@ AddConfigVar('warn.sum_div_dimshuffle_bug',
BoolParam(warn_default('0.3')), BoolParam(warn_default('0.3')),
in_c_key=False) in_c_key=False)
AddConfigVar('warn.subtensor_merge_bug', AddConfigVar(
"Warn if previous versions of Theano (before 0.5rc2) could have given " 'warn.subtensor_merge_bug',
"incorrect results when indexing into a subtensor with negative " "Warn if previous versions of Theano (before 0.5rc2) could have given "
"stride (for instance, for instance, x[a:b:-1][c]).", "incorrect results when indexing into a subtensor with negative "
BoolParam(warn_default('0.5')), "stride (for instance, for instance, x[a:b:-1][c]).",
in_c_key=False) BoolParam(warn_default('0.5')),
in_c_key=False)
AddConfigVar('warn.gpu_set_subtensor1',
"Warn if previous versions of Theano (before 0.6) could have given " AddConfigVar(
"incorrect results when moving to the gpu " 'warn.gpu_set_subtensor1',
"set_subtensor(x[int vector], new_value)", "Warn if previous versions of Theano (before 0.6) could have given "
BoolParam(warn_default('0.6')), "incorrect results when moving to the gpu "
in_c_key=False) "set_subtensor(x[int vector], new_value)",
BoolParam(warn_default('0.6')),
AddConfigVar('warn.vm_gc_bug', in_c_key=False)
"There was a bug that existed in the default Theano configuration,"
" only in the development version between July 5th 2012" AddConfigVar(
" and July 30th 2012. This was not in a released version." 'warn.vm_gc_bug',
" If your code was affected by this bug, a warning" "There was a bug that existed in the default Theano configuration,"
" will be printed during the code execution if you use the" " only in the development version between July 5th 2012"
" `linker=vm,vm.lazy=True,warn.vm_gc_bug=True` Theano flags." " and July 30th 2012. This was not in a released version."
" This warning is disabled by default as the bug was not released.", " If your code was affected by this bug, a warning"
BoolParam(False), " will be printed during the code execution if you use the"
in_c_key=False) " `linker=vm,vm.lazy=True,warn.vm_gc_bug=True` Theano flags."
" This warning is disabled by default as the bug was not released.",
BoolParam(False),
in_c_key=False)
AddConfigVar('warn.signal_conv2d_interface', AddConfigVar('warn.signal_conv2d_interface',
("Warn we use the new signal.conv2d() when its interface" ("Warn we use the new signal.conv2d() when its interface"
...@@ -474,13 +491,14 @@ AddConfigVar('warn.inc_set_subtensor1', ...@@ -474,13 +491,14 @@ AddConfigVar('warn.inc_set_subtensor1',
BoolParam(warn_default('0.7')), BoolParam(warn_default('0.7')),
in_c_key=False) in_c_key=False)
AddConfigVar('compute_test_value', AddConfigVar(
("If 'True', Theano will run each op at graph build time, using " 'compute_test_value',
"Constants, SharedVariables and the tag 'test_value' as inputs " ("If 'True', Theano will run each op at graph build time, using "
"to the function. This helps the user track down problems in the " "Constants, SharedVariables and the tag 'test_value' as inputs "
"graph before it gets optimized."), "to the function. This helps the user track down problems in the "
EnumStr('off', 'ignore', 'warn', 'raise', 'pdb'), "graph before it gets optimized."),
in_c_key=False) EnumStr('off', 'ignore', 'warn', 'raise', 'pdb'),
in_c_key=False)
AddConfigVar('compute_test_value_opt', AddConfigVar('compute_test_value_opt',
...@@ -497,10 +515,11 @@ AddConfigVar('unpickle_function', ...@@ -497,10 +515,11 @@ AddConfigVar('unpickle_function',
BoolParam(True), BoolParam(True),
in_c_key=False) in_c_key=False)
AddConfigVar('reoptimize_unpickled_function', AddConfigVar(
"Re-optimize the graph when a theano function is unpickled from the disk.", 'reoptimize_unpickled_function',
BoolParam(True, allow_override=True), "Re-optimize the graph when a theano function is unpickled from the disk.",
in_c_key=False) BoolParam(True, allow_override=True),
in_c_key=False)
"""Note to developers: """Note to developers:
...@@ -509,17 +528,18 @@ AddConfigVar('reoptimize_unpickled_function', ...@@ -509,17 +528,18 @@ AddConfigVar('reoptimize_unpickled_function',
== 'high', you should include a call to printing.min_informative_str == 'high', you should include a call to printing.min_informative_str
on all important apply nodes. on all important apply nodes.
""" """
AddConfigVar('exception_verbosity', AddConfigVar(
"If 'low', the text of exceptions will generally refer " \ 'exception_verbosity',
+ "to apply nodes with short names such as " \ "If 'low', the text of exceptions will generally refer "
+ "Elemwise{add_no_inplace}. If 'high', some exceptions " \ "to apply nodes with short names such as "
+ "will also refer to apply nodes with long descriptions " \ "Elemwise{add_no_inplace}. If 'high', some exceptions "
+ """ like: "will also refer to apply nodes with long descriptions "
A. Elemwise{add_no_inplace} """ like:
B. log_likelihood_v_given_h A. Elemwise{add_no_inplace}
C. log_likelihood_h""", B. log_likelihood_v_given_h
EnumStr('low', 'high'), C. log_likelihood_h""",
in_c_key=False) EnumStr('low', 'high'),
in_c_key=False)
# Test if the env variable is set # Test if the env variable is set
var = os.getenv('OMP_NUM_THREADS', None) var = os.getenv('OMP_NUM_THREADS', None)
...@@ -560,7 +580,7 @@ AddConfigVar('openmp', ...@@ -560,7 +580,7 @@ AddConfigVar('openmp',
" If it is set to 1, we disable openmp in Theano by default.", " If it is set to 1, we disable openmp in Theano by default.",
BoolParam(default_openmp), BoolParam(default_openmp),
in_c_key=False, in_c_key=False,
) )
AddConfigVar('openmp_elemwise_minsize', AddConfigVar('openmp_elemwise_minsize',
"If OpenMP is enabled, this is the minimum size of vectors " "If OpenMP is enabled, this is the minimum size of vectors "
...@@ -568,19 +588,21 @@ AddConfigVar('openmp_elemwise_minsize', ...@@ -568,19 +588,21 @@ AddConfigVar('openmp_elemwise_minsize',
"in element wise ops.", "in element wise ops.",
IntParam(200000), IntParam(200000),
in_c_key=False, in_c_key=False,
) )
AddConfigVar('check_input', AddConfigVar(
"Specify if types should check their input in their C code. " 'check_input',
"It can be used to speed up compilation, reduce overhead " "Specify if types should check their input in their C code. "
"(particularly for scalars) and reduce the number of generated C " "It can be used to speed up compilation, reduce overhead "
"files.", "(particularly for scalars) and reduce the number of generated C "
BoolParam(True)) "files.",
BoolParam(True))
AddConfigVar('cache_optimizations',
"WARNING: work in progress, does not work yet. " AddConfigVar(
"Specify if the optimization cache should be used. This cache will " 'cache_optimizations',
"any optimized graph and its optimization. Actually slow downs a lot " "WARNING: work in progress, does not work yet. "
"the first optimization, and could possibly still contains some bugs. " "Specify if the optimization cache should be used. This cache will "
"Use at your own risks.", "any optimized graph and its optimization. Actually slow downs a lot "
BoolParam(False)) "the first optimization, and could possibly still contains some bugs. "
"Use at your own risks.",
BoolParam(False))
...@@ -44,9 +44,9 @@ def parse_config_string(config_string, issue_warnings=True): ...@@ -44,9 +44,9 @@ def parse_config_string(config_string, issue_warnings=True):
if len(kv_tuple) == 1: if len(kv_tuple) == 1:
if issue_warnings: if issue_warnings:
TheanoConfigWarning.warn( TheanoConfigWarning.warn(
("Config key '%s' has no value, ignoring it" ("Config key '%s' has no value, ignoring it"
% kv_tuple[0]), % kv_tuple[0]),
stacklevel=1) stacklevel=1)
else: else:
k, v = kv_tuple k, v = kv_tuple
# subsequent values for k will override earlier ones # subsequent values for k will override earlier ones
...@@ -77,7 +77,7 @@ theano_cfg = ConfigParser.SafeConfigParser( ...@@ -77,7 +77,7 @@ theano_cfg = ConfigParser.SafeConfigParser(
'TEMP': os.getenv("TEMP", ""), 'TEMP': os.getenv("TEMP", ""),
'TMP': os.getenv("TMP", ""), 'TMP': os.getenv("TMP", ""),
'PID': str(os.getpid()), 'PID': str(os.getpid()),
} }
) )
theano_cfg.read(config_files) theano_cfg.read(config_files)
# Having a raw version of the config around as well enables us to pass # Having a raw version of the config around as well enables us to pass
...@@ -145,7 +145,7 @@ def get_config_md5(): ...@@ -145,7 +145,7 @@ def get_config_md5():
all_opts = sorted([c for c in _config_var_list if c.in_c_key], all_opts = sorted([c for c in _config_var_list if c.in_c_key],
key=lambda cv: cv.fullname) key=lambda cv: cv.fullname)
return theano.gof.cc.hash_from_code('\n'.join( return theano.gof.cc.hash_from_code('\n'.join(
['%s = %s' % (cv.fullname, cv.__get__()) for cv in all_opts])) ['%s = %s' % (cv.fullname, cv.__get__()) for cv in all_opts]))
class TheanoConfigParser(object): class TheanoConfigParser(object):
...@@ -217,11 +217,11 @@ def AddConfigVar(name, doc, configparam, root=config, in_c_key=True): ...@@ -217,11 +217,11 @@ def AddConfigVar(name, doc, configparam, root=config, in_c_key=True):
_i_am_a_config_class = True _i_am_a_config_class = True
setattr(root.__class__, sections[0], SubObj()) setattr(root.__class__, sections[0], SubObj())
newroot = getattr(root, sections[0]) newroot = getattr(root, sections[0])
if (not getattr(newroot, '_i_am_a_config_class', False) if (not getattr(newroot, '_i_am_a_config_class', False) or
or isinstance(newroot, type)): isinstance(newroot, type)):
raise TypeError( raise TypeError(
'Internal config nodes must be config class instances', 'Internal config nodes must be config class instances',
newroot) newroot)
return AddConfigVar('.'.join(sections[1:]), doc, configparam, return AddConfigVar('.'.join(sections[1:]), doc, configparam,
root=newroot, in_c_key=in_c_key) root=newroot, in_c_key=in_c_key)
else: else:
...@@ -235,7 +235,8 @@ def AddConfigVar(name, doc, configparam, root=config, in_c_key=True): ...@@ -235,7 +235,8 @@ def AddConfigVar(name, doc, configparam, root=config, in_c_key=True):
if not callable(configparam.default): if not callable(configparam.default):
configparam.__get__() configparam.__get__()
else: else:
# We do not want to evaluate now the default value when it is a callable. # We do not want to evaluate now the default value
# when it is a callable.
try: try:
fetch_val_for_key(configparam.fullname) fetch_val_for_key(configparam.fullname)
# The user provided a value, filter it now. # The user provided a value, filter it now.
...@@ -282,8 +283,8 @@ class ConfigParam(object): ...@@ -282,8 +283,8 @@ class ConfigParam(object):
def __set__(self, cls, val): def __set__(self, cls, val):
if not self.allow_override and hasattr(self, 'val'): if not self.allow_override and hasattr(self, 'val'):
raise Exception( raise Exception(
"Can't change the value of this config parameter " "Can't change the value of this config parameter "
"after initialization!") "after initialization!")
# print "SETTING PARAM", self.fullname,(cls), val # print "SETTING PARAM", self.fullname,(cls), val
if self.filter: if self.filter:
self.val = self.filter(val) self.val = self.filter(val)
...@@ -300,7 +301,7 @@ class EnumStr(ConfigParam): ...@@ -300,7 +301,7 @@ class EnumStr(ConfigParam):
for val in self.all: for val in self.all:
if not isinstance(val, basestring): if not isinstance(val, basestring):
raise ValueError('Valid values for an EnumStr parameter ' raise ValueError('Valid values for an EnumStr parameter '
'should be strings', val, type(val)) 'should be strings', val, type(val))
convert = kwargs.get("convert", None) convert = kwargs.get("convert", None)
...@@ -332,13 +333,13 @@ class TypedParam(ConfigParam): ...@@ -332,13 +333,13 @@ class TypedParam(ConfigParam):
return cast_val return cast_val
else: else:
raise ValueError( raise ValueError(
'Invalid value (%s) for configuration variable ' 'Invalid value (%s) for configuration variable '
'"%s".' '"%s".'
% (val, self.fullname), val) % (val, self.fullname), val)
return cast_val return cast_val
super(TypedParam, self).__init__(default, filter, super(TypedParam, self).__init__(default, filter,
allow_override=allow_override) allow_override=allow_override)
def __str__(self): def __str__(self):
return '%s (%s) ' % (self.fullname, self.mytype) return '%s (%s) ' % (self.fullname, self.mytype)
...@@ -375,4 +376,4 @@ def BoolParam(default, is_valid=None, allow_override=True): ...@@ -375,4 +376,4 @@ def BoolParam(default, is_valid=None, allow_override=True):
is_valid = is_valid_bool is_valid = is_valid_bool
return TypedParam(default, booltype, is_valid, return TypedParam(default, booltype, is_valid,
allow_override=allow_override) allow_override=allow_override)
"""Driver for gradient calculations.""" """Driver for gradient calculations."""
__authors__ = "James Bergstra, Razvan Pascanu, Arnaud Bergeron, Ian Goodfellow"
__copyright__ = "(c) 2011, Universite de Montreal"
__license__ = "3-clause BSD License"
__contact__ = "theano-dev <theano-dev@googlegroups.com>"
__docformat__ = "restructuredtext en"
import __builtin__ import __builtin__
from itertools import izip from itertools import izip
import logging import logging
import time import time
import warnings import warnings
_logger = logging.getLogger('theano.gradient')
import numpy # for numeric_grad import numpy # for numeric_grad
np = numpy
import theano import theano
...@@ -26,6 +16,15 @@ from theano.gof.null_type import NullType, null_type ...@@ -26,6 +16,15 @@ from theano.gof.null_type import NullType, null_type
from theano.gof.op import get_debug_values from theano.gof.op import get_debug_values
from theano.compile import ViewOp from theano.compile import ViewOp
np = numpy
__authors__ = "James Bergstra, Razvan Pascanu, Arnaud Bergeron, Ian Goodfellow"
__copyright__ = "(c) 2011, Universite de Montreal"
__license__ = "3-clause BSD License"
__contact__ = "theano-dev <theano-dev@googlegroups.com>"
__docformat__ = "restructuredtext en"
_logger = logging.getLogger('theano.gradient')
# we can't do "import theano.tensor" # we can't do "import theano.tensor"
# tensor depends on theano.compile # tensor depends on theano.compile
# theano.compile depends on theano.gradient (this file) # theano.compile depends on theano.gradient (this file)
...@@ -86,7 +85,7 @@ def grad_not_implemented(op, x_pos, x, comment=""): ...@@ -86,7 +85,7 @@ def grad_not_implemented(op, x_pos, x, comment=""):
return (NullType(( return (NullType((
"This variable is Null because the grad method for " "This variable is Null because the grad method for "
"input %s (%s) of the %s op is not implemented. %s" "input %s (%s) of the %s op is not implemented. %s"
) % (x_pos, x, op, comment)))() ) % (x_pos, x, op, comment)))()
def grad_undefined(op, x_pos, x, comment=""): def grad_undefined(op, x_pos, x, comment=""):
...@@ -467,16 +466,17 @@ def grad(cost, wrt, consider_constant=None, ...@@ -467,16 +466,17 @@ def grad(cost, wrt, consider_constant=None,
g_cost = known_grads[cost] g_cost = known_grads[cost]
else: else:
g_cost = _float_ones_like(cost) g_cost = _float_ones_like(cost)
# g_cost may be Disconnected or NullType. A creative use of the function, # g_cost may be Disconnected or NullType. A creative use of the
# sure, but nonetheless one we can and should support. So before we try # function, sure, but nonetheless one we can and should support.
# to cast it make sure it even has a dtype # So before we try to cast it make sure it even has a dtype
if (hasattr(g_cost.type, 'dtype') and if (hasattr(g_cost.type, 'dtype') and
cost.type.dtype not in tensor.discrete_dtypes): cost.type.dtype not in tensor.discrete_dtypes):
# Here we enforce the constraint that floating point variables have # Here we enforce the constraint that floating point variables
# the same dtype as their gradient. # have the same dtype as their gradient.
g_cost = g_cost.astype(cost.type.dtype) g_cost = g_cost.astype(cost.type.dtype)
# DO NOT enforce g_cost to be 0 if cost is an integer. # DO NOT enforce g_cost to be 0 if cost is an integer.
# This is to be enforced by the Op.grad method for the Op that outputs cost. # This is to be enforced by the Op.grad method for the
# Op that outputs cost.
if hasattr(g_cost.type, 'dtype'): if hasattr(g_cost.type, 'dtype'):
assert g_cost.type.dtype not in tensor.discrete_dtypes assert g_cost.type.dtype not in tensor.discrete_dtypes
...@@ -491,10 +491,10 @@ def grad(cost, wrt, consider_constant=None, ...@@ -491,10 +491,10 @@ def grad(cost, wrt, consider_constant=None,
' or sparse theano variable' % str(type(g_var))) ' or sparse theano variable' % str(type(g_var)))
if (not isinstance(g_var.type, (NullType, DisconnectedType)) and if (not isinstance(g_var.type, (NullType, DisconnectedType)) and
'float' not in str(g_var.type.dtype)): 'float' not in str(g_var.type.dtype)):
raise TypeError("Gradients must always be NullType, " raise TypeError("Gradients must always be NullType, "
"DisconnectedType, or continuous, but grad was " "DisconnectedType, or continuous, but grad was "
"given a known_grad of type "+str(g_var.type)) "given a known_grad of type " + str(g_var.type))
# DO NOT check that these gradients are equal to 0 if var is int # DO NOT check that these gradients are equal to 0 if var is int
# The gradient is allowed to be non-zero on var in that case # The gradient is allowed to be non-zero on var in that case
...@@ -734,9 +734,9 @@ def _node_to_pattern(node): ...@@ -734,9 +734,9 @@ def _node_to_pattern(node):
if not isinstance(output_pattern, list): if not isinstance(output_pattern, list):
raise TypeError( raise TypeError(
'%s.connection_pattern should return' % '%s.connection_pattern should return' %
node.op + ' a list of lists, but element %d' % ii node.op + ' a list of lists, but element %d' % ii +
+ 'is %s of type %s.' % (output_pattern, 'is %s of type %s.' % (output_pattern,
type(output_pattern))) type(output_pattern)))
else: else:
connection_pattern = [[True for output in node.outputs] connection_pattern = [[True for output in node.outputs]
for ipt in node.inputs] for ipt in node.inputs]
...@@ -846,10 +846,10 @@ def _populate_var_to_app_to_idx(outputs, wrt, consider_constant): ...@@ -846,10 +846,10 @@ def _populate_var_to_app_to_idx(outputs, wrt, consider_constant):
if ipt not in var_to_app_to_idx: if ipt not in var_to_app_to_idx:
# This object here *must* be an OrderedDict, because # This object here *must* be an OrderedDict, because
# we iterate over its keys when adding up the terms of # we iterate over its keys when adding up the terms of the
# the gradient on ipt. If it is a regular dict, the grad # gradient on ipt. If it is a regular dict, the grad method
# method will return something that is analytically correct, # will return something that is analytically correct, but
# but whose order of doing additions depends on the memory # whose order of doing additions depends on the memory
# location of the apply nodes. # location of the apply nodes.
var_to_app_to_idx[ipt] = OrderedDict() var_to_app_to_idx[ipt] = OrderedDict()
app_to_idx = var_to_app_to_idx[ipt] app_to_idx = var_to_app_to_idx[ipt]
...@@ -923,8 +923,8 @@ def _populate_grad_dict(var_to_app_to_idx, ...@@ -923,8 +923,8 @@ def _populate_grad_dict(var_to_app_to_idx,
grad_dict: A dictionary mapping variables to their gradients. grad_dict: A dictionary mapping variables to their gradients.
Should be populated by grad function, which should: Should be populated by grad function, which should:
-Set the gradient with respect to the cost to 1 -Set the gradient with respect to the cost to 1
-Load all gradients from known_grads, possibly overriding -Load all gradients from known_grads, possibly
the cost overriding the cost
-Set the gradient for disconnected -Set the gradient for disconnected
inputs to a variable with type DisconnectedType() inputs to a variable with type DisconnectedType()
...@@ -1004,10 +1004,10 @@ def _populate_grad_dict(var_to_app_to_idx, ...@@ -1004,10 +1004,10 @@ def _populate_grad_dict(var_to_app_to_idx,
# call the op's grad method # call the op's grad method
# Each Op's grad function requires inputs and output_grads # Each Op's grad function requires inputs and output_grads
# If the Op destroys any input, but the grad expression uses it, # If the Op destroys any input, but the grad expression uses
# then chances are the resulting graph will have a dependency # it, then chances are the resulting graph will have a
# cycle. We avoid this cycle by passing (symbolic) copies of # dependency cycle. We avoid this cycle by passing (symbolic)
# each destroyed input. # copies of each destroyed input.
try: try:
dinputs = [node.inputs[x[0]] for x in dinputs = [node.inputs[x[0]] for x in
node.op.destroy_map.values()] node.op.destroy_map.values()]
...@@ -1030,15 +1030,16 @@ def _populate_grad_dict(var_to_app_to_idx, ...@@ -1030,15 +1030,16 @@ def _populate_grad_dict(var_to_app_to_idx,
# If an output is of an integer dtype, then we just leave it # If an output is of an integer dtype, then we just leave it
# alone. # alone.
# DO NOT force integer variables to have zero grad. This causes # DO NOT force integer variables to have zero grad. This causes
# bugs where we fail to detect disconnected or undefined gradients. # bugs where we fail to detect disconnected or undefined
# DO NOT force integer variables to have integer dtype. This is # gradients.
# a violation of the op contract. # DO NOT force integer variables to have integer dtype.
# This is a violation of the op contract.
new_output_grads = [] new_output_grads = []
for o, og in zip(node.outputs, output_grads): for o, og in zip(node.outputs, output_grads):
o_dt = getattr(o.type, 'dtype', None) o_dt = getattr(o.type, 'dtype', None)
og_dt = getattr(og.type, 'dtype', None) og_dt = getattr(og.type, 'dtype', None)
if (o_dt not in theano.tensor.discrete_dtypes and if (o_dt not in theano.tensor.discrete_dtypes and
og_dt and o_dt != og_dt): og_dt and o_dt != og_dt):
new_output_grads.append(og.astype(o_dt)) new_output_grads.append(og.astype(o_dt))
else: else:
new_output_grads.append(og) new_output_grads.append(og)
...@@ -1049,7 +1050,7 @@ def _populate_grad_dict(var_to_app_to_idx, ...@@ -1049,7 +1050,7 @@ def _populate_grad_dict(var_to_app_to_idx,
o_dt = getattr(o.type, 'dtype', None) o_dt = getattr(o.type, 'dtype', None)
ng_dt = getattr(ng.type, 'dtype', None) ng_dt = getattr(ng.type, 'dtype', None)
if (ng_dt is not None and if (ng_dt is not None and
o_dt not in theano.tensor.discrete_dtypes): o_dt not in theano.tensor.discrete_dtypes):
assert ng_dt == o_dt assert ng_dt == o_dt
# Someone who had obviously not read the Op contract tried # Someone who had obviously not read the Op contract tried
...@@ -1063,14 +1064,15 @@ def _populate_grad_dict(var_to_app_to_idx, ...@@ -1063,14 +1064,15 @@ def _populate_grad_dict(var_to_app_to_idx,
assert (getattr(ng.type, 'dtype', None) assert (getattr(ng.type, 'dtype', None)
not in theano.tensor.discrete_dtypes) not in theano.tensor.discrete_dtypes)
# If config.compute_test_value is turned on, check that the gradients # If config.compute_test_value is turned on, check that the
# on the outputs of this node have the right shape. # gradients on the outputs of this node have the right shape.
# We also check the gradient on the inputs later--both checks are needed, # We also check the gradient on the inputs later--both checks
# because some gradients are only ever specified by the user, not computed # are needed, because some gradients are only ever specified
# by Op.grad, and some gradients are only computed and returned, but never # by the user, not computed by Op.grad, and some gradients are
# passed as another node's output grads. # only computed and returned, but never passed as another
# node's output grads.
for idx, packed in enumerate(izip(node.outputs, for idx, packed in enumerate(izip(node.outputs,
new_output_grads)): new_output_grads)):
orig_output, new_output_grad = packed orig_output, new_output_grad = packed
if not hasattr(orig_output, 'shape'): if not hasattr(orig_output, 'shape'):
continue continue
...@@ -1098,14 +1100,14 @@ def _populate_grad_dict(var_to_app_to_idx, ...@@ -1098,14 +1100,14 @@ def _populate_grad_dict(var_to_app_to_idx,
# We can not enforce this, as AdvancedSubtensor1 has an option to # We can not enforce this, as AdvancedSubtensor1 has an option to
# return the sparse grad for optimization reason. # return the sparse grad for optimization reason.
# for ig, i in zip(input_grads, inputs): # for ig, i in zip(input_grads, inputs):
# if (not isinstance(ig.type, (DisconnectedType, NullType)) and # if (not isinstance(ig.type, (DisconnectedType, NullType)) and
# type(ig.type) != type(i.type)): # type(ig.type) != type(i.type)):
# raise ValueError( # raise ValueError(
# "%s returned the wrong type for gradient terms." # "%s returned the wrong type for gradient terms."
# " Sparse inputs must have sparse grads and dense" # " Sparse inputs must have sparse grads and dense"
# " inputs must have dense grad. Got %s, expected %s" % ( # " inputs must have dense grad. Got %s, expected %s" %(
# str(node.op), ig.type, i.type)) # str(node.op), ig.type, i.type))
# must convert to list in case the op returns a tuple # must convert to list in case the op returns a tuple
# we won't be able to post-process out the Nones if it does that # we won't be able to post-process out the Nones if it does that
...@@ -1138,7 +1140,8 @@ def _populate_grad_dict(var_to_app_to_idx, ...@@ -1138,7 +1140,8 @@ def _populate_grad_dict(var_to_app_to_idx,
'the grad_undefined or grad_unimplemented helper ' 'the grad_undefined or grad_unimplemented helper '
'functions.') % node.op) 'functions.') % node.op)
# Check that the gradient term for this input has the right shape # Check that the gradient term for this input
# has the right shape
if hasattr(term, 'shape'): if hasattr(term, 'shape'):
orig_ipt = inputs[i] orig_ipt = inputs[i]
for orig_ipt_v, term_v in get_debug_values(orig_ipt, term): for orig_ipt_v, term_v in get_debug_values(orig_ipt, term):
...@@ -1384,12 +1387,13 @@ class numeric_grad(object): ...@@ -1384,12 +1387,13 @@ class numeric_grad(object):
total_size = __builtin__.sum(prod(sh) for sh in shapes) total_size = __builtin__.sum(prod(sh) for sh in shapes)
working_dtype = __builtin__.min((self.type_eps[dt], dt) working_dtype = __builtin__.min(
for dt in dtypes)[1] (self.type_eps[dt], dt) for dt in dtypes)[1]
# create un-initialized memory # create un-initialized memory
x = numpy.ndarray((total_size,), dtype=working_dtype) x = numpy.ndarray((total_size,), dtype=working_dtype)
if (not out_type is None) and (out_type.startswith('complex')): # (not out_type is None) --> (out_type is not None) ???
if (out_type is not None) and (out_type.startswith('complex')):
gx = numpy.ndarray((total_size,), dtype=out_type) gx = numpy.ndarray((total_size,), dtype=out_type)
else: else:
gx = numpy.ndarray((total_size,), dtype=working_dtype) gx = numpy.ndarray((total_size,), dtype=working_dtype)
...@@ -1734,10 +1738,10 @@ def jacobian(expression, wrt, consider_constant=None, ...@@ -1734,10 +1738,10 @@ def jacobian(expression, wrt, consider_constant=None,
from theano.tensor import arange from theano.tensor import arange
# Check inputs have the right format # Check inputs have the right format
assert isinstance(expression, Variable), \ assert isinstance(expression, Variable), \
"tensor.jacobian expects a Variable as `expression`" "tensor.jacobian expects a Variable as `expression`"
assert expression.ndim < 2, \ assert expression.ndim < 2, \
("tensor.jacobian expects a 1 dimensional variable as " ("tensor.jacobian expects a 1 dimensional variable as "
"`expression`. If not use flatten to make it a vector") "`expression`. If not use flatten to make it a vector")
using_list = isinstance(wrt, list) using_list = isinstance(wrt, list)
using_tuple = isinstance(wrt, tuple) using_tuple = isinstance(wrt, tuple)
...@@ -1774,9 +1778,9 @@ def jacobian(expression, wrt, consider_constant=None, ...@@ -1774,9 +1778,9 @@ def jacobian(expression, wrt, consider_constant=None,
sequences=arange(expression.shape[0]), sequences=arange(expression.shape[0]),
non_sequences=[expression] + wrt) non_sequences=[expression] + wrt)
assert not updates, \ assert not updates, \
("Scan has returned a list of updates. This should not " ("Scan has returned a list of updates. This should not "
"happen! Report this to theano-users (also include the " "happen! Report this to theano-users (also include the "
"script that generated the error)") "script that generated the error)")
return format_as(using_list, using_tuple, jacobs) return format_as(using_list, using_tuple, jacobs)
...@@ -1808,9 +1812,9 @@ def hessian(cost, wrt, consider_constant=None, ...@@ -1808,9 +1812,9 @@ def hessian(cost, wrt, consider_constant=None,
from theano.tensor import arange from theano.tensor import arange
# Check inputs have the right format # Check inputs have the right format
assert isinstance(cost, Variable), \ assert isinstance(cost, Variable), \
"tensor.hessian expects a Variable as `cost`" "tensor.hessian expects a Variable as `cost`"
assert cost.ndim == 0, \ assert cost.ndim == 0, \
"tensor.hessian expects a 0 dimensional variable as `cost`" "tensor.hessian expects a 0 dimensional variable as `cost`"
using_list = isinstance(wrt, list) using_list = isinstance(wrt, list)
using_tuple = isinstance(wrt, tuple) using_tuple = isinstance(wrt, tuple)
...@@ -1823,10 +1827,10 @@ def hessian(cost, wrt, consider_constant=None, ...@@ -1823,10 +1827,10 @@ def hessian(cost, wrt, consider_constant=None,
hessians = [] hessians = []
for input in wrt: for input in wrt:
assert isinstance(input, Variable), \ assert isinstance(input, Variable), \
"tensor.hessian expects a (list of) Variable as `wrt`" "tensor.hessian expects a (list of) Variable as `wrt`"
assert input.ndim == 1, \ assert input.ndim == 1, \
"tensor.hessian expects a (list of) 1 dimensional variable "\ "tensor.hessian expects a (list of) 1 dimensional variable "\
"as `wrt`" "as `wrt`"
expr = grad(cost, input, consider_constant=consider_constant, expr = grad(cost, input, consider_constant=consider_constant,
disconnected_inputs=disconnected_inputs) disconnected_inputs=disconnected_inputs)
...@@ -1834,16 +1838,16 @@ def hessian(cost, wrt, consider_constant=None, ...@@ -1834,16 +1838,16 @@ def hessian(cost, wrt, consider_constant=None,
# even if they are connected to cost. # even if they are connected to cost.
# This should not be an error. # This should not be an error.
hess, updates = theano.scan(lambda i, y, x: grad( hess, updates = theano.scan(lambda i, y, x: grad(
y[i], y[i],
x, x,
consider_constant=consider_constant, consider_constant=consider_constant,
disconnected_inputs='ignore'), disconnected_inputs='ignore'),
sequences=arange(expr.shape[0]), sequences=arange(expr.shape[0]),
non_sequences=[expr, input]) non_sequences=[expr, input])
assert not updates, \ assert not updates, \
("Scan has returned a list of updates. This should not " ("Scan has returned a list of updates. This should not "
"happen! Report this to theano-users (also include the " "happen! Report this to theano-users (also include the "
"script that generated the error)") "script that generated the error)")
hessians.append(hess) hessians.append(hess)
return format_as(using_list, using_tuple, hessians) return format_as(using_list, using_tuple, hessians)
...@@ -1974,6 +1978,7 @@ def disconnected_grad(x): ...@@ -1974,6 +1978,7 @@ def disconnected_grad(x):
class GradClip(ViewOp): class GradClip(ViewOp):
# See doc in user fct grad_clip # See doc in user fct grad_clip
__props__ = () __props__ = ()
def __init__(self, clip_lower_bound, clip_upper_bound): def __init__(self, clip_lower_bound, clip_upper_bound):
# We do not put those member in __eq__ or __hash__ # We do not put those member in __eq__ or __hash__
# as they do not influence the perform of this op. # as they do not influence the perform of this op.
...@@ -1996,7 +2001,7 @@ def grad_clip(x, lower_bound, upper_bound): ...@@ -1996,7 +2001,7 @@ def grad_clip(x, lower_bound, upper_bound):
:param x: the variable we want its gradient inputs clipped :param x: the variable we want its gradient inputs clipped
:param lower_bound: The lower bound of the gradient value :param lower_bound: The lower bound of the gradient value
:param upper_bound: The upper bound of the gradient value. :param upper_bound: The upper bound of the gradient value.
:examples: :examples:
x = theano.tensor.scalar() x = theano.tensor.scalar()
......
...@@ -10,15 +10,6 @@ which value to report. Note also that `switch` is an elemwise operation (so ...@@ -10,15 +10,6 @@ which value to report. Note also that `switch` is an elemwise operation (so
it picks each entry of a matrix according to the condition) while `ifelse` it picks each entry of a matrix according to the condition) while `ifelse`
is a global operation with a scalar condition. is a global operation with a scalar condition.
""" """
__docformat__ = 'restructedtext en'
__authors__ = ("Razvan Pascanu "
"James Bergstra "
"Dumitru Erhan "
"David Warde-Farley")
__copyright__ = "(c) 2010, Universite de Montreal"
__contact__ = "Razvan Pascanu <r.pascanu@gmail>"
from copy import deepcopy from copy import deepcopy
from itertools import izip from itertools import izip
import logging import logging
...@@ -34,6 +25,15 @@ from theano.tensor import opt ...@@ -34,6 +25,15 @@ from theano.tensor import opt
from theano.scan_module.scan_utils import find_up from theano.scan_module.scan_utils import find_up
from theano.scan_module.scan_utils import clone from theano.scan_module.scan_utils import clone
__docformat__ = 'restructedtext en'
__authors__ = ("Razvan Pascanu "
"James Bergstra "
"Dumitru Erhan "
"David Warde-Farley")
__copyright__ = "(c) 2010, Universite de Montreal"
__contact__ = "Razvan Pascanu <r.pascanu@gmail>"
_logger = logging.getLogger('theano.ifelse') _logger = logging.getLogger('theano.ifelse')
...@@ -142,8 +142,8 @@ class IfElse(PureOp): ...@@ -142,8 +142,8 @@ class IfElse(PureOp):
gpu=False, gpu=False,
name='_'.join(name_tokens)) name='_'.join(name_tokens))
new_outs = new_ifelse(node.inputs[0], new_outs = new_ifelse(node.inputs[0],
*(new_ts_inputs + new_fs_inputs), *(new_ts_inputs + new_fs_inputs),
**dict(return_list=True)) **dict(return_list=True))
else: else:
new_outs = [] new_outs = []
...@@ -160,8 +160,8 @@ class IfElse(PureOp): ...@@ -160,8 +160,8 @@ class IfElse(PureOp):
def make_node(self, c, *args): def make_node(self, c, *args):
assert len(args) == 2 * self.n_outs, ( assert len(args) == 2 * self.n_outs, (
"Wrong number of arguments to make_node: " "Wrong number of arguments to make_node: "
"expected %d, got %d" % (2 * self.n_outs, len(args)) "expected %d, got %d" % (2 * self.n_outs, len(args))
) )
if not self.gpu: if not self.gpu:
# When gpu is true, we are given only cuda ndarrays, and we want # When gpu is true, we are given only cuda ndarrays, and we want
...@@ -328,35 +328,35 @@ def ifelse(condition, then_branch, else_branch, name=None): ...@@ -328,35 +328,35 @@ def ifelse(condition, then_branch, else_branch, name=None):
for then_branch_elem, else_branch_elem in izip(then_branch, else_branch): for then_branch_elem, else_branch_elem in izip(then_branch, else_branch):
if not isinstance(then_branch_elem, theano.Variable): if not isinstance(then_branch_elem, theano.Variable):
then_branch_elem = theano.tensor.as_tensor_variable( then_branch_elem = theano.tensor.as_tensor_variable(
then_branch_elem) then_branch_elem)
if not isinstance(else_branch_elem, theano.Variable): if not isinstance(else_branch_elem, theano.Variable):
else_branch_elem = theano.tensor.as_tensor_variable( else_branch_elem = theano.tensor.as_tensor_variable(
else_branch_elem) else_branch_elem)
if then_branch_elem.type != else_branch_elem.type: if then_branch_elem.type != else_branch_elem.type:
# If one of them is a TensorType, and the other one can be # If one of them is a TensorType, and the other one can be
# converted into one, then we try to do that. # converted into one, then we try to do that.
# This case happens when one of the elements has a GPU type, # This case happens when one of the elements has a GPU type,
# for instance a shared variable that was silently moved to GPU. # for instance a shared variable that was silently moved to GPU.
if (isinstance(then_branch_elem.type, TensorType) if (isinstance(then_branch_elem.type, TensorType) and not
and not isinstance(else_branch_elem.type, TensorType)): isinstance(else_branch_elem.type, TensorType)):
else_branch_elem = then_branch_elem.type.filter_variable( else_branch_elem = then_branch_elem.type.filter_variable(
else_branch_elem) else_branch_elem)
elif (isinstance(else_branch_elem.type, TensorType) elif (isinstance(else_branch_elem.type, TensorType) and not
and not isinstance(then_branch_elem.type, TensorType)): isinstance(then_branch_elem.type, TensorType)):
then_branch_elem = else_branch_elem.type.filter_variable( then_branch_elem = else_branch_elem.type.filter_variable(
then_branch_elem) then_branch_elem)
if then_branch_elem.type != else_branch_elem.type: if then_branch_elem.type != else_branch_elem.type:
# If the types still don't match, there is a problem. # If the types still don't match, there is a problem.
raise TypeError( raise TypeError(
'The two branches should have identical types, but ' 'The two branches should have identical types, but '
'they are %s and %s respectively. This error could be ' 'they are %s and %s respectively. This error could be '
'raised if for example you provided a one element ' 'raised if for example you provided a one element '
'list on the `then` branch but a tensor on the `else` ' 'list on the `then` branch but a tensor on the `else` '
'branch.' % 'branch.' %
(then_branch_elem.type, else_branch_elem.type)) (then_branch_elem.type, else_branch_elem.type))
new_then_branch.append(then_branch_elem) new_then_branch.append(then_branch_elem)
new_else_branch.append(else_branch_elem) new_else_branch.append(else_branch_elem)
...@@ -396,7 +396,7 @@ def cond_make_inplace(node): ...@@ -396,7 +396,7 @@ def cond_make_inplace(node):
optdb.register('cond_make_inplace', opt.in2out(cond_make_inplace, optdb.register('cond_make_inplace', opt.in2out(cond_make_inplace,
ignore_newtrees=True), 95, 'fast_run', 'inplace') ignore_newtrees=True), 95, 'fast_run', 'inplace')
# XXX: Optimizations commented pending further debugging (certain optimizations # XXX: Optimizations commented pending further debugging (certain optimizations
# make computation less lazy than it should be currently). # make computation less lazy than it should be currently).
...@@ -460,7 +460,7 @@ def ifelse_lift_single_if_through_acceptable_ops(main_node): ...@@ -460,7 +460,7 @@ def ifelse_lift_single_if_through_acceptable_ops(main_node):
for inp in main_node.inputs: for inp in main_node.inputs:
all_inp_nodes.add(inp.owner) all_inp_nodes.add(inp.owner)
ifnodes = [x for x in list(all_inp_nodes) ifnodes = [x for x in list(all_inp_nodes)
if x and isinstance(x.op, IfElse)] if x and isinstance(x.op, IfElse)]
# if we have multiple ifs as inputs .. it all becomes quite complicated # if we have multiple ifs as inputs .. it all becomes quite complicated
# :) # :)
if len(ifnodes) != 1: if len(ifnodes) != 1:
...@@ -471,7 +471,7 @@ def ifelse_lift_single_if_through_acceptable_ops(main_node): ...@@ -471,7 +471,7 @@ def ifelse_lift_single_if_through_acceptable_ops(main_node):
ts = node.inputs[1:][:op.n_outs] ts = node.inputs[1:][:op.n_outs]
fs = node.inputs[1:][op.n_outs:] fs = node.inputs[1:][op.n_outs:]
outs = main_node.outputs # outs = main_node.outputs
mop = main_node.op mop = main_node.op
true_ins = [] true_ins = []
false_ins = [] false_ins = []
...@@ -486,8 +486,8 @@ def ifelse_lift_single_if_through_acceptable_ops(main_node): ...@@ -486,8 +486,8 @@ def ifelse_lift_single_if_through_acceptable_ops(main_node):
false_ins.append(x) false_ins.append(x)
true_eval = mop(*true_ins, **dict(return_list=True)) true_eval = mop(*true_ins, **dict(return_list=True))
false_eval = mop(*false_ins, **dict(return_list=True)) false_eval = mop(*false_ins, **dict(return_list=True))
#true_eval = clone(outs, replace = dict(zip(node.outputs, ts))) # true_eval = clone(outs, replace = dict(zip(node.outputs, ts)))
#false_eval = clone(outs, replace = dict(zip(node.outputs, fs))) # false_eval = clone(outs, replace = dict(zip(node.outputs, fs)))
nw_outs = ifelse(node.inputs[0], true_eval, false_eval, return_list=True) nw_outs = ifelse(node.inputs[0], true_eval, false_eval, return_list=True)
return nw_outs return nw_outs
...@@ -503,10 +503,10 @@ def cond_merge_ifs_true(node): ...@@ -503,10 +503,10 @@ def cond_merge_ifs_true(node):
replace = {} replace = {}
for idx, tval in enumerate(t_ins): for idx, tval in enumerate(t_ins):
if (tval.owner and isinstance(tval.owner.op, IfElse) and if (tval.owner and isinstance(tval.owner.op, IfElse) and
tval.owner.inputs[0] == node.inputs[0]): tval.owner.inputs[0] == node.inputs[0]):
ins_op = tval.owner.op ins_op = tval.owner.op
ins_t = tval.owner.inputs[1:][:ins_op.n_outs] ins_t = tval.owner.inputs[1:][:ins_op.n_outs]
replace[idx + 1] = ins_t[tval.owner.outputs.index(tval)] replace[idx + 1] = ins_t[tval.owner.outputs.index(tval)]
if len(replace.items()) == 0: if len(replace.items()) == 0:
return False return False
...@@ -527,10 +527,10 @@ def cond_merge_ifs_false(node): ...@@ -527,10 +527,10 @@ def cond_merge_ifs_false(node):
replace = {} replace = {}
for idx, fval in enumerate(f_ins): for idx, fval in enumerate(f_ins):
if (fval.owner and isinstance(fval.owner.op, IfElse) and if (fval.owner and isinstance(fval.owner.op, IfElse) and
fval.owner.inputs[0] == node.inputs[0]): fval.owner.inputs[0] == node.inputs[0]):
ins_op = fval.owner.op ins_op = fval.owner.op
ins_t = fval.owner.inputs[1:][ins_op.n_outs:] ins_t = fval.owner.inputs[1:][ins_op.n_outs:]
replace[idx + 1 + op.n_outs] = \ replace[idx + 1 + op.n_outs] = \
ins_t[fval.owner.outputs.index(fval)] ins_t[fval.owner.outputs.index(fval)]
if len(replace.items()) == 0: if len(replace.items()) == 0:
...@@ -555,7 +555,7 @@ class CondMerge(gof.Optimizer): ...@@ -555,7 +555,7 @@ class CondMerge(gof.Optimizer):
merging_node = cond_nodes[0] merging_node = cond_nodes[0]
for proposal in cond_nodes[1:]: for proposal in cond_nodes[1:]:
if (proposal.inputs[0] == merging_node.inputs[0] and if (proposal.inputs[0] == merging_node.inputs[0] and
not find_up(proposal, merging_node)): not find_up(proposal, merging_node)):
# Create a list of replacements for proposal # Create a list of replacements for proposal
mn_ts = merging_node.inputs[1:][:merging_node.op.n_outs] mn_ts = merging_node.inputs[1:][:merging_node.op.n_outs]
mn_fs = merging_node.inputs[1:][merging_node.op.n_outs:] mn_fs = merging_node.inputs[1:][merging_node.op.n_outs:]
...@@ -567,8 +567,8 @@ class CondMerge(gof.Optimizer): ...@@ -567,8 +567,8 @@ class CondMerge(gof.Optimizer):
if merging_node.op.name: if merging_node.op.name:
mn_name = merging_node.op.name mn_name = merging_node.op.name
pl_name = '?' pl_name = '?'
mn_n_ts = len(mn_ts) # mn_n_ts = len(mn_ts)
mn_n_fs = len(mn_fs) # mn_n_fs = len(mn_fs)
if proposal.op.name: if proposal.op.name:
pl_name = proposal.op.name pl_name = proposal.op.name
new_ifelse = IfElse( new_ifelse = IfElse(
...@@ -607,8 +607,8 @@ def cond_remove_identical(node): ...@@ -607,8 +607,8 @@ def cond_remove_identical(node):
if idx not in out_map: if idx not in out_map:
for jdx in xrange(idx + 1, len(node.outputs)): for jdx in xrange(idx + 1, len(node.outputs)):
if (ts[idx] == ts[jdx] and if (ts[idx] == ts[jdx] and
fs[idx] == fs[jdx] and fs[idx] == fs[jdx] and
jdx not in out_map): jdx not in out_map):
out_map[jdx] = idx out_map[jdx] = idx
if len(out_map.keys()) == 0: if len(out_map.keys()) == 0:
...@@ -652,7 +652,7 @@ def cond_merge_random_op(main_node): ...@@ -652,7 +652,7 @@ def cond_merge_random_op(main_node):
for inp in main_node.inputs: for inp in main_node.inputs:
all_inp_nodes.add(inp.owner) all_inp_nodes.add(inp.owner)
cond_nodes = [x for x in list(all_inp_nodes) cond_nodes = [x for x in list(all_inp_nodes)
if x and isinstance(x.op, IfElse)] if x and isinstance(x.op, IfElse)]
if len(cond_nodes) < 2: if len(cond_nodes) < 2:
return False return False
...@@ -660,8 +660,8 @@ def cond_merge_random_op(main_node): ...@@ -660,8 +660,8 @@ def cond_merge_random_op(main_node):
merging_node = cond_nodes[0] merging_node = cond_nodes[0]
for proposal in cond_nodes[1:]: for proposal in cond_nodes[1:]:
if (proposal.inputs[0] == merging_node.inputs[0] and if (proposal.inputs[0] == merging_node.inputs[0] and
not find_up(proposal, merging_node) and not find_up(proposal, merging_node) and
not find_up(merging_node, proposal)): not find_up(merging_node, proposal)):
# Create a list of replacements for proposal # Create a list of replacements for proposal
mn_ts = merging_node.inputs[1:][:merging_node.op.n_outs] mn_ts = merging_node.inputs[1:][:merging_node.op.n_outs]
mn_fs = merging_node.inputs[1:][merging_node.op.n_outs:] mn_fs = merging_node.inputs[1:][merging_node.op.n_outs:]
...@@ -673,8 +673,8 @@ def cond_merge_random_op(main_node): ...@@ -673,8 +673,8 @@ def cond_merge_random_op(main_node):
if merging_node.op.name: if merging_node.op.name:
mn_name = merging_node.op.name mn_name = merging_node.op.name
pl_name = '?' pl_name = '?'
mn_n_ts = len(mn_ts) # mn_n_ts = len(mn_ts)
mn_n_fs = len(mn_fs) # mn_n_fs = len(mn_fs)
if proposal.op.name: if proposal.op.name:
pl_name = proposal.op.name pl_name = proposal.op.name
new_ifelse = IfElse( new_ifelse = IfElse(
......
...@@ -17,13 +17,8 @@ except ImportError: ...@@ -17,13 +17,8 @@ except ImportError:
flake8_available = False flake8_available = False
whitelist_flake8 = [ whitelist_flake8 = [
"updates.py",
"__init__.py", "__init__.py",
"configparser.py",
"ifelse.py",
"version.py", "version.py",
"configdefaults.py",
"gradient.py",
"compat/python2x.py", "compat/python2x.py",
"compat/six.py", "compat/six.py",
"compat/__init__.py", "compat/__init__.py",
......
"""Defines Updates object for storing a (SharedVariable, new_value) mapping. """Defines Updates object for storing a (SharedVariable, new_value) mapping.
""" """
from theano.compat.python2x import OrderedDict
from theano.compile.sharedvalue import SharedVariable
import logging
import warnings
__authors__ = "theano-dev" __authors__ = "theano-dev"
__copyright__ = "(c) 2010, Universite de Montreal" __copyright__ = "(c) 2010, Universite de Montreal"
__license__ = "3-clause BSD License" __license__ = "3-clause BSD License"
...@@ -8,12 +15,7 @@ __contact__ = "theano-dev <theano-dev@googlegroups.com>" ...@@ -8,12 +15,7 @@ __contact__ = "theano-dev <theano-dev@googlegroups.com>"
__docformat__ = "restructuredtext en" __docformat__ = "restructuredtext en"
from theano.compat.python2x import OrderedDict
from theano.compile.sharedvalue import SharedVariable
import logging
logger = logging.getLogger('theano.updates') logger = logging.getLogger('theano.updates')
import warnings
# Must be an OrderedDict or updates will be applied in a non-deterministic # Must be an OrderedDict or updates will be applied in a non-deterministic
...@@ -26,9 +28,9 @@ class OrderedUpdates(OrderedDict): ...@@ -26,9 +28,9 @@ class OrderedUpdates(OrderedDict):
""" """
def __init__(self, *key, **kwargs): def __init__(self, *key, **kwargs):
if (len(key) >= 1 and if (len(key) >= 1 and
isinstance(key[0], dict) and isinstance(key[0], dict) and
len(key[0]) > 1 and len(key[0]) > 1 and
not isinstance(key[0], OrderedDict)): not isinstance(key[0], OrderedDict)):
# Warn when using as input a non-ordered dictionary. # Warn when using as input a non-ordered dictionary.
warnings.warn('Initializing an `OrderedUpdates` from a ' warnings.warn('Initializing an `OrderedUpdates` from a '
'non-ordered dictionary with 2+ elements could ' 'non-ordered dictionary with 2+ elements could '
...@@ -62,8 +64,8 @@ class OrderedUpdates(OrderedDict): ...@@ -62,8 +64,8 @@ class OrderedUpdates(OrderedDict):
if other is None: if other is None:
return return
if (isinstance(other, dict) and if (isinstance(other, dict) and
len(other) > 1 and len(other) > 1 and
not isinstance(other, OrderedDict)): not isinstance(other, OrderedDict)):
# Warn about non-determinism. # Warn about non-determinism.
warnings.warn('Updating an `OrderedUpdates` with a ' warnings.warn('Updating an `OrderedUpdates` with a '
'non-ordered dictionary with 2+ elements could ' 'non-ordered dictionary with 2+ elements could '
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论