test_inference_model_io.py 17.1 KB
Newer Older
1
#   Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
D
dzhwinter 已提交
2
#
D
dzhwinter 已提交
3 4 5
# 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
D
dzhwinter 已提交
6
#
D
dzhwinter 已提交
7
#     http://www.apache.org/licenses/LICENSE-2.0
D
dzhwinter 已提交
8
#
D
dzhwinter 已提交
9 10 11 12 13 14
# 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.

15 16
from __future__ import print_function

D
dzhwinter 已提交
17 18
import unittest

19
import os
M
minqiyang 已提交
20
import six
21
import tempfile
D
dzhwinter 已提交
22
import numpy as np
23
import paddle.fluid.core as core
24 25
import paddle.fluid as fluid
import warnings
26

27
import paddle
28 29 30
import paddle.fluid.executor as executor
import paddle.fluid.layers as layers
import paddle.fluid.optimizer as optimizer
T
tangwei12 已提交
31
from paddle.fluid.compiler import CompiledProgram
32
from paddle.fluid.framework import Program, program_guard
33
from paddle.fluid.io import save_inference_model, load_inference_model, save_persistables
D
dzhwinter 已提交
34
from paddle.fluid.transpiler import memory_optimize
35

36
paddle.enable_static()
37 38


39
class InferModel(object):
40

41 42 43 44 45
    def __init__(self, list):
        self.program = list[0]
        self.feed_var_names = list[1]
        self.fetch_vars = list[2]

46

47
class TestBook(unittest.TestCase):
48

49
    def test_fit_line_inference_model(self):
50 51 52
        root_path = tempfile.TemporaryDirectory()
        MODEL_DIR = os.path.join(root_path.name, "inference_model")
        UNI_MODEL_DIR = os.path.join(root_path.name, "inference_model1")
53 54 55

        init_program = Program()
        program = Program()
56 57 58 59 60 61 62 63

        with program_guard(program, init_program):
            x = layers.data(name='x', shape=[2], dtype='float32')
            y = layers.data(name='y', shape=[1], dtype='float32')

            y_predict = layers.fc(input=x, size=1, act=None)

            cost = layers.square_error_cost(input=y_predict, label=y)
Y
Yu Yang 已提交
64
            avg_cost = layers.mean(cost)
65 66 67

            sgd_optimizer = optimizer.SGDOptimizer(learning_rate=0.001)
            sgd_optimizer.minimize(avg_cost, init_program)
68 69 70 71 72 73

        place = core.CPUPlace()
        exe = executor.Executor(place)

        exe.run(init_program, feed={}, fetch_list=[])

M
minqiyang 已提交
74
        for i in six.moves.xrange(100):
75 76
            tensor_x = np.array([[1, 1], [1, 2], [3, 4], [5,
                                                          2]]).astype("float32")
D
dzhwinter 已提交
77
            tensor_y = np.array([[-2], [-3], [-7], [-7]]).astype("float32")
78 79

            exe.run(program,
80 81 82 83
                    feed={
                        'x': tensor_x,
                        'y': tensor_y
                    },
84 85
                    fetch_list=[avg_cost])

86
        # Separated model and unified model
87
        save_inference_model(MODEL_DIR, ["x", "y"], [avg_cost], exe, program)
88 89 90 91 92 93
        save_inference_model(UNI_MODEL_DIR, ["x", "y"], [avg_cost], exe,
                             program, 'model', 'params')
        main_program = program.clone()._prune_with_input(
            feeded_var_names=["x", "y"], targets=[avg_cost])
        params_str = save_persistables(exe, None, main_program, None)

D
dzhwinter 已提交
94
        expected = exe.run(program,
95 96 97 98
                           feed={
                               'x': tensor_x,
                               'y': tensor_y
                           },
D
dzhwinter 已提交
99
                           fetch_list=[avg_cost])[0]
100

M
minqiyang 已提交
101
        six.moves.reload_module(executor)  # reload to build a new scope
102

103
        model_0 = InferModel(load_inference_model(MODEL_DIR, exe))
104 105
        with open(os.path.join(UNI_MODEL_DIR, 'model'), "rb") as f:
            model_str = f.read()
106
        model_1 = InferModel(
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
            load_inference_model(None, exe, model_str, params_str))

        for model in [model_0, model_1]:
            outs = exe.run(model.program,
                           feed={
                               model.feed_var_names[0]: tensor_x,
                               model.feed_var_names[1]: tensor_y
                           },
                           fetch_list=model.fetch_vars)
            actual = outs[0]

            self.assertEqual(model.feed_var_names, ["x", "y"])
            self.assertEqual(len(model.fetch_vars), 1)
            print("fetch %s" % str(model.fetch_vars[0]))
            self.assertEqual(expected, actual)

