Files
paddlepaddle--paddle/test/legacy_test/test_take_along_axis_op.py
T
2026-07-13 12:40:42 +08:00

513 lines
17 KiB
Python

# 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.
import sys
import unittest
import numpy as np
from op_test import (
OpTest,
convert_float_to_uint16,
get_device_place,
get_places,
is_custom_device,
)
from utils import dygraph_guard
import paddle
from paddle.framework import core
paddle.enable_static()
class TestTakeAlongAxis0Size(OpTest):
def setUp(self):
self.python_api = paddle.take_along_axis
self.op_type = "take_along_axis"
self.dtype = "float64"
self.check_pir = True
x = np.zeros((2, 0, 5)).astype(self.dtype)
indices = np.zeros((2, 3, 5)).astype("int64")
self.inputs = {'Input': x, 'Index': indices}
self.attrs = {'Axis': 1}
output = np.zeros((2, 3, 5)).astype(self.dtype)
self.outputs = {'Result': output}
def test_check_output(self):
self.check_output(check_pir=self.check_pir)
def test_check_grad(self):
self.check_grad(['Input'], 'Result', check_pir=self.check_pir)
class TestTakeAlongAxis0Size2(OpTest):
def setUp(self):
self.python_api = paddle.take_along_axis
self.op_type = "take_along_axis"
self.dtype = "float64"
self.check_pir = True
x = np.random.rand(2, 3, 5).astype(self.dtype)
indices = np.zeros((2, 0, 5)).astype("int64")
self.inputs = {'Input': x, 'Index': indices}
self.attrs = {'Axis': 1}
output = np.zeros((2, 0, 5)).astype(self.dtype)
self.outputs = {'Result': output}
def test_check_output(self):
self.check_output(check_pir=self.check_pir)
def test_check_grad(self):
self.grad = np.zeros_like(self.outputs['Result']).astype(self.dtype)
self.check_grad(
['Input'],
'Result',
user_defined_grads=[self.grad],
check_pir=self.check_pir,
)
class TestTakeAlongAxisOp(OpTest):
def setUp(self):
self.init_data()
self.op_type = "take_along_axis"
self.prim_op_type = "prim"
self.python_api = paddle.tensor.take_along_axis
self.public_python_api = paddle.tensor.take_along_axis
self.check_cinn = True
self.xnp = np.random.random(self.x_shape).astype(self.x_type)
self.target = np.take_along_axis(self.xnp, self.index, self.axis)
broadcast_shape_list = list(self.x_shape)
broadcast_shape_list[self.axis] = 1
self.broadcast_shape = tuple(broadcast_shape_list)
self.index_broadcast = np.broadcast_to(self.index, self.broadcast_shape)
self.inputs = {
'Input': self.xnp,
'Index': self.index_broadcast,
}
self.attrs = {'Axis': self.axis}
self.outputs = {'Result': self.target}
def test_check_output(self):
self.check_output(check_cinn=self.check_cinn, check_pir=True)
def test_check_grad(self):
self.check_grad(
['Input'],
'Result',
check_cinn=self.check_cinn,
check_pir=True,
check_prim_pir=True,
)
def init_data(self):
self.x_type = "float64"
self.x_shape = (5, 5, 5)
self.index_type = "int32"
self.axis = 2
dim_size = self.x_shape[self.axis]
self.index = np.random.randint(
-dim_size, dim_size, size=(5, 1, 1)
).astype(self.index_type)
self.axis_type = "int64"
class TestTakeAlongAxisDuplicatedIndices(TestTakeAlongAxisOp):
def init_data(self):
self.dtype = np.float32
self.x_type = "float32"
self.x_shape = (5, 6, 7)
self.index_type = "int64"
self.axis = 2
dim_size = self.x_shape[self.axis]
self.index = (
np.asarray([-dim_size, -dim_size, dim_size - 1, dim_size - 1, 0])
.astype(self.index_type)
.reshape([5, 1, 1])
)
self.axis_type = "int64"
def test_check_output(self):
self.check_output(
check_cinn=self.check_cinn, check_pir=True, check_prim_pir=True
)
def test_check_grad(self):
self.check_grad(
['Input'],
'Result',
check_cinn=self.check_cinn,
check_pir=True,
check_prim_pir=True,
)
class TestTakeAlongAxisFP16Op(TestTakeAlongAxisOp):
def init_data(self):
self.dtype = np.float16
self.x_type = "float16"
self.x_shape = (5, 5, 5)
self.index_type = "int32"
self.axis = 2
dim_size = self.x_shape[self.axis]
self.index = np.random.randint(
-dim_size, dim_size, size=(5, 1, 1)
).astype(self.index_type)
self.axis_type = "int64"
class TestTakeAlongAxisOp2(OpTest):
def setUp(self):
self.init_data()
self.op_type = "take_along_axis"
self.python_api = paddle.tensor.take_along_axis
self.check_cinn = True
self.xnp = np.random.random(self.x_shape).astype(self.x_type)
self.target = np.zeros((2, 3, 4)).astype(self.x_type)
for i in range(2):
for j in range(3):
for k in range(4):
self.target[i, j, k] = self.xnp[i, j, self.index[i, j, k]]
self.inputs = {
'Input': self.xnp,
'Index': self.index,
}
self.attrs = {'Axis': self.axis, 'broadcast': False}
self.outputs = {'Result': self.target}
def init_data(self):
self.x_type = "float64"
self.x_shape = (10, 10, 10)
self.index_type = "int64"
self.axis = 2
dim_size = self.x_shape[self.axis]
self.index = np.random.randint(-dim_size, dim_size, (2, 3, 4)).astype(
self.index_type
)
self.axis_type = "int64"
@unittest.skipIf(
not (core.is_compiled_with_cuda() or is_custom_device())
or not core.is_bfloat16_supported(get_device_place()),
"core is not compiled with CUDA and not support the bfloat16",
)
class TestTakeAlongAxisBF16Op(OpTest):
def setUp(self):
self.init_data()
self.op_type = "take_along_axis"
self.prim_op_type = "prim"
self.python_api = paddle.tensor.take_along_axis
self.public_python_api = paddle.tensor.take_along_axis
self.check_cinn = True
self.xnp = np.random.random(self.x_shape).astype(self.x_type)
self.target = np.take_along_axis(self.xnp, self.index, self.axis)
broadcast_shape_list = list(self.x_shape)
broadcast_shape_list[self.axis] = 1
self.broadcast_shape = tuple(broadcast_shape_list)
self.index_broadcast = np.broadcast_to(self.index, self.broadcast_shape)
self.inputs = {
'Input': self.xnp,
'Index': self.index_broadcast,
}
self.attrs = {'Axis': self.axis}
self.outputs = {'Result': self.target}
self.inputs['Input'] = convert_float_to_uint16(self.inputs['Input'])
self.outputs['Result'] = convert_float_to_uint16(self.outputs['Result'])
self.place = get_device_place()
def test_check_output(self):
self.check_output_with_place(
self.place, check_cinn=self.check_cinn, check_pir=True
)
def test_check_grad(self):
self.check_grad_with_place(
self.place,
['Input'],
'Result',
check_cinn=self.check_cinn,
check_pir=True,
check_prim_pir=True,
)
def init_data(self):
self.dtype = np.uint16
self.x_type = "float32"
self.x_shape = (5, 5, 5)
self.index_type = "int32"
self.axis = 2
dim_size = self.x_shape[self.axis]
self.index = np.random.randint(
-dim_size, dim_size, size=(5, 1, 1)
).astype(self.index_type)
self.axis_type = "int64"
class TestCase1(TestTakeAlongAxisOp):
def init_data(self):
self.x_type = "float64"
self.x_shape = (5, 5, 5)
self.index_type = "int32"
self.axis = 0
dim_size = self.x_shape[self.axis]
self.index = np.random.randint(
-dim_size, dim_size, size=(1, 1, 5)
).astype(self.index_type)
self.axis_type = "int64"
class TestTakeAlongAxisAPI(unittest.TestCase):
def setUp(self):
np.random.seed(0)
self.shape = [3, 3]
self.index_shape = [1, 3]
self.axis = 0
dim_size = self.shape[self.axis]
self.index_np = np.random.randint(
-dim_size, dim_size, size=([1, 3])
).astype('int64')
self.x_np = np.random.random(self.shape).astype(np.float32)
self.place = get_places()
def test_api_static(self):
paddle.enable_static()
with paddle.static.program_guard(paddle.static.Program()):
x = paddle.static.data('X', self.shape)
index = paddle.static.data('Index', self.index_shape, "int64")
out = paddle.take_along_axis(x, index, self.axis)
exe = paddle.static.Executor(self.place[0])
res = exe.run(
feed={'X': self.x_np, 'Index': self.index_np}, fetch_list=[out]
)
out_ref = np.array(
np.take_along_axis(self.x_np, self.index_np, self.axis)
)
for out in res:
np.testing.assert_allclose(out, out_ref, rtol=0.001)
def test_api_dygraph(self):
paddle.disable_static(self.place[0])
x_tensor = paddle.to_tensor(self.x_np)
self.index = paddle.to_tensor(self.index_np)
out = paddle.take_along_axis(x_tensor, self.index, self.axis)
out_ref = np.array(
np.take_along_axis(self.x_np, self.index_np, self.axis)
)
np.testing.assert_allclose(out.numpy(), out_ref, rtol=0.001)
paddle.enable_static()
def test_api_dygraph_dtype(self):
if sys.platform == 'darwin' or sys.platform == 'win32':
return
paddle.disable_static(paddle.CPUPlace())
with self.assertRaises(AssertionError):
x_tensor = paddle.to_tensor(self.x_np)
self.index = paddle.to_tensor(self.index_np).astype("float32")
out = paddle.take_along_axis(x_tensor, self.index, self.axis)
out_ref = np.array(
np.take_along_axis(self.x_np, self.index_np, self.axis)
)
np.testing.assert_allclose(out.numpy(), out_ref, rtol=0.001)
paddle.enable_static()
class TestTakeAlongAxisAPICase1(TestTakeAlongAxisAPI):
def setUp(self):
np.random.seed(0)
self.shape = [2, 2]
self.index_shape = [4, 2]
self.axis = 0
dim_size = self.shape[self.axis]
self.index_np = np.random.randint(
-dim_size, dim_size, size=(4, 2)
).astype('int64')
self.x_np = np.random.random(self.shape).astype(np.float32)
self.place = get_places()
class TestTakeAlongAxisAPICase2(unittest.TestCase):
def setUp(self):
np.random.seed(0)
self.shape = [3, 3]
self.index_shape = [1, 3]
self.axis = 0
dim_size = self.shape[self.axis]
self.index_np = np.random.randint(
-dim_size, dim_size, size=(1, 3)
).astype('int64')
self.x_np = np.random.random(self.shape).astype(np.float32)
self.place = get_places()
def test_api_static(self):
paddle.enable_static()
with paddle.static.program_guard(paddle.static.Program()):
x = paddle.static.data('X', self.shape)
index = paddle.static.data('Index', self.index_shape, "int64")
out = paddle.take_along_axis(x, index, self.axis, False)
exe = paddle.static.Executor(self.place[0])
res = exe.run(
feed={'X': self.x_np, 'Index': self.index_np}, fetch_list=[out]
)
out_ref = np.zeros_like(self.index_np, dtype=self.x_np.dtype)
for i in range(self.index_shape[0]):
for j in range(self.index_shape[1]):
out_ref[i, j] = self.x_np[self.index_np[i, j], j]
for out in res:
np.testing.assert_allclose(out, out_ref, rtol=0.001)
def test_api_dygraph(self):
paddle.disable_static(self.place[0])
x_tensor = paddle.to_tensor(self.x_np)
self.index = paddle.to_tensor(self.index_np)
out = paddle.take_along_axis(x_tensor, self.index, self.axis, False)
out_ref = np.zeros_like(self.index_np, dtype=self.x_np.dtype)
for i in range(self.index_shape[0]):
for j in range(self.index_shape[1]):
out_ref[i, j] = self.x_np[self.index_np[i, j], j]
np.testing.assert_allclose(out.numpy(), out_ref, rtol=0.001)
paddle.enable_static()
def test_error(self):
paddle.disable_static(self.place[0])
tensorx = paddle.to_tensor([[1, 2, 3], [4, 5, 6]]).astype("float32")
indices = paddle.to_tensor([1]).astype("int32")
# len(arr.shape) != len(indices.shape)
with self.assertRaises(ValueError):
res = paddle.take_along_axis(tensorx, indices, 0, False)
# the element of indices out of range
# (only catch cpu assertion though gpu can raise exception)
with self.assertRaises(IndexError):
indices = paddle.to_tensor([[100]]).astype("int32")
res = paddle.take_along_axis(
tensorx.to("cpu"), indices.to("cpu"), 0, False
)
with self.assertRaises(IndexError):
indices = paddle.to_tensor([[-100]]).astype("int32")
res = paddle.take_along_axis(
tensorx.to("cpu"), indices.to("cpu"), 0, False
)
# the shape of indices doesn't match
with self.assertRaises(RuntimeError):
indices = paddle.to_tensor(
[[1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]]
).astype("int32")
res = paddle.take_along_axis(tensorx, indices, 0, False)
class TestTakeAlongAxisAPICase4(unittest.TestCase):
def test_static_shape_take_along_axis(self):
with dygraph_guard():
x = paddle.randn([4, 2])
ind = paddle.to_tensor([[0, 1]])
static_f = paddle.jit.to_static(
paddle.take_along_axis,
input_spec=[
paddle.static.InputSpec(
shape=[-1, -1], dtype="float32", name="arr"
),
paddle.static.InputSpec(
shape=[-1, 2], dtype="int64", name="indices"
),
],
full_graph=True,
)
_ = static_f(x, ind, axis=0, broadcast=False)
class TestTakeAlongAxis_ZeroSize(OpTest):
def setUp(self):
self.python_api = paddle.take_along_axis
self.op_type = "take_along_axis"
self.dtype = "float64"
self.check_pir = True
x = np.zeros((2, 0, 5)).astype(self.dtype)
indices = np.zeros((2, 3, 5)).astype("int64")
self.inputs = {'Input': x, 'Index': indices}
self.attrs = {'Axis': 1}
output = np.zeros((2, 3, 5)).astype(self.dtype)
self.outputs = {'Result': output}
def test_check_output(self):
self.check_output_with_place(
paddle.CPUPlace(), check_pir=self.check_pir
)
if core.is_compiled_with_cuda() or is_custom_device():
self.check_output_with_place(
get_device_place(), check_pir=self.check_pir
)
def test_check_grad(self):
self.check_grad_with_place(
paddle.CPUPlace(), ['Input'], 'Result', check_pir=self.check_pir
)
if core.is_compiled_with_cuda() or is_custom_device():
self.check_grad_with_place(
get_device_place(),
['Input'],
'Result',
check_pir=self.check_pir,
)
class TestTakeAlongAxisInt16(TestTakeAlongAxisOp):
def init_data(self):
self.dtype = np.int16
self.x_type = "int16"
self.x_shape = (5, 5, 5)
self.index_type = "int32"
self.axis = 2
dim_size = self.x_shape[self.axis]
self.index = np.random.randint(
-dim_size, dim_size, size=(5, 1, 1)
).astype(self.index_type)
self.axis_type = "int64"
def test_check_grad(self):
"""int16 does not require and allow for grad check"""
pass
class TestTakeAlongAxisUInt8(TestTakeAlongAxisOp):
def init_data(self):
self.dtype = np.uint8
self.x_type = "uint8"
self.x_shape = (5, 5, 5)
self.index_type = "int32"
self.axis = 2
dim_size = self.x_shape[self.axis]
self.index = np.random.randint(
-dim_size, dim_size, size=(5, 1, 1)
).astype(self.index_type)
self.axis_type = "int64"
def test_check_grad(self):
"""uint8 does not require and allow for grad check"""
pass
if __name__ == "__main__":
paddle.enable_static()
unittest.main()