test_model.py 37.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# 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 os
import shutil
import tempfile
18 19 20
import unittest

import numpy as np
21

L
Leo Chen 已提交
22
import paddle
23 24 25 26 27 28 29
import paddle.jit as jit
import paddle.vision.models as models
from paddle import Model, fluid, to_tensor
from paddle.hapi.model import prepare_distributed_context
from paddle.io import Dataset, DistributedBatchSampler
from paddle.jit.dy2static.program_translator import ProgramTranslator
from paddle.metric import Accuracy
30
from paddle.nn import Conv2D, Linear, ReLU, Sequential
31
from paddle.nn.layer.loss import CrossEntropyLoss
32
from paddle.static import InputSpec
33 34
from paddle.vision.datasets import MNIST
from paddle.vision.models import LeNet
35 36


37
class LeNetDygraph(paddle.nn.Layer):
L
LielinJiang 已提交
38
    def __init__(self, num_classes=10):
39
        super().__init__()
40
        self.num_classes = num_classes
41 42 43
        self.features = Sequential(
            Conv2D(1, 6, 3, stride=1, padding=1),
            ReLU(),
W
wangzhen38 已提交
44
            paddle.nn.MaxPool2D(2, 2),
45 46
            Conv2D(6, 16, 5, stride=1, padding=0),
            ReLU(),
W
wangzhen38 已提交
47
            paddle.nn.MaxPool2D(2, 2),
48
        )
49 50

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

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

        if self.num_classes > 0:
59
            x = paddle.flatten(x, 1, -1)
60 61 62 63
            x = self.fc(x)
        return x


64 65
class ModelInner(paddle.nn.Layer):
    def __init__(self):
66
        super().__init__()
67 68 69 70 71 72 73 74 75
        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):
76
        super().__init__()
77 78 79 80 81 82 83 84 85
        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


86 87
class LeNetListInput(paddle.nn.Layer):
    def __init__(self, num_classes=10):
88
        super().__init__()
89 90 91 92
        self.num_classes = num_classes
        self.cov = Conv2D(1, 6, 3, stride=1, padding=1)
        for param in self.cov.parameters():
            param.trainable = False
93 94 95
        self.features = Sequential(
            self.cov,
            ReLU(),
W
wangzhen38 已提交
96
            paddle.nn.MaxPool2D(2, 2),
97 98
            Conv2D(6, 16, 5, stride=1, padding=0),
            ReLU(),
W
wangzhen38 已提交
99
            paddle.nn.MaxPool2D(2, 2),
100
        )
101 102

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

107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
    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


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

    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):
154 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
        avg_loss = paddle.sum(loss)
162 163 164 165 166 167 168 169 170 171 172 173
        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 177 178 179 180 181
            cnt += (
                (
                    np.argmax(outputs.numpy(), -1)[:, np.newaxis]
                    == labels.numpy()
                )
                .astype('int')
                .sum()
            )
182 183 184 185

    return cnt / len(dataloader.dataset)


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

        seed = 333
C
cnn 已提交
215
        paddle.seed(seed)
L
Leo Chen 已提交
216
        paddle.framework.random._manual_program_seed(seed)
217 218 219 220 221 222 223

        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)

224 225
        cls.inputs = [InputSpec([-1, 1, 28, 28], 'float32', 'image')]
        cls.labels = [InputSpec([None, 1], 'int64', 'label')]
226

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

245 246 247 248 249 250
    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)

251 252 253 254 255 256
    def test_fit_dynamic_with_rank(self):
        self.fit(True, 2, 0)

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

257 258 259 260 261 262
    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)

263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
    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()

278
    def fit(self, dynamic, num_replicas=None, rank=None, num_iters=None):
279 280
        fluid.enable_dygraph(self.device) if dynamic else None
        seed = 333
C
cnn 已提交
281
        paddle.seed(seed)
L
Leo Chen 已提交
282
        paddle.framework.random._manual_program_seed(seed)
283

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

299 300 301 302 303 304 305 306 307 308 309
        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
        )

310 311
        model.fit(self.train_dataset, batch_size=(64, 64), shuffle=False)

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

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

365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
        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,
        )
393 394 395 396 397 398

        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
399 400
        model = Model(LeNet(), self.inputs, self.labels)
        model.prepare(metrics=Accuracy())
401 402 403 404
        model.load(self.weight_path)
        result = model.evaluate(self.val_dataset, batch_size=64)
        np.testing.assert_allclose(result['acc'], self.acc1)

