diff --git a/python/paddle/fluid/dygraph/layers.py b/python/paddle/fluid/dygraph/layers.py index 3df0c60852727624b7c798d857340f3423c4382a..36637abc6d0b85049bbf68b081aea94ccaf385c4 100644 --- a/python/paddle/fluid/dygraph/layers.py +++ b/python/paddle/fluid/dygraph/layers.py @@ -22,6 +22,8 @@ import copy import weakref import warnings from copy import deepcopy +import inspect + import paddle from . import parallel_helper @@ -1294,10 +1296,12 @@ class Layer(core.Layer): if state is None: raise ValueError("{} is not found in the provided dict.".format( key)) - if list(state.shape) != list(param.shape): + state_shape = state.shape() if inspect.ismethod( + state.shape) else state.shape + if list(state_shape) != list(param.shape): raise ValueError( "{} receives a shape {}, but the expected shape is {}.". - format(key, list(state.shape), list(param.shape))) + format(key, list(state_shape), list(param.shape))) return param, state matched_param_state = [] diff --git a/python/paddle/fluid/framework.py b/python/paddle/fluid/framework.py index be795b9e59c0975fb1921fc3e6384295191ce33e..d5c01d20a918247524910ac820d9e0c5a1e9e885 100644 --- a/python/paddle/fluid/framework.py +++ b/python/paddle/fluid/framework.py @@ -24,6 +24,7 @@ import re import traceback import six import copy +from types import MethodType, FunctionType import numpy as np import subprocess @@ -1183,37 +1184,6 @@ class Variable(object): """ pass - @fake_interface_only - def set_value(self, value): - """ - **Notes**: - **This API is ONLY available in Dygraph mode** - - Set a new value for this Variable. - - Args: - value (Variable|np.ndarray): the new value. - - Examples: - .. code-block:: python - - import paddle.fluid as fluid - from paddle.fluid.dygraph.base import to_variable - from paddle.fluid.dygraph import Linear - import numpy as np - - data = np.ones([3, 1024], dtype='float32') - with fluid.dygraph.guard(): - linear = fluid.dygraph.Linear(1024, 4) - t = to_variable(data) - linear(t) # call with default weight - custom_weight = np.random.randn(1024, 4).astype("float32") - linear.weight.set_value(custom_weight) # change existing weight - out = linear(t) # call with different weight - - """ - pass - @fake_interface_only def backward(self, retain_graph=False): """ @@ -2011,6 +1981,159 @@ class Variable(object): return self + def get_value(self, scope=None): + """ + Get the value of variable in given scope. + + Args: + scope(Scope, optional) : If `scope` is None, it will be set to global scope + obtained through 'paddle.static.global_scope()'. Otherwise, use `scope`. + Default: None + + Returns: + Tensor: the value in given scope. + + Examples: + .. code-block:: python + + import paddle + import paddle.static as static + import numpy as np + + paddle.enable_static() + + x = static.data(name="x", shape=[10, 10], dtype='float32') + + y = static.nn.fc(x, 10, name='fc') + place = paddle.CPUPlace() + exe = static.Executor(place) + prog = paddle.static.default_main_program() + exe.run(static.default_startup_program()) + inputs = np.ones((10, 10), dtype='float32') + exe.run(prog, feed={'x': inputs}, fetch_list=[y, ]) + path = 'temp/tensor_' + for var in prog.list_vars(): + if var.persistable: + t = var.get_value() + paddle.save(t, path+var.name+'.pdtensor') + + for var in prog.list_vars(): + if var.persistable: + t_load = paddle.load(path+var.name+'.pdtensor') + var.set_value(t_load) + """ + # The 'framework' is a low-level module, and 'executor' + # can not be imported at the begainning of this file. + # Therefore, the above two modules are dynamically imported. + from .executor import global_scope + if scope is not None and not isinstance(scope, core._Scope): + raise TypeError( + "`scope` should be None or `paddle.static.Scope` type, but received {}.". + format(type(scope))) + + if scope is None: + scope = global_scope() + var_temp = scope.find_var(self.name) + if var_temp is None: + raise ValueError("Can not find Variable '{}' in the Scope.".format( + self.name)) + t = var_temp.get_tensor() + return t + + def set_value(self, value, scope=None): + ''' + Set the value to the tensor in given scope. + + Args: + value(Tensor/ndarray) : The value to be set. + scope(Scope, optional) : If `scope` is None, it will be set to global scope + obtained through 'paddle.static.global_scope()'. Otherwise, use `scope`. + Default: None + + Returns: + None + + Examples: + .. code-block:: python + + import paddle + import paddle.static as static + import numpy as np + + paddle.enable_static() + + x = static.data(name="x", shape=[10, 10], dtype='float32') + + y = static.nn.fc(x, 10, name='fc') + place = paddle.CPUPlace() + exe = static.Executor(place) + prog = paddle.static.default_main_program() + exe.run(static.default_startup_program()) + inputs = np.ones((10, 10), dtype='float32') + exe.run(prog, feed={'x': inputs}, fetch_list=[y, ]) + path = 'temp/tensor_' + for var in prog.list_vars(): + if var.persistable: + t = var.get_value() + paddle.save(t, path+var.name+'.pdtensor') + + for var in prog.list_vars(): + if var.persistable: + t_load = paddle.load(path+var.name+'.pdtensor') + var.set_value(t_load) + ''' + + # The 'framework' is a low-level module, and 'executor' + # can not be imported at the begainning of this file. + # Therefore, the above two modules are dynamically imported. + from .executor import global_scope + + if not (isinstance(value, np.ndarray) or hasattr(value, '__array__')): + raise TypeError( + "`value` should be `numpy.ndarray` or `LoDTensor`, but received {}.". + format(type(value))) + + if scope is not None and not isinstance(scope, core._Scope): + raise TypeError( + "`scope` should be None or `paddle.static.Scope` type, but received {}.". + format(type(scope))) + + if scope is None: + scope = global_scope() + + var_temp = scope.find_var(self.name) + if var_temp is None: + raise ValueError("Can not find Variable '{}' in the Scope.".format( + self.name)) + + t = var_temp.get_tensor() + + if hasattr(value, 'shape'): + if isinstance(value.shape, (MethodType, FunctionType)): + value_shape = value.shape() + else: + value_shape = value.shape + if list(t.shape()) != list(value_shape): + raise ValueError( + "{} expected a shape {}, but the received shape is {}.". + format(self.name, list(t.shape()), list(value_shape))) + + p = t._place() + if p.is_cpu_place(): + place = core.CPUPlace() + elif p.is_cuda_pinned_place(): + place = core.CUDAPinnedPlace() + elif p.is_xpu_place(): + p = core.Place() + p.set_place(t._place()) + place = core.XPUPlace(p.xpu_device_id()) + else: + p = core.Place() + p.set_place(t._place()) + place = core.CUDAPlace(p.gpu_device_id()) + + t.set(value, place) + def get_all_op_protos(): """ @@ -5319,6 +5442,173 @@ class Program(object): parameters.extend(each_block.all_parameters()) return parameters + def state_dict(self, mode='all', scope=None): + """ + Get parameters and persistable buffers of program as a dict. The key is the name of the parameter or the name of the buffer. + The value is the tensor of this variable in the given scope. + + .. note:: + This function MUST called after run start_up_program + + Args: + mode(str, optional): Source of the obtained parameters and buffers. + 'opt' : The return value only contains the variable in the optimizer. + 'param' : The return value only contains the variable in the network, not the variable in the optimizer. + 'all' : The return value contains the variable in the network and optimizer. + Default: 'all' + scope(Scope, optional) : If scope is None, state_dict will be set to global scope + obtained through 'paddle.static.global_scope()'. Otherwise, value will be set to scope. + Default: None + + Retruns: + dict: a dict contains the parameters and persistable buffers. + + Examples: + .. code-block:: python + + import paddle + import paddle.static as static + + paddle.enable_static() + + x = static.data(name="x", shape=[10, 10], dtype='float32') + y = static.nn.fc(x, 10) + z = static.nn.fc(y, 10) + + place = paddle.CPUPlace() + exe = static.Executor(place) + exe.run(static.default_startup_program()) + prog = static.default_main_program() + + path = "./temp/model.pdparams" + paddle.save(prog.state_dict(), path) + """ + # The 'framework' is a low-level module, and 'executor' + # can not be imported at the begainning of this file. + # Therefore, the above two modules are dynamically imported. + from .executor import global_scope + if scope is not None and not isinstance(scope, core._Scope): + raise TypeError( + "`scope` should be None or `paddle.static.Scope'` type, but received {}.". + format(type(scope))) + + if scope is None: + scope = global_scope() + + if not isinstance(mode, str): + raise TypeError("Type of `mode` should be string, but received {}.". + format(type(mode))) + + def is_parameter(var): + return isinstance(var, Parameter) + + def is_persistable(var): + if var.desc.type() == core.VarDesc.VarType.FEED_MINIBATCH or \ + var.desc.type() == core.VarDesc.VarType.FETCH_LIST or \ + var.desc.type() == core.VarDesc.VarType.READER: + return False + return var.persistable + + def is_belong_to_optimizer(var): + if not (isinstance(var, Parameter) or var.desc.need_check_feed()): + return is_persistable(var) + return False + + def condition(var): + + if mode == 'param': + return is_parameter(var) + elif mode == 'opt': + return is_belong_to_optimizer(var) + elif mode == 'all': + return is_parameter(var) or is_belong_to_optimizer(var) + else: + raise ValueError( + "`mode` string should be 'param', 'opt' or 'all', but received {}.". + format(mode)) + + var_list = filter(condition, self.list_vars()) + + state_dict = dict() + for var in var_list: + var_temp = scope.find_var(var.name) + if var_temp is None: + raise ValueError( + "Can not find Variable '{}' in the scope. Make sure it is initialized". + format(var.name)) + state_dict[var.name] = var_temp.get_tensor() + + return state_dict + + def set_state_dict(self, state_dict, scope=None): + """ + Set parameters and persistable buffers in state_dict to program. + An exception will throw if shape or dtype of the parameters is not match. + + .. note:: + This function MUST called after run start_up_program + + Args: + state_dict(dict): the dict store parameters and persistable buffers. + The key is the name of the parameter or the name of the buffer. + The value is the tensor of this variable in the given scope. + scope(Scope, optional) : If scope is None, state_dict will be set to global scope + obtained through 'paddle.static.global_scope()'. Otherwise, value will be set to scope. + Default: None + + Returns: + None + + Examples: + .. code-block:: python + + import paddle + import paddle.static as static + + paddle.enable_static() + + x = static.data(name="x", shape=[10, 10], dtype='float32') + y = static.nn.fc(x, 10) + z = static.nn.fc(y, 10) + + place = paddle.CPUPlace() + exe = static.Executor(place) + exe.run(static.default_startup_program()) + prog = static.default_main_program() + + path = "./temp/model.pdparams" + paddle.save(prog.state_dict(), path) + state_dict_load = paddle.load(path) + prog.set_state_dict(state_dict_load) + """ + + if not isinstance(state_dict, dict): + raise TypeError( + "Type of `state_dict` should be dict, but received {}.".format( + type(state_dict))) + + vars_dict = {var.name: var for var in self.list_vars()} + condition = True if 'StructuredToParameterName@@' in state_dict else False + for name, value in state_dict.items(): + if condition: + if name == "StructuredToParameterName@@": + continue + if name in state_dict['StructuredToParameterName@@']: + name = state_dict['StructuredToParameterName@@'][name] + if name in vars_dict: + try: + vars_dict[name].set_value(value, scope) + except ValueError as err: + warnings.warn( + ("Skip loading for '{}'. ".format(name) + str(err))) + except TypeError as err: + warnings.warn( + ("Skip loading for '{}'. ".format(name) + str(err))) + else: + warnings.warn(( + "Skip loading for '{0}'. Because '{0}' not in the program.". + format(name))) + @six.add_metaclass(ParameterMetaClass) class Parameter(Variable): diff --git a/python/paddle/fluid/io.py b/python/paddle/fluid/io.py index 9cca3e16de5132bd602dac9d9ceb9013d95d2a36..cfb4b125993855ae01b0bcdd8a8e4c6e4a1bae76 100644 --- a/python/paddle/fluid/io.py +++ b/python/paddle/fluid/io.py @@ -1765,7 +1765,30 @@ def _pack_loaded_dict(load_obj): @static_only -def save(program, model_path, pickle_protocol=2): +def _legacy_save(param_dict, model_path, protocol=2): + def get_tensor(var): + if isinstance(var, core.VarBase): + return var.numpy() + elif isinstance(var, core.LoDTensor): + return np.array(var) + return var + + param_dict = {name: get_tensor(param_dict[name]) for name in param_dict} + + # When value of dict is lager than 4GB ,there is a Bug on 'MAC python3' + if sys.platform == 'darwin' and sys.version_info.major == 3: + pickle_bytes = pickle.dumps(param_dict, protocol=protocol) + with open(model_path, 'wb') as f: + max_bytes = 2**30 + for i in range(0, len(pickle_bytes), max_bytes): + f.write(pickle_bytes[i:i + max_bytes]) + else: + with open(model_path, 'wb') as f: + pickle.dump(param_dict, f, protocol=protocol) + + +@static_only +def save(program, model_path, protocol=2, **configs): """ :api_attr: Static Graph @@ -1778,8 +1801,9 @@ def save(program, model_path, pickle_protocol=2): Args: program(Program) : The program to saved. model_path(str): the file prefix to save the program. The format is "dirname/file_prefix". If file_prefix is empty str. A exception will be raised - pickle_protocol(int, optional): The protocol version of pickle module must be greater than 1 and less than 5. + protocol(int, optional): The protocol version of pickle module must be greater than 1 and less than 5. Default: 2 + configs(dict, optional) : optional keyword arguments. Returns: None @@ -1807,14 +1831,19 @@ def save(program, model_path, pickle_protocol=2): base_name = os.path.basename(model_path) assert base_name != "", \ "The input model_path MUST be format of dirname/filename [dirname\\filename in Windows system], but received model_path is empty string." + if 'pickle_protocol' in configs: + protocol = configs['pickle_protocol'] + warnings.warn( + "'pickle_protocol' is a deprecated argument. Please use 'protocol' instead." + ) - if not isinstance(pickle_protocol, int): + if not isinstance(protocol, int): raise ValueError("The 'protocol' MUST be `int`, but received {}".format( - type(pickle_protocol))) + type(protocol))) - if pickle_protocol < 2 or pickle_protocol > 4: + if protocol < 2 or protocol > 4: raise ValueError("Expected 1<'protocol'<5, but received protocol={}". - format(pickle_protocol)) + format(protocol)) dir_name = os.path.dirname(model_path) if dir_name and not os.path.exists(dir_name): @@ -1827,26 +1856,25 @@ def save(program, model_path, pickle_protocol=2): parameter_list = list(filter(is_parameter, program.list_vars())) param_dict = {p.name: get_tensor(p) for p in parameter_list} - param_dict = _unpack_saved_dict(param_dict, pickle_protocol) + param_dict = _unpack_saved_dict(param_dict, protocol) - # When value of dict is lager than 4GB ,there is a Bug on 'MAC python3.5/6' - if sys.platform == 'darwin' and sys.version_info.major == 3 and ( - sys.version_info.minor == 5 or sys.version_info.minor == 6): - pickle_bytes = pickle.dumps(param_dict, protocol=pickle_protocol) + # When value of dict is lager than 4GB ,there is a Bug on 'MAC python3' + if sys.platform == 'darwin' and sys.version_info.major == 3: + pickle_bytes = pickle.dumps(param_dict, protocol=protocol) with open(model_path + ".pdparams", 'wb') as f: max_bytes = 2**30 for i in range(0, len(pickle_bytes), max_bytes): f.write(pickle_bytes[i:i + max_bytes]) else: with open(model_path + ".pdparams", 'wb') as f: - pickle.dump(param_dict, f, protocol=pickle_protocol) + pickle.dump(param_dict, f, protocol=protocol) optimizer_var_list = list( filter(is_belong_to_optimizer, program.list_vars())) opt_dict = {p.name: get_tensor(p) for p in optimizer_var_list} with open(model_path + ".pdopt", 'wb') as f: - pickle.dump(opt_dict, f, protocol=pickle_protocol) + pickle.dump(opt_dict, f, protocol=protocol) main_program = program.clone() program.desc.flush() @@ -1857,6 +1885,17 @@ def save(program, model_path, pickle_protocol=2): f.write(program.desc.serialize_to_string()) +def _pickle_loads_mac(path, f): + pickle_bytes = bytearray(0) + file_size = os.path.getsize(path) + max_bytes = 2**30 + for _ in range(0, file_size, max_bytes): + pickle_bytes += f.read(max_bytes) + load_result = pickle.loads(pickle_bytes) if six.PY2 else pickle.loads( + pickle_bytes, encoding='latin1') + return load_result + + @static_only def load(program, model_path, executor=None, var_list=None): """ @@ -2016,8 +2055,13 @@ def load(program, model_path, executor=None, var_list=None): global_scope(), executor._default_executor) with open(parameter_file_name, 'rb') as f: - load_dict = pickle.load(f) if six.PY2 else pickle.load( - f, encoding='latin1') + + # When value of dict is lager than 4GB ,there is a Bug on 'MAC python3' + if sys.platform == 'darwin' and sys.version_info.major == 3: + load_dict = _pickle_loads_mac(parameter_file_name, f) + else: + load_dict = pickle.load(f) if six.PY2 else pickle.load( + f, encoding='latin1') load_dict = _pack_loaded_dict(load_dict) for v in parameter_list: assert v.name in load_dict, \ @@ -2196,8 +2240,12 @@ def load_program_state(model_path, var_list=None): "Parameter file [{}] not exits".format(parameter_file_name) with open(parameter_file_name, 'rb') as f: - para_dict = pickle.load(f) if six.PY2 else pickle.load( - f, encoding='latin1') + # When value of dict is lager than 4GB ,there is a Bug on 'MAC python3' + if sys.platform == 'darwin' and sys.version_info.major == 3: + para_dict = _pickle_loads_mac(parameter_file_name, f) + else: + para_dict = pickle.load(f) if six.PY2 else pickle.load( + f, encoding='latin1') para_dict = _pack_loaded_dict(para_dict) opt_file_name = model_prefix + ".pdopt" diff --git a/python/paddle/fluid/tests/unittests/CMakeLists.txt b/python/paddle/fluid/tests/unittests/CMakeLists.txt index 28f5177c20486535e131b4679e7d671e3eb47582..add3bbee41d14bba733754ce5081a19a1fd6f32a 100644 --- a/python/paddle/fluid/tests/unittests/CMakeLists.txt +++ b/python/paddle/fluid/tests/unittests/CMakeLists.txt @@ -726,7 +726,7 @@ if (WIN32) set_tests_properties(test_paddle_save_load PROPERTIES TIMEOUT 250) else() set_tests_properties(test_static_save_load_large PROPERTIES TIMEOUT 600) - set_tests_properties(test_paddle_save_load PROPERTIES TIMEOUT 150) + set_tests_properties(test_paddle_save_load PROPERTIES TIMEOUT 250) endif() set_tests_properties(test_imperative_selected_rows_to_lod_tensor PROPERTIES TIMEOUT 120) set_tests_properties(test_index_select_op PROPERTIES TIMEOUT 120) diff --git a/python/paddle/fluid/tests/unittests/test_imperative_save_load_v2.py b/python/paddle/fluid/tests/unittests/test_imperative_save_load_v2.py index 672ffa9d394184e4ec14df8bded9b815dba0e186..9f0dcdb4d8f0c2e6da5baf31c970431ae261d698 100644 --- a/python/paddle/fluid/tests/unittests/test_imperative_save_load_v2.py +++ b/python/paddle/fluid/tests/unittests/test_imperative_save_load_v2.py @@ -930,7 +930,7 @@ class TestDygraphPtbRnn(unittest.TestCase): paddle.save(state_dict, os.path.join('saved_dy', 'emb_dy.pdparams')) para_state_dict = paddle.load( - os.path.join('saved_dy', 'emb_dy.pdparams')) + os.path.join('saved_dy', 'emb_dy.pdparams'), return_numpy=True) para_state_dict['weight'] = np.expand_dims( para_state_dict['weight'], axis=-1) diff --git a/python/paddle/fluid/tests/unittests/test_paddle_save_load.py b/python/paddle/fluid/tests/unittests/test_paddle_save_load.py index 06f63d1416b8f44628e28f8d18d9abca0381b22e..b58d63969a5e5cf8d7b3ee367ecca1324e610543 100644 --- a/python/paddle/fluid/tests/unittests/test_paddle_save_load.py +++ b/python/paddle/fluid/tests/unittests/test_paddle_save_load.py @@ -18,10 +18,15 @@ import unittest import numpy as np import os import sys +import six import paddle import paddle.nn as nn import paddle.optimizer as opt +import paddle.fluid as fluid +from paddle.fluid.optimizer import Adam +import paddle.fluid.framework as framework +from test_imperative_base import new_program_scope BATCH_SIZE = 16 BATCH_NUM = 4 @@ -31,7 +36,10 @@ SEED = 10 IMAGE_SIZE = 784 CLASS_NUM = 10 -LARGE_PARAM = 2**26 +if six.PY2: + LARGE_PARAM = 2**2 +else: + LARGE_PARAM = 2**26 def random_batch_reader(): @@ -95,15 +103,22 @@ class TestSaveLoadLargeParameters(unittest.TestCase): path = os.path.join("test_paddle_save_load_large_param_save", "layer.pdparams") - paddle.save(layer.state_dict(), path) + if six.PY2: + protocol = 2 + else: + protocol = 4 + paddle.save(save_dict, path, protocol=protocol) dict_load = paddle.load(path) # compare results before and after saving for key, value in save_dict.items(): - self.assertTrue(np.array_equal(dict_load[key], value.numpy())) + self.assertTrue( + np.array_equal(dict_load[key].numpy(), value.numpy())) class TestSaveLoadPickle(unittest.TestCase): def test_pickle_protocol(self): + # enable dygraph mode + paddle.disable_static() # create network layer = LinearNet() save_dict = layer.state_dict() @@ -124,11 +139,236 @@ class TestSaveLoadPickle(unittest.TestCase): if sys.version_info.major >= 3 and sys.version_info.minor >= 4: protocols += [3, 4] for protocol in protocols: - paddle.save(save_dict, path, protocol) + paddle.save(save_dict, path, pickle_protocol=protocol) dict_load = paddle.load(path) # compare results before and after saving for key, value in save_dict.items(): - self.assertTrue(np.array_equal(dict_load[key], value.numpy())) + self.assertTrue( + np.array_equal(dict_load[key].numpy(), value.numpy())) + + +class TestSaveLoadAny(unittest.TestCase): + def set_zero(self, prog, place, scope=None): + if scope is None: + scope = fluid.global_scope() + for var in prog.list_vars(): + if isinstance(var, framework.Parameter) or var.persistable: + ten = scope.find_var(var.name).get_tensor() + if ten is not None: + ten.set(np.zeros_like(np.array(ten)), place) + new_t = np.array(scope.find_var(var.name).get_tensor()) + self.assertTrue(np.sum(np.abs(new_t)) == 0) + + def replace_static_save(self, program, model_path, pickle_protocol=2): + with self.assertRaises(TypeError): + program.state_dict(1) + with self.assertRaises(TypeError): + program.state_dict(scope=1) + with self.assertRaises(ValueError): + program.state_dict('x') + state_dict_param = program.state_dict('param') + paddle.save(state_dict_param, model_path + '.pdparams') + state_dict_opt = program.state_dict('opt') + paddle.save(state_dict_opt, model_path + '.pdopt') + state_dict_all = program.state_dict() + paddle.save(state_dict_opt, model_path + '.pdall') + + def replace_static_load(self, program, model_path): + with self.assertRaises(TypeError): + program.set_state_dict(1) + state_dict_param = paddle.load(model_path + '.pdparams') + state_dict_param['fake_var_name.@@'] = np.random.randn(1, 2) + state_dict_param['static_x'] = 'UserWarning' + program.set_state_dict(state_dict_param) + state_dict_param['static_x'] = np.random.randn(1, 2) + program.set_state_dict(state_dict_param) + program.set_state_dict(state_dict_param) + state_dict_opt = paddle.load(model_path + '.pdopt') + program.set_state_dict(state_dict_opt) + + def test_replace_static_save_load(self): + paddle.enable_static() + with new_program_scope(): + x = paddle.static.data( + name="static_x", shape=[None, IMAGE_SIZE], dtype='float32') + z = paddle.static.nn.fc(x, 10) + z = paddle.static.nn.fc(z, 10, bias_attr=False) + loss = fluid.layers.reduce_mean(z) + opt = Adam(learning_rate=1e-3) + opt.minimize(loss) + place = paddle.CPUPlace() + exe = paddle.static.Executor(place) + exe.run(paddle.static.default_startup_program()) + prog = paddle.static.default_main_program() + fake_inputs = np.random.randn(2, IMAGE_SIZE).astype('float32') + exe.run(prog, feed={'static_x': fake_inputs}, fetch_list=[loss]) + base_map = {} + for var in prog.list_vars(): + if isinstance(var, framework.Parameter) or var.persistable: + t = np.array(fluid.global_scope().find_var(var.name) + .get_tensor()) + base_map[var.name] = t + path = os.path.join("test_replace_static_save_load", "model") + # paddle.save, legacy paddle.fluid.load + self.replace_static_save(prog, path) + self.set_zero(prog, place) + paddle.fluid.io.load(prog, path) + for var in prog.list_vars(): + if isinstance(var, framework.Parameter) or var.persistable: + new_t = np.array(fluid.global_scope().find_var(var.name) + .get_tensor()) + base_t = base_map[var.name] + self.assertTrue(np.array_equal(new_t, np.array(base_t))) + # legacy paddle.fluid.save, paddle.load + paddle.fluid.io.save(prog, path) + self.set_zero(prog, place) + self.replace_static_load(prog, path) + for var in prog.list_vars(): + if isinstance(var, framework.Parameter) or var.persistable: + new_t = np.array(fluid.global_scope().find_var(var.name) + .get_tensor()) + base_t = base_map[var.name] + self.assertTrue(np.array_equal(new_t, base_t)) + # test for return tensor + path_vars = 'test_replace_save_load_return_tensor_static/model' + for var in prog.list_vars(): + if var.persistable: + tensor = var.get_value(fluid.global_scope()) + paddle.save(tensor, os.path.join(path_vars, var.name)) + with self.assertRaises(TypeError): + var.get_value('fluid.global_scope()') + with self.assertRaises(ValueError): + x.get_value() + with self.assertRaises(TypeError): + x.set_value('1') + fake_data = np.zeros([3, 2, 1, 2, 3]) + with self.assertRaises(TypeError): + x.set_value(fake_data, '1') + with self.assertRaises(ValueError): + x.set_value(fake_data) + with self.assertRaises(ValueError): + var.set_value(fake_data) + # set var to zero + self.set_zero(prog, place) + for var in prog.list_vars(): + if var.persistable: + tensor = paddle.load( + os.path.join(path_vars, var.name), return_numpy=False) + var.set_value(tensor) + new_t = np.array(fluid.global_scope().find_var(var.name) + .get_tensor()) + base_t = base_map[var.name] + self.assertTrue(np.array_equal(new_t, base_t)) + + def test_paddle_save_load_v2(self): + paddle.disable_static() + layer = LinearNet() + state_dict = layer.state_dict() + path = 'paddle_save_load_v2/model.pdparams' + with self.assertRaises(TypeError): + paddle.save(state_dict, path, use_binary_format='False') + # legacy paddle.save, paddle.load + paddle.framework.io._legacy_save(state_dict, path) + load_dict_tensor = paddle.load(path, return_numpy=False) + # legacy paddle.load, paddle.save + paddle.save(state_dict, path) + load_dict_np = paddle.framework.io._legacy_load(path) + for k, v in state_dict.items(): + self.assertTrue( + np.array_equal(v.numpy(), load_dict_tensor[k].numpy())) + self.assertTrue(np.array_equal(v.numpy(), load_dict_np[k])) + + def test_single_pickle_var_dygraph(self): + # enable dygraph mode + paddle.disable_static() + layer = LinearNet() + path = 'paddle_save_load_v2/var_dygraph' + tensor = layer._linear.weight + with self.assertRaises(ValueError): + paddle.save(tensor, path, pickle_protocol='3') + with self.assertRaises(ValueError): + paddle.save(tensor, path, pickle_protocol=5) + paddle.save(tensor, path) + t_dygraph = paddle.load(path) + np_dygraph = paddle.load(path, return_numpy=True) + self.assertTrue(isinstance(t_dygraph, paddle.fluid.core.VarBase)) + self.assertTrue(np.array_equal(tensor.numpy(), np_dygraph)) + self.assertTrue(np.array_equal(tensor.numpy(), t_dygraph.numpy())) + paddle.enable_static() + lod_static = paddle.load(path) + np_static = paddle.load(path, return_numpy=True) + self.assertTrue(isinstance(lod_static, paddle.fluid.core.LoDTensor)) + self.assertTrue(np.array_equal(tensor.numpy(), np_static)) + self.assertTrue(np.array_equal(tensor.numpy(), np.array(lod_static))) + + def test_single_pickle_var_static(self): + # enable static mode + paddle.enable_static() + with new_program_scope(): + # create network + x = paddle.static.data( + name="x", shape=[None, IMAGE_SIZE], dtype='float32') + z = paddle.static.nn.fc(x, 128) + loss = fluid.layers.reduce_mean(z) + place = fluid.CPUPlace( + ) if not paddle.fluid.core.is_compiled_with_cuda( + ) else fluid.CUDAPlace(0) + exe = paddle.static.Executor(place) + exe.run(paddle.static.default_startup_program()) + prog = paddle.static.default_main_program() + for var in prog.list_vars(): + if list(var.shape) == [IMAGE_SIZE, 128]: + tensor = var.get_value() + break + scope = fluid.global_scope() + origin_tensor = np.array(tensor) + path = 'test_single_pickle_var_static/var' + paddle.save(tensor, path) + self.set_zero(prog, place, scope) + # static load + lod_static = paddle.load(path) + np_static = paddle.load(path, return_numpy=True) + # set_tensor(np.ndarray) + var.set_value(np_static, scope) + self.assertTrue(np.array_equal(origin_tensor, np.array(tensor))) + # set_tensor(LoDTensor) + self.set_zero(prog, place, scope) + var.set_value(lod_static, scope) + self.assertTrue(np.array_equal(origin_tensor, np.array(tensor))) + # enable dygraph mode + paddle.disable_static() + var_dygraph = paddle.load(path) + np_dygraph = paddle.load(path, return_numpy=True) + self.assertTrue(np.array_equal(np.array(tensor), np_dygraph)) + self.assertTrue(np.array_equal(np.array(tensor), var_dygraph.numpy())) + + def test_dygraph_save_static_load(self): + inps = np.random.randn(1, IMAGE_SIZE).astype('float32') + path = 'test_dygraph_save_static_load/dy-static.pdparams' + paddle.disable_static() + with paddle.utils.unique_name.guard(): + layer = LinearNet() + state_dict_dy = layer.state_dict() + paddle.save(state_dict_dy, path) + paddle.enable_static() + with new_program_scope(): + layer = LinearNet() + data = paddle.static.data( + name='x_static_save', shape=(None, IMAGE_SIZE), dtype='float32') + y_static = layer(data) + program = paddle.static.default_main_program() + place = fluid.CPUPlace( + ) if not paddle.fluid.core.is_compiled_with_cuda( + ) else fluid.CUDAPlace(0) + exe = paddle.static.Executor(paddle.CPUPlace()) + exe.run(paddle.static.default_startup_program()) + state_dict = paddle.load(path, keep_name_table=True) + program.set_state_dict(state_dict) + state_dict_param = program.state_dict("param") + for name, tensor in state_dict_dy.items(): + self.assertTrue( + np.array_equal(tensor.numpy(), + np.array(state_dict_param[tensor.name]))) class TestSaveLoad(unittest.TestCase): @@ -158,7 +398,9 @@ class TestSaveLoad(unittest.TestCase): def check_load_state_dict(self, orig_dict, load_dict): for var_name, value in orig_dict.items(): - self.assertTrue(np.array_equal(value.numpy(), load_dict[var_name])) + load_value = load_dict[var_name].numpy() if hasattr( + load_dict[var_name], 'numpy') else np.array(load_dict[var_name]) + self.assertTrue(np.array_equal(value.numpy(), load_value)) def test_save_load(self): layer, opt = self.build_and_train_model() diff --git a/python/paddle/fluid/tests/unittests/test_static_save_load_large.py b/python/paddle/fluid/tests/unittests/test_static_save_load_large.py index 08413d711be55b0b7072b3d2dfd0dc5efdeb8462..c5dc98af5c8f6d0dded8700bbdcdbbc325989066 100644 --- a/python/paddle/fluid/tests/unittests/test_static_save_load_large.py +++ b/python/paddle/fluid/tests/unittests/test_static_save_load_large.py @@ -25,12 +25,17 @@ import six import pickle import os +# Python2.x no longer supports saving and loading large parameters. +if six.PY2: + LARGE_PARAM = 2 +else: + LARGE_PARAM = 2**26 + class TestStaticSaveLoadLargeParameters(unittest.TestCase): def test_large_parameters_static_save(self): # enable static mode paddle.enable_static() - LARGE_PARAM = 2**26 with new_program_scope(): # create network x = paddle.static.data( @@ -54,7 +59,11 @@ class TestStaticSaveLoadLargeParameters(unittest.TestCase): path = os.path.join("test_static_save_load_large_param", "static_save") - paddle.fluid.save(prog, path) + if six.PY2: + protocol = 2 + else: + protocol = 4 + paddle.fluid.save(prog, path, pickle_protocol=protocol) # set var to zero for var in prog.list_vars(): if isinstance(var, framework.Parameter) or var.persistable: @@ -92,3 +101,7 @@ class TestStaticSaveLoadLargeParameters(unittest.TestCase): .get_tensor()) base_t = base_map[var.name] self.assertTrue(np.array_equal(new_t, base_t)) + + +if __name__ == '__main__': + unittest.main() diff --git a/python/paddle/fluid/tests/unittests/test_variable.py b/python/paddle/fluid/tests/unittests/test_variable.py index 8d5ab0a5be757a3f6f0c86854d281210e01d3d99..690ac46e563ef04a7ea416aa9615441245f6a56b 100644 --- a/python/paddle/fluid/tests/unittests/test_variable.py +++ b/python/paddle/fluid/tests/unittests/test_variable.py @@ -190,7 +190,6 @@ class TestVariable(unittest.TestCase): with fluid.dygraph.guard(): self.assertRaises(AssertionError, var.detach) self.assertRaises(AssertionError, var.numpy) - self.assertRaises(AssertionError, var.set_value, None) self.assertRaises(AssertionError, var.backward) self.assertRaises(AssertionError, var.gradient) self.assertRaises(AssertionError, var.clear_gradient) diff --git a/python/paddle/framework/io.py b/python/paddle/framework/io.py index 3d93bed32ecc4da923e564ac0030d84cf01d697a..3b953efab71c47ed60fdfff40ee34c07a7944bae 100644 --- a/python/paddle/framework/io.py +++ b/python/paddle/framework/io.py @@ -22,13 +22,18 @@ import warnings import sys import numpy as np +if not six.PY2: + import copyreg + import paddle # deprecated module import from paddle import fluid from paddle.fluid import core -from paddle.fluid.io import _unpack_saved_dict, _pack_loaded_dict -from paddle.fluid.framework import Variable, _varbase_creator, _dygraph_tracer +from paddle.fluid.io import _unpack_saved_dict, _pack_loaded_dict, _pickle_loads_mac +from paddle.fluid.io import _legacy_save as _legacy_static_save + +from paddle.fluid.framework import Variable, _varbase_creator, _dygraph_tracer, in_dygraph_mode, ParamBase, _current_expected_place from paddle.fluid.dygraph.jit import _SaveLoadConfig from paddle.fluid.dygraph.io import _construct_program_holders, _construct_params_and_buffers from paddle.fluid.dygraph.io import INFER_MODEL_SUFFIX, INFER_PARAMS_SUFFIX, INFER_PARAMS_INFO_SUFFIX @@ -181,7 +186,9 @@ def _build_load_path_and_config(path, config): def _parse_load_config(configs): - supported_configs = ['model_filename', 'params_filename', 'keep_name_table'] + supported_configs = [ + 'model_filename', 'params_filename', 'keep_name_table', 'return_numpy' + ] # input check for key in configs: @@ -195,16 +202,158 @@ def _parse_load_config(configs): inner_config.model_filename = configs.get('model_filename', None) inner_config.params_filename = configs.get('params_filename', None) inner_config.keep_name_table = configs.get('keep_name_table', None) + inner_config.return_numpy = configs.get('return_numpy', False) return inner_config -def save(obj, path, pickle_protocol=2): +def _parse_save_config(configs): + supported_configs = ['use_binary_format', 'pickle_protocol'] + + # input check + for key in configs: + if key not in supported_configs: + raise ValueError( + "The additional config (%s) of `paddle.save` is not supported." + % key) + + # construct inner config + inner_config = _SaveLoadConfig() + inner_config.use_binary_format = configs.get('use_binary_format', False) + inner_config.pickle_protocol = configs.get('pickle_protocol', None) + + return inner_config + + +def _pickle_save(obj, f, protocol): + # TODO(weixin):add support for BytesIO. + if not isinstance(protocol, int): + raise ValueError("The 'protocol' MUST be `int`, but received {}".format( + type(protocol))) + + if protocol < 2 or protocol > 4: + raise ValueError("Expected 1<'protocol'<5, but received protocol={}". + format(protocol)) + + if not isinstance(obj, (core.LoDTensor, core.VarBase)): + raise NotImplementedError( + "Support 'paddle.Tensor' or 'paddle.core.LoDTensor', but received {}.". + format(type(obj))) + + def reudce_varbase(self): + data = self.numpy() + name = self.name + + return (tuple, ((name, data), )) + + def reduce_LoDTensor(self): + data = np.array(self) + + return (eval, ('data', {'data': data})) + + def add_dispatch_table(): + # This is not a good method, because the pickle module has been modified. + pickle.dispatch_table[core.VarBase] = reudce_varbase + pickle.dispatch_table[ParamBase] = reudce_varbase + pickle.dispatch_table[core.LoDTensor] = reduce_LoDTensor + + def pop_dispatch_table(): + pickle.dispatch_table.pop(core.VarBase) + pickle.dispatch_table.pop(core.LoDTensor) + pickle.dispatch_table.pop(ParamBase) + + # When value of dict is lager than 4GB ,there is a Bug on 'MAC python3' + if sys.platform == 'darwin' and sys.version_info.major == 3: + add_dispatch_table() + pickle_bytes = pickle.dumps(obj) + pop_dispatch_table() + + max_bytes = 2**30 + for i in range(0, len(pickle_bytes), max_bytes): + f.write(pickle_bytes[i:i + max_bytes]) + else: + if six.PY2: + add_dispatch_table() + pickle_bytes = pickle.dump(obj, f, protocol) + pop_dispatch_table() + else: + pickler = pickle.Pickler(f, protocol) + pickler.dispatch_table = copyreg.dispatch_table.copy() + + pickler.dispatch_table[core.VarBase] = reudce_varbase + pickler.dispatch_table[core.LoDTensor] = reduce_LoDTensor + pickler.dispatch_table[ParamBase] = reudce_varbase + + pickler.dump(obj) + + +def _use_legacy(obj): + # TODO(weixin):If `obj` is any object, the judgment condition should be more precise. + if not isinstance(obj, dict): + return False + return True + + +def _transformed_from_varbase(obj): + # In paddle2.1 version, VarBase is saved as tuple(tensor.name, tensor.numpy()). + # When executing paddle.load, use this function to determine whether to restore to VarBase/LoDTensor. + if isinstance(obj, tuple) and len(obj) == 2: + if six.PY2: + name_types = (str, unicode) + else: + name_types = str + if isinstance(obj[0], name_types) and isinstance(obj[1], np.ndarray): + return True + return False + + +def _transformed_from_lodtensor(obj): + # In paddle2.1 version, LoDTensor is saved as np.array(tensor). + # When executing paddle.load, use this function to determine whether to restore to VarBase/LoDTensor. + if isinstance(obj, np.ndarray): + return True + return False + + +def _to_LodTensor(ndarray): + if not isinstance(ndarray, np.ndarray): + raise TypeError( + 'Type of `ndarray` should be numpy.ndarray, but received {}.'. + format(type(ndarray))) + t = core.LoDTensor() + place = _current_expected_place() + t.set(ndarray, place) + return t + + +def _tuple_to_tensor(obj, return_numpy): + if return_numpy: + return obj[1] + if in_dygraph_mode(): + t = paddle.to_tensor(obj[1]) + # This function does modify the name of return value. + # Loading the same variable multiple times may cause the same name. + t.name = obj[0] + return t + else: + return _to_LodTensor(obj[1]) + + +def _ndarray_to_tensor(obj, return_numpy): + if return_numpy: + return obj + if in_dygraph_mode(): + return paddle.to_tensor(obj) + else: + return _to_LodTensor(obj) + + +def save(obj, path, protocol=2, **configs): ''' Save an object to the specified path. .. note:: - Now only supports save ``state_dict`` of Layer or Optimizer. + Now supports saving ``state_dict`` of Layer or Optimizer, Tensor. .. note:: Different from ``paddle.jit.save``, since the save result of ``paddle.save`` is a single file, @@ -219,8 +368,12 @@ def save(obj, path, pickle_protocol=2): obj(Object) : The object to be saved. path(str) : The path of the object to be saved. If saved in the current directory, the input path string will be used as the file name. - pickle_protocol(int, optional): The protocol version of pickle module must be greater than 1 and less than 5. + protocol(int, optional): The protocol version of pickle module must be greater than 1 and less than 5. Default: 2 + **configs(dict, optional): optional keyword arguments. The following options are currently supported: + use_binary_format(bool): When the saved object is static graph variable, you can specify ``use_binary_for_var``. + If True, save the file in the c++ binary format when saving a single static graph variable; otherwise, save it in pickle format. + Default: False Returns: None @@ -228,20 +381,91 @@ def save(obj, path, pickle_protocol=2): Examples: .. code-block:: python + # example 1: dynamic graph import paddle - emb = paddle.nn.Embedding(10, 10) layer_state_dict = emb.state_dict() + + # save state_dict of emb paddle.save(layer_state_dict, "emb.pdparams") - scheduler = paddle.optimizer.lr.NoamDecay( + + scheduler = paddle.optimizer.lr.NoamDecay( d_model=0.01, warmup_steps=100, verbose=True) adam = paddle.optimizer.Adam( learning_rate=scheduler, parameters=emb.parameters()) opt_state_dict = adam.state_dict() + + # save state_dict of optimizer paddle.save(opt_state_dict, "adam.pdopt") + # save weight of emb + paddle.save(emb.weight, "emb.weight.pdtensor") + + # example 2: static graph + import paddle + import paddle.static as static + + paddle.enable_static() + + # create network + x = paddle.static.data(name="x", shape=[None, 224], dtype='float32') + z = paddle.static.nn.fc(x, 10) + + place = paddle.CPUPlace() + exe = paddle.static.Executor(place) + exe.run(paddle.static.default_startup_program()) + prog = paddle.static.default_main_program() + for var in prog.list_vars(): + if list(var.shape) == [224, 10]: + tensor = var.get_tensor() + break + + # save/load tensor + path_tensor = 'temp/tensor.pdtensor' + paddle.save(tensor, path_tensor) + + # save/load state_dict + path_state_dict = 'temp/model.pdparams' + paddle.save(prog.state_dict("param"), path_tensor) ''' + # 1. input check + filename = os.path.basename(path) + if filename == "": + raise ValueError("The input path MUST be format of dirname/filename " + "[dirname\\filename in Windows system], but received " + "filename is empty string.") + + # 2. save object + dirname = os.path.dirname(path) + if dirname and not os.path.exists(dirname): + os.makedirs(dirname) + + config = _parse_save_config(configs) + + if not isinstance(config.use_binary_format, bool): + raise TypeError( + "Type of `use_binary_format` should be bool, but received {}.". + format(type(config.use_binary_format))) + + # `protocol` need to be used, `pickle_protocol` is a deprecated arg. + if config.pickle_protocol is not None: + protocol = config.pickle_protocol + warnings.warn( + "'pickle_protocol' is a deprecated argument. Please use 'protocol' instead." + ) + + if _use_legacy(obj): + if in_dygraph_mode(): + _legacy_save(obj, path, protocol) + else: + _legacy_static_save(obj, path, protocol) + else: + # save single variable + with open(path, 'wb') as f: + _pickle_save(obj, f, protocol) + +def _legacy_save(obj, path, protocol=2): # 1. input check if not isinstance(obj, dict): raise NotImplementedError( @@ -257,13 +481,13 @@ def save(obj, path, pickle_protocol=2): "[dirname\\filename in Windows system], but received " "filename is empty string.") - if not isinstance(pickle_protocol, int): + if not isinstance(protocol, int): raise ValueError("The 'protocol' MUST be `int`, but received {}".format( - type(pickle_protocol))) + type(protocol))) - if pickle_protocol < 2 or pickle_protocol > 4: + if protocol < 2 or protocol > 4: raise ValueError("Expected 1<'protocol'<5, but received protocol={}". - format(pickle_protocol)) + format(protocol)) # 2. save object dirname = os.path.dirname(path) @@ -274,19 +498,18 @@ def save(obj, path, pickle_protocol=2): if isinstance(obj, dict): saved_obj = _build_saved_state_dict(obj) - saved_obj = _unpack_saved_dict(saved_obj, pickle_protocol) + saved_obj = _unpack_saved_dict(saved_obj, protocol) - # When value of dict is lager than 4GB ,there is a Bug on 'MAC python3.5/6' - if sys.platform == 'darwin' and sys.version_info.major == 3 and ( - sys.version_info.minor == 5 or sys.version_info.minor == 6): - pickle_bytes = pickle.dumps(saved_obj, protocol=pickle_protocol) + # When value of dict is lager than 4GB ,there is a Bug on 'MAC python3' + if sys.platform == 'darwin' and sys.version_info.major == 3: + pickle_bytes = pickle.dumps(saved_obj, protocol=protocol) with open(path, 'wb') as f: max_bytes = 2**30 for i in range(0, len(pickle_bytes), max_bytes): f.write(pickle_bytes[i:i + max_bytes]) else: with open(path, 'wb') as f: - pickle.dump(saved_obj, f, protocol=pickle_protocol) + pickle.dump(saved_obj, f, protocol=protocol) def load(path, **configs): @@ -294,7 +517,7 @@ def load(path, **configs): Load an object can be used in paddle from specified path. .. note:: - Now only supports load ``state_dict`` of Layer or Optimizer. + Now supports load ``state_dict`` of Layer or Optimizer, Tensor. .. note:: In order to use the model parameters saved by paddle more efficiently, @@ -331,7 +554,9 @@ def load(path, **configs): ``save_inference_model`` save format. Default file name is :code:`__model__` . (2) params_filename (str): The persistable variables file name of the paddle 1.x ``save_inference_model`` save format. No default file name, save variables separately - by default. + by default. + (3) return_numpy(bool): If specified as True, return tensor as numpy.ndarray, otherwise return tensor as paddle.Tensor. + Default False. Returns: Object(Object): a target object can be used in paddle @@ -341,20 +566,115 @@ def load(path, **configs): import paddle + # example 1: dynamic graph + import paddle emb = paddle.nn.Embedding(10, 10) layer_state_dict = emb.state_dict() + + # save state_dict of emb paddle.save(layer_state_dict, "emb.pdparams") - scheduler = paddle.optimizer.lr.NoamDecay( + + scheduler = paddle.optimizer.lr.NoamDecay( d_model=0.01, warmup_steps=100, verbose=True) adam = paddle.optimizer.Adam( learning_rate=scheduler, parameters=emb.parameters()) opt_state_dict = adam.state_dict() + + # save state_dict of optimizer paddle.save(opt_state_dict, "adam.pdopt") + # save weight of emb + paddle.save(emb.weight, "emb.weight.pdtensor") + # load state_dict of emb load_layer_state_dict = paddle.load("emb.pdparams") + # load state_dict of optimizer load_opt_state_dict = paddle.load("adam.pdopt") + # load weight of emb + load_weight = paddle.load("emb.weight.pdtensor") + + + # example 2: static graph + import paddle + import paddle.static as static + + paddle.enable_static() + + # create network + x = paddle.static.data(name="x", shape=[None, 224], dtype='float32') + z = paddle.static.nn.fc(x, 10) + + place = paddle.CPUPlace() + exe = paddle.static.Executor(place) + exe.run(paddle.static.default_startup_program()) + prog = paddle.static.default_main_program() + for var in prog.list_vars(): + if list(var.shape) == [224, 10]: + tensor = var.get_tensor() + break + + # save/load tensor + path_tensor = 'temp/tensor.pdtensor' + paddle.save(tensor, path_tensor) + load_tensor = paddle.load(path_tensor) + + # save/load state_dict + path_state_dict = 'temp/model.pdparams' + paddle.save(prog.state_dict("param"), path_tensor) + load_state_dict = paddle.load(path_tensor) + ''' + + if os.path.isfile(path): + config = _parse_load_config(configs) + with open(path, 'rb') as f: + # When value of dict is lager than 4GB ,there is a Bug on 'MAC python3' + if sys.platform == 'darwin' and sys.version_info.major == 3: + load_result = _pickle_loads_mac(path, f) + else: + load_result = pickle.load(f) if six.PY2 else pickle.load( + f, encoding='latin1') + + # TODO(weixin):If `obj` is any object, the judgment condition should be more precise. + if isinstance(load_result, dict): + if isinstance(load_result, dict): + load_result = _pack_loaded_dict(load_result) + # paddle2.0: paddle.save/load + if "StructuredToParameterName@@" in load_result: + + for key in load_result["StructuredToParameterName@@"]: + load_result[key] = _ndarray_to_tensor( + load_result[key], config.return_numpy) + + if not config.keep_name_table and "StructuredToParameterName@@" in load_result: + del load_result["StructuredToParameterName@@"] + else: + # paddle2.1 static.save/load + for key in load_result: + load_result[key] = _ndarray_to_tensor( + load_result[key], config.return_numpy) + + else: + # TODO(weixin): support complex objects such as layer. + # If `obj` is any object, the judgment condition should be more precise. + if _transformed_from_lodtensor(load_result): + load_result = _ndarray_to_tensor(load_result, + config.return_numpy) + elif _transformed_from_varbase(load_result): + load_result = _tuple_to_tensor(load_result, + config.return_numpy) + else: + raise NotImplementedError( + 'Only support tensor and state_dict, but received {}.'. + format(type(load_result))) + + else: + load_result = _legacy_load(path, **configs) + + return load_result + + +def _legacy_load(path, **configs): load_result = None config = _parse_load_config(configs) diff --git a/tools/__pycache__/static_mode_white_list.cpython-37.pyc b/tools/__pycache__/static_mode_white_list.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..937267ff7180abf32341455e5d21fcac417782ae Binary files /dev/null and b/tools/__pycache__/static_mode_white_list.cpython-37.pyc differ diff --git a/tools/static_mode_white_list.pyc b/tools/static_mode_white_list.pyc deleted file mode 100644 index e9012c233595b6844f54e625972360f5aeeb0d3b..0000000000000000000000000000000000000000 Binary files a/tools/static_mode_white_list.pyc and /dev/null differ