test_gather_nd_op.py 18.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#   Copyright (c) 2019 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 unittest
16

17
import numpy as np
W
wanghuancoder 已提交
18
from eager_op_test import OpTest, convert_float_to_uint16
19

20
import paddle
21 22
from paddle import fluid
from paddle.fluid import core
23 24 25


class TestGatherNdOpWithEmptyIndex(OpTest):
H
hong 已提交
26
    # Index has empty element, which means copy entire tensor
27 28 29

    def setUp(self):
        self.op_type = "gather_nd"
30
        self.prim_op_type = "prim"
H
hong 已提交
31
        self.python_api = paddle.gather_nd
32
        self.public_python_api = paddle.gather_nd
33 34 35 36 37 38 39 40 41 42 43 44
        self.config_dtype()
        if self.dtype == np.float64:
            target_dtype = "float64"
        elif self.dtype == np.float16:
            target_dtype = "float16"
        else:
            target_dtype = "float32"
        xnp = np.random.random((5, 20)).astype(target_dtype)
        output = np.vstack((xnp[np.newaxis, :], xnp[np.newaxis, :]))
        if self.dtype == np.uint16:
            xnp = convert_float_to_uint16(xnp)
            output = convert_float_to_uint16(output)
45
        self.inputs = {'X': xnp, 'Index': np.array([[], []]).astype("int32")}
46 47 48 49
        self.outputs = {'Out': output}

    def config_dtype(self):
        self.dtype = np.float64
50 51

    def test_check_output(self):
W
wanghuancoder 已提交
52
        self.check_output()
53 54

    def test_check_grad(self):
W
wanghuancoder 已提交
55
        self.check_grad(['X'], 'Out', check_prim=True)
56 57


58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
class TestGatherNdOpWithEmptyIndexFP16(TestGatherNdOpWithEmptyIndex):
    def config_dtype(self):
        self.dtype = np.float16


@unittest.skipIf(
    not core.is_compiled_with_cuda()
    or not core.is_bfloat16_supported(core.CUDAPlace(0)),
    "core is not complied with CUDA and not support the bfloat16",
)
class TestGatherNdOpWithEmptyIndexBF16(TestGatherNdOpWithEmptyIndex):
    def config_dtype(self):
        self.dtype = np.uint16

    def test_check_output(self):
        place = core.CUDAPlace(0)
W
wanghuancoder 已提交
74
        self.check_output_with_place(place)
75 76 77

    def test_check_grad(self):
        place = core.CUDAPlace(0)
W
wanghuancoder 已提交
78
        self.check_grad_with_place(place, ['X'], 'Out', check_prim=True)
79 80


81 82 83
class TestGatherNdOpWithIndex1(OpTest):
    def setUp(self):
        self.op_type = "gather_nd"
84
        self.prim_op_type = "prim"
H
hong 已提交
85
        self.python_api = paddle.gather_nd
86
        self.public_python_api = paddle.gather_nd
87 88 89 90 91 92 93 94 95
        self.config_dtype()
        if self.dtype == np.float64:
            target_dtype = "float64"
        elif self.dtype == np.float16:
            target_dtype = "float16"
        else:
            target_dtype = "float32"
        xnp = np.random.random((5, 20)).astype(target_dtype)
        index = np.array([1]).astype("int32")
96
        output = xnp[index[-1]]
97 98 99 100 101 102 103 104
        if self.dtype == np.uint16:
            xnp = convert_float_to_uint16(xnp)
            output = convert_float_to_uint16(output)
        self.inputs = {'X': xnp, 'Index': index}
        self.outputs = {'Out': output}

    def config_dtype(self):
        self.dtype = np.float64
105 106

    def test_check_output(self):
W
wanghuancoder 已提交
107
        self.check_output()
108 109

    def test_check_grad(self):
W
wanghuancoder 已提交
110
        self.check_grad(['X'], 'Out', check_prim=True)
111 112


113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
class TestGatherNdOpWithIndex1FP16(TestGatherNdOpWithIndex1):
    def config_dtype(self):
        self.dtype = np.float16


@unittest.skipIf(
    not core.is_compiled_with_cuda()
    or not core.is_bfloat16_supported(core.CUDAPlace(0)),
    "core is not complied with CUDA and not support the bfloat16",
)
class TestGatherNdOpWithIndex1BF16(TestGatherNdOpWithIndex1):
    def config_dtype(self):
        self.dtype = np.uint16

    def test_check_output(self):
        place = core.CUDAPlace(0)
