提交 6ef6b985 authored 作者: Pascal Lamblin's avatar Pascal Lamblin

Merge pull request #2989 from lamblin/fix_scan_mode

[MRG] Fix for using MonitorMode with scan
...@@ -2646,4 +2646,5 @@ class DebugMode(Mode): ...@@ -2646,4 +2646,5 @@ class DebugMode(Mode):
return "DebugMode(linker=%s, optimizer=%s)" % ( return "DebugMode(linker=%s, optimizer=%s)" % (
self.provided_linker, self.provided_optimizer) self.provided_linker, self.provided_optimizer)
register_mode('DEBUG_MODE', DebugMode(optimizer='fast_run')) register_mode('DEBUG_MODE', DebugMode(optimizer='fast_run'))
...@@ -254,7 +254,7 @@ class Mode(object): ...@@ -254,7 +254,7 @@ class Mode(object):
linker = config.linker linker = config.linker
if optimizer is 'default': if optimizer is 'default':
optimizer = config.optimizer optimizer = config.optimizer
self.__setstate__((linker, optimizer)) Mode.__setstate__(self, (linker, optimizer))
# self.provided_optimizer - typically the `optimizer` arg. # self.provided_optimizer - typically the `optimizer` arg.
# But if the `optimizer` arg is keyword corresponding to a predefined # But if the `optimizer` arg is keyword corresponding to a predefined
...@@ -321,6 +321,21 @@ class Mode(object): ...@@ -321,6 +321,21 @@ class Mode(object):
self.provided_optimizer) self.provided_optimizer)
return self.__class__(linker=link, optimizer=opt.requiring(*tags)) return self.__class__(linker=link, optimizer=opt.requiring(*tags))
def clone(self, link_kwargs=None, **kwargs):
"""
Create a new instance of this Mode.
Keyword arguments can be provided for the linker,
in which case its `clone` method will be called with these
arguments.
"""
new_linker = self.linker.clone(**link_kwargs)
new_optimizer = self.provided_optimizer
new_mode = type(self)(linker=new_linker,
optimizer=new_optimizer)
return new_mode
# If a string is passed as the mode argument in function or # If a string is passed as the mode argument in function or
# FunctionMaker, the Mode will be taken from this dictionary using the # FunctionMaker, the Mode will be taken from this dictionary using the
# string as the key # string as the key
......
...@@ -54,6 +54,16 @@ class MonitorMode(Mode): ...@@ -54,6 +54,16 @@ class MonitorMode(Mode):
super(MonitorMode, self).__init__(wrap_linker, optimizer=optimizer) super(MonitorMode, self).__init__(wrap_linker, optimizer=optimizer)
def __getstate__(self):
lnk, opt = super(MonitorMode, self).__getstate__()
return (lnk, opt, self.pre_func, self.post_func)
def __setstate__(self, state):
lnk, opt, pre_func, post_func = state
self.pre_func = pre_func
self.post_func = post_func
super(MonitorMode, self).__setstate__((lnk, opt))
def eval(self, i, node, fn): def eval(self, i, node, fn):
""" """
The method that calls the thunk `fn`. The method that calls the thunk `fn`.
...@@ -82,10 +92,24 @@ class MonitorMode(Mode): ...@@ -82,10 +92,24 @@ class MonitorMode(Mode):
ret.post_func = self.post_func ret.post_func = self.post_func
return ret return ret
def clone(self, link_kwargs=None, **kwargs):
"""
Create a new instance of this Mode.
Keyword arguments can be provided for the linker,
but they will be ignored, because ProfileMode needs
to use its own linker.
"""
new_mode = type(self)(pre_func=self.pre_func,
post_func=self.post_func,
linker=None,
optimizer=self.provided_optimizer)
return new_mode
def detect_nan(i, node, fn): def detect_nan(i, node, fn):
for output in fn.outputs: for output in fn.outputs:
if (not isinstance(numpy.random.RandomState, output[0]) and if (not isinstance(output[0], numpy.random.RandomState) and
numpy.isnan(output[0]).any()): numpy.isnan(output[0]).any()):
print('*** NaN detected ***') print('*** NaN detected ***')
theano.printing.debugprint(node) theano.printing.debugprint(node)
......
...@@ -696,6 +696,29 @@ Test them first, as they are not guaranteed to always provide a speedup.""") ...@@ -696,6 +696,29 @@ Test them first, as they are not guaranteed to always provide a speedup.""")
if not printed_tip: if not printed_tip:
print(" Sorry, no tip for today.") print(" Sorry, no tip for today.")
def clone(self, link_kwargs=None, message=None):
"""
Create a new instance of this Mode.
Keyword arguments can be provided for the linker,
in which case its `clone` method will be called with these
arguments.
"""
new_linker = self.linker.clone(**link_kwargs)
new_optimizer = self.provided_optimizer
new_mode = type(self)(linker=new_linker,
optimizer=new_optimizer)
# If self is in the list or profiles to print, then add the
# new one as well
if self in prof_mode_instance_to_print:
prof_mode_instance_to_print.append(new_mode)
if message:
new_mode.message = message
return new_mode
register_mode('PROFILE_MODE', ProfileMode()) register_mode('PROFILE_MODE', ProfileMode())
......
...@@ -173,25 +173,16 @@ class Scan(PureOp): ...@@ -173,25 +173,16 @@ class Scan(PureOp):
self.output_types = self.output_types[:-1] self.output_types = self.output_types[:-1]
mode_instance = compile.mode.get_mode(self.mode) mode_instance = compile.mode.get_mode(self.mode)
# if the default mode is used, and that mode is ProfileMode # Clone mode_instance, altering "allow_gc" for the linker,
# then we need to copy the mode otherwise the time for a given # and adding a message if the mode is a ProfileMode.
# op will be counted multiple times
if (self.mode is None and
isinstance(mode_instance, compile.profilemode.ProfileMode)):
mode_instance = compile.profilemode.ProfileMode(
optimizer=mode_instance.provided_optimizer,
linker=mode_instance.linker.clone(allow_gc=self.allow_gc))
compile.profilemode.prof_mode_instance_to_print.append(
mode_instance)
self.mode_instance = mode_instance
if self.name: if self.name:
self.mode_instance.message = self.name + " sub profile" message = self.name + " sub profile"
else: else:
self.mode_instance.message = "Scan sub profile" message = "Scan sub profile"
else:
self.mode_instance = type(mode_instance)( self.mode_instance = mode_instance.clone(
optimizer=mode_instance.provided_optimizer, link_kwargs=dict(allow_gc=self.allow_gc),
linker=mode_instance.linker.clone(allow_gc=self.allow_gc)) message=message)
# Now that scan has its mode instance, if memory pre-allocation is # Now that scan has its mode instance, if memory pre-allocation is
# activated for the outputs, we activate the optimization # activated for the outputs, we activate the optimization
......
...@@ -4194,6 +4194,40 @@ class T_Scan(unittest.TestCase): ...@@ -4194,6 +4194,40 @@ class T_Scan(unittest.TestCase):
f_strict = theano.function([x0_], ret_strict[0][-1]) f_strict = theano.function([x0_], ret_strict[0][-1])
result_strict = f_strict(x0) result_strict = f_strict(x0)
def test_monitor_mode(self):
# Test that it is possible to pass an instance of MonitorMode
# to the inner function
k = tensor.iscalar("k")
A = tensor.vector("A")
# Build a MonitorMode that counts how many values are greater than 10
def detect_large_outputs(i, node, fn):
for output in fn.outputs:
if isinstance(output[0], numpy.ndarray):
detect_large_outputs.large_count += (output[0] > 10).sum()
detect_large_outputs.large_count = 0
mode = theano.compile.MonitorMode(post_func=detect_large_outputs)
# Symbolic description of the result
result, updates = theano.scan(
fn=lambda prior_result, A: prior_result * A,
outputs_info=tensor.ones_like(A),
non_sequences=A,
n_steps=k,
mode=mode)
final_result = result[-1]
f = theano.function(inputs=[A, k],
outputs=final_result,
updates=updates)
f([2, 3, .1, 0, 1], 4)
# There should be 3 outputs greater than 10: prior_result[0] at step 3,
# and prior_result[1] at steps 2 and 3.
assert detect_large_outputs.large_count == 3
class ScanGpuTests: class ScanGpuTests:
""" This class defines a number of tests for Scan on GPU as well as a few """ This class defines a number of tests for Scan on GPU as well as a few
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论