test_layer_norm_bf16_mkldnn_op.py 5.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#   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.

# from paddle.fluid.tests.unittests.test_layer_norm_op import *
import unittest
17 18 19
from functools import reduce
from operator import mul

20
import numpy as np
21 22 23 24
from test_layer_norm_mkldnn_op import (
    TestLayerNormMKLDNNOp,
    _reference_layer_norm_naive,
)
25

26 27
from paddle import enable_static, fluid
from paddle.fluid import core
28 29 30 31
from paddle.fluid.tests.unittests.eager_op_test import (
    _set_use_system_allocator,
    convert_float_to_uint16,
)
32 33 34 35 36 37

np.random.random(123)

_set_use_system_allocator(True)


38 39 40
@unittest.skipIf(
    not core.supports_bfloat16(), "place does not support BF16 evaluation"
)
41 42
class TestLayerNormBF16MKLDNNOp(TestLayerNormMKLDNNOp):
    def __assert_close(self, tensor, np_array, msg, rtol=2e-02, atol=2):
43 44 45 46 47 48 49
        np.testing.assert_allclose(
            np.array(tensor), np_array, rtol=rtol, atol=atol, err_msg=msg
        )

    def check_forward(
        self, shape, begin_norm_axis, with_scale_bias=True, with_is_test=False
    ):
50 51 52
        # attr
        epsilon = 0.00001
        x_shape = shape
53
        D = reduce(mul, x_shape[begin_norm_axis : len(x_shape)], 1)
54 55 56 57 58 59 60 61 62 63 64 65 66 67
        scale_shape = [D]

        np.random.seed(123)
        x = np.random.random_sample(x_shape).astype(np.float32)
        x_bf16 = convert_float_to_uint16(x)

        if with_scale_bias:
            scale = np.random.random_sample(scale_shape).astype(np.float32)
            bias = np.random.random_sample(scale_shape).astype(np.float32)
        else:
            scale = np.array([])
            bias = np.array([])

        # reference forward & backward
68 69 70
        y, mean, variance = _reference_layer_norm_naive(
            x, scale, bias, epsilon, begin_norm_axis
        )
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87

        y_bf16 = convert_float_to_uint16(y)

        var_dict = locals()
        var_names = ['x_bf16', 'mean', 'variance', 'y_bf16']
        if with_scale_bias:
            var_names.append('scale')
            var_names.append('bias')
        ground_truth = {name: var_dict[name] for name in var_names}

        program = fluid.Program()
        with fluid.program_guard(program):
            block = program.global_block()

            # scale and bias are fp32 and other vars are of bf16
            for name in ground_truth:
                if name == 'x_bf16' or name == 'y_bf16':
88 89 90 91 92
                    block.create_var(
                        name=name,
                        dtype='uint16',
                        shape=ground_truth[name].shape,
                    )
93
                else:
94 95 96 97 98
                    block.create_var(
                        name=name,
                        dtype='float32',
                        shape=ground_truth[name].shape,
                    )
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116

            inputs = {"X": block.var('x_bf16')}
            if with_scale_bias:
                inputs["Scale"] = block.var('scale')
                inputs["Bias"] = block.var('bias')

            block.append_op(
                type="layer_norm",
                inputs=inputs,
                outputs={
                    "Y": block.var('y_bf16'),
                    "Mean": block.var('mean'),  # share the same memory
                    "Variance": block.var('variance'),  # share the same memory
                },
                attrs={
                    "epsilon": epsilon,
                    "begin_norm_axis": begin_norm_axis,
                    "use_mkldnn": True,
117 118 119
                    "is_test": with_is_test,
                },
            )
120 121 122 123 124 125 126 127

            exe = fluid.Executor(core.CPUPlace())

            input_list = ['x_bf16']
            if with_scale_bias:
                input_list.append('scale')
                input_list.append('bias')

128 129 130 131 132
            out = exe.run(
                program,
                feed={name: var_dict[name] for name in input_list},
                fetch_list=['y_bf16', 'mean', 'variance'],
            )
133 134 135 136 137 138
            self.__assert_close(y_bf16, out[0], "y_bf16", 2)
            if not with_is_test:
                self.__assert_close(mean, out[1], "mean")
                self.__assert_close(variance, out[2], "variance", 1e-3)

    def test_check_forward_with_is_test(self):
139 140 141
        self.check_forward(
            shape=[2, 3, 4, 5], begin_norm_axis=3, with_is_test=True
        )
142 143 144 145 146 147 148 149 150 151 152 153

    # TODO (jczaja): Enable those to test when enabling training using bf16
    def test_check_forward_with_scale_and_bias(self):
        pass

    def test_check_forward_without_scale_and_bias(self):
        pass


if __name__ == "__main__":
    enable_static()
    unittest.main()