123 124
        root_path.cleanup()

125 126
        self.assertRaises(ValueError, fluid.io.load_inference_model, None, exe,
                          model_str, None)
127 128


D
dzhwinter 已提交
129
class TestSaveInferenceModel(unittest.TestCase):
130

D
dzhwinter 已提交
131
    def test_save_inference_model(self):
132 133
        root_path = tempfile.TemporaryDirectory()
        MODEL_DIR = os.path.join(root_path.name, "inference_model2")
D
dzhwinter 已提交
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
        init_program = Program()
        program = Program()

        # fake program without feed/fetch
        with program_guard(program, init_program):
            x = layers.data(name='x', shape=[2], dtype='float32')
            y = layers.data(name='y', shape=[1], dtype='float32')

            y_predict = layers.fc(input=x, size=1, act=None)

            cost = layers.square_error_cost(input=y_predict, label=y)
            avg_cost = layers.mean(cost)

        place = core.CPUPlace()
        exe = executor.Executor(place)
        exe.run(init_program, feed={}, fetch_list=[])

D
dzhwinter 已提交
151
        save_inference_model(MODEL_DIR, ["x", "y"], [avg_cost], exe, program)
152
        root_path.cleanup()
D
dzhwinter 已提交
153

154
    def test_save_inference_model_with_auc(self):
155 156
        root_path = tempfile.TemporaryDirectory()
        MODEL_DIR = os.path.join(root_path.name, "inference_model4")
157 158 159 160 161 162
        init_program = Program()
        program = Program()

        # fake program without feed/fetch
        with program_guard(program, init_program):
            x = layers.data(name='x', shape=[2], dtype='float32')
163
            y = layers.data(name='y', shape=[1], dtype='int32')
164 165 166 167 168 169 170 171 172 173 174 175 176 177
            predict = fluid.layers.fc(input=x, size=2, act='softmax')
            acc = fluid.layers.accuracy(input=predict, label=y)
            auc_var, batch_auc_var, auc_states = fluid.layers.auc(input=predict,
                                                                  label=y)
            cost = fluid.layers.cross_entropy(input=predict, label=y)
            avg_cost = fluid.layers.mean(x=cost)

        place = core.CPUPlace()
        exe = executor.Executor(place)
        exe.run(init_program, feed={}, fetch_list=[])
        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            save_inference_model(MODEL_DIR, ["x", "y"], [avg_cost], exe,
                                 program)
178
            root_path.cleanup()
179 180 181 182
            expected_warn = "please ensure that you have set the auc states to zeros before saving inference model"
            self.assertTrue(len(w) > 0)
            self.assertTrue(expected_warn == str(w[0].message))

D
dzhwinter 已提交
183

T
tangwei12 已提交
184
class TestInstance(unittest.TestCase):
185

T
tangwei12 已提交
186
    def test_save_inference_model(self):
187 188
        root_path = tempfile.TemporaryDirectory()
        MODEL_DIR = os.path.join(root_path.name, "inference_model3")
T
tangwei12 已提交
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
        init_program = Program()
        program = Program()

        # fake program without feed/fetch
        with program_guard(program, init_program):
            x = layers.data(name='x', shape=[2], dtype='float32')
            y = layers.data(name='y', shape=[1], dtype='float32')

            y_predict = layers.fc(input=x, size=1, act=None)

            cost = layers.square_error_cost(input=y_predict, label=y)
            avg_cost = layers.mean(cost)

        place = core.CPUPlace()
        exe = executor.Executor(place)
        exe.run(init_program, feed={}, fetch_list=[])

        # will print warning message

        cp_prog = CompiledProgram(program).with_data_parallel(
            loss_name=avg_cost.name)

C
chengduo 已提交
211
        save_inference_model(MODEL_DIR, ["x", "y"], [avg_cost], exe, cp_prog)
T
tangwei12 已提交
212 213
        self.assertRaises(TypeError, save_inference_model,
                          [MODEL_DIR, ["x", "y"], [avg_cost], [], cp_prog])
214
        root_path.cleanup()
T
tangwei12 已提交
215 216


217
class TestSaveInferenceModelNew(unittest.TestCase):
218

219
    def test_save_and_load_inference_model(self):