405 406 407
        sampler = DistributedBatchSampler(
            self.val_dataset, batch_size=64, shuffle=False
        )
408

409 410 411 412 413 414
        val_loader = fluid.io.DataLoader(
            self.val_dataset,
            batch_sampler=sampler,
            places=self.device,
            return_list=True,
        )
415 416 417 418 419 420 421

        model.evaluate(val_loader)

        fluid.disable_dygraph() if dynamic else None

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

433 434 435
        sampler = DistributedBatchSampler(
            self.test_dataset, batch_size=64, shuffle=False
        )
436

437 438 439 440 441 442
        test_loader = fluid.io.DataLoader(
            self.test_dataset,
            batch_sampler=sampler,
            places=self.device,
            return_list=True,
        )
443 444 445 446 447

        model.evaluate(test_loader)

        fluid.disable_dygraph() if dynamic else None

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

460 461 462
    def test_summary_gpu(self):
        paddle.disable_static(self.device)
        rnn = paddle.nn.LSTM(16, 32, 2)
463 464 465
        params_info = paddle.summary(
            rnn, [(-1, 23, 16), ((2, None, 32), (2, -1, 32))]
        )
466

467

468
class MyModel(paddle.nn.Layer):
L
LielinJiang 已提交
469
    def __init__(self):
470
        super().__init__()
471
        self._fc = Linear(20, 10)
472 473 474 475 476 477

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


478 479
class MyDataset(Dataset):
    def __getitem__(self, idx):
480 481 482
        return np.random.random(size=(20,)).astype(
            np.float32
        ), np.random.randint(0, 10, size=(1,)).astype(np.int64)
483 484 485 486 487

    def __len__(self):
        return 40


488 489
class TestModelFunction(unittest.TestCase):
    def set_seed(self, seed=1024):
C
cnn 已提交
490
        paddle.seed(seed)
L
Leo Chen 已提交
491
        paddle.framework.random._manual_program_seed(seed)
492 493 494 495 496 497 498 499 500

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

L
LielinJiang 已提交
521
            net = MyModel()
522 523 524
            optim2 = fluid.optimizer.SGD(
                learning_rate=0.001, parameter_list=net.parameters()
            )
525

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

534
    def test_test_batch(self):
535 536 537 538 539 540 541 542
        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()
543
            output = m(to_tensor(data))
544 545 546 547 548
            fluid.disable_dygraph()
            return output.numpy()

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

558
            np.testing.assert_allclose(out, ref, rtol=1e-6)
559 560 561
            fluid.disable_dygraph() if dynamic else None

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

583 584
    def test_dynamic_load(self):
        mnist_data = MnistDataset(mode='train')
585 586 587 588 589

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

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

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

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

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

656
        device = paddle.set_device('cpu')
657
        fluid.enable_dygraph(device)  # if dynamic else None
658

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

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

704 705
            model.summary(input_size=(20))
            model.summary(input_size=[(20)])
L
LielinJiang 已提交
706
            model.summary(input_size=(20), dtype='float32')
707

708 709 710
    def test_summary_non_tensor(self):
        paddle.summary(ModelOutter(), input_size=(-1, 3))

L
LielinJiang 已提交
711
    def test_summary_nlp(self):
712 713 714 715 716 717
        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

718 719 720
        nlp_net = paddle.nn.GRU(
            input_size=2, hidden_size=3, num_layers=3, direction="bidirectional"
        )
L
LielinJiang 已提交
721
        paddle.summary(nlp_net, (1, 1, 2))
722

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

740
    def test_summary_input(self):
741 742 743 744 745 746
        paddle.enable_static()
        mymodel = MyModel()
        input_data = paddle.rand([1, 20])
        paddle.summary(mymodel, input=input_data)
        paddle.disable_static()

747 748 749 750 751 752 753 754 755 756 757
        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]),
758
            'x2': paddle.rand([1, 400]),
759 760 761
        }
        paddle.summary(lenet_dict_input, input=input_data)

L
LielinJiang 已提交
762 763 764 765 766
    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 已提交
767 768 769
    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 已提交
770
            paddle.summary(nlp_net, (1, 1, '2'))
L
LielinJiang 已提交
771 772 773 774 775 776 777

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

Y
yukavio 已提交
780
    def test_static_flops(self):
J
Jiabin Yang 已提交
781 782
        if paddle.fluid.framework._in_eager_without_dygraph_check():
            return
