test_softmax_op.py 8.3 KB
Newer Older
1
#   Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
D
dzhwinter 已提交
2
#
D
dzhwinter 已提交
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
D
dzhwinter 已提交
6
#
D
dzhwinter 已提交
7
#     http://www.apache.org/licenses/LICENSE-2.0
D
dzhwinter 已提交
8
#
D
dzhwinter 已提交
9 10 11 12 13 14
# 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 16
from __future__ import print_function

Q
qijun 已提交
17 18
import unittest
import numpy as np
Q
qijun 已提交
19
from op_test import OpTest
20
import paddle.fluid.core as core
21 22
import paddle.fluid as fluid
from paddle.fluid import compiler, Program, program_guard
23
import paddle
24
import paddle.nn.functional as F
25 26

np.random.seed(10)
Q
qijun 已提交
27 28 29 30


def stable_softmax(x):
    """Compute the softmax of vector x in a numerically stable way."""
31 32 33
    # clip to shiftx, otherwise, when calc loss with
    # log(exp(shiftx)), may get log(0)=INF
    shiftx = (x - np.max(x)).clip(-64.)
Q
qijun 已提交
34 35 36 37
    exps = np.exp(shiftx)
    return exps / np.sum(exps)


38 39 40 41 42 43 44 45 46
def ref_softmax(x, axis=None, dtype=None):
    x_t = x.copy()
    if dtype is not None:
        x_t = x_t.astype(dtype)
    if axis is None:
        axis = -1
    return np.apply_along_axis(stable_softmax, axis, x_t)


Q
qijun 已提交
47
class TestSoftmaxOp(OpTest):
F
fengjiayi 已提交
48 49 50
    def get_x_shape(self):
        return [10, 10]

D
dengkaipeng 已提交
51 52 53
    def get_axis(self):
        return -1

Q
qijun 已提交
54
    def setUp(self):
Q
fix bug  
qijun 已提交
55
        self.op_type = "softmax"
56
        self.use_cudnn = False
K
Kexin Zhao 已提交
57
        self.use_mkldnn = False
58
        self.dtype = np.float64
K
Kexin Zhao 已提交
59
        self.init_kernel_type()
F
fengjiayi 已提交
60
        self.shape = self.get_x_shape()
D
dengkaipeng 已提交
61
        self.axis = self.get_axis()
F
fengjiayi 已提交
62

63
        np.random.seed(0)
F
fengjiayi 已提交
64
        x = np.random.uniform(0.1, 1, self.shape).astype(self.dtype)
D
dengkaipeng 已提交
65
        out = np.apply_along_axis(stable_softmax, self.axis, x)
K
Kexin Zhao 已提交
66 67 68

        self.inputs = {'X': OpTest.np_dtype_to_fluid_dtype(x)}
        self.outputs = {'Out': out}
69
        self.attrs = {
D
dengkaipeng 已提交
70
            'axis': self.axis,
71
            'use_cudnn': self.use_cudnn,
72
            'use_mkldnn': self.use_mkldnn
73
        }
74

K
Kexin Zhao 已提交
75
    def init_kernel_type(self):
76
        pass
Q
qijun 已提交
77

Q
qijun 已提交
78
    def test_check_output(self):
79
        # TODO(wangzhongpu): support mkldnn op in dygraph mode
80 81
        if self.use_cudnn:
            place = core.CUDAPlace(0)
82 83
            self.check_output_with_place(
                place, atol=1e-5, check_dygraph=(self.use_mkldnn == False))
84
        else:
85
            self.check_output(check_dygraph=(self.use_mkldnn == False))
Q
qijun 已提交
86

Q
qijun 已提交
87
    def test_check_grad(self):
88
        # TODO(wangzhongpu): support mkldnn op in dygraph mode
C
chengduo 已提交
89
        if self.use_cudnn or self.dtype == np.float16:
90
            place = core.CUDAPlace(0)
C
chengduo 已提交
91 92
            if core.is_float16_supported(place):
                self.check_grad_with_place(
93 94 95 96
                    place, ["X"],
                    "Out",
                    max_relative_error=0.01,
                    check_dygraph=(self.use_mkldnn == False))
97
        else:
98 99 100 101 102
            self.check_grad(
                ["X"],
                "Out",
                max_relative_error=0.01,
                check_dygraph=(self.use_mkldnn == False))
103 104


F
fengjiayi 已提交
105 106 107 108 109
class TestSoftmaxOp2(TestSoftmaxOp):
    def get_x_shape(self):
        return [2, 3, 4, 5]


D
dengkaipeng 已提交
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
class TestSoftmaxOp3(TestSoftmaxOp):
    def get_x_shape(self):
        return [2, 3, 4, 5]

    def get_axis(self):
        return 0


class TestSoftmaxOp4(TestSoftmaxOp):
    def get_x_shape(self):
        return [2, 3, 4, 5]

    def get_axis(self):
        return 1


class TestSoftmaxOp5(TestSoftmaxOp):
    def get_x_shape(self):
        return [2, 3, 4, 5]

    def get_axis(self):
        return 2


134
class TestSoftmaxOp6(TestSoftmaxOp):
D
dengkaipeng 已提交
135 136 137 138 139 140 141
    def get_x_shape(self):
        return [2, 3, 4, 5]

    def get_axis(self):
        return 3


142 143
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
144
class TestSoftmaxCUDNNOp(TestSoftmaxOp):
K
Kexin Zhao 已提交
145 146 147 148
    def init_kernel_type(self):
        self.use_cudnn = True


