New save load interface (#20148)
* add new save load interface; test=develop * add new save interface; test=develop * add save load interface ; * fix save load error; * fix dygraph set dict bug; * add save load unit test; test=develop * fix test_imperative_optimizer bug; test=develop * fix unitest optimizer bug; test=develop * fix code coverage; test=develop * fix converage; test=develop * add document for apis; test=develop * fix unitest error; test=develop * fix save load unit test error; test=develop * fix error message; test=develop * change set_parameter set_optimizer to save_dygraph; test=develop * add load_graph check; test=develop * fix api spec; test=developrevert-20712-fix_depthwise_conv
parent
e2c7b6821a
commit
fa43e80e19
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/fluid/framework/scope.h"
|
||||
#include "paddle/fluid/framework/tensor.h"
|
||||
#include "paddle/fluid/imperative/type_defs.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace framework {
|
||||
|
||||
bool SaveStaticNameListToDisk(
|
||||
const std::string& file_name,
|
||||
const std::vector<std::string>& vec_tensor_name_list, const Scope& scope);
|
||||
|
||||
bool LoadStaticNameListFromDisk(
|
||||
const std::string& file_name,
|
||||
const std::vector<std::string>& vec_tensor_name_list, const Scope& scope);
|
||||
|
||||
bool SaveDygraphVarBaseListToDisk(
|
||||
const std::string& file_name,
|
||||
const std::vector<std::shared_ptr<imperative::VarBase>>& vec_var_base_list);
|
||||
|
||||
const std::vector<std::shared_ptr<imperative::VarBase>>
|
||||
LoadDygraphVarBaseListFromDisk(const std::string& file_name);
|
||||
|
||||
bool SaveTensorToDisk(const std::string& file_name,
|
||||
const std::map<std::string, Tensor*>& map_tensor);
|
||||
|
||||
bool LoadTensorFromDisk(
|
||||
const std::string& file_name,
|
||||
std::map<std::string, std::shared_ptr<Tensor>>* map_tensor);
|
||||
|
||||
} // namespace framework
|
||||
} // namespace paddle
|
@ -0,0 +1,78 @@
|
||||
// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "paddle/fluid/framework/save_load_util.h"
|
||||
#include "paddle/fluid/platform/macros.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace framework {
|
||||
TEST(test_save_load_util, test_save_load) {
|
||||
srand(time(NULL));
|
||||
auto cpu_place = platform::CPUPlace();
|
||||
Tensor tensor1;
|
||||
tensor1.Resize({1000, 1000});
|
||||
auto src_data_1 = tensor1.mutable_data<float>(cpu_place);
|
||||
Tensor tensor2;
|
||||
tensor2.Resize({5000, 1000});
|
||||
auto src_data_2 = tensor2.mutable_data<float>(cpu_place);
|
||||
|
||||
for (int64_t i = 0; i < tensor1.numel(); ++i) {
|
||||
float temp = (rand() % 10000) * 1.0 / 50000 - 1.0; // NOLINT
|
||||
|
||||
src_data_1[i] = temp;
|
||||
}
|
||||
|
||||
for (int64_t i = 0; i < tensor2.numel(); ++i) {
|
||||
float temp = (rand() % 10000) * 1.0 / 50000 - 1.0; // NOLINT
|
||||
|
||||
src_data_2[i] = temp;
|
||||
}
|
||||
|
||||
std::map<std::string, Tensor*> map_tensor;
|
||||
map_tensor["t1"] = &tensor1;
|
||||
map_tensor["t2"] = &tensor2;
|
||||
|
||||
SaveTensorToDisk("test_1", map_tensor);
|
||||
|
||||
std::map<std::string, std::shared_ptr<Tensor>> load_map_tensor;
|
||||
|
||||
LoadTensorFromDisk("test_1", &load_map_tensor);
|
||||
|
||||
ASSERT_TRUE(load_map_tensor.find("t1") != load_map_tensor.end());
|
||||
ASSERT_TRUE(load_map_tensor.find("t2") != load_map_tensor.end());
|
||||
|
||||
auto new_tensor_1 = load_map_tensor["t1"];
|
||||
auto new_tensor_2 = load_map_tensor["t2"];
|
||||
|
||||
float* ptr_1 = tensor1.data<float>();
|
||||
float* ptr_1_new = new_tensor_1->data<float>();
|
||||
|
||||
for (int64_t i = 0; i < tensor1.numel(); ++i) {
|
||||
ASSERT_EQ(ptr_1[i], ptr_1_new[i]);
|
||||
}
|
||||
|
||||
float* ptr_2 = tensor2.data<float>();
|
||||
float* ptr_2_new = new_tensor_2->data<float>();
|
||||
|
||||
for (int64_t i = 0; i < tensor2.numel(); ++i) {
|
||||
ASSERT_EQ(ptr_2[i], ptr_2_new[i]);
|
||||
}
|
||||
}
|
||||
} // namespace framework
|
||||
} // namespace paddle
|
File diff suppressed because it is too large
Load Diff
@ -1,172 +0,0 @@
|
||||
# Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
import numpy as np
|
||||
|
||||
import paddle
|
||||
import paddle.fluid as fluid
|
||||
from paddle.fluid.optimizer import SGDOptimizer
|
||||
from paddle.fluid import Conv2D, Pool2D, FC, core
|
||||
from paddle.fluid.dygraph.base import to_variable
|
||||
|
||||
|
||||
class SimpleImgConvPool(fluid.Layer):
|
||||
def __init__(self,
|
||||
name_scope,
|
||||
num_filters,
|
||||
filter_size,
|
||||
pool_size,
|
||||
pool_stride,
|
||||
pool_padding=0,
|
||||
pool_type='max',
|
||||
global_pooling=False,
|
||||
conv_stride=1,
|
||||
conv_padding=0,
|
||||
conv_dilation=1,
|
||||
conv_groups=1,
|
||||
act=None,
|
||||
use_cudnn=False,
|
||||
param_attr=None,
|
||||
bias_attr=None):
|
||||
super(SimpleImgConvPool, self).__init__(name_scope)
|
||||
|
||||
self._conv2d = Conv2D(
|
||||
self.full_name(),
|
||||
num_filters=num_filters,
|
||||
filter_size=filter_size,
|
||||
stride=conv_stride,
|
||||
padding=conv_padding,
|
||||
dilation=conv_dilation,
|
||||
groups=conv_groups,
|
||||
param_attr=None,
|
||||
bias_attr=None,
|
||||
use_cudnn=use_cudnn)
|
||||
|
||||
self._pool2d = Pool2D(
|
||||
self.full_name(),
|
||||
pool_size=pool_size,
|
||||
pool_type=pool_type,
|
||||
pool_stride=pool_stride,
|
||||
pool_padding=pool_padding,
|
||||
global_pooling=global_pooling,
|
||||
use_cudnn=use_cudnn)
|
||||
|
||||
def forward(self, inputs):
|
||||
x = self._conv2d(inputs)
|
||||
x = self._pool2d(x)
|
||||
return x
|
||||
|
||||
|
||||
class MNIST(fluid.Layer):
|
||||
def __init__(self, name_scope):
|
||||
super(MNIST, self).__init__(name_scope)
|
||||
|
||||
self._simple_img_conv_pool_1 = SimpleImgConvPool(
|
||||
self.full_name(), 20, 5, 2, 2, act="relu")
|
||||
|
||||
self._simple_img_conv_pool_2 = SimpleImgConvPool(
|
||||
self.full_name(), 50, 5, 2, 2, act="relu")
|
||||
|
||||
pool_2_shape = 50 * 4 * 4
|
||||
SIZE = 10
|
||||
scale = (2.0 / (pool_2_shape**2 * SIZE))**0.5
|
||||
self._fc = FC(self.full_name(),
|
||||
10,
|
||||
param_attr=fluid.param_attr.ParamAttr(
|
||||
initializer=fluid.initializer.NormalInitializer(
|
||||
loc=0.0, scale=scale)),
|
||||
act="softmax")
|
||||
|
||||
def forward(self, inputs):
|
||||
x = self._simple_img_conv_pool_1(inputs)
|
||||
x = self._simple_img_conv_pool_2(x)
|
||||
x = self._fc(x)
|
||||
return x
|
||||
|
||||
|
||||
class TestDygraphCheckpoint(unittest.TestCase):
|
||||
def reader_decorator(self, reader):
|
||||
def _reader_imple():
|
||||
for item in reader():
|
||||
image = np.array(item[0]).reshape(1, 28, 28)
|
||||
label = np.array(item[1]).astype('int64').reshape(1)
|
||||
yield image, label
|
||||
|
||||
return _reader_imple
|
||||
|
||||
def test_save_load_persistables(self):
|
||||
seed = 90
|
||||
epoch_num = 1
|
||||
batch_size = 128
|
||||
|
||||
with fluid.dygraph.guard():
|
||||
fluid.default_startup_program().random_seed = seed
|
||||
fluid.default_main_program().random_seed = seed
|
||||
|
||||
mnist = MNIST("mnist")
|
||||
sgd = SGDOptimizer(learning_rate=1e-3)
|
||||
|
||||
batch_py_reader = fluid.io.PyReader(capacity=1)
|
||||
batch_py_reader.decorate_sample_list_generator(
|
||||
paddle.batch(
|
||||
self.reader_decorator(paddle.dataset.mnist.train()),
|
||||
batch_size=batch_size,
|
||||
drop_last=True),
|
||||
places=fluid.CPUPlace())
|
||||
|
||||
dy_param_init_value = {}
|
||||
|
||||
for epoch in range(epoch_num):
|
||||
for batch_id, data in enumerate(batch_py_reader()):
|
||||
img = data[0]
|
||||
label = data[1]
|
||||
label.stop_gradient = True
|
||||
|
||||
cost = mnist(img)
|
||||
loss = fluid.layers.cross_entropy(cost, label)
|
||||
avg_loss = fluid.layers.mean(loss)
|
||||
|
||||
dy_out = avg_loss.numpy()
|
||||
|
||||
avg_loss.backward()
|
||||
sgd.minimize(avg_loss)
|
||||
fluid.dygraph.save_persistables(mnist.state_dict(),
|
||||
"save_dir")
|
||||
mnist.clear_gradients()
|
||||
|
||||
for param in mnist.parameters():
|
||||
dy_param_init_value[param.name] = param.numpy()
|
||||
|
||||
restore, _ = fluid.dygraph.load_persistables("save_dir")
|
||||
|
||||
self.assertRaises(IOError, fluid.dygraph.load_persistables,
|
||||
"not_exist_dir")
|
||||
|
||||
mnist.load_dict(restore)
|
||||
|
||||
self.assertEqual(len(dy_param_init_value), len(restore))
|
||||
for ky, value in restore.items():
|
||||
self.assertTrue(
|
||||
np.allclose(value.numpy(), dy_param_init_value[
|
||||
value.name]))
|
||||
self.assertTrue(np.isfinite(value.numpy().all()))
|
||||
self.assertFalse(np.isnan(value.numpy().any()))
|
||||
|
||||
if batch_id > 10:
|
||||
break
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
File diff suppressed because it is too large
Load Diff
@ -1,196 +0,0 @@
|
||||
# Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import unittest
|
||||
import numpy as np
|
||||
|
||||
import paddle
|
||||
import paddle.fluid as fluid
|
||||
from paddle.fluid.optimizer import SGDOptimizer, Adam
|
||||
from paddle.fluid.dygraph.nn import FC
|
||||
from paddle.fluid.dygraph.base import to_variable
|
||||
|
||||
|
||||
class MLP(fluid.Layer):
|
||||
def __init__(self, name_scope):
|
||||
super(MLP, self).__init__(name_scope)
|
||||
|
||||
self._fc1 = FC(self.full_name(), 10)
|
||||
self._fc2 = FC(self.full_name(), 10)
|
||||
|
||||
def forward(self, inputs):
|
||||
y = self._fc1(inputs)
|
||||
y = self._fc2(y)
|
||||
return y
|
||||
|
||||
|
||||
class TestImperativeOptimizerBase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.batch_num = 20
|
||||
|
||||
def get_optimizer(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _check_mlp(self):
|
||||
seed = 90
|
||||
with fluid.dygraph.guard():
|
||||
fluid.default_startup_program().random_seed = seed
|
||||
fluid.default_main_program().random_seed = seed
|
||||
|
||||
mlp = MLP('mlp')
|
||||
optimizer = self.get_optimizer()
|
||||
optimizer2 = SGDOptimizer(
|
||||
learning_rate=fluid.layers.natural_exp_decay(
|
||||
learning_rate=0.1,
|
||||
decay_steps=10000,
|
||||
decay_rate=0.5,
|
||||
staircase=True))
|
||||
train_reader = paddle.batch(
|
||||
paddle.dataset.mnist.train(), batch_size=128, drop_last=True)
|
||||
|
||||
for batch_id, data in enumerate(train_reader()):
|
||||
dy_x_data = np.array(
|
||||
[x[0].reshape(1, 28, 28) for x in data]).astype('float32')
|
||||
y_data = np.array([x[1] for x in data]).astype('int64').reshape(
|
||||
128, 1)
|
||||
|
||||
img = to_variable(dy_x_data)
|
||||
label = to_variable(y_data)
|
||||
label._stop_gradient = True
|
||||
|
||||
cost = mlp(img)
|
||||
avg_loss = fluid.layers.reduce_mean(cost)
|
||||
|
||||
avg_loss.backward()
|
||||
optimizer.minimize(avg_loss)
|
||||
optimizer2.minimize(avg_loss)
|
||||
mlp.clear_gradients()
|
||||
fluid.dygraph.save_persistables(mlp.state_dict(), "save_dir_2",
|
||||
[optimizer, optimizer2])
|
||||
if batch_id == 2:
|
||||
break
|
||||
|
||||
with fluid.dygraph.guard():
|
||||
fluid.default_startup_program().random_seed = seed
|
||||
fluid.default_main_program().random_seed = seed
|
||||
|
||||
mlp_load = MLP('mlp')
|
||||
optimizer_load1 = self.get_optimizer()
|
||||
optimizer_load2 = SGDOptimizer(
|
||||
learning_rate=fluid.layers.natural_exp_decay(
|
||||
learning_rate=0.1,
|
||||
decay_steps=10000,
|
||||
decay_rate=0.5,
|
||||
staircase=True))
|
||||
parameters, optimizers = fluid.dygraph.load_persistables(
|
||||
"save_dir_2")
|
||||
mlp_load.load_dict(parameters)
|
||||
optimizer_load1.load(optimizers)
|
||||
optimizer_load2.load(optimizers)
|
||||
|
||||
self.assertTrue(optimizer._learning_rate.__dict__ ==
|
||||
optimizer_load1._learning_rate.__dict__)
|
||||
self.assertTrue(optimizer2._learning_rate.__dict__ ==
|
||||
optimizer_load2._learning_rate.__dict__)
|
||||
|
||||
|
||||
class TestImperativeOptimizerPiecewiseDecay(TestImperativeOptimizerBase):
|
||||
def get_optimizer(self):
|
||||
bd = [3, 6, 9]
|
||||
optimizer = SGDOptimizer(learning_rate=fluid.layers.piecewise_decay(
|
||||
boundaries=bd, values=[0.1 * (0.1**i) for i in range(len(bd) + 1)]))
|
||||
return optimizer
|
||||
|
||||
def test_sgd(self):
|
||||
self._check_mlp()
|
||||
|
||||
|
||||
class TestImperativeOptimizerNaturalExpDecay(TestImperativeOptimizerBase):
|
||||
def get_optimizer(self):
|
||||
optimizer = SGDOptimizer(learning_rate=fluid.layers.natural_exp_decay(
|
||||
learning_rate=0.1,
|
||||
decay_steps=10000,
|
||||
decay_rate=0.5,
|
||||
staircase=True))
|
||||
return optimizer
|
||||
|
||||
def test_sgd(self):
|
||||
self._check_mlp()
|
||||
|
||||
|
||||
class TestImperativeOptimizerExponentialDecay(TestImperativeOptimizerBase):
|
||||
def get_optimizer(self):
|
||||
optimizer = SGDOptimizer(learning_rate=fluid.layers.exponential_decay(
|
||||
learning_rate=0.1,
|
||||
decay_steps=10000,
|
||||
decay_rate=0.5,
|
||||
staircase=True))
|
||||
return optimizer
|
||||
|
||||
def test_sgd(self):
|
||||
self._check_mlp()
|
||||
|
||||
|
||||
class TestImperativeOptimizerInverseTimeDecay(TestImperativeOptimizerBase):
|
||||
def get_optimizer(self):
|
||||
optimizer = Adam(learning_rate=fluid.layers.inverse_time_decay(
|
||||
learning_rate=0.1,
|
||||
decay_steps=10000,
|
||||
decay_rate=0.5,
|
||||
staircase=True))
|
||||
return optimizer
|
||||
|
||||
def test_adam(self):
|
||||
self._check_mlp()
|
||||
|
||||
|
||||
class TestImperativeOptimizerPolynomialDecay(TestImperativeOptimizerBase):
|
||||
def get_optimizer(self):
|
||||
optimizer = SGDOptimizer(learning_rate=fluid.layers.polynomial_decay(
|
||||
learning_rate=0.1, decay_steps=5, cycle=self.cycle))
|
||||
return optimizer
|
||||
|
||||
def test_sgd_cycle(self):
|
||||
self.cycle = True
|
||||
self._check_mlp()
|
||||
|
||||
def test_sgd(self):
|
||||
self.cycle = False
|
||||
self._check_mlp()
|
||||
|
||||
|
||||
class TestImperativeOptimizerCosineDecay(TestImperativeOptimizerBase):
|
||||
def get_optimizer(self):
|
||||
optimizer = SGDOptimizer(learning_rate=fluid.layers.cosine_decay(
|
||||
learning_rate=0.1, step_each_epoch=10000, epochs=120))
|
||||
return optimizer
|
||||
|
||||
def test_sgd(self):
|
||||
self._check_mlp()
|
||||
|
||||
|
||||
class TestImperativeOptimizerNoamDecay(TestImperativeOptimizerBase):
|
||||
def get_optimizer(self):
|
||||
optimizer = SGDOptimizer(learning_rate=fluid.layers.noam_decay(
|
||||
d_model=512, warmup_steps=8000))
|
||||
return optimizer
|
||||
|
||||
def test_sgd(self):
|
||||
self._check_mlp()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue