test_custom_relu_model.py 10.1 KB
Newer Older
1
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
2
#
3 4 5
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
6
#
7
#     http://www.apache.org/licenses/LICENSE-2.0
8
#
9 10 11 12 13 14 15
# 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
16
import tempfile
17
import unittest
18

19
import numpy as np
20
from utils import IS_MAC, extra_cc_args, extra_nvcc_args, paddle_includes
21 22 23

import paddle
from paddle import nn
24
from paddle.utils.cpp_extension import get_build_directory, load
25 26
from paddle.utils.cpp_extension.extension_utils import run_cmd

27
# Because Windows don't use docker, the shared lib already exists in the
28 29
# cache dir, it will not be compiled again unless the shared lib is removed.
file = '{}\\custom_relu_for_model_jit\\custom_relu_for_model_jit.pyd'.format(
30 31
    get_build_directory()
)
32 33 34 35 36 37 38 39
if os.name == 'nt' and os.path.isfile(file):
    cmd = 'del {}'.format(file)
    run_cmd(cmd, True)

# Compile and load custom op Just-In-Time.
# custom_relu_op_dup.cc is only used for multi ops test,
# not a new op, if you want to test only one op, remove this
# source file
40 41 42 43
source_files = ['custom_relu_op.cc']
if not IS_MAC:
    source_files.append('custom_relu_op.cu')

44 45
custom_module = load(
    name='custom_relu_for_model_jit',
46
    sources=source_files,
47
    extra_include_paths=paddle_includes,  # add for Coverage CI
48 49
    extra_cxx_cflags=extra_cc_args,  # test for cc flags
    extra_cuda_cflags=extra_nvcc_args,  # test for nvcc flags
50 51
    verbose=True,
)
52 53 54 55 56 57 58 59


class Net(nn.Layer):
    """
    A simple exmaple for Regression Model.
    """

    def __init__(self, in_dim, out_dim, use_custom_op=False):
60
        super().__init__()
61 62
        self.fc1 = nn.Linear(in_dim, in_dim)
        self.fc2 = nn.Linear(in_dim, out_dim)
63 64 65
        self.relu_act = (
            custom_module.custom_relu if use_custom_op else nn.functional.relu
        )
66 67 68 69 70 71 72 73 74 75 76 77 78

    def forward(self, x):
        out = self.fc1(x)
        out = self.relu_act(out)
        out = self.fc2(out)
        out = self.relu_act(out)

        out = paddle.mean(out, axis=-1)

        return out


class TestDygraphModel(unittest.TestCase):
79 80 81
    def tearDown(self):
        self.temp_dir.cleanup()

82 83 84 85 86 87 88 89
    def setUp(self):

        self.seed = 2021
        self.in_dim = 10
        self.out_dim = 64
        self.batch_num = 10
        self.batch_size = 4
        self.datas = [
90 91 92
            np.random.uniform(size=[self.batch_size, self.in_dim]).astype(
                'float32'
            )
93 94 95 96 97 98 99
            for i in range(self.batch_num)
        ]
        self.labels = [
            np.random.uniform(size=[self.batch_size, 1]).astype('float32')
            for i in range(self.batch_num)
        ]

100
        self.devices = ['cpu', 'gpu'] if not IS_MAC else ['cpu']
101 102

        # for saving model
103 104 105
        self.temp_dir = tempfile.TemporaryDirectory()
        self.model_save_dir = os.path.join(self.temp_dir.name, 'infer_model')
        self.model_path_template = os.path.join(
106 107
            self.model_save_dir, 'custom_relu_dygaph_model_{}.pdparams'
        )
108
        self.model_dy2stat_path = os.path.join(
109 110
            self.model_save_dir, 'infer_model/custom_relu_model_dy2sta'
        )
111 112

        # for dy2stat
113 114 115
        self.x_spec = paddle.static.InputSpec(
            shape=[None, self.in_dim], dtype='float32', name='x'
        )
116

117
    def test_train_eval(self):
118 119 120 121 122 123 124 125
        for device in self.devices:
            # set device
            paddle.set_device(device)

            # for train
            origin_relu_train_out = self.train_model(use_custom_op=False)
            custom_relu_train_out = self.train_model(use_custom_op=True)

126 127 128
            np.testing.assert_array_equal(
                origin_relu_train_out, custom_relu_train_out
            )
129 130 131 132 133

            # for eval
            origin_relu_eval_out = self.eval_model(use_custom_op=False)
            custom_relu_eval_out = self.eval_model(use_custom_op=True)

134 135 136
            np.testing.assert_array_equal(
                origin_relu_eval_out, custom_relu_eval_out
            )
137

138 139 140 141 142 143 144 145 146 147
    def train_model(self, use_custom_op=False, dy2stat=False):
        # reset random seed
        paddle.seed(self.seed)
        np.random.seed(self.seed)
        # paddle.framework.random._manual_program_seed(SEED)

        net = Net(self.in_dim, self.out_dim, use_custom_op)
        if dy2stat:
            net = paddle.jit.to_static(net, input_spec=[self.x_spec])
        mse_loss = paddle.nn.MSELoss()
148 149 150
        sgd = paddle.optimizer.SGD(
            learning_rate=0.1, parameters=net.parameters()
        )
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167

        for batch_id in range(self.batch_num):
            x = paddle.to_tensor(self.datas[batch_id])
            y = paddle.to_tensor(self.labels[batch_id])

            out = net(x)
            loss = mse_loss(out, y)

            loss.backward()
            sgd.minimize(loss)
            net.clear_gradients()

        # save inference model
        net.eval()
        if dy2stat:
            paddle.jit.save(net, self.model_dy2stat_path)
        else:
168 169 170
            paddle.save(
                net.state_dict(), self.model_path_template.format(use_custom_op)
            )
171 172 173 174 175 176 177 178 179 180

        return out.numpy()

    def eval_model(self, use_custom_op=False, dy2stat=False):
        net = Net(self.in_dim, self.out_dim, use_custom_op)

        if dy2stat:
            net = paddle.jit.load(self.model_dy2stat_path)
        else:
            state_dict = paddle.load(
181 182
                self.model_path_template.format(use_custom_op)
            )
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
            net.set_state_dict(state_dict)

        sample_x = paddle.to_tensor(self.datas[0])
        net.eval()
        out = net(sample_x)

        return out.numpy()


class TestStaticModel(unittest.TestCase):
    def setUp(self):
        self.seed = 2021
        self.in_dim = 10
        self.out_dim = 64
        self.batch_num = 10
        self.batch_size = 8
        self.datas = [
200 201 202
            np.random.uniform(size=[self.batch_size, self.in_dim]).astype(
                'float32'
            )
203 204 205 206 207 208 209
            for i in range(self.batch_num)
        ]
        self.labels = [
            np.random.uniform(size=[self.batch_size, 1]).astype('float32')
            for i in range(self.batch_num)
        ]

210
        self.devices = ['cpu', 'gpu'] if not IS_MAC else ['cpu']
211 212

        # for saving model
213 214 215
        self.temp_dir = tempfile.TemporaryDirectory()
        self.model_save_dir = os.path.join(self.temp_dir.name, 'infer_model')
        self.model_path_template = os.path.join(
216
            self.model_save_dir, 'custom_relu_static_model_{}'
217
        )
218 219 220 221 222

        paddle.enable_static()

    def tearDown(self):
        paddle.disable_static()
223
        self.temp_dir.cleanup()
224 225 226 227

    def test_train_eval(self):
        for device in self.devices:
            # for train
228 229 230
            original_relu_train_out = self.train_model(
                device, use_custom_op=False
            )
231
            custom_relu_train_out = self.train_model(device, use_custom_op=True)
232 233 234 235

            np.testing.assert_array_equal(
                original_relu_train_out, custom_relu_train_out
            )
236 237

            # for eval
238 239 240
            original_relu_eval_out = self.eval_model(
                device, use_custom_op=False
            )
241
            custom_relu_eval_out = self.eval_model(device, use_custom_op=True)
242 243 244 245

            np.testing.assert_array_equal(
                original_relu_eval_out, custom_relu_eval_out
            )
246

247
    def train_model(self, device, use_custom_op=False):
248 249 250 251 252 253 254
        # reset random seed
        paddle.seed(self.seed)
        np.random.seed(self.seed)
        # set device
        paddle.set_device(device)

        with paddle.static.scope_guard(paddle.static.Scope()):
255 256 257 258 259 260 261 262 263
            with paddle.static.program_guard(
                paddle.static.Program(), paddle.static.Program()
            ):
                x = paddle.static.data(
                    shape=[None, self.in_dim], name='x', dtype='float32'
                )
                y = paddle.static.data(
                    shape=[None, 1], name='y', dtype='float32'
                )
264 265 266 267 268 269 270 271 272 273 274

                net = Net(self.in_dim, self.out_dim, use_custom_op)
                out = net(x)

                loss = nn.functional.mse_loss(out, y)
                sgd = paddle.optimizer.SGD(learning_rate=0.01)
                sgd.minimize(loss)

                exe = exe = paddle.static.Executor()
                exe.run(paddle.static.default_startup_program())

275
                main_program = paddle.static.default_main_program()
276 277 278 279 280

                for batch_id in range(self.batch_num):
                    x_data = self.datas[batch_id]
                    y_data = self.labels[batch_id]

281 282 283 284 285
                    res = exe.run(
                        main_program,
                        feed={'x': x_data, 'y': y_data},
                        fetch_list=[out],
                    )
286 287 288

                # save model
                paddle.static.save_inference_model(
289
                    self.model_path_template.format(use_custom_op),
290 291 292 293
                    [x],
                    [out],
                    exe,
                )
294 295 296

                return res[0]

297
    def eval_model(self, device, use_custom_op=False):
298 299 300 301 302 303
        paddle.set_device(device)

        with paddle.static.scope_guard(paddle.static.Scope()):
            with paddle.static.program_guard(paddle.static.Program()):
                exe = paddle.static.Executor()

304 305 306 307 308
                [
                    inference_program,
                    feed_target_names,
                    fetch_targets,
                ] = paddle.static.load_inference_model(
309
                    self.model_path_template.format(use_custom_op), exe
310
                )
311 312

                x_data = self.datas[0]
313 314 315 316 317
                results = exe.run(
                    inference_program,
                    feed={feed_target_names[0]: x_data},
                    fetch_list=fetch_targets,
                )
318 319 320 321 322 323

                return results[0]


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