test_model.py 39.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
# copyright (c) 2020 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 os
import numpy as np
import shutil
import tempfile

L
Leo Chen 已提交
22
import paddle
23
from paddle import fluid
24
from paddle import to_tensor
25
from paddle.nn import Conv2D, Linear, ReLU, Sequential
26

27 28
from paddle import Model
from paddle.static import InputSpec
29
from paddle.nn.layer.loss import CrossEntropyLoss
30
from paddle.metric import Accuracy
31 32
from paddle.vision.datasets import MNIST
from paddle.vision.models import LeNet
Y
yukavio 已提交
33 34
import paddle.vision.models as models
import paddle.fluid.dygraph.jit as jit
35
from paddle.io import DistributedBatchSampler, Dataset
36
from paddle.hapi.model import prepare_distributed_context
37
from paddle.fluid.dygraph.dygraph_to_static.program_translator import ProgramTranslator
38 39


40
class LeNetDygraph(paddle.nn.Layer):
41

L
LielinJiang 已提交
42
    def __init__(self, num_classes=10):
43 44
        super(LeNetDygraph, self).__init__()
        self.num_classes = num_classes
45 46 47 48 49
        self.features = Sequential(Conv2D(1, 6, 3, stride=1, padding=1), ReLU(),
                                   paddle.fluid.dygraph.Pool2D(2, 'max', 2),
                                   Conv2D(6, 16, 5, stride=1, padding=0),
                                   ReLU(),
                                   paddle.fluid.dygraph.Pool2D(2, 'max', 2))
50 51

        if num_classes > 0:
52 53
            self.fc = Sequential(Linear(400, 120), Linear(120, 84),
                                 Linear(84, 10))
54 55 56 57 58 59 60 61 62 63

    def forward(self, inputs):
        x = self.features(inputs)

        if self.num_classes > 0:
            x = fluid.layers.flatten(x, 1)
            x = self.fc(x)
        return x


64
class ModelInner(paddle.nn.Layer):
65

66 67 68 69 70 71 72 73 74 75
    def __init__(self):
        super(ModelInner, self).__init__()
        self.fc = paddle.nn.Linear(3, 4)

    def forward(self, x):
        y = self.fc(x)
        return y, 0


class ModelOutter(paddle.nn.Layer):
76

77 78 79 80 81 82 83 84 85 86 87
    def __init__(self):
        super(ModelOutter, self).__init__()
        self.module1 = ModelInner()
        self.module2 = paddle.nn.Linear(4, 5)

    def forward(self, x):
        y, dummpy = self.module1(x)
        y = self.module2(y)
        return y, 3


88
class LeNetListInput(paddle.nn.Layer):
89

90 91 92 93 94 95
    def __init__(self, num_classes=10):
        super(LeNetListInput, self).__init__()
        self.num_classes = num_classes
        self.cov = Conv2D(1, 6, 3, stride=1, padding=1)
        for param in self.cov.parameters():
            param.trainable = False
96 97 98 99 100
        self.features = Sequential(self.cov, ReLU(),
                                   paddle.fluid.dygraph.Pool2D(2, 'max', 2),
                                   Conv2D(6, 16, 5, stride=1, padding=0),
                                   ReLU(),
                                   paddle.fluid.dygraph.Pool2D(2, 'max', 2))
101 102

        if num_classes > 0:
103 104
            self.fc = Sequential(Linear(400, 120), Linear(120, 84),
                                 Linear(84, 10))
105

106 107 108 109 110 111 112 113 114 115 116
    def forward(self, inputs):
        x = inputs[0]
        x = self.features(x)

        if self.num_classes > 0:
            x = paddle.flatten(x, 1)
            x = self.fc(x + inputs[1])
        return x


class LeNetDictInput(LeNetDygraph):
117

118 119 120 121 122 123 124 125 126
    def forward(self, inputs):
        x = self.features(inputs['x1'])

        if self.num_classes > 0:
            x = paddle.flatten(x, 1)
            x = self.fc(x + inputs['x2'])
        return x


127
class MnistDataset(MNIST):
128

129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
    def __init__(self, mode, return_label=True, sample_num=None):
        super(MnistDataset, self).__init__(mode=mode)
        self.return_label = return_label
        if sample_num:
            self.images = self.images[:sample_num]
            self.labels = self.labels[:sample_num]

    def __getitem__(self, idx):
        img, label = self.images[idx], self.labels[idx]
        img = np.reshape(img, [1, 28, 28])
        if self.return_label:
            return img, np.array(self.labels[idx]).astype('int64')
        return img,

    def __len__(self):
        return len(self.images)


def compute_acc(pred, label):
    pred = np.argmax(pred, -1)
    label = np.array(label)
    correct = pred[:, np.newaxis] == label
    return np.sum(correct) / correct.shape[0]


def dynamic_train(model, dataloader):
155 156
    optim = fluid.optimizer.Adam(learning_rate=0.001,
                                 parameter_list=model.parameters())
157 158 159
    model.train()
    for inputs, labels in dataloader:
        outputs = model(inputs)
160
        loss = CrossEntropyLoss(reduction="sum")(outputs, labels)
161 162 163 164 165 166 167 168 169 170 171 172 173
        avg_loss = fluid.layers.reduce_sum(loss)
        avg_loss.backward()
        optim.minimize(avg_loss)
        model.clear_gradients()


def dynamic_evaluate(model, dataloader):
    with fluid.dygraph.no_grad():
        model.eval()
        cnt = 0
        for inputs, labels in dataloader:
            outputs = model(inputs)

174 175 176
            cnt += (np.argmax(
                outputs.numpy(),
                -1)[:, np.newaxis] == labels.numpy()).astype('int').sum()
177 178 179 180 181 182 183

    return cnt / len(dataloader.dataset)


@unittest.skipIf(not fluid.is_compiled_with_cuda(),
                 'CPU testing is not supported')
class TestModel(unittest.TestCase):
184

185 186 187
    @classmethod
    def setUpClass(cls):
        if not fluid.is_compiled_with_cuda():
J
Jiangxinz 已提交
188
            cls().skipTest('module not tested when ONLY_CPU compling')
189
        cls.device = paddle.set_device('gpu')
190 191 192 193 194
        fluid.enable_dygraph(cls.device)

        sp_num = 1280
        cls.train_dataset = MnistDataset(mode='train', sample_num=sp_num)
        cls.val_dataset = MnistDataset(mode='test', sample_num=sp_num)
195 196 197 198 199 200 201 202 203 204 205 206 207
        cls.test_dataset = MnistDataset(mode='test',
                                        return_label=False,
                                        sample_num=sp_num)

        cls.train_loader = fluid.io.DataLoader(cls.train_dataset,
                                               places=cls.device,
                                               batch_size=64)
        cls.val_loader = fluid.io.DataLoader(cls.val_dataset,
                                             places=cls.device,
                                             batch_size=64)
        cls.test_loader = fluid.io.DataLoader(cls.test_dataset,
                                              places=cls.device,
                                              batch_size=64)
208 209

        seed = 333
C
cnn 已提交
210
        paddle.seed(seed)
L
Leo Chen 已提交
211
        paddle.framework.random._manual_program_seed(seed)
212 213 214 215 216 217 218

        dy_lenet = LeNetDygraph()
        cls.init_param = dy_lenet.state_dict()
        dynamic_train(dy_lenet, cls.train_loader)

        cls.acc1 = dynamic_evaluate(dy_lenet, cls.val_loader)

219 220
        cls.inputs = [InputSpec([-1, 1, 28, 28], 'float32', 'image')]
        cls.labels = [InputSpec([None, 1], 'int64', 'label')]
221

222 223 224
        cls.save_dir = os.path.join(tempfile.mkdtemp(), '.cache_test_model')
        if not os.path.exists(cls.save_dir):
            os.makedirs(cls.save_dir)
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
        cls.weight_path = os.path.join(cls.save_dir, 'lenet')
        fluid.dygraph.save_dygraph(dy_lenet.state_dict(), cls.weight_path)

        fluid.disable_dygraph()

    @classmethod
    def tearDownClass(cls):
        shutil.rmtree(cls.save_dir)

    def test_fit_dygraph(self):
        self.fit(True)

    def test_fit_static(self):
        self.fit(False)

240 241 242 243 244 245
    def test_fit_dynamic_with_tuple_input(self):
        self.fit_with_tuple_input(True)

    def test_fit_static_with_tuple_input(self):
        self.fit_with_tuple_input(False)

246 247 248 249 250 251
    def test_fit_dynamic_with_rank(self):
        self.fit(True, 2, 0)

    def test_fit_static_with_rank(self):
        self.fit(False, 2, 0)

252 253 254 255 256 257
    def test_fit_dynamic_with_num_iters(self):
        self.fit(True, num_iters=1)

    def test_fit_static_with_num_iters(self):
        self.fit(False, num_iters=1)

258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
    def test_evaluate_dygraph(self):
        self.evaluate(True)

    def test_evaluate_static(self):
        self.evaluate(False)

    def test_predict_dygraph(self):
        self.predict(True)

    def test_predict_static(self):
        self.predict(False)

    def test_prepare_context(self):
        prepare_distributed_context()

273
    def fit(self, dynamic, num_replicas=None, rank=None, num_iters=None):
274 275
        fluid.enable_dygraph(self.device) if dynamic else None
        seed = 333
C
cnn 已提交
276
        paddle.seed(seed)
L
Leo Chen 已提交
277
        paddle.framework.random._manual_program_seed(seed)
278

L
LielinJiang 已提交
279
        net = LeNet()
280 281
        optim_new = fluid.optimizer.Adam(learning_rate=0.001,
                                         parameter_list=net.parameters())
282
        model = Model(net, inputs=self.inputs, labels=self.labels)
283 284 285
        model.prepare(optim_new,
                      loss=CrossEntropyLoss(reduction="sum"),
                      metrics=Accuracy())
286 287 288 289 290
        model.fit(self.train_dataset, batch_size=64, shuffle=False)

        result = model.evaluate(self.val_dataset, batch_size=64)
        np.testing.assert_allclose(result['acc'], self.acc1)

291 292 293 294 295
        model.fit(self.train_dataset,
                  batch_size=64,
                  shuffle=False,
                  num_iters=num_iters)

296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
        result = model.evaluate(self.val_dataset,
                                batch_size=64,
                                num_iters=num_iters)

        train_sampler = DistributedBatchSampler(self.train_dataset,
                                                batch_size=64,
                                                shuffle=False,
                                                num_replicas=num_replicas,
                                                rank=rank)
        val_sampler = DistributedBatchSampler(self.val_dataset,
                                              batch_size=64,
                                              shuffle=False,
                                              num_replicas=num_replicas,
                                              rank=rank)

        train_loader = fluid.io.DataLoader(self.train_dataset,
                                           batch_sampler=train_sampler,
                                           places=self.device,
                                           return_list=True)

        val_loader = fluid.io.DataLoader(self.val_dataset,
                                         batch_sampler=val_sampler,
                                         places=self.device,
                                         return_list=True)
320 321 322 323 324 325 326 327 328 329 330

        model.fit(train_loader, val_loader)
        fluid.disable_dygraph() if dynamic else None

    def fit_with_tuple_input(self, dynamic, num_replicas=None, rank=None):
        fluid.enable_dygraph(self.device) if dynamic else None
        seed = 333
        paddle.seed(seed)
        paddle.framework.random._manual_program_seed(seed)

        net = LeNet()
331 332
        optim_new = fluid.optimizer.Adam(learning_rate=0.001,
                                         parameter_list=net.parameters())
333
        model = Model(net, inputs=tuple(self.inputs), labels=tuple(self.labels))
334 335 336
        model.prepare(optim_new,
                      loss=CrossEntropyLoss(reduction="sum"),
                      metrics=Accuracy())
337 338 339 340 341
        model.fit(self.train_dataset, batch_size=64, shuffle=False)

        result = model.evaluate(self.val_dataset, batch_size=64)
        np.testing.assert_allclose(result['acc'], self.acc1)

342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
        train_sampler = DistributedBatchSampler(self.train_dataset,
                                                batch_size=64,
                                                shuffle=False,
                                                num_replicas=num_replicas,
                                                rank=rank)
        val_sampler = DistributedBatchSampler(self.val_dataset,
                                              batch_size=64,
                                              shuffle=False,
                                              num_replicas=num_replicas,
                                              rank=rank)

        train_loader = fluid.io.DataLoader(self.train_dataset,
                                           batch_sampler=train_sampler,
                                           places=self.device,
                                           return_list=True)

        val_loader = fluid.io.DataLoader(self.val_dataset,
                                         batch_sampler=val_sampler,
                                         places=self.device,
                                         return_list=True)
362 363 364 365 366 367

        model.fit(train_loader, val_loader)
        fluid.disable_dygraph() if dynamic else None

    def evaluate(self, dynamic):
        fluid.enable_dygraph(self.device) if dynamic else None
368 369
        model = Model(LeNet(), self.inputs, self.labels)
        model.prepare(metrics=Accuracy())
370 371 372 373
        model.load(self.weight_path)
        result = model.evaluate(self.val_dataset, batch_size=64)
        np.testing.assert_allclose(result['acc'], self.acc1)

374 375 376
        sampler = DistributedBatchSampler(self.val_dataset,
                                          batch_size=64,
                                          shuffle=False)
377

378 379 380 381
        val_loader = fluid.io.DataLoader(self.val_dataset,
                                         batch_sampler=sampler,
                                         places=self.device,
                                         return_list=True)
382 383 384 385 386 387 388

        model.evaluate(val_loader)

        fluid.disable_dygraph() if dynamic else None

    def predict(self, dynamic):
        fluid.enable_dygraph(self.device) if dynamic else None
389 390
        model = Model(LeNet(), self.inputs)
        model.prepare()
391
        model.load(self.weight_path)
392 393 394
        output = model.predict(self.test_dataset,
                               batch_size=64,
                               stack_outputs=True)
395 396 397 398 399
        np.testing.assert_equal(output[0].shape[0], len(self.test_dataset))

        acc = compute_acc(output[0], self.val_dataset.labels)
        np.testing.assert_allclose(acc, self.acc1)

400 401 402
        sampler = DistributedBatchSampler(self.test_dataset,
                                          batch_size=64,
                                          shuffle=False)
403

404 405 406 407
        test_loader = fluid.io.DataLoader(self.test_dataset,
                                          batch_sampler=sampler,
                                          places=self.device,
                                          return_list=True)
408 409 410 411 412

        model.evaluate(test_loader)

        fluid.disable_dygraph() if dynamic else None

413 414 415 416 417 418
    def test_predict_without_inputs(self):
        fluid.enable_dygraph(self.device)
        model = Model(LeNet())
        model.prepare()
        model.load(self.weight_path)
        model._inputs = None
419 420 421
        output = model.predict(self.test_dataset,
                               batch_size=64,
                               stack_outputs=True)
422 423 424
        np.testing.assert_equal(output[0].shape[0], len(self.test_dataset))
        fluid.disable_dygraph()

425 426 427
    def test_summary_gpu(self):
        paddle.disable_static(self.device)
        rnn = paddle.nn.LSTM(16, 32, 2)
428 429
        params_info = paddle.summary(rnn, [(-1, 23, 16),
                                           ((2, None, 32), (2, -1, 32))])
430

431

432
class MyModel(paddle.nn.Layer):
433

L
LielinJiang 已提交
434
    def __init__(self):
435
        super(MyModel, self).__init__()
436
        self._fc = Linear(20, 10)
437 438 439 440 441 442

    def forward(self, x):
        y = self._fc(x)
        return y


443
class MyDataset(Dataset):
444

445 446 447 448 449 450 451 452
    def __getitem__(self, idx):
        return np.random.random(size=(20,)).astype(np.float32), \
               np.random.randint(0, 10, size=(1,)).astype(np.int64)

    def __len__(self):
        return 40


453
class TestModelFunction(unittest.TestCase):
454

455
    def set_seed(self, seed=1024):
C
cnn 已提交
456
        paddle.seed(seed)
L
Leo Chen 已提交
457
        paddle.framework.random._manual_program_seed(seed)
458 459 460 461 462 463 464 465 466

    def test_train_batch(self, dynamic=True):
        dim = 20
        data = np.random.random(size=(4, dim)).astype(np.float32)
        label = np.random.randint(0, 10, size=(4, 1)).astype(np.int64)

        def get_expect():
            fluid.enable_dygraph(fluid.CPUPlace())
            self.set_seed()
L
LielinJiang 已提交
467
            m = MyModel()
468 469 470
            optim = fluid.optimizer.SGD(learning_rate=0.001,
                                        parameter_list=m.parameters())
            m.train()
471 472
            output = m(to_tensor(data))
            loss = CrossEntropyLoss(reduction='sum')(output, to_tensor(label))
473 474 475 476 477 478 479 480 481
            avg_loss = fluid.layers.reduce_sum(loss)
            avg_loss.backward()
            optim.minimize(avg_loss)
            m.clear_gradients()
            fluid.disable_dygraph()
            return avg_loss.numpy()

        ref = get_expect()
        for dynamic in [True, False]:
482
            device = paddle.set_device('cpu')
483 484 485
            fluid.enable_dygraph(device) if dynamic else None
            self.set_seed()

L
LielinJiang 已提交
486
            net = MyModel()
487
            optim2 = fluid.optimizer.SGD(learning_rate=0.001,
488
                                         parameter_list=net.parameters())
489

490 491
            inputs = [InputSpec([None, dim], 'float32', 'x')]
            labels = [InputSpec([None, 1], 'int64', 'label')]
492
            model = Model(net, inputs, labels)
493
            model.prepare(optim2, loss=CrossEntropyLoss(reduction="sum"))
494 495 496 497
            loss, = model.train_batch([data], [label])
            np.testing.assert_allclose(loss.flatten(), ref.flatten())
            fluid.disable_dygraph() if dynamic else None

498
    def test_test_batch(self):
499 500 501 502 503 504 505 506
        dim = 20
        data = np.random.random(size=(4, dim)).astype(np.float32)

        def get_expect():
            fluid.enable_dygraph(fluid.CPUPlace())
            self.set_seed()
            m = MyModel()
            m.eval()
507
            output = m(to_tensor(data))
508 509 510 511 512
            fluid.disable_dygraph()
            return output.numpy()

        ref = get_expect()
        for dynamic in [True, False]:
513
            device = paddle.set_device('cpu')
514 515
            fluid.enable_dygraph(device) if dynamic else None
            self.set_seed()
516
            net = MyModel()
517
            inputs = [InputSpec([None, dim], 'float32', 'x')]
518 519
            model = Model(net, inputs)
            model.prepare()
520
            out, = model.predict_batch([data])
521

522
            np.testing.assert_allclose(out, ref, rtol=1e-6)
523 524 525
            fluid.disable_dygraph() if dynamic else None

    def test_save_load(self):
526 527 528
        path = os.path.join(tempfile.mkdtemp(), '.cache_test_save_load')
        if not os.path.exists(path):
            os.makedirs(path)
529
        for dynamic in [True, False]:
530
            device = paddle.set_device('cpu')
531
            fluid.enable_dygraph(device) if dynamic else None
L
LielinJiang 已提交
532
            net = MyModel()
533 534
            inputs = [InputSpec([None, 20], 'float32', 'x')]
            labels = [InputSpec([None, 1], 'int64', 'label')]
535
            optim = fluid.optimizer.SGD(learning_rate=0.001,
536 537
                                        parameter_list=net.parameters())
            model = Model(net, inputs, labels)
538 539
            model.prepare(optimizer=optim,
                          loss=CrossEntropyLoss(reduction="sum"))
540 541
            model.save(path)
            model.load(path)
542
            fluid.disable_dygraph() if dynamic else None
543
        shutil.rmtree(path)
544

545 546
    def test_dynamic_load(self):
        mnist_data = MnistDataset(mode='train')
547 548 549 550 551

        path = os.path.join(tempfile.mkdtemp(), '.cache_dynamic_load')
        if not os.path.exists(path):
            os.makedirs(path)

552 553 554 555 556 557
        for new_optimizer in [True, False]:
            paddle.disable_static()
            net = LeNet()
            inputs = [InputSpec([None, 1, 28, 28], 'float32', 'x')]
            labels = [InputSpec([None, 1], 'int64', 'label')]
            if new_optimizer:
558 559
                optim = paddle.optimizer.Adam(learning_rate=0.001,
                                              parameters=net.parameters())
560
            else:
561 562
                optim = fluid.optimizer.Adam(learning_rate=0.001,
                                             parameter_list=net.parameters())
563
            model = Model(net, inputs, labels)
564 565
            model.prepare(optimizer=optim,
                          loss=CrossEntropyLoss(reduction="sum"))
566
            model.fit(mnist_data, batch_size=64, verbose=0)
567 568
            model.save(path)
            model.load(path)
569
            paddle.enable_static()
570
        shutil.rmtree(path)
571

572
    def test_dynamic_save_static_load(self):
573 574 575 576
        path = os.path.join(tempfile.mkdtemp(),
                            '.cache_dynamic_save_static_load')
        if not os.path.exists(path):
            os.makedirs(path)
577
        # dynamic saving
578
        device = paddle.set_device('cpu')
579
        fluid.enable_dygraph(device)
580
        model = Model(MyModel())
581 582
        optim = fluid.optimizer.SGD(learning_rate=0.001,
                                    parameter_list=model.parameters())
583
        model.prepare(optimizer=optim, loss=CrossEntropyLoss(reduction="sum"))
584
        model.save(path)
585
        fluid.disable_dygraph()
586

587 588
        inputs = [InputSpec([None, 20], 'float32', 'x')]
        labels = [InputSpec([None, 1], 'int64', 'label')]
L
LielinJiang 已提交
589
        model = Model(MyModel(), inputs, labels)
590 591
        optim = fluid.optimizer.SGD(learning_rate=0.001,
                                    parameter_list=model.parameters())
592
        model.prepare(optimizer=optim, loss=CrossEntropyLoss(reduction="sum"))
593
        model.load(path)
594 595 596
        shutil.rmtree(path)

    def test_static_save_dynamic_load(self):
597 598 599 600
        path = os.path.join(tempfile.mkdtemp(),
                            '.cache_test_static_save_dynamic_load')
        if not os.path.exists(path):
            os.makedirs(path)
L
LielinJiang 已提交
601
        net = MyModel()
602 603
        inputs = [InputSpec([None, 20], 'float32', 'x')]
        labels = [InputSpec([None, 1], 'int64', 'label')]
604
        optim = fluid.optimizer.SGD(learning_rate=0.001,
605 606
                                    parameter_list=net.parameters())
        model = Model(net, inputs, labels)
607
        model.prepare(optimizer=optim, loss=CrossEntropyLoss(reduction="sum"))
608
        model.save(path)
609

610
        device = paddle.set_device('cpu')
611 612
        fluid.enable_dygraph(device)  #if dynamic else None

L
LielinJiang 已提交
613
        net = MyModel()
614 615
        inputs = [InputSpec([None, 20], 'float32', 'x')]
        labels = [InputSpec([None, 1], 'int64', 'label')]
616
        optim = fluid.optimizer.SGD(learning_rate=0.001,
617 618
                                    parameter_list=net.parameters())
        model = Model(net, inputs, labels)
619
        model.prepare(optimizer=optim, loss=CrossEntropyLoss(reduction="sum"))
620
        model.load(path)
621 622 623 624 625
        shutil.rmtree(path)
        fluid.disable_dygraph()

    def test_parameters(self):
        for dynamic in [True, False]:
626
            device = paddle.set_device('cpu')
627
            fluid.enable_dygraph(device) if dynamic else None
628
            net = MyModel()
629
            inputs = [InputSpec([None, 20], 'float32', 'x')]
630 631
            model = Model(net, inputs)
            model.prepare()
632 633 634 635 636
            params = model.parameters()
            self.assertTrue(params[0].shape[0] == 20)
            self.assertTrue(params[0].shape[1] == 10)
            fluid.disable_dygraph() if dynamic else None

L
LielinJiang 已提交
637
    def test_summary(self):
638

L
LielinJiang 已提交
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657
        def _get_param_from_state_dict(state_dict):
            params = 0
            for k, v in state_dict.items():
                params += np.prod(v.numpy().shape)
            return params

        for dynamic in [True, False]:
            device = paddle.set_device('cpu')
            fluid.enable_dygraph(device) if dynamic else None
            net = MyModel()
            inputs = [InputSpec([None, 20], 'float32', 'x')]
            model = Model(net, inputs)
            model.prepare()
            params_info = model.summary()
            gt_params = _get_param_from_state_dict(net.state_dict())

            np.testing.assert_allclose(params_info['total_params'], gt_params)
            print(params_info)

658 659
            model.summary(input_size=(20))
            model.summary(input_size=[(20)])
L
LielinJiang 已提交
660
            model.summary(input_size=(20), dtype='float32')
661

662 663 664
    def test_summary_non_tensor(self):
        paddle.summary(ModelOutter(), input_size=(-1, 3))

L
LielinJiang 已提交
665
    def test_summary_nlp(self):
666

667 668 669 670 671 672
        def _get_param_from_state_dict(state_dict):
            params = 0
            for k, v in state_dict.items():
                params += np.prod(v.numpy().shape)
            return params

L
LielinJiang 已提交
673 674 675 676 677
        nlp_net = paddle.nn.GRU(input_size=2,
                                hidden_size=3,
                                num_layers=3,
                                direction="bidirectional")
        paddle.summary(nlp_net, (1, 1, 2))
678

L
LielinJiang 已提交
679
        rnn = paddle.nn.LSTM(16, 32, 2)
680 681
        params_info = paddle.summary(rnn, [(-1, 23, 16),
                                           ((2, None, 32), (2, -1, 32))])
682 683 684 685 686 687 688 689 690 691 692 693
        gt_params = _get_param_from_state_dict(rnn.state_dict())
        np.testing.assert_allclose(params_info['total_params'], gt_params / 2.0)

        rnn = paddle.nn.GRU(16, 32, 2, direction='bidirectional')
        params_info = paddle.summary(rnn, (4, 23, 16))
        gt_params = _get_param_from_state_dict(rnn.state_dict())
        np.testing.assert_allclose(params_info['total_params'], gt_params / 2.0)

        rnn = paddle.nn.SimpleRNN(16, 32, 2, direction='bidirectional')
        params_info = paddle.summary(rnn, (4, 23, 16))
        gt_params = _get_param_from_state_dict(rnn.state_dict())
        np.testing.assert_allclose(params_info['total_params'], gt_params / 2.0)
L
LielinJiang 已提交
694

695
    def test_summary_input(self):
696 697 698 699 700 701
        paddle.enable_static()
        mymodel = MyModel()
        input_data = paddle.rand([1, 20])
        paddle.summary(mymodel, input=input_data)
        paddle.disable_static()

702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
        rnn = paddle.nn.SimpleRNN(16, 32, 2, direction='bidirectional')
        input_data = paddle.rand([4, 23, 16])
        paddle.summary(rnn, input=input_data)

        lenet_List_input = LeNetListInput()
        input_data = [paddle.rand([1, 1, 28, 28]), paddle.rand([1, 400])]
        paddle.summary(lenet_List_input, input=input_data)

        lenet_dict_input = LeNetDictInput()
        input_data = {
            'x1': paddle.rand([1, 1, 28, 28]),
            'x2': paddle.rand([1, 400])
        }
        paddle.summary(lenet_dict_input, input=input_data)

L
LielinJiang 已提交
717 718 719 720 721
    def test_summary_dtype(self):
        input_shape = (3, 1)
        net = paddle.nn.Embedding(10, 3, sparse=True)
        paddle.summary(net, input_shape, dtypes='int64')

L
LielinJiang 已提交
722 723 724
    def test_summary_error(self):
        with self.assertRaises(TypeError):
            nlp_net = paddle.nn.GRU(input_size=2, hidden_size=3, num_layers=3)
L
LielinJiang 已提交
725
            paddle.summary(nlp_net, (1, 1, '2'))
L
LielinJiang 已提交
726 727 728 729 730 731 732

        with self.assertRaises(ValueError):
            nlp_net = paddle.nn.GRU(input_size=2, hidden_size=3, num_layers=3)
            paddle.summary(nlp_net, (-1, -1))

        paddle.disable_static()
        nlp_net = paddle.nn.GRU(input_size=2, hidden_size=3, num_layers=3)
L
LielinJiang 已提交
733
        paddle.summary(nlp_net, (1, 1, 2))
L
LielinJiang 已提交
734

Y
yukavio 已提交
735
    def test_static_flops(self):
J
Jiabin Yang 已提交
736 737
        if paddle.fluid.framework._in_eager_without_dygraph_check():
            return
Y
yukavio 已提交
738 739 740 741 742 743 744 745 746 747 748 749
        paddle.disable_static()
        net = models.__dict__['mobilenet_v2'](pretrained=False)
        inputs = paddle.randn([1, 3, 224, 224])
        static_program = jit._trace(net, inputs=[inputs])[1]
        paddle.flops(static_program, [1, 3, 224, 224], print_detail=True)

    def test_dynamic_flops(self):
        net = models.__dict__['mobilenet_v2'](pretrained=False)

        def customize_dropout(m, x, y):
            m.total_ops += 0

750 751 752
        paddle.flops(net, [1, 3, 224, 224],
                     custom_ops={paddle.nn.Dropout: customize_dropout},
                     print_detail=True)
Y
yukavio 已提交
753

754
    def test_dynamic_flops_with_multiple_outputs(self):
755 756 757 758
        net = paddle.nn.MaxPool2D(kernel_size=2,
                                  stride=2,
                                  padding=0,
                                  return_mask=True)
759 760 761 762

        def customize_dropout(m, x, y):
            m.total_ops += 0

763 764 765
        paddle.flops(net, [1, 2, 32, 32],
                     custom_ops={paddle.nn.Dropout: customize_dropout},
                     print_detail=True)
766

767
    def test_export_deploy_model(self):
768
        self.set_seed()
769
        np.random.seed(201)
770 771 772 773 774 775

        save_dir = os.path.join(tempfile.mkdtemp(),
                                '.cache_test_export_deploy_model')
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)

776
        for dynamic in [True, False]:
777
            paddle.disable_static() if dynamic else None
778 779
            prog_translator = ProgramTranslator()
            prog_translator.enable(False) if not dynamic else None
780
            net = LeNet()
781
            inputs = [InputSpec([None, 1, 28, 28], 'float32', 'x')]
782 783
            model = Model(net, inputs)
            model.prepare()
784

785 786
            tensor_img = np.array(np.random.random((1, 1, 28, 28)),
                                  dtype=np.float32)
787

788
            model.save(save_dir, training=False)
789
            ori_results = model.predict_batch(tensor_img)
790
            fluid.disable_dygraph() if dynamic else None
791

792 793
            place = fluid.CPUPlace(
            ) if not fluid.is_compiled_with_cuda() else fluid.CUDAPlace(0)
794 795 796
            new_scope = fluid.Scope()
            with fluid.scope_guard(new_scope):
                exe = fluid.Executor(place)
797 798 799
                [inference_program, feed_target_names,
                 fetch_targets] = (paddle.static.io.load_inference_model(
                     path_prefix=save_dir, executor=exe))
800 801 802
                results = exe.run(inference_program,
                                  feed={feed_target_names[0]: tensor_img},
                                  fetch_list=fetch_targets)
803 804 805 806
                np.testing.assert_allclose(results,
                                           ori_results,
                                           rtol=1e-5,
                                           atol=1e-6)
807

808
            paddle.enable_static()
809

810 811
        shutil.rmtree(save_dir)

L
LiuChiachi 已提交
812
    def test_dygraph_export_deploy_model_about_inputs(self):
J
Jiaqi Liu 已提交
813 814
        self.set_seed()
        np.random.seed(201)
815 816
        mnist_data = MnistDataset(mode='train')
        paddle.disable_static()
L
LiuChiachi 已提交
817
        # without inputs
818 819 820 821
        save_dir = os.path.join(tempfile.mkdtemp(),
                                '.cache_test_dygraph_export_deploy')
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
822
        for initial in ["fit", "train_batch", "eval_batch", "predict_batch"]:
823 824
            net = LeNet()
            model = Model(net)
825 826 827 828
            optim = fluid.optimizer.Adam(learning_rate=0.001,
                                         parameter_list=model.parameters())
            model.prepare(optimizer=optim,
                          loss=CrossEntropyLoss(reduction="sum"))
829 830 831
            if initial == "fit":
                model.fit(mnist_data, batch_size=64, verbose=0)
            else:
832 833
                img = np.array(np.random.random((1, 1, 28, 28)),
                               dtype=np.float32)
834 835 836 837 838 839
                label = np.array(np.random.rand(1, 1), dtype=np.int64)
                if initial == "train_batch":
                    model.train_batch([img], [label])
                elif initial == "eval_batch":
                    model.eval_batch([img], [label])
                else:
840
                    model.predict_batch([img])
841 842

            model.save(save_dir, training=False)
843
        shutil.rmtree(save_dir)
L
LiuChiachi 已提交
844
        # with inputs, and the type of inputs is InputSpec
845 846
        save_dir = os.path.join(tempfile.mkdtemp(),
                                '.cache_test_dygraph_export_deploy_2')
L
LiuChiachi 已提交
847 848 849 850 851
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
        net = LeNet()
        inputs = InputSpec([None, 1, 28, 28], 'float32', 'x')
        model = Model(net, inputs)
852 853
        optim = fluid.optimizer.Adam(learning_rate=0.001,
                                     parameter_list=model.parameters())
L
LiuChiachi 已提交
854 855 856
        model.prepare(optimizer=optim, loss=CrossEntropyLoss(reduction="sum"))
        model.save(save_dir, training=False)
        shutil.rmtree(save_dir)
857

L
lyuwenyu 已提交
858 859 860 861 862 863 864 865 866
    def test_accumulate(self, ):
        dim = 20
        data = np.random.random(size=(4, dim)).astype(np.float32)
        label = np.random.randint(0, 10, size=(4, 1)).astype(np.int64)
        net = MyModel()
        optim = fluid.optimizer.SGD(learning_rate=0.001,
                                    parameter_list=net.parameters())
        inputs = [InputSpec([None, dim], 'float32', 'x')]
        labels = [InputSpec([None, 1], 'int64', 'label')]
L
lyuwenyu 已提交
867

L
lyuwenyu 已提交
868 869
        for amp_cfg in [None, 'O1']:
            model = Model(net, inputs, labels)
870 871 872
            model.prepare(optim,
                          loss=CrossEntropyLoss(reduction="sum"),
                          amp_configs=amp_cfg)
L
lyuwenyu 已提交
873 874 875 876 877 878 879 880
            losses, grads = [], []
            for stat in [False, False, True]:
                loss, = model.train_batch([data], [label], update=stat)
                losses.append(loss)
                grads.append([p.grad.numpy() for p in net.parameters()])

            for grad1, grad2, grad3 in zip(*grads):
                np.testing.assert_almost_equal(grad1 * 2, grad2, decimal=4)
881 882 883
                np.testing.assert_almost_equal(grad3,
                                               np.zeros_like(grad3),
                                               decimal=4)
L
lyuwenyu 已提交
884 885 886

            np.testing.assert_almost_equal(losses[0], losses[1], decimal=4)
            np.testing.assert_almost_equal(losses[0], losses[2], decimal=4)
L
lyuwenyu 已提交
887

888

889
class TestModelWithLRScheduler(unittest.TestCase):
890

891 892 893 894
    def test_fit_by_step(self):
        base_lr = 1e-3
        boundaries = [5, 8]

895 896 897 898 899 900 901 902 903 904 905 906
        def make_optimizer(parameters=None):
            momentum = 0.9
            weight_decay = 5e-4
            values = [base_lr * (0.1**i) for i in range(len(boundaries) + 1)]
            learning_rate = paddle.optimizer.lr.PiecewiseDecay(
                boundaries=boundaries, values=values)
            learning_rate = paddle.optimizer.lr.LinearWarmup(
                learning_rate=learning_rate,
                warmup_steps=4,
                start_lr=base_lr / 5.,
                end_lr=base_lr,
                verbose=True)
907 908 909 910
            optimizer = paddle.optimizer.Momentum(learning_rate=learning_rate,
                                                  weight_decay=weight_decay,
                                                  momentum=momentum,
                                                  parameters=parameters)
911 912
            return optimizer

913
        # dynamic test
914 915 916 917 918 919 920 921 922 923 924 925
        device = paddle.set_device('cpu')
        fluid.enable_dygraph(device)
        net = MyModel()
        inputs = [InputSpec([None, 20], 'float32', 'x')]
        labels = [InputSpec([None, 1], 'int64', 'label')]
        optim = make_optimizer(net.parameters())
        model = Model(net, inputs, labels)
        model.prepare(optimizer=optim, loss=CrossEntropyLoss(reduction="sum"))

        dataset = MyDataset()
        model.fit(dataset, dataset, batch_size=4, epochs=10, num_workers=0)

926 927
        np.testing.assert_allclose(model._optimizer._learning_rate.last_lr,
                                   base_lr * (0.1**len(boundaries)))
928
        # static test
929 930
        paddle.enable_static()

931 932 933 934 935 936 937 938 939 940
        net = MyModel()
        inputs = [InputSpec([None, 20], 'float32', 'x')]
        labels = [InputSpec([None, 1], 'int64', 'label')]
        optim = make_optimizer(net.parameters())
        model = Model(net, inputs, labels)
        model.prepare(optimizer=optim, loss=CrossEntropyLoss(reduction="sum"))

        dataset = MyDataset()
        model.fit(dataset, dataset, batch_size=4, epochs=10, num_workers=0)

941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961
        np.testing.assert_allclose(model._optimizer._learning_rate.last_lr,
                                   base_lr * (0.1**len(boundaries)))

    def test_fit_by_epoch(self):
        base_lr = 1e-3
        boundaries = [5, 8]
        epochs = 10
        wamup_epochs = 4

        def make_optimizer(parameters=None):
            momentum = 0.9
            weight_decay = 5e-4
            values = [base_lr * (0.1**i) for i in range(len(boundaries) + 1)]
            learning_rate = paddle.optimizer.lr.PiecewiseDecay(
                boundaries=boundaries, values=values)
            learning_rate = paddle.optimizer.lr.LinearWarmup(
                learning_rate=learning_rate,
                warmup_steps=wamup_epochs,
                start_lr=base_lr / 5.,
                end_lr=base_lr,
                verbose=True)
962 963 964 965
            optimizer = paddle.optimizer.Momentum(learning_rate=learning_rate,
                                                  weight_decay=weight_decay,
                                                  momentum=momentum,
                                                  parameters=parameters)
966 967 968 969 970 971 972 973 974 975 976 977 978 979
            return optimizer

        # dynamic test
        device = paddle.set_device('cpu')
        fluid.enable_dygraph(device)
        net = MyModel()
        inputs = [InputSpec([None, 20], 'float32', 'x')]
        labels = [InputSpec([None, 1], 'int64', 'label')]
        optim = make_optimizer(net.parameters())
        model = Model(net, inputs, labels)
        model.prepare(optimizer=optim, loss=CrossEntropyLoss(reduction="sum"))

        dataset = MyDataset()

980 981
        lr_scheduler_callback = paddle.callbacks.LRScheduler(by_step=False,
                                                             by_epoch=True)
982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008

        model.fit(dataset,
                  dataset,
                  batch_size=4,
                  epochs=epochs,
                  num_workers=0,
                  callbacks=lr_scheduler_callback)

        cnt = 0
        for b in boundaries:
            if b + wamup_epochs <= epochs:
                cnt += 1

        np.testing.assert_allclose(model._optimizer._learning_rate.last_lr,
                                   base_lr * (0.1**cnt))
        # static test
        paddle.enable_static()

        net = MyModel()
        inputs = [InputSpec([None, 20], 'float32', 'x')]
        labels = [InputSpec([None, 1], 'int64', 'label')]
        optim = make_optimizer(net.parameters())
        model = Model(net, inputs, labels)
        model.prepare(optimizer=optim, loss=CrossEntropyLoss(reduction="sum"))

        dataset = MyDataset()

1009 1010
        lr_scheduler_callback = paddle.callbacks.LRScheduler(by_step=False,
                                                             by_epoch=True)
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026

        model.fit(dataset,
                  dataset,
                  batch_size=4,
                  epochs=epochs,
                  num_workers=0,
                  callbacks=lr_scheduler_callback)

        cnt = 0
        for b in boundaries:
            if b + wamup_epochs <= epochs:
                cnt += 1

        np.testing.assert_allclose(model._optimizer._learning_rate.last_lr,
                                   base_lr * (0.1**cnt))

1027

1028
class TestRaiseError(unittest.TestCase):
1029

1030
    def test_input_without_name(self):
L
LielinJiang 已提交
1031
        net = MyModel()
1032 1033
        inputs = [InputSpec([None, 10], 'float32')]
        labels = [InputSpec([None, 1], 'int64', 'label')]
1034 1035 1036
        with self.assertRaises(ValueError):
            model = Model(net, inputs, labels)

1037 1038 1039 1040 1041 1042 1043 1044 1045
    def test_static_without_inputs(self):
        paddle.enable_static()
        net = MyModel()
        with self.assertRaises(TypeError):
            model = Model(net)

    def test_save_infer_model_without_inputs_and_run_in_dygraph(self):
        paddle.disable_static()
        net = MyModel()
1046
        save_dir = os.path.join(tempfile.mkdtemp(), '.cache_test_save_infer')
1047 1048 1049 1050 1051 1052
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
        with self.assertRaises(RuntimeError):
            model = Model(net)
            model.save(save_dir, training=False)
        paddle.enable_static()
1053
        shutil.rmtree(save_dir)
1054

1055 1056 1057 1058 1059 1060 1061
    def test_save_infer_model_without_file_prefix(self):
        paddle.enable_static()
        net = LeNet()
        inputs = [InputSpec([None, 1, 28, 28], 'float32', 'x')]
        model = Model(net, inputs)
        model.prepare()
        path = ""
1062 1063
        tensor_img = np.array(np.random.random((1, 1, 28, 28)),
                              dtype=np.float32)
1064 1065 1066
        with self.assertRaises(ValueError):
            model.save(path, training=False)

1067

1068 1069
if __name__ == '__main__':
    unittest.main()