From 0b8664eabfcb5dae019e4b46ae500b0b7ac0736d Mon Sep 17 00:00:00 2001 From: 0x45f <23097963+0x45f@users.noreply.github.com> Date: Tue, 14 Sep 2021 12:09:51 +0800 Subject: [PATCH] [dy2stat_error] add revise suggestion for two error cases (#35648) * dy2stat_error: add revise suggestion for two error cases * fix test_error * fix review --- .../fluid/dygraph/dygraph_to_static/error.py | 36 +++++++++++ .../dygraph_to_static/partial_program.py | 11 ++-- .../unittests/dygraph_to_static/test_error.py | 59 +++++++++++++++++++ 3 files changed, 101 insertions(+), 5 deletions(-) diff --git a/python/paddle/fluid/dygraph/dygraph_to_static/error.py b/python/paddle/fluid/dygraph/dygraph_to_static/error.py index ffcc8c95bbc..2a975bf00d1 100644 --- a/python/paddle/fluid/dygraph/dygraph_to_static/error.py +++ b/python/paddle/fluid/dygraph/dygraph_to_static/error.py @@ -143,6 +143,23 @@ class TraceBackFrameRange(OriginInfo): return msg + '\n'.join(self.source_code) + '\n' +class SuggestionDict(object): + def __init__(self): + # {(keywords): (suggestions)} + self.suggestion_dict = { + ('is not initialized.', 'Hint:', 'IsInitialized'): + ("Please ensure all your sublayers are inheritted from nn.Layer.", + "Please ensure there is no tensor created explicitly depended on external data, we suggest to register it as buffer tensor. See https://www.paddlepaddle.org.cn/documentation/docs/zh/guides/04_dygraph_to_static/export_model/principle_cn.html#parameters-buffers for details" + ) + } + + def keys(self): + return self.suggestion_dict.keys() + + def __getitem__(self, key): + return self.suggestion_dict[key] + + class ErrorData(object): """ Error data attached to an exception which is raised in un-transformed code. @@ -155,6 +172,7 @@ class ErrorData(object): self.origin_traceback = origin_traceback self.origin_info_map = origin_info_map self.in_runtime = False + self.suggestion_dict = SuggestionDict() def create_exception(self): message = self.create_message() @@ -215,6 +233,22 @@ class ErrorData(object): return '\n'.join(message_lines) + def _create_revise_suggestion(self, bottom_error_message): + revise_suggestions = [ + '', ' ' * BLANK_COUNT_BEFORE_FILE_STR + 'Revise suggestion: ' + ] + for keywords in self.suggestion_dict.keys(): + contain_keywords = [ + True for i in keywords if i in ''.join(bottom_error_message) + ] + if len(contain_keywords) == len( + keywords): # all keywords should be in bottom_error_message + for suggestion in self.suggestion_dict[keywords]: + suggestion_msg = ' ' * BLANK_COUNT_BEFORE_FILE_STR * 2 + '{}. {}'.format( + str(len(revise_suggestions) - 1), suggestion) + revise_suggestions.append(suggestion_msg) + return revise_suggestions if len(revise_suggestions) > 2 else [] + def _simplify_error_value(self): """ Simplifies error value to improve readability if error is raised in runtime. @@ -240,6 +274,7 @@ class ErrorData(object): # use empty line to locate the bottom_error_message empty_line_idx = error_value_lines_strip.index('') bottom_error_message = error_value_lines[empty_line_idx + 1:] + revise_suggestion = self._create_revise_suggestion(bottom_error_message) filepath = '' error_from_user_code = [] @@ -269,6 +304,7 @@ class ErrorData(object): error_frame.insert(0, traceback_frame.formated_message()) error_frame.extend(bottom_error_message) + error_frame.extend(revise_suggestion) error_value_str = '\n'.join(error_frame) self.error_value = self.error_type(error_value_str) diff --git a/python/paddle/fluid/dygraph/dygraph_to_static/partial_program.py b/python/paddle/fluid/dygraph/dygraph_to_static/partial_program.py index e275ee04858..663f95af89c 100644 --- a/python/paddle/fluid/dygraph/dygraph_to_static/partial_program.py +++ b/python/paddle/fluid/dygraph/dygraph_to_static/partial_program.py @@ -474,11 +474,12 @@ class PartialProgramLayer: if isinstance(var, framework.Parameter): if name not in param_and_buffer_names_set: raise ValueError( - "\n\tWe don't support to define layer with parameters in the function " - "decorated by `@declarative`.\n\tBecause that will re-defined parameters " - "every time when you run the function.\n\t" - "But we found parameter(%s) was created in the decorated function.\n\t" - "Please define the layer with parameters in `__init__` function." + "\n\tWe don't support to define layer with parameters in the function decorated by `@to_static`." + "\n\tBut we found parameter(%s) was created in the decorated function." + "\n" + "\n\tRevise suggestion: " + "\n\t\t1. Please ensure all your sublayers are inheritted from nn.Layer." + "\n\t\t2. Please use nn.ParameterList and nn.LayerList as container instead of using a native Python container such as List" % name) def _valid_vars(self, vars): diff --git a/python/paddle/fluid/tests/unittests/dygraph_to_static/test_error.py b/python/paddle/fluid/tests/unittests/dygraph_to_static/test_error.py index 6dd8c8e0766..8058234cb5f 100644 --- a/python/paddle/fluid/tests/unittests/dygraph_to_static/test_error.py +++ b/python/paddle/fluid/tests/unittests/dygraph_to_static/test_error.py @@ -108,6 +108,31 @@ def func_error_in_runtime_with_empty_line(x): return x +class SuggestionErrorTestNet(paddle.nn.Layer): + def __init__(self): + super(SuggestionErrorTestNet, self).__init__() + self.inner_net = SuggestionErrorTestNet2() + + @paddle.jit.to_static + def forward(self, x): + return self.inner_net.forward(x) + + +class SuggestionErrorTestNet2(): + def __init__(self): + super(SuggestionErrorTestNet2, self).__init__() + self.w = paddle.to_tensor([2.]) + + def forward(self, x): + out = paddle.matmul(self.w, x) + return out + + +def func_suggestion_error_in_runtime(x): + net = SuggestionErrorTestNet() + net(x) + + class TestFlags(unittest.TestCase): def setUp(self): self.reset_flags_to_default() @@ -385,5 +410,39 @@ class TestErrorInOther(unittest.TestCase): func_decorated_by_other_2() +class TestSuggestionErrorInRuntime(TestErrorBase): + def set_func(self): + self.func = func_suggestion_error_in_runtime + + def set_input(self): + self.input = paddle.to_tensor([2.]) + + def set_exception_type(self): + self.exception_type = ValueError + + def set_message(self): + self.expected_message = \ + [ + 'File "{}", line 118, in forward'.format(self.filepath), + 'return self.inner_net.forward(x)', + 'File "{}", line 127, in forward'.format(self.filepath), + 'def forward(self, x):', + 'out = paddle.matmul(self.w, x)', + '<--- HERE', + 'return out', + 'Revise suggestion:', + 'Please ensure all your sublayers are inheritted from nn.Layer.', + 'Please ensure there is no tensor created explicitly depended on external data, we suggest to register it as buffer tensor. See' + ] + + def set_func_call(self): + # NOTE: self.func(self.input) is the StaticLayer().__call__(self.input) + self.func_call = lambda: self.func(self.input) + + def test_error(self): + for disable_new_error in [0, 1]: + self._test_raise_new_exception(disable_new_error) + + if __name__ == '__main__': unittest.main() -- GitLab