W
wanghuancoder 已提交
129
        self.check_output_with_place(place)
130 131 132

    def test_check_grad(self):
        place = core.CUDAPlace(0)
W
wanghuancoder 已提交
133
        self.check_grad_with_place(place, ['X'], 'Out', check_prim=True)
134 135


136
class TestGatherNdOpWithLowIndex(OpTest):
137
    # Index has low rank, X has high rank
138 139 140

    def setUp(self):
        self.op_type = "gather_nd"
141
        self.prim_op_type = "prim"
H
hong 已提交
142
        self.python_api = paddle.gather_nd
143
        self.public_python_api = paddle.gather_nd
144 145 146 147 148 149 150 151
        self.config_dtype()
        if self.dtype == np.float64:
            target_dtype = "float64"
        elif self.dtype == np.float16:
            target_dtype = "float16"
        else:
            target_dtype = "float32"
        xnp = np.random.uniform(0, 100, (10, 10)).astype(target_dtype)
152
        index = np.array([[1], [2]]).astype("int64")
153
        output = xnp[tuple(index.T)]  # shape is [2, 10]
154 155 156 157

        if self.dtype == np.uint16:
            xnp = convert_float_to_uint16(xnp)
            output = convert_float_to_uint16(output)
158 159

        self.inputs = {'X': xnp, 'Index': index}
160
        self.outputs = {'Out': output}
161

162 163
    def config_dtype(self):
        self.dtype = np.float64
164 165

    def test_check_output(self):
W
wanghuancoder 已提交
166
        self.check_output()
167 168

    def test_check_grad(self):
W
wanghuancoder 已提交
169
        self.check_grad(['X'], 'Out', check_prim=True)
170 171


172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
class TestGatherNdOpWithLowIndexFP16(TestGatherNdOpWithLowIndex):
    def config_dtype(self):
        self.dtype = np.float16


@unittest.skipIf(
    not core.is_compiled_with_cuda()
    or not core.is_bfloat16_supported(core.CUDAPlace(0)),
    "core is not complied with CUDA and not support the bfloat16",
)
class TestGatherNdOpWithLowIndexBF16(TestGatherNdOpWithLowIndex):
    def config_dtype(self):
        self.dtype = np.uint16

    def test_check_output(self):
        place = core.CUDAPlace(0)
W
wanghuancoder 已提交
188
        self.check_output_with_place(place)
189 190 191

    def test_check_grad(self):
        place = core.CUDAPlace(0)
W
wanghuancoder 已提交
192
        self.check_grad_with_place(place, ['X'], 'Out', check_prim=True)
193 194


195
class TestGatherNdOpIndex1(OpTest):
196
    # Index has low rank, X has high rank
197 198 199

    def setUp(self):
        self.op_type = "gather_nd"
200
        self.prim_op_type = "prim"
H
hong 已提交
201
        self.python_api = paddle.gather_nd
202
        self.public_python_api = paddle.gather_nd
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
        self.config_dtype()
        if self.dtype == np.float64:
            target_dtype = "float64"
        elif self.dtype == np.float16:
            target_dtype = "float16"
        else:
            target_dtype = "float32"
        xnp = np.random.uniform(0, 100, (10, 10)).astype(target_dtype)
        index = np.array([1, 2]).astype("int32")
        output = xnp[tuple(index.T)]
        if self.dtype == np.uint16:
            xnp = convert_float_to_uint16(xnp)
            output = convert_float_to_uint16(output)
        self.inputs = {'X': xnp, 'Index': index}
        self.outputs = {'Out': output}
218
        # the outputs are 0D-tensor, CINN not support
219 220
        self.enable_cinn = False

221 222
    def config_dtype(self):
        self.dtype = np.float64
223 224

    def test_check_output(self):
W
wanghuancoder 已提交
225
        self.check_output()
226 227

    def test_check_grad(self):
W
wanghuancoder 已提交
228
        self.check_grad(['X'], 'Out', check_prim=True)
229 230 231


class TestGatherNdOpIndex1FP16(TestGatherNdOpIndex1):
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
    def config_dtype(self):
        self.dtype = np.float16


@unittest.skipIf(
    not core.is_compiled_with_cuda()
    or not core.is_bfloat16_supported(core.CUDAPlace(0)),
    "core is not complied with CUDA and not support the bfloat16",
)
class TestGatherNdOpIndex1BF16(TestGatherNdOpIndex1):
    def config_dtype(self):
        self.dtype = np.uint16

    def test_check_output(self):
        place = core.CUDAPlace(0)
W
wanghuancoder 已提交
247
        self.check_output_with_place(place)
248 249 250

    def test_check_grad(self):
        place = core.CUDAPlace(0)
W
wanghuancoder 已提交
251
        self.check_grad_with_place(place, ['X'], 'Out', check_prim=True)
252 253


254
class TestGatherNdOpWithSameIndexAsX(OpTest):
255
    # Index has same rank as X's rank
256 257
    def setUp(self):
        self.op_type = "gather_nd"
258
        self.prim_op_type = "prim"
H
hong 已提交
259
        self.python_api = paddle.gather_nd
260
        self.public_python_api = paddle.gather_nd
261 262 263 264 265 266 267 268
        self.config_dtype()
        if self.dtype == np.float64:
            target_dtype = "float64"
        elif self.dtype == np.float16:
            target_dtype = "float16"
        else:
            target_dtype = "float32"
        xnp = np.random.uniform(0, 100, (10, 10)).astype(target_dtype)
269
        index = np.array([[1, 1], [2, 1]]).astype("int64")
270 271 272 273
        output = xnp[tuple(index.T)]  # [25, 22]
        if self.dtype == np.uint16:
            xnp = convert_float_to_uint16(xnp)
            output = convert_float_to_uint16(output)
274
        self.inputs = {'X': xnp, 'Index': index}
275 276 277 278
        self.outputs = {'Out': output}

    def config_dtype(self):
        self.dtype = np.float64
279 280

    def test_check_output(self):
W
wanghuancoder 已提交
281
        self.check_output()
282 283

    def test_check_grad(self):
W
wanghuancoder 已提交
284
        self.check_grad(['X'], 'Out', check_prim=True)
285 286


287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
class TestGatherNdOpWithSameIndexAsXFP16(TestGatherNdOpWithSameIndexAsX):
    def config_dtype(self):
        self.dtype = np.float16


@unittest.skipIf(
    not core.is_compiled_with_cuda()
    or not core.is_bfloat16_supported(core.CUDAPlace(0)),
    "core is not complied with CUDA and not support the bfloat16",
)
class TestGatherNdOpWithSameIndexAsXBF16(TestGatherNdOpWithSameIndexAsX):
    def config_dtype(self):
        self.dtype = np.uint16

    def test_check_output(self):
        place = core.CUDAPlace(0)
W
wanghuancoder 已提交
303
        self.check_output_with_place(place)
304 305 306

    def test_check_grad(self):
        place = core.CUDAPlace(0)
W
wanghuancoder 已提交
307
        self.check_grad_with_place(place, ['X'], 'Out', check_prim=True)
308 309


310
class TestGatherNdOpWithHighRankSame(OpTest):
311
    # Both Index and X have high rank, and Rank(Index) = Rank(X)
312 313 314

    def setUp(self):
        self.op_type = "gather_nd"
315
        self.prim_op_type = "prim"
H
hong 已提交
316
        self.python_api = paddle.gather_nd
317
        self.public_python_api = paddle.gather_nd
S
ShenLiang 已提交
318
        shape = (5, 2, 3, 1, 10)
319 320 321 322 323 324 325 326
        self.config_dtype()
        if self.dtype == np.float64:
            target_dtype = "float64"
        elif self.dtype == np.float16:
            target_dtype = "float16"
        else:
            target_dtype = "float32"
        xnp = np.random.rand(*shape).astype(target_dtype)
S
ShenLiang 已提交
327
        index = np.vstack([np.random.randint(0, s, size=2) for s in shape]).T
328 329 330 331
        output = xnp[tuple(index.T)]
        if self.dtype == np.uint16:
            xnp = convert_float_to_uint16(xnp)
            output = convert_float_to_uint16(output)
332
        self.inputs = {'X': xnp, 'Index': index.astype("int32")}
333 334 335 336
        self.outputs = {'Out': output}

    def config_dtype(self):
        self.dtype = np.float64
337 338

    def test_check_output(self):
W
wanghuancoder 已提交
339
        self.check_output()
340 341

    def test_check_grad(self):
W
wanghuancoder 已提交
342
        self.check_grad(['X'], 'Out', check_prim=True)
343 344


345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
class TestGatherNdOpWithHighRankSameFP16(TestGatherNdOpWithHighRankSame):
    def config_dtype(self):
        self.dtype = np.float16


@unittest.skipIf(
    not core.is_compiled_with_cuda()
    or not core.is_bfloat16_supported(core.CUDAPlace(0)),
    "core is not complied with CUDA and not support the bfloat16",
)
class TestGatherNdOpWithHighRankSameBF16(TestGatherNdOpWithHighRankSame):
    def config_dtype(self):
        self.dtype = np.uint16

    def test_check_output(self):
        place = core.CUDAPlace(0)
W
wanghuancoder 已提交
361
        self.check_output_with_place(place)
362 363 364

    def test_check_grad(self):
        place = core.CUDAPlace(0)
W
wanghuancoder 已提交
365
        self.check_grad_with_place(place, ['X'], 'Out', check_prim=True)
366 367


368
class TestGatherNdOpWithHighRankDiff(OpTest):
369
    # Both Index and X have high rank, and Rank(Index) < Rank(X)
370 371 372

    def setUp(self):
        self.op_type = "gather_nd"
373
        self.prim_op_type = "prim"
H
hong 已提交
374
        self.python_api = paddle.gather_nd
375
        self.public_python_api = paddle.gather_nd
S
ShenLiang 已提交
376
        shape = (2, 3, 4, 1, 10)
377 378 379 380 381 382 383 384
        self.config_dtype()
        if self.dtype == np.float64:
            target_dtype = "float64"
        elif self.dtype == np.float16:
            target_dtype = "float16"
        else:
            target_dtype = "float32"
        xnp = np.random.rand(*shape).astype(target_dtype)
S
ShenLiang 已提交
385 386
        index = np.vstack([np.random.randint(0, s, size=200) for s in shape]).T
        index_re = index.reshape([20, 5, 2, 5])
387 388 389 390
        output = xnp[tuple(index.T)].reshape([20, 5, 2])
        if self.dtype == np.uint16:
            xnp = convert_float_to_uint16(xnp)
            output = convert_float_to_uint16(output)
391
        self.inputs = {'X': xnp, 'Index': index_re.astype("int32")}
392 393 394 395
        self.outputs = {'Out': output}

    def config_dtype(self):
        self.dtype = np.float64
396 397

    def test_check_output(self):
W
wanghuancoder 已提交
398
        self.check_output()
399 400

    def test_check_grad(self):
W
wanghuancoder 已提交
401
        self.check_grad(['X'], 'Out', check_prim=True)
402 403


404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
class TestGatherNdOpWithHighRankDiffFP16(TestGatherNdOpWithHighRankDiff):
    def config_dtype(self):
        self.dtype = np.float16


@unittest.skipIf(
    not core.is_compiled_with_cuda()
    or not core.is_bfloat16_supported(core.CUDAPlace(0)),
    "core is not complied with CUDA and not support the bfloat16",
)
class TestGatherNdOpWithHighRankDiffBF16(TestGatherNdOpWithHighRankDiff):
    def config_dtype(self):
        self.dtype = np.uint16

    def test_check_output(self):
        place = core.CUDAPlace(0)
W
wanghuancoder 已提交
420
        self.check_output_with_place(place)
421 422 423

    def test_check_grad(self):
        place = core.CUDAPlace(0)
W
wanghuancoder 已提交
424
        self.check_grad_with_place(place, ['X'], 'Out', check_prim=True)
425 426


427
# Test Python API
428
class TestGatherNdOpAPI(unittest.TestCase):
429
    def test_case1(self):
G
GGBond8488 已提交
430 431 432 433 434
        x1 = paddle.static.data(
            name='x1', shape=[-1, 30, 40, 50, 60], dtype='float32'
        )
        index1 = paddle.static.data(
            name='index1', shape=[-1, 2, 4], dtype='int32'
435
        )
436
        output1 = paddle.gather_nd(x1, index1)
437 438

    def test_case2(self):
G
GGBond8488 已提交
439 440 441 442 443 444
        x2 = paddle.static.data(
            name='x2', shape=[-1, 30, 40, 50], dtype='float32'
        )
        index2 = paddle.static.data(
            name='index2', shape=[-1, 2, 2], dtype='int64'
        )
445
        output2 = paddle.gather_nd(x2, index2)
446 447

    def test_case3(self):
G
GGBond8488 已提交
448 449 450 451
        x3 = paddle.static.data(name='x3', shape=[-1, 3, 4, 5], dtype='float32')
        index3 = paddle.static.data(
            name='index3', shape=[-1, 2, 1], dtype='int32'
        )
452
        output3 = paddle.gather_nd(x3, index3, name="gather_nd_layer")
453 454


455
# Test Raise Index Error
456
class TestGatherNdOpRaise(unittest.TestCase):
457 458 459
    def test_check_raise(self):
        def check_raise_is_test():
            try:
G
GGBond8488 已提交
460 461
                x = paddle.static.data(
                    name='x', shape=[-1, 3, 4, 5], dtype='float32'
462
                )
G
GGBond8488 已提交
463 464
                index = paddle.static.data(
                    name='index', shape=[-1, 2, 10], dtype='int32'
465
                )
466
                output = paddle.gather_nd(x, index)
467
            except Exception as e:
468
                t = "Input(Index).shape[-1] should be no greater than Input(X).rank"
469 470 471 472 473 474
                if t in str(e):
                    raise IndexError

        self.assertRaises(IndexError, check_raise_is_test)


475 476
class TestGatherNdError(unittest.TestCase):
    def test_error(self):
477 478 479
        with paddle.static.program_guard(
            paddle.static.Program(), paddle.static.Program()
        ):
480 481

            shape = [8, 9, 6]
482 483 484
            x = paddle.static.data(shape=shape, dtype='float32', name='x')
            index = paddle.static.data(shape=shape, dtype='bool', name='index')
            index_float = paddle.static.data(
485 486
                shape=shape, dtype='float32', name='index_float'
            )
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
            np_x = np.random.random(shape).astype('float32')
            np_index = np.array(np.random.randint(2, size=shape, dtype=bool))

            def test_x_type():
                paddle.gather_nd(np_x, index)

            self.assertRaises(TypeError, test_x_type)

            def test_index_type():
                paddle.gather_nd(x, np_index)

            self.assertRaises(TypeError, test_index_type)

            def test_index_dtype():
                paddle.gather_nd(x, index_float)

            self.assertRaises(TypeError, test_index_dtype)


class TestGatherNdAPI2(unittest.TestCase):
    def test_static(self):
        with fluid.program_guard(fluid.Program(), fluid.Program()):
G
GGBond8488 已提交
509 510 511 512
            data1 = paddle.static.data('data1', shape=[-1, 2], dtype='float64')
            data1.desc.set_need_check_feed(False)
            index = paddle.static.data('index', shape=[-1, 1], dtype='int32')
            index.desc.set_need_check_feed(False)
513 514 515 516
            out = paddle.gather_nd(data1, index)
            place = fluid.CPUPlace()
            exe = fluid.Executor(place)
            input = np.array([[1, 2], [3, 4], [5, 6]])
G
GGBond8488 已提交
517
            index_1 = np.array([[1]]).astype('int32')
518 519 520
            (result,) = exe.run(
                feed={"data1": input, "index": index_1}, fetch_list=[out]
            )
521
            expected_output = np.array([[3, 4]])
522
        np.testing.assert_allclose(result, expected_output, rtol=1e-05)
523

张春乔 已提交
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
    def test_static_fp16_with_gpu(self):
        if paddle.fluid.core.is_compiled_with_cuda():
            place = paddle.CUDAPlace(0)
            with paddle.static.program_guard(
                paddle.static.Program(), paddle.static.Program()
            ):
                input = np.array(
                    [[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 10], [11, 12]]],
                    dtype='float16',
                )
                index = np.array([[0, 1]], dtype='int32')
                res_np = np.array([[3, 4]], dtype='float16')

                x = paddle.static.data(
                    name="x", shape=[2, 3, 2], dtype="float16"
                )
                x.desc.set_need_check_feed(False)
                idx = paddle.static.data(
                    name="index", shape=[1, 2], dtype="int32"
                )
                idx.desc.set_need_check_feed(False)

                y = paddle.gather_nd(x, idx)

                exe = paddle.static.Executor(place)
                res = exe.run(
                    paddle.static.default_main_program(),
                    feed={"x": input, "index": index},
                    fetch_list=[y],
                )

                np.testing.assert_allclose(res[0], res_np, rtol=1e-05)

557 558 559 560 561 562
    def test_imperative(self):
        paddle.disable_static()
        input_1 = np.array([[1, 2], [3, 4], [5, 6]])
        index_1 = np.array([[1]])
        input = fluid.dygraph.to_variable(input_1)
        index = fluid.dygraph.to_variable(index_1)
563
        output = paddle.gather(input, index)
564
        output_np = output.numpy()
565 566
        expected_output = np.array([[3, 4]])
        np.testing.assert_allclose(output_np, expected_output, rtol=1e-05)
567 568 569
        paddle.enable_static()


570
if __name__ == "__main__":
H
hong 已提交
571
    paddle.enable_static()
572
    unittest.main()