test_model.py 37.8 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
import paddle.vision.models as models
34
import paddle.jit as jit
35
from paddle.io import DistributedBatchSampler, Dataset
36
from paddle.hapi.model import prepare_distributed_context
37
from paddle.jit.dy2static.program_translator import (
38 39
    ProgramTranslator,
)
40 41


42
class LeNetDygraph(paddle.nn.Layer):
L
LielinJiang 已提交
43
    def __init__(self, num_classes=10):
44
        super().__init__()
45
        self.num_classes = num_classes
46 47 48 49 50 51 52 53
        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),
        )
54 55

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

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

        if self.num_classes > 0:
64
            x = paddle.flatten(x, 1, -1)
65 66 67 68
            x = self.fc(x)
        return x


69 70
class ModelInner(paddle.nn.Layer):
    def __init__(self):
71
        super().__init__()
72 73 74 75 76 77 78 79 80
        self.fc = paddle.nn.Linear(3, 4)

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


class ModelOutter(paddle.nn.Layer):
    def __init__(self):
81
        super().__init__()
82 83 84 85 86 87 88 89 90
        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


91 92
class LeNetListInput(paddle.nn.Layer):
    def __init__(self, num_classes=10):
93
        super().__init__()
94 95 96 97
        self.num_classes = num_classes
        self.cov = Conv2D(1, 6, 3, stride=1, padding=1)
        for param in self.cov.parameters():
            param.trainable = False
98 99 100 101 102 103 104 105
        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),
        )
106 107

        if num_classes > 0:
108 109 110
            self.fc = Sequential(
                Linear(400, 120), Linear(120, 84), Linear(84, 10)
            )
111

112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
    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):
    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


132 133
class MnistDataset(MNIST):
    def __init__(self, mode, return_label=True, sample_num=None):
134
        super().__init__(mode=mode)
135 136 137 138 139 140 141 142 143 144
        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')
145
        return (img,)
146 147 148 149 150 151 152 153 154 155 156 157 158

    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):
159 160 161
    optim = fluid.optimizer.Adam(
        learning_rate=0.001, parameter_list=model.parameters()
    )
162 163 164
    model.train()
    for inputs, labels in dataloader:
        outputs = model(inputs)
165
        loss = CrossEntropyLoss(reduction="sum")(outputs, labels)
166
        avg_loss = paddle.sum(loss)
167 168 169 170 171 172 173 174 175 176 177 178
        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)

179 180 181 182 183 184 185 186
            cnt += (
                (
                    np.argmax(outputs.numpy(), -1)[:, np.newaxis]
                    == labels.numpy()
                )
                .astype('int')
                .sum()
            )
187 188 189 190

    return cnt / len(dataloader.dataset)


191 192 193
@unittest.skipIf(
    not fluid.is_compiled_with_cuda(), 'CPU testing is not supported'
)
194 195 196 197
class TestModel(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        if not fluid.is_compiled_with_cuda():
J
Jiangxinz 已提交
198
            cls().skipTest('module not tested when ONLY_CPU compling')
199
        cls.device = paddle.set_device('gpu')
200 201 202 203 204
        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)
205 206 207 208 209 210 211 212 213 214 215 216 217
        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
        )
218 219

        seed = 333
C
cnn 已提交
220
        paddle.seed(seed)
L
Leo Chen 已提交
221
        paddle.framework.random._manual_program_seed(seed)
222 223 224 225 226 227 228

        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)

229 230
        cls.inputs = [InputSpec([-1, 1, 28, 28], 'float32', 'image')]
        cls.labels = [InputSpec([None, 1], 'int64', 'label')]
231

232 233 234
        cls.save_dir = os.path.join(tempfile.mkdtemp(), '.cache_test_model')
        if not os.path.exists(cls.save_dir):
            os.makedirs(cls.save_dir)
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
        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)

250 251 252 253 254 255
    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)

256 257 258 259 260 261
    def test_fit_dynamic_with_rank(self):
        self.fit(True, 2, 0)

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

262 263 264 265 266 267
    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)

268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
    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()

283
    def fit(self, dynamic, num_replicas=None, rank=None, num_iters=None):
284 285
        fluid.enable_dygraph(self.device) if dynamic else None
        seed = 333
C
cnn 已提交
286
        paddle.seed(seed)
L
Leo Chen 已提交
287
        paddle.framework.random._manual_program_seed(seed)
288

L
LielinJiang 已提交
289
        net = LeNet()
290 291 292
        optim_new = fluid.optimizer.Adam(
            learning_rate=0.001, parameter_list=net.parameters()
        )
293
        model = Model(net, inputs=self.inputs, labels=self.labels)
294 295 296 297 298
        model.prepare(
            optim_new,
            loss=CrossEntropyLoss(reduction="sum"),
            metrics=Accuracy(),
        )
299 300 301 302 303
        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)

304 305 306 307 308 309 310 311 312 313 314
        model.fit(
            self.train_dataset,
            batch_size=64,
            shuffle=False,
            num_iters=num_iters,
        )

        result = model.evaluate(
            self.val_dataset, batch_size=64, num_iters=num_iters
        )

315 316
        model.fit(self.train_dataset, batch_size=(64, 64), shuffle=False)

317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
        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,
        )
345 346 347 348 349 350 351 352 353 354 355

        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()
356 357 358
        optim_new = fluid.optimizer.Adam(
            learning_rate=0.001, parameter_list=net.parameters()
        )
359
        model = Model(net, inputs=tuple(self.inputs), labels=tuple(self.labels))
360 361 362 363 364
        model.prepare(
            optim_new,
            loss=CrossEntropyLoss(reduction="sum"),
            metrics=Accuracy(),
        )
365 366 367 368 369
        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)

370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
        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,
        )
398 399 400 401 402 403

        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
404 405
        model = Model(LeNet(), self.inputs, self.labels)
        model.prepare(metrics=Accuracy())
406 407 408 409
        model.load(self.weight_path)
        result = model.evaluate(self.val_dataset, batch_size=64)
        np.testing.assert_allclose(result['acc'], self.acc1)

410 411 412
        sampler = DistributedBatchSampler(
            self.val_dataset, batch_size=64, shuffle=False
        )
413

414 415 416 417 418 419
        val_loader = fluid.io.DataLoader(
            self.val_dataset,
            batch_sampler=sampler,
            places=self.device,
            return_list=True,
        )
420 421 422 423 424 425 426

        model.evaluate(val_loader)

        fluid.disable_dygraph() if dynamic else None

    def predict(self, dynamic):
        fluid.enable_dygraph(self.device) if dynamic else None
427 428
        model = Model(LeNet(), self.inputs)
        model.prepare()
429
        model.load(self.weight_path)
430 431 432
        output = model.predict(
            self.test_dataset, batch_size=64, stack_outputs=True
        )
433 434 435 436 437
        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)

438 439 440
        sampler = DistributedBatchSampler(
            self.test_dataset, batch_size=64, shuffle=False
        )
441

442 443 444 445 446 447
        test_loader = fluid.io.DataLoader(
            self.test_dataset,
            batch_sampler=sampler,
            places=self.device,
            return_list=True,
        )
448 449 450 451 452

        model.evaluate(test_loader)

        fluid.disable_dygraph() if dynamic else None

453 454 455 456 457 458
    def test_predict_without_inputs(self):
        fluid.enable_dygraph(self.device)
        model = Model(LeNet())
        model.prepare()
        model.load(self.weight_path)
        model._inputs = None
459 460 461
        output = model.predict(
            self.test_dataset, batch_size=64, stack_outputs=True
        )
462 463 464
        np.testing.assert_equal(output[0].shape[0], len(self.test_dataset))
        fluid.disable_dygraph()

465 466 467
    def test_summary_gpu(self):
        paddle.disable_static(self.device)
        rnn = paddle.nn.LSTM(16, 32, 2)
468 469 470
        params_info = paddle.summary(
            rnn, [(-1, 23, 16), ((2, None, 32), (2, -1, 32))]
        )
471

472

473
class MyModel(paddle.nn.Layer):
L
LielinJiang 已提交
474
    def __init__(self):
475
        super().__init__()
476
        self._fc = Linear(20, 10)
477 478 479 480 481 482

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


483 484
class MyDataset(Dataset):
    def __getitem__(self, idx):
485 486 487
        return np.random.random(size=(20,)).astype(
            np.float32
        ), np.random.randint(0, 10, size=(1,)).astype(np.int64)
488 489 490 491 492

    def __len__(self):
        return 40


493 494
class TestModelFunction(unittest.TestCase):
    def set_seed(self, seed=1024):
C
cnn 已提交
495
        paddle.seed(seed)
L
Leo Chen 已提交
496
        paddle.framework.random._manual_program_seed(seed)
497 498 499 500 501 502 503 504 505

    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 已提交
506
            m = MyModel()
507 508 509
            optim = fluid.optimizer.SGD(
                learning_rate=0.001, parameter_list=m.parameters()
            )
510
            m.train()
511 512
            output = m(to_tensor(data))
            loss = CrossEntropyLoss(reduction='sum')(output, to_tensor(label))
513
            avg_loss = paddle.sum(loss)
514 515 516 517 518 519 520 521
            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]:
522
            device = paddle.set_device('cpu')
523 524 525
            fluid.enable_dygraph(device) if dynamic else None
            self.set_seed()

L
LielinJiang 已提交
526
            net = MyModel()
527 528 529
            optim2 = fluid.optimizer.SGD(
                learning_rate=0.001, parameter_list=net.parameters()
            )
530

531 532
            inputs = [InputSpec([None, dim], 'float32', 'x')]
            labels = [InputSpec([None, 1], 'int64', 'label')]
533
            model = Model(net, inputs, labels)
534
            model.prepare(optim2, loss=CrossEntropyLoss(reduction="sum"))
535
            (loss,) = model.train_batch([data], [label])
536 537 538
            np.testing.assert_allclose(loss.flatten(), ref.flatten())
            fluid.disable_dygraph() if dynamic else None

539
    def test_test_batch(self):
540 541 542 543 544 545 546 547
        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()
548
            output = m(to_tensor(data))
549 550 551 552 553
            fluid.disable_dygraph()
            return output.numpy()

        ref = get_expect()
        for dynamic in [True, False]:
554
            device = paddle.set_device('cpu')
555 556
            fluid.enable_dygraph(device) if dynamic else None
            self.set_seed()
557
            net = MyModel()
558
            inputs = [InputSpec([None, dim], 'float32', 'x')]
559 560
            model = Model(net, inputs)
            model.prepare()
561
            (out,) = model.predict_batch([data])
562

563
            np.testing.assert_allclose(out, ref, rtol=1e-6)
564 565 566
            fluid.disable_dygraph() if dynamic else None

    def test_save_load(self):
567 568 569
        path = os.path.join(tempfile.mkdtemp(), '.cache_test_save_load')
        if not os.path.exists(path):
            os.makedirs(path)
570
        for dynamic in [True, False]:
571
            device = paddle.set_device('cpu')
572
            fluid.enable_dygraph(device) if dynamic else None
L
LielinJiang 已提交
573
            net = MyModel()
574 575
            inputs = [InputSpec([None, 20], 'float32', 'x')]
            labels = [InputSpec([None, 1], 'int64', 'label')]
576 577 578
            optim = fluid.optimizer.SGD(
                learning_rate=0.001, parameter_list=net.parameters()
            )
579
            model = Model(net, inputs, labels)
580 581 582
            model.prepare(
                optimizer=optim, loss=CrossEntropyLoss(reduction="sum")
            )
583 584
            model.save(path)
            model.load(path)
585
            fluid.disable_dygraph() if dynamic else None
586
        shutil.rmtree(path)
587

588 589
    def test_dynamic_load(self):
        mnist_data = MnistDataset(mode='train')
590 591 592 593 594

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

595 596 597 598 599 600
        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:
601 602 603
                optim = paddle.optimizer.Adam(
                    learning_rate=0.001, parameters=net.parameters()
                )
604
            else:
605 606 607
                optim = fluid.optimizer.Adam(
                    learning_rate=0.001, parameter_list=net.parameters()
                )
608
            model = Model(net, inputs, labels)
609 610 611
            model.prepare(
                optimizer=optim, loss=CrossEntropyLoss(reduction="sum")
            )
612
            model.fit(mnist_data, batch_size=64, verbose=0)
613 614
            model.save(path)
            model.load(path)
615
            paddle.enable_static()
616
        shutil.rmtree(path)
617

618
    def test_dynamic_save_static_load(self):
619 620 621
        path = os.path.join(
            tempfile.mkdtemp(), '.cache_dynamic_save_static_load'
        )
622 623
        if not os.path.exists(path):
            os.makedirs(path)
624
        # dynamic saving
625
        device = paddle.set_device('cpu')
626
        fluid.enable_dygraph(device)
627
        model = Model(MyModel())
628 629 630
        optim = fluid.optimizer.SGD(
            learning_rate=0.001, parameter_list=model.parameters()
        )
631
        model.prepare(optimizer=optim, loss=CrossEntropyLoss(reduction="sum"))
632
        model.save(path)
633
        fluid.disable_dygraph()
634

635 636
        inputs = [InputSpec([None, 20], 'float32', 'x')]
        labels = [InputSpec([None, 1], 'int64', 'label')]
L
LielinJiang 已提交
637
        model = Model(MyModel(), inputs, labels)
638 639 640
        optim = fluid.optimizer.SGD(
            learning_rate=0.001, parameter_list=model.parameters()
        )
641
        model.prepare(optimizer=optim, loss=CrossEntropyLoss(reduction="sum"))
642
        model.load(path)
643 644 645
        shutil.rmtree(path)

    def test_static_save_dynamic_load(self):
646 647 648
        path = os.path.join(
            tempfile.mkdtemp(), '.cache_test_static_save_dynamic_load'
        )
649 650
        if not os.path.exists(path):
            os.makedirs(path)
L
LielinJiang 已提交
651
        net = MyModel()
652 653
        inputs = [InputSpec([None, 20], 'float32', 'x')]
        labels = [InputSpec([None, 1], 'int64', 'label')]
654 655 656
        optim = fluid.optimizer.SGD(
            learning_rate=0.001, parameter_list=net.parameters()
        )
657
        model = Model(net, inputs, labels)
658
        model.prepare(optimizer=optim, loss=CrossEntropyLoss(reduction="sum"))
659
        model.save(path)
660

661
        device = paddle.set_device('cpu')
662
        fluid.enable_dygraph(device)  # if dynamic else None
663

L
LielinJiang 已提交
664
        net = MyModel()
665 666
        inputs = [InputSpec([None, 20], 'float32', 'x')]
        labels = [InputSpec([None, 1], 'int64', 'label')]
667 668 669
        optim = fluid.optimizer.SGD(
            learning_rate=0.001, parameter_list=net.parameters()
        )
670
        model = Model(net, inputs, labels)
671
        model.prepare(optimizer=optim, loss=CrossEntropyLoss(reduction="sum"))
672
        model.load(path)
673 674 675 676 677
        shutil.rmtree(path)
        fluid.disable_dygraph()

    def test_parameters(self):
        for dynamic in [True, False]:
678
            device = paddle.set_device('cpu')
679
            fluid.enable_dygraph(device) if dynamic else None
680
            net = MyModel()
681
            inputs = [InputSpec([None, 20], 'float32', 'x')]
682 683
            model = Model(net, inputs)
            model.prepare()
684 685 686 687 688
            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 已提交
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
    def test_summary(self):
        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)

709 710
            model.summary(input_size=(20))
            model.summary(input_size=[(20)])
L
LielinJiang 已提交
711
            model.summary(input_size=(20), dtype='float32')
712

713 714 715
    def test_summary_non_tensor(self):
        paddle.summary(ModelOutter(), input_size=(-1, 3))

L
LielinJiang 已提交
716
    def test_summary_nlp(self):
717 718 719 720 721 722
        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

723 724 725
        nlp_net = paddle.nn.GRU(
            input_size=2, hidden_size=3, num_layers=3, direction="bidirectional"
        )
L
LielinJiang 已提交
726
        paddle.summary(nlp_net, (1, 1, 2))
727

L
LielinJiang 已提交
728
        rnn = paddle.nn.LSTM(16, 32, 2)
729 730 731
        params_info = paddle.summary(
            rnn, [(-1, 23, 16), ((2, None, 32), (2, -1, 32))]
        )
732 733 734 735 736 737 738 739 740 741 742 743
        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 已提交
744

745
    def test_summary_input(self):
746 747 748 749 750 751
        paddle.enable_static()
        mymodel = MyModel()
        input_data = paddle.rand([1, 20])
        paddle.summary(mymodel, input=input_data)
        paddle.disable_static()

752 753 754 755 756 757 758 759 760 761 762
        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]),
763
            'x2': paddle.rand([1, 400]),
764 765 766
        }
        paddle.summary(lenet_dict_input, input=input_data)

L
LielinJiang 已提交
767 768 769 770 771
    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 已提交
772 773 774
    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 已提交
775
            paddle.summary(nlp_net, (1, 1, '2'))
L
LielinJiang 已提交
776 777 778 779 780 781 782

        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 已提交
783
        paddle.summary(nlp_net, (1, 1, 2))
L
LielinJiang 已提交
784

Y
yukavio 已提交
785
    def test_static_flops(self):
J
Jiabin Yang 已提交
786 787
        if paddle.fluid.framework._in_eager_without_dygraph_check():
            return
Y
yukavio 已提交
788 789 790 791 792 793 794 795 796 797 798 799
        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

800 801 802 803 804 805
        paddle.flops(
            net,
            [1, 3, 224, 224],
            custom_ops={paddle.nn.Dropout: customize_dropout},
            print_detail=True,
        )
Y
yukavio 已提交
806

807
    def test_dynamic_flops_with_multiple_outputs(self):
808 809 810
        net = paddle.nn.MaxPool2D(
            kernel_size=2, stride=2, padding=0, return_mask=True
        )
811 812 813 814

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

815 816 817 818 819 820
        paddle.flops(
            net,
            [1, 2, 32, 32],
            custom_ops={paddle.nn.Dropout: customize_dropout},
            print_detail=True,
        )
821

822
    def test_export_deploy_model(self):
823
        self.set_seed()
824
        np.random.seed(201)
825

826 827 828
        save_dir = os.path.join(
            tempfile.mkdtemp(), '.cache_test_export_deploy_model'
        )
829 830 831
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)

832
        for dynamic in [True, False]:
833
            paddle.disable_static() if dynamic else None
834 835
            prog_translator = ProgramTranslator()
            prog_translator.enable(False) if not dynamic else None
836
            net = LeNet()
837
            inputs = [InputSpec([None, 1, 28, 28], 'float32', 'x')]
838 839
            model = Model(net, inputs)
            model.prepare()
840

841 842 843
            tensor_img = np.array(
                np.random.random((1, 1, 28, 28)), dtype=np.float32
            )
844

845
            model.save(save_dir, training=False)
846
            ori_results = model.predict_batch(tensor_img)
847
            fluid.disable_dygraph() if dynamic else None
848

849 850 851 852 853
            place = (
                fluid.CPUPlace()
                if not fluid.is_compiled_with_cuda()
                else fluid.CUDAPlace(0)
            )
854 855 856
            new_scope = fluid.Scope()
            with fluid.scope_guard(new_scope):
                exe = fluid.Executor(place)
857 858 859 860 861 862 863 864 865 866 867 868 869 870 871
                [
                    inference_program,
                    feed_target_names,
                    fetch_targets,
                ] = paddle.static.io.load_inference_model(
                    path_prefix=save_dir, executor=exe
                )
                results = exe.run(
                    inference_program,
                    feed={feed_target_names[0]: tensor_img},
                    fetch_list=fetch_targets,
                )
                np.testing.assert_allclose(
                    results, ori_results, rtol=1e-5, atol=1e-6
                )
872

873
            paddle.enable_static()
874

875 876
        shutil.rmtree(save_dir)

L
LiuChiachi 已提交
877
    def test_dygraph_export_deploy_model_about_inputs(self):
J
Jiaqi Liu 已提交
878 879
        self.set_seed()
        np.random.seed(201)
880 881
        mnist_data = MnistDataset(mode='train')
        paddle.disable_static()
L
LiuChiachi 已提交
882
        # without inputs
883 884 885
        save_dir = os.path.join(
            tempfile.mkdtemp(), '.cache_test_dygraph_export_deploy'
        )
886 887
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
888
        for initial in ["fit", "train_batch", "eval_batch", "predict_batch"]:
889 890
            net = LeNet()
            model = Model(net)
891 892 893 894 895 896
            optim = fluid.optimizer.Adam(
                learning_rate=0.001, parameter_list=model.parameters()
            )
            model.prepare(
                optimizer=optim, loss=CrossEntropyLoss(reduction="sum")
            )
897 898 899
            if initial == "fit":
                model.fit(mnist_data, batch_size=64, verbose=0)
            else:
900 901 902
                img = np.array(
                    np.random.random((1, 1, 28, 28)), dtype=np.float32
                )
903 904 905 906 907 908
                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:
909
                    model.predict_batch([img])
910 911

            model.save(save_dir, training=False)
912
        shutil.rmtree(save_dir)
L
LiuChiachi 已提交
913
        # with inputs, and the type of inputs is InputSpec
914 915 916
        save_dir = os.path.join(
            tempfile.mkdtemp(), '.cache_test_dygraph_export_deploy_2'
        )
L
LiuChiachi 已提交
917 918 919 920 921
        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)
922 923 924
        optim = fluid.optimizer.Adam(
            learning_rate=0.001, parameter_list=model.parameters()
        )
L
LiuChiachi 已提交
925 926 927
        model.prepare(optimizer=optim, loss=CrossEntropyLoss(reduction="sum"))
        model.save(save_dir, training=False)
        shutil.rmtree(save_dir)
928

929 930 931
    def test_accumulate(
        self,
    ):
L
lyuwenyu 已提交
932 933 934 935
        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()
936 937 938
        optim = fluid.optimizer.SGD(
            learning_rate=0.001, parameter_list=net.parameters()
        )
L
lyuwenyu 已提交
939 940
        inputs = [InputSpec([None, dim], 'float32', 'x')]
        labels = [InputSpec([None, 1], 'int64', 'label')]
L
lyuwenyu 已提交
941

L
lyuwenyu 已提交
942 943
        for amp_cfg in [None, 'O1']:
            model = Model(net, inputs, labels)
944 945 946 947 948
            model.prepare(
                optim,
                loss=CrossEntropyLoss(reduction="sum"),
                amp_configs=amp_cfg,
            )
L
lyuwenyu 已提交
949 950
            losses, grads = [], []
            for stat in [False, False, True]:
951
                (loss,) = model.train_batch([data], [label], update=stat)
L
lyuwenyu 已提交
952 953 954 955 956
                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)
957 958 959
                np.testing.assert_almost_equal(
                    grad3, np.zeros_like(grad3), decimal=4
                )
L
lyuwenyu 已提交
960 961 962

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

964

965
class TestModelWithLRScheduler(unittest.TestCase):
966 967 968 969
    def test_fit_by_step(self):
        base_lr = 1e-3
        boundaries = [5, 8]

970 971 972 973 974
        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(
975 976
                boundaries=boundaries, values=values
            )
977 978 979
            learning_rate = paddle.optimizer.lr.LinearWarmup(
                learning_rate=learning_rate,
                warmup_steps=4,
980
                start_lr=base_lr / 5.0,
981
                end_lr=base_lr,
982 983 984 985 986 987 988 989
                verbose=True,
            )
            optimizer = paddle.optimizer.Momentum(
                learning_rate=learning_rate,
                weight_decay=weight_decay,
                momentum=momentum,
                parameters=parameters,
            )
990 991
            return optimizer

992
        # dynamic test
993 994 995 996 997 998 999 1000 1001 1002 1003 1004
        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)

1005 1006 1007 1008
        np.testing.assert_allclose(
            model._optimizer._learning_rate.last_lr,
            base_lr * (0.1 ** len(boundaries)),
        )
1009
        # static test
1010 1011
        paddle.enable_static()

1012 1013 1014 1015 1016 1017 1018 1019 1020 1021
        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)

1022 1023 1024 1025
        np.testing.assert_allclose(
            model._optimizer._learning_rate.last_lr,
            base_lr * (0.1 ** len(boundaries)),
        )
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037

    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(
1038 1039
                boundaries=boundaries, values=values
            )
1040 1041 1042
            learning_rate = paddle.optimizer.lr.LinearWarmup(
                learning_rate=learning_rate,
                warmup_steps=wamup_epochs,
1043
                start_lr=base_lr / 5.0,
1044
                end_lr=base_lr,
1045 1046 1047 1048 1049 1050 1051 1052
                verbose=True,
            )
            optimizer = paddle.optimizer.Momentum(
                learning_rate=learning_rate,
                weight_decay=weight_decay,
                momentum=momentum,
                parameters=parameters,
            )
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
            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()

1067 1068 1069
        lr_scheduler_callback = paddle.callbacks.LRScheduler(
            by_step=False, by_epoch=True
        )
1070

1071 1072 1073 1074 1075 1076 1077 1078
        model.fit(
            dataset,
            dataset,
            batch_size=4,
            epochs=epochs,
            num_workers=0,
            callbacks=lr_scheduler_callback,
        )
1079 1080 1081 1082 1083 1084

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

1085 1086 1087
        np.testing.assert_allclose(
            model._optimizer._learning_rate.last_lr, base_lr * (0.1**cnt)
        )
1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099
        # 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()

1100 1101 1102
        lr_scheduler_callback = paddle.callbacks.LRScheduler(
            by_step=False, by_epoch=True
        )
1103

1104 1105 1106 1107 1108 1109 1110 1111
        model.fit(
            dataset,
            dataset,
            batch_size=4,
            epochs=epochs,
            num_workers=0,
            callbacks=lr_scheduler_callback,
        )
1112 1113 1114 1115 1116 1117

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

1118 1119 1120
        np.testing.assert_allclose(
            model._optimizer._learning_rate.last_lr, base_lr * (0.1**cnt)
        )
1121

1122

1123 1124
class TestRaiseError(unittest.TestCase):
    def test_input_without_name(self):
L
LielinJiang 已提交
1125
        net = MyModel()
1126 1127
        inputs = [InputSpec([None, 10], 'float32')]
        labels = [InputSpec([None, 1], 'int64', 'label')]
1128 1129 1130
        with self.assertRaises(ValueError):
            model = Model(net, inputs, labels)

1131 1132 1133 1134 1135 1136 1137 1138 1139
    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()
1140
        save_dir = os.path.join(tempfile.mkdtemp(), '.cache_test_save_infer')
1141 1142 1143 1144 1145 1146
        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()
1147
        shutil.rmtree(save_dir)
1148

1149 1150 1151 1152 1153 1154 1155
    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 = ""
1156 1157 1158
        tensor_img = np.array(
            np.random.random((1, 1, 28, 28)), dtype=np.float32
        )
1159 1160 1161
        with self.assertRaises(ValueError):
            model.save(path, training=False)

1162

1163 1164
if __name__ == '__main__':
    unittest.main()