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

Merge pull request #4067 from abergeron/debugmode_empty

Make DebugMode handle a special version of perform.
......@@ -266,6 +266,19 @@ Optional methods or attributes
As done in the Alloc op, you can return False only in some cases by
analyzing the graph from the node parameter.
.. function:: debug_perform(node, inputs, output_storage)
Undefined by default.
If you define this function then it will be used instead of C code
or perform() to do the computation while debugging (currently
DebugMode, but others may also use it in the future). It has the
same signature and contract as :func:`perform`.
This enables ops that cause trouble with DebugMode with their
normal behaviour to adopt a different one when run under that
mode. If your op doesn't have any problems, don't implement this.
If you want your op to work with gradient.grad() you also need to
implement the functions described below.
......
......@@ -1849,8 +1849,10 @@ class _Linker(gof.link.LocalLinker):
if new_node is not None:
node = new_node
debug = hasattr(node.op, 'debug_perform')
try:
if not self.maker.mode.check_c_code:
if not self.maker.mode.check_c_code or debug:
raise utils.MethodNotDefined()
# Ops that do not inherit from gof.op.Op don't have certain
# methods defined that the CLinker expects (Scan is an
......@@ -1868,18 +1870,18 @@ class _Linker(gof.link.LocalLinker):
# Pure ops don't really have a perform ( or their perform just
# raises an not implemented exception), so in those cases we
# consider that we don't have a python implementation
if (self.maker.mode.check_py_code or thunks_c[-1] is None) and \
node.op.perform.__code__ != gof.op.PureOp.perform.__code__:
if (((self.maker.mode.check_py_code or thunks_c[-1] is None) and
node.op.perform.__code__ != gof.op.PureOp.perform.__code__) or
debug):
thunk = node.op.make_py_thunk(node, storage_map, compute_map,
no_recycling)
no_recycling, debug=debug)
thunks_py.append(thunk)
else:
thunks_py.append(None)
if not self.maker.mode.check_c_code and thunks_py[-1] is None:
_logger.warn(
"Op %s don't have a perform, forcing check of the c code" %
node.op)
_logger.warn("Op %s doesn't have a perform, "
"forcing check of the C code" % node.op)
thunk = node.op.make_c_thunk(node, storage_map, compute_map,
no_recycling)
thunks_c[-1] = thunk
......
......@@ -1177,11 +1177,13 @@ class CLinker(link.Linker):
List of lists of length 1. In order to use
the thunk returned by __compile__, the inputs must be put in
that storage. If None, storage will be allocated.
@param output_storage: list of lists of length 1. The thunk returned
by __compile__ will put the variables of the computation in these
lists. If None, storage will be allocated.
@param storage_map: dict that map variables to storages. This is used
when you need to customize the storage of this thunk.
output_storage: list of lists of length 1.
The thunk returned by __compile__ will put the variables
of the computation in these lists. If None, storage will
be allocated.
storage_map: dict that map variables to storages.
This is used when you need to customize the storage of
this thunk.
Returns: thunk, input_storage, output_storage
......
......@@ -890,7 +890,8 @@ class Op(utils.object2, PureOp, CLinkerOp):
rval.lazy = False
return rval
def make_py_thunk(self, node, storage_map, compute_map, no_recycling):
def make_py_thunk(self, node, storage_map, compute_map, no_recycling,
debug=False):
"""
Like make_thunk() but only makes python thunks.
......@@ -898,7 +899,10 @@ class Op(utils.object2, PureOp, CLinkerOp):
node_input_storage = [storage_map[r] for r in node.inputs]
node_output_storage = [storage_map[r] for r in node.outputs]
p = node.op.perform
if debug:
p = node.op.debug_perform
else:
p = node.op.perform
params = node.run_params()
......
......@@ -3682,6 +3682,13 @@ class GpuAllocEmpty(GpuOp):
output.type.filter_checks_isfinite = False
return Apply(self, shape, [output])
def debug_perform(self, node, inputs, out_):
self.perform(self, node, inputs, out_)
# __setitem__ is limited on CudaNdarray
tmp = numpy.empty(out_[0][0].shape, dtype='float32')
tmp.fill(-123456789)
out_[0][0][:] = tmp
def perform(self, node, inputs, out_):
out, = out_
sh = tuple([int(i) for i in inputs])
......
......@@ -723,6 +723,10 @@ class GpuAllocEmpty(HideC, Alloc):
output.type.filter_checks_isfinite = False
return Apply(self, sh, [output])
def debug_perform(self, node, inputs, out_, ctx):
self.perform(node, inputs, out_, ctx)
out_[0][0][:] = -123456789
def perform(self, node, inputs, out_, ctx):
out = out_[0]
sh = [int(i) for i in inputs]
......
......@@ -6240,6 +6240,10 @@ class AllocEmpty(gof.Op):
output.type.filter_checks_isfinite = False
return Apply(self, shape, [output])
def debug_perform(self, node, inputs, out_):
self.perform(node, inputs, out_)
out_[0][0].fill(-123456789)
def perform(self, node, inputs, out_):
out, = out_
sh = tuple([int(i) for i in inputs])
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论