Y
yukavio 已提交
783 784 785 786 787 788 789 790 791 792 793 794
        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

795 796 797 798 799 800
        paddle.flops(
            net,
            [1, 3, 224, 224],
            custom_ops={paddle.nn.Dropout: customize_dropout},
            print_detail=True,
        )
Y
yukavio 已提交
801

802
    def test_dynamic_flops_with_multiple_outputs(self):
803 804 805
        net = paddle.nn.MaxPool2D(
            kernel_size=2, stride=2, padding=0, return_mask=True
        )
806 807 808 809

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

810 811 812 813 814 815
        paddle.flops(
            net,
            [1, 2, 32, 32],
            custom_ops={paddle.nn.Dropout: customize_dropout},
            print_detail=True,
        )
816

817
    def test_export_deploy_model(self):
818
        self.set_seed()
819
        np.random.seed(201)
820

821 822 823
        save_dir = os.path.join(
            tempfile.mkdtemp(), '.cache_test_export_deploy_model'
        )
824 825 826
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)

827
        for dynamic in [True, False]:
828
            paddle.disable_static() if dynamic else None
829 830
            prog_translator = ProgramTranslator()
            prog_translator.enable(False) if not dynamic else None
831
            net = LeNet()
832
            inputs = [InputSpec([None, 1, 28, 28], 'float32', 'x')]
833 834
            model = Model(net, inputs)
            model.prepare()
835

836 837 838
            tensor_img = np.array(
                np.random.random((1, 1, 28, 28)), dtype=np.float32
            )
839

840
            model.save(save_dir, training=False)
841
            ori_results = model.predict_batch(tensor_img)
842
            fluid.disable_dygraph() if dynamic else None
843

844 845 846 847 848
            place = (
                fluid.CPUPlace()
                if not fluid.is_compiled_with_cuda()
                else fluid.CUDAPlace(0)
            )
849 850 851
            new_scope = fluid.Scope()
            with fluid.scope_guard(new_scope):
                exe = fluid.Executor(place)
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
                [
                    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
                )
867

868
            paddle.enable_static()
869

870 871
        shutil.rmtree(save_dir)

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

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

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

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

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

959

960
class TestModelWithLRScheduler(unittest.TestCase):
961 962 963 964
    def test_fit_by_step(self):
        base_lr = 1e-3
        boundaries = [5, 8]

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

987
        # dynamic test
988 989 990 991 992 993 994 995 996 997 998 999
        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)

1000 1001 1002 1003
        np.testing.assert_allclose(
            model._optimizer._learning_rate.last_lr,
            base_lr * (0.1 ** len(boundaries)),
        )
1004
        # static test
1005 1006
        paddle.enable_static()

1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
        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)

1017 1018 1019 1020
        np.testing.assert_allclose(
            model._optimizer._learning_rate.last_lr,
            base_lr * (0.1 ** len(boundaries)),
        )
1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032

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

1062 1063 1064
        lr_scheduler_callback = paddle.callbacks.LRScheduler(
            by_step=False, by_epoch=True
        )
1065

1066 1067 1068 1069 1070 1071 1072 1073
        model.fit(
            dataset,
            dataset,
            batch_size=4,
            epochs=epochs,
            num_workers=0,
            callbacks=lr_scheduler_callback,
        )
1074 1075 1076 1077 1078 1079

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

1080 1081 1082
        np.testing.assert_allclose(
            model._optimizer._learning_rate.last_lr, base_lr * (0.1**cnt)
        )
1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
        # 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()

1095 1096 1097
        lr_scheduler_callback = paddle.callbacks.LRScheduler(
            by_step=False, by_epoch=True
        )
1098

1099 1100 1101 1102 1103 1104 1105 1106
        model.fit(
            dataset,
            dataset,
            batch_size=4,
            epochs=epochs,
            num_workers=0,
            callbacks=lr_scheduler_callback,
        )
1107 1108 1109 1110 1111 1112

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

1113 1114 1115
        np.testing.assert_allclose(
            model._optimizer._learning_rate.last_lr, base_lr * (0.1**cnt)
        )
1116

1117

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

1126 1127 1128 1129 1130 1131 1132 1133 1134
    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()
1135
        save_dir = os.path.join(tempfile.mkdtemp(), '.cache_test_save_infer')
1136 1137 1138 1139 1140 1141
        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()
1142
        shutil.rmtree(save_dir)
1143

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

1157

1158 1159
if __name__ == '__main__':
    unittest.main()