220 221
        root_path = tempfile.TemporaryDirectory()
        MODEL_DIR = os.path.join(root_path.name, "inference_model5")
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
        init_program = fluid.default_startup_program()
        program = fluid.default_main_program()

        # fake program without feed/fetch
        with program_guard(program, init_program):
            x = layers.data(name='x', shape=[2], dtype='float32')
            y = layers.data(name='y', shape=[1], dtype='float32')

            y_predict = layers.fc(input=x, size=1, act=None)

            cost = layers.square_error_cost(input=y_predict, label=y)
            avg_cost = layers.mean(cost)

            sgd_optimizer = optimizer.SGDOptimizer(learning_rate=0.001)
            sgd_optimizer.minimize(avg_cost, init_program)

        place = core.CPUPlace()
        exe = executor.Executor(place)
        exe.run(init_program, feed={}, fetch_list=[])

        tensor_x = np.array([[1, 1], [1, 2], [5, 2]]).astype("float32")
        tensor_y = np.array([[-2], [-3], [-7]]).astype("float32")
        for i in six.moves.xrange(3):
            exe.run(program,
246 247 248 249
                    feed={
                        'x': tensor_x,
                        'y': tensor_y
                    },
250 251
                    fetch_list=[avg_cost])

252 253
        self.assertRaises(ValueError, paddle.static.save_inference_model, None,
                          ['x', 'y'], [avg_cost], exe)
254
        self.assertRaises(ValueError, paddle.static.save_inference_model,
255
                          MODEL_DIR + "/", [x, y], [avg_cost], exe)
256
        self.assertRaises(ValueError, paddle.static.save_inference_model,
257
                          MODEL_DIR, ['x', 'y'], [avg_cost], exe)
258
        self.assertRaises(ValueError, paddle.static.save_inference_model,
259
                          MODEL_DIR, 'x', [avg_cost], exe)
260
        self.assertRaises(ValueError, paddle.static.save_inference_model,
261
                          MODEL_DIR, [x, y], ['avg_cost'], exe)
262
        self.assertRaises(ValueError, paddle.static.save_inference_model,
263
                          MODEL_DIR, [x, y], 'avg_cost', exe)
264 265 266 267

        model_path = MODEL_DIR + "_isdir.pdmodel"
        os.makedirs(model_path)
        self.assertRaises(ValueError, paddle.static.save_inference_model,
268
                          MODEL_DIR + "_isdir", [x, y], [avg_cost], exe)
269 270 271 272 273
        os.rmdir(model_path)

        params_path = MODEL_DIR + "_isdir.pdmodel"
        os.makedirs(params_path)
        self.assertRaises(ValueError, paddle.static.save_inference_model,
274
                          MODEL_DIR + "_isdir", [x, y], [avg_cost], exe)
275 276
        os.rmdir(params_path)

277 278
        paddle.static.io.save_inference_model(MODEL_DIR, [x, y], [avg_cost],
                                              exe)
279 280 281 282 283

        self.assertTrue(os.path.exists(MODEL_DIR + ".pdmodel"))
        self.assertTrue(os.path.exists(MODEL_DIR + ".pdiparams"))

        expected = exe.run(program,
284 285 286 287
                           feed={
                               'x': tensor_x,
                               'y': tensor_y
                           },
288 289 290 291
                           fetch_list=[avg_cost])[0]

        six.moves.reload_module(executor)  # reload to build a new scope

292 293
        self.assertRaises(ValueError, paddle.static.load_inference_model, None,
                          exe)
294
        self.assertRaises(ValueError, paddle.static.load_inference_model,
295
                          MODEL_DIR + "/", exe)
296
        self.assertRaises(ValueError, paddle.static.load_inference_model,
297
                          [MODEL_DIR], exe)
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
        self.assertRaises(ValueError,
                          paddle.static.load_inference_model,
                          MODEL_DIR,
                          exe,
                          pserver_endpoints=None)
        self.assertRaises(ValueError,
                          paddle.static.load_inference_model,
                          MODEL_DIR,
                          exe,
                          unsupported_param=None)
        self.assertRaises((TypeError, ValueError),
                          paddle.static.load_inference_model,
                          None,
                          exe,
                          model_filename="illegal",
                          params_filename="illegal")

        model = InferModel(paddle.static.io.load_inference_model(
            MODEL_DIR, exe))
317
        root_path.cleanup()
318 319 320 321 322 323 324 325 326 327 328 329

        outs = exe.run(model.program,
                       feed={
                           model.feed_var_names[0]: tensor_x,
                           model.feed_var_names[1]: tensor_y
                       },
                       fetch_list=model.fetch_vars)
        actual = outs[0]

        self.assertEqual(model.feed_var_names, ["x", "y"])
        self.assertEqual(len(model.fetch_vars), 1)
        self.assertEqual(expected, actual)
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
        # test save_to_file content type should be bytes
        self.assertRaises(ValueError, paddle.static.io.save_to_file, '', 123)
        # test _get_valid_program
        self.assertRaises(TypeError, paddle.static.io._get_valid_program, 0)
        p = Program()
        cp = CompiledProgram(p)
        paddle.static.io._get_valid_program(cp)
        self.assertTrue(paddle.static.io._get_valid_program(cp) is p)
        cp._program = None
        self.assertRaises(TypeError, paddle.static.io._get_valid_program, cp)

    def test_serialize_program_and_persistables(self):
        init_program = fluid.default_startup_program()
        program = fluid.default_main_program()

        # fake program without feed/fetch
        with program_guard(program, init_program):
            x = layers.data(name='x', shape=[2], dtype='float32')
            y = layers.data(name='y', shape=[1], dtype='float32')

            y_predict = layers.fc(input=x, size=1, act=None)

            cost = layers.square_error_cost(input=y_predict, label=y)
            avg_cost = layers.mean(cost)

            sgd_optimizer = optimizer.SGDOptimizer(learning_rate=0.001)
            sgd_optimizer.minimize(avg_cost, init_program)

        place = core.CPUPlace()
        exe = executor.Executor(place)
        exe.run(init_program, feed={}, fetch_list=[])

        tensor_x = np.array([[1, 1], [1, 2], [5, 2]]).astype("float32")
        tensor_y = np.array([[-2], [-3], [-7]]).astype("float32")
        for i in six.moves.xrange(3):
            exe.run(program,
366 367 368 369
                    feed={
                        'x': tensor_x,
                        'y': tensor_y
                    },
370
                    fetch_list=[avg_cost])
371

372 373 374 375 376 377 378 379 380 381 382
        # test if return type of serialize_program is bytes
        res1 = paddle.static.io.serialize_program([x, y], [avg_cost])
        self.assertTrue(isinstance(res1, bytes))
        # test if return type of serialize_persistables is bytes
        res2 = paddle.static.io.serialize_persistables([x, y], [avg_cost], exe)
        self.assertTrue(isinstance(res2, bytes))
        # test if variables in program is empty
        res = paddle.static.io._serialize_persistables(Program(), None)
        self.assertEqual(res, None)
        self.assertRaises(TypeError, paddle.static.io.deserialize_persistables,
                          None, None, None)
383

384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
    def test_normalize_program(self):
        init_program = fluid.default_startup_program()
        program = fluid.default_main_program()

        # fake program without feed/fetch
        with program_guard(program, init_program):
            x = layers.data(name='x', shape=[2], dtype='float32')
            y = layers.data(name='y', shape=[1], dtype='float32')

            y_predict = layers.fc(input=x, size=1, act=None)

            cost = layers.square_error_cost(input=y_predict, label=y)
            avg_cost = layers.mean(cost)

            sgd_optimizer = optimizer.SGDOptimizer(learning_rate=0.001)
            sgd_optimizer.minimize(avg_cost, init_program)

        place = core.CPUPlace()
        exe = executor.Executor(place)
        exe.run(init_program, feed={}, fetch_list=[])

        tensor_x = np.array([[1, 1], [1, 2], [5, 2]]).astype("float32")
        tensor_y = np.array([[-2], [-3], [-7]]).astype("float32")
        for i in six.moves.xrange(3):
            exe.run(program,
409 410 411 412
                    feed={
                        'x': tensor_x,
                        'y': tensor_y
                    },
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
                    fetch_list=[avg_cost])

        # test if return type of serialize_program is bytes
        res = paddle.static.normalize_program(program, [x, y], [avg_cost])
        self.assertTrue(isinstance(res, Program))
        # test program type
        self.assertRaises(TypeError, paddle.static.normalize_program, None,
                          [x, y], [avg_cost])
        # test feed_vars type
        self.assertRaises(TypeError, paddle.static.normalize_program, program,
                          'x', [avg_cost])
        # test fetch_vars type
        self.assertRaises(TypeError, paddle.static.normalize_program, program,
                          [x, y], 'avg_cost')

428

429
class TestLoadInferenceModelError(unittest.TestCase):
430

431 432 433 434 435 436 437
    def test_load_model_not_exist(self):
        place = core.CPUPlace()
        exe = executor.Executor(place)
        self.assertRaises(ValueError, load_inference_model,
                          './test_not_exist_dir', exe)


438 439
if __name__ == '__main__':
    unittest.main()