op_test_ipu.py 5.1 KB
Newer Older
J
jianghaicheng 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#   Copyright (c) 2021 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.

15
import os
J
jianghaicheng 已提交
16 17 18
import random
import unittest
import numpy as np
19
from enum import IntEnum
J
jianghaicheng 已提交
20

21 22
import paddle
import paddle.static
J
jianghaicheng 已提交
23 24 25 26 27 28 29 30 31 32 33 34 35

map_np_dtype_to_fluid_dtype = {
    'bool': "bool",
    'int8': "int8",
    'uint8': "uint8",
    "int32": "int32",
    "int64": "int64",
    "float16": "float16",
    "float32": "float32",
    "float64": "float64",
}


36 37
class ExecutionModeFull(IntEnum):
    # Run fp32 model on cpu
38
    CPU_FP32 = 1
39
    # Run fp32 model on ipu
40
    IPU_FP32 = 2
41 42 43
    # Convert model to fp16 using popart transform
    # All parameters will be converted to fp16
    # TODO rename to IPU_FP16
44
    IPU_POPART_FP16 = 3
45 46 47
    # Mix-precision mode, using `paddle.static.amp.fp16_guard()` to control the
    # precision of each operator
    IPU_MIXED_PRECISION = 4
48 49


50 51 52 53
class ExecutionMode(IntEnum):
    CPU_FP32 = ExecutionModeFull.CPU_FP32
    IPU_FP32 = ExecutionModeFull.IPU_FP32
    IPU_POPART_FP16 = ExecutionModeFull.IPU_POPART_FP16
54 55


J
jianghaicheng 已提交
56 57 58 59 60 61 62
def np_dtype_to_fluid_str(dtype: np.dtype) -> str:
    return map_np_dtype_to_fluid_dtype[dtype.name]


class IPUOpTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
63
        # Get random seeds
J
jianghaicheng 已提交
64 65 66
        cls._np_rand_state = np.random.get_state()
        cls._py_rand_state = random.getstate()

67
        cls.SEED = 2021
J
jianghaicheng 已提交
68 69 70
        np.random.seed(cls.SEED)
        random.seed(cls.SEED)

71 72 73 74 75 76
        # For ipu, most ops support fp16
        cls.amp_list = paddle.static.amp.CustomOpLists(
            custom_black_list=[], custom_white_list=[])
        cls.amp_list.unsupported_list = {}
        cls.amp_list.black_list = {}

77 78
        # Enable paddle static graph mode
        paddle.enable_static()
J
jianghaicheng 已提交
79 80 81 82 83 84 85

    @classmethod
    def tearDownClass(cls):
        """Restore random seeds"""
        np.random.set_state(cls._np_rand_state)
        random.setstate(cls._py_rand_state)

86 87 88 89 90 91 92 93
    @classmethod
    def use_ipumodel(cls):
        if 'POPLAR_IPUMODEL' not in os.environ:
            return False
        else:
            flag = os.environ['POPLAR_IPUMODEL']
            if flag.upper() in ['1', "TRUE"]:
                return True
J
jianghaicheng 已提交
94 95

    def set_atol(self):
96 97 98 99
        self.atol = 1e-10
        self.rtol = 1e-6
        self.atol_fp16 = 1e-3
        self.rtol_fp16 = 1e-3
J
jianghaicheng 已提交
100 101 102 103

    def set_training(self):
        self.is_training = False
        self.epoch = 1
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129

    def check(self, outputs, check_shape=False):
        cpu_fp32 = outputs[ExecutionMode.CPU_FP32]
        ipu_fp32 = outputs[ExecutionMode.IPU_FP32]
        max_diff = np.abs(cpu_fp32 - ipu_fp32).max()
        fp32_flag = np.allclose(
            cpu_fp32, ipu_fp32, rtol=self.rtol, atol=self.atol)
        self.assertTrue(fp32_flag, "max diff is %f" % (max_diff))

        if check_shape:
            self.assertTrue(cpu_fp32.shape == ipu_fp32.shape)

        ipu_popart_fp16 = None
        if ExecutionMode.IPU_POPART_FP16 in outputs.keys():
            ipu_popart_fp16 = outputs[ExecutionMode.IPU_POPART_FP16]
            max_diff = np.abs(ipu_popart_fp16.astype(np.float32) -
                              cpu_fp32).max()
            fp16_flag = np.allclose(
                ipu_popart_fp16.astype(np.float32),
                cpu_fp32,
                rtol=self.rtol_fp16,
                atol=self.atol_fp16)
            self.assertTrue(fp16_flag, "max diff is %f" % (max_diff))

            if check_shape:
                self.assertTrue(ipu_popart_fp16.shape == cpu_fp32.shape)
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156

            ipu_mixed_precision = None
            if ExecutionModeFull.IPU_MIXED_PRECISION in outputs.keys():
                ipu_mixed_precision = outputs[
                    ExecutionModeFull.IPU_MIXED_PRECISION]
                max_diff = np.abs(
                    ipu_mixed_precision.astype(np.float32) - cpu_fp32).max()
                fp16_flag = np.allclose(
                    ipu_mixed_precision.astype(np.float32),
                    cpu_fp32,
                    rtol=self.rtol_fp16,
                    atol=self.atol_fp16)
                self.assertTrue(fp16_flag, "max diff is %f" % (max_diff))

                if check_shape:
                    self.assertTrue(ipu_mixed_precision.shape == cpu_fp32.shape)

            if ExecutionMode.IPU_POPART_FP16 in outputs.keys(
            ) and ExecutionModeFull.IPU_MIXED_PRECISION in outputs.keys():
                max_diff = np.abs(ipu_popart_fp16 - ipu_mixed_precision).max()
                self.assertEqual(ipu_popart_fp16.all(),
                                 ipu_mixed_precision.all(),
                                 "max diff is %f" % (max_diff))

                if check_shape:
                    self.assertTrue(
                        ipu_popart_fp16.shape == ipu_mixed_precision.shape)