F
fengjiayi 已提交
149 150 151 152 153 154 155
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
class TestSoftmaxCUDNNOp2(TestSoftmaxCUDNNOp):
    def get_x_shape(self):
        return [2, 3, 4, 5]


D
dengkaipeng 已提交
156 157
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
D
dengkaipeng 已提交
158
class TestSoftmaxCUDNNOp5(TestSoftmaxCUDNNOp):
D
dengkaipeng 已提交
159 160 161 162
    def get_x_shape(self):
        return [2, 3, 4, 5]

    def get_axis(self):
163
        return 3
D
dengkaipeng 已提交
164 165


166 167
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
168 169 170 171 172 173 174 175 176 177
class TestSoftmaxFP16Op(TestSoftmaxOp):
    def init_kernel_type(self):
        self.dtype = np.float16

    def test_check_output(self):
        if core.is_compiled_with_cuda():
            place = core.CUDAPlace(0)
            if core.is_float16_supported(place):
                self.check_output_with_place(place, atol=1e-3)

C
chengduo 已提交
178 179 180 181
    # FIXME: If the x_shape is [10, 10], gradient failed.
    def test_check_grad(self):
        pass

182

183
@unittest.skip('disable TestSoftmaxFP16Op2')
C
chengduo 已提交
184 185 186 187 188 189 190 191 192 193
class TestSoftmaxFP16Op2(TestSoftmaxOp):
    def init_kernel_type(self):
        self.dtype = np.float16

    def test_check_output(self):
        if core.is_compiled_with_cuda():
            place = core.CUDAPlace(0)
            if core.is_float16_supported(place):
                self.check_output_with_place(place, atol=1e-3)

F
fengjiayi 已提交
194 195 196
    def get_x_shape(self):
        return [2, 3, 4, 5]

197 198 199
    def test_check_grad(self):
        pass

F
fengjiayi 已提交
200

201 202
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
K
Kexin Zhao 已提交
203 204
class TestSoftmaxFP16CUDNNOp(TestSoftmaxOp):
    def init_kernel_type(self):
205
        self.use_cudnn = True
K
Kexin Zhao 已提交
206 207 208 209 210 211 212
        self.dtype = np.float16

    def test_check_output(self):
        if core.is_compiled_with_cuda():
            place = core.CUDAPlace(0)
            if core.is_float16_supported(place):
                self.check_output_with_place(place, atol=1e-3)
Q
Qiao Longfei 已提交
213 214


F
fengjiayi 已提交
215 216 217 218 219 220 221
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
class TestSoftmaxFP16CUDNNOp2(TestSoftmaxFP16CUDNNOp):
    def get_x_shape(self):
        return [2, 3, 4, 5]


222
class TestSoftmaxAPI(unittest.TestCase):
223 224 225 226 227 228
    def setUp(self):
        self.place = paddle.CUDAPlace(0) if core.is_compiled_with_cuda(
        ) else paddle.CPUPlace()
        self.x_np = np.random.uniform(-1., 1., [2, 3, 4, 5]).astype('float32')
        self.out_ref = np.apply_along_axis(stable_softmax, -1, self.x_np)

229 230
    def test_static_check(self):
        with paddle.static.program_guard(paddle.static.Program()):
231
            x = paddle.data('X', self.x_np.shape, 'float32')
232 233 234
            out1 = F.softmax(x)
            m = paddle.nn.Softmax()
            out2 = m(x)
235
            exe = paddle.static.Executor(self.place)
236 237 238 239
            res = exe.run(feed={'X': self.x_np}, fetch_list=[out1, out2])
        out_ref = ref_softmax(self.x_np, axis=-1, dtype=None)
        for r in res:
            self.assertEqual(np.allclose(out_ref, r), True)
240

241
    def test_dygraph_check(self):
242
        paddle.disable_static(self.place)
243

244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
        x = paddle.to_tensor(self.x_np)
        out1 = F.softmax(x)
        m = paddle.nn.Softmax()
        out2 = m(x)
        out_ref = ref_softmax(self.x_np, axis=-1, dtype=None)
        for r in [out1, out2]:
            self.assertEqual(np.allclose(out_ref, r.numpy()), True)

        out1 = F.softmax(x, axis=0)
        m = paddle.nn.Softmax(axis=0)
        out2 = m(x)
        out_ref = ref_softmax(self.x_np, axis=0, dtype=None)
        for r in [out1, out2]:
            self.assertEqual(np.allclose(out_ref, r.numpy()), True)

        out = F.softmax(x, dtype=np.float64)
        out_ref = ref_softmax(self.x_np, axis=-1, dtype=np.float64)
261
        self.assertEqual(np.allclose(out_ref, out.numpy()), True)
262

263
        paddle.enable_static()
264 265

    def test_error(self):
266 267 268 269 270 271 272 273 274
        with paddle.static.program_guard(paddle.static.Program()):
            # The input type must be Variable.
            self.assertRaises(TypeError, F.softmax, 1)
            # The input dtype must be float16, float32, float64.
            x_int32 = paddle.data(name='x_int32', shape=[2, 3], dtype='int32')
            self.assertRaises(TypeError, F.softmax, x_int32)
            # support the input dtype is float16
            x_fp16 = paddle.data(name='x_fp16', shape=[2, 3], dtype='float16')
            F.softmax(x_fp16)
275 276


C
caoying03 已提交
277
if __name__ == "__main__":
Q
qijun 已提交
278
    unittest.main()