From fe88aeb293f080fba129d0f391919f01528a1f7a Mon Sep 17 00:00:00 2001 From: hong <43953930+phlrain@users.noreply.github.com> Date: Thu, 16 Jan 2020 15:47:17 +0800 Subject: [PATCH] Check dygraph weight name (#22140) (#22238) * add parameter check; test=develop * change parameter name checker in dygraph guard; test=develop * fix test layers error; test=develop * revert some code to develop; test=develop * fix exampel error; test=develop * fix comment error; test=develop * fix comment error; test=develop --- python/paddle/fluid/layer_helper_base.py | 8 +++ .../fluid/tests/unittests/test_layers.py | 16 +++++- python/paddle/fluid/unique_name.py | 53 ++++++++++++++++--- 3 files changed, 69 insertions(+), 8 deletions(-) diff --git a/python/paddle/fluid/layer_helper_base.py b/python/paddle/fluid/layer_helper_base.py index 3140a84c09..f6cf2a7d49 100644 --- a/python/paddle/fluid/layer_helper_base.py +++ b/python/paddle/fluid/layer_helper_base.py @@ -331,6 +331,14 @@ class LayerHelperBase(object): if in_dygraph_mode(): # In dygraph mode, we want the returned parameter to be # initialized so that it can be used imperatively. + # check parameter name + is_used = unique_name.dygraph_parameter_name_checker(attr.name) + if is_used: + raise ValueError( + "parameter name [{}] have be been used. " + "In dygraph mode, the name of parameter can't be same." + "Please check the parameter attr value passed to self.create_parameter or " + "constructor of dygraph Layers".format(attr.name)) return self.main_program.global_block().create_parameter( dtype=dtype, shape=shape, diff --git a/python/paddle/fluid/tests/unittests/test_layers.py b/python/paddle/fluid/tests/unittests/test_layers.py index cde4264ff1..384acc2360 100644 --- a/python/paddle/fluid/tests/unittests/test_layers.py +++ b/python/paddle/fluid/tests/unittests/test_layers.py @@ -1550,6 +1550,15 @@ class TestLayer(LayerTest): class TestBook(LayerTest): + def setUp(self): + self.only_static_set = set({"make_word_embedding"}) + self.not_compare_static_dygraph_set = set({ + "make_gaussian_random", "make_gaussian_random_batch_size_like", + "make_kldiv_loss", "make_prelu", + "make_sampled_softmax_with_cross_entropy", "make_sampling_id", + "make_uniform_random_batch_size_like" + }) + def test_all_layers(self): attrs = (getattr(self, name) for name in dir(self)) methods = filter(inspect.ismethod, attrs) @@ -1572,9 +1581,12 @@ class TestBook(LayerTest): feed=self._feed_dict, fetch_list=fetch_list, force_to_use_cpu=self._force_to_use_cpu) + else: assert method.__name__ in ('make_get_places') continue + if method.__name__ in self.only_static_set: + continue with self.dynamic_graph(self._force_to_use_cpu): dy_result = method() @@ -1582,7 +1594,9 @@ class TestBook(LayerTest): dy_result = dy_result[0] dy_result_value = dy_result.numpy() - self.assertTrue(np.array_equal(static_result[0], dy_result_value)) + if method.__name__ not in self.not_compare_static_dygraph_set: + self.assertTrue( + np.array_equal(static_result[0], dy_result_value)) def _get_np_data(self, shape, dtype, append_batch_size=True): np.random.seed(self.seed) diff --git a/python/paddle/fluid/unique_name.py b/python/paddle/fluid/unique_name.py index 550364a22f..6129bd1c80 100644 --- a/python/paddle/fluid/unique_name.py +++ b/python/paddle/fluid/unique_name.py @@ -51,6 +51,33 @@ class UniqueNameGenerator(object): return self.prefix + "_".join([key, str(tmp)]) +class DygraphParameterNameChecker(object): + """ + Check whether the name of parameter is used. + """ + + def __init__(self): + self._name_set = set() + + def __call__(self, name): + ''' + Check whether the name is used. If not used, insert into the _name_set. + + Args: + name(str): The name of parameter to check. + + Returns(bool): If the name is in name_set, return True; Otherwise, return False. + + ''' + if name in self._name_set: + return True + else: + self._name_set.add(name) + return False + + +dygraph_parameter_name_checker = DygraphParameterNameChecker() + generator = UniqueNameGenerator() @@ -101,7 +128,7 @@ def generate_with_ignorable_key(key): return generator(key) -def switch(new_generator=None): +def switch(new_generator=None, new_para_name_checker=None): """ Switch the namespace of in current context to a new namespace. Though :code:`switch()` and :code:`guard()` can both change namespace, @@ -112,9 +139,13 @@ def switch(new_generator=None): new_generator(UniqueNameGenerator, optional): A new UniqueNameGenerator, not required normally. Default is None, which means switch to a new anonymous namespace. + new_para_name_checker(DygraphParameterNameChecker, optional): A new DygraphParameterNameChecker, + not required normally. Default is None, which means switch to a new parameter name + checker. Returns: UniqueNameGenerator: The previous UniqueNameGenerator. + DygraphParameterNameChecker: The previous DygraphParameterNameChecker Examples: @@ -125,22 +156,29 @@ def switch(new_generator=None): name2 = fluid.unique_name.generate('fc') print(name1, name2) # fc_0, fc_1 - pre_generator = fluid.unique_name.switch() # switch to a new anonymous namespace. + pre_generator, pre_dygraph_name_checker = fluid.unique_name.switch() # switch to a new anonymous namespace. name2 = fluid.unique_name.generate('fc') print(name2) # fc_0 - fluid.unique_name.switch(pre_generator) # switch back to pre_generator. + fluid.unique_name.switch(pre_generator, pre_dygraph_name_checker) # switch back to pre_generator. name3 = fluid.unique_name.generate('fc') print(name3) # fc_2, since pre_generator has generated fc_0, fc_1. """ global generator - old = generator + old_generator = generator + global dygraph_parameter_name_checker + old_para_name_checker = dygraph_parameter_name_checker if new_generator is None: generator = UniqueNameGenerator() else: generator = new_generator - return old + + if new_para_name_checker is None: + dygraph_parameter_name_checker = DygraphParameterNameChecker() + else: + dygraph_parameter_name_checker = new_para_name_checker + return old_generator, old_para_name_checker @signature_safe_contextmanager @@ -180,6 +218,7 @@ def guard(new_generator=None): new_generator = UniqueNameGenerator(new_generator) elif isinstance(new_generator, six.binary_type): new_generator = UniqueNameGenerator(new_generator.decode()) - old = switch(new_generator) + + old_generator, old_para_name_checker = switch(new_generator) yield - switch(old) + switch(old_generator, old_para_name_checker) -- GitLab