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

1362 lines
47 KiB
Python

# Copyright (c) 2023 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 copy
import unittest
import numpy as np
from op_test import get_device_place, get_devices, is_custom_device
import paddle
from paddle.base import core
def compute_index_put_ref(x_np, indices_np, value_np, accumulate=False):
if accumulate:
x_np[indices_np] += value_np
return x_np
else:
x_np[indices_np] = value_np
return x_np
def raw_index_put(x, indices, value, accumulate):
return paddle.index_put(x, indices, value, accumulate)
def has_duplicate_index(indices, shapes):
bd_shape = np.broadcast_shapes(*shapes)
bd_indices = [
list(np.broadcast_to(indice, bd_shape).flatten()) for indice in indices
]
zip_res = list(zip(*bd_indices))
if len(zip_res) == len(set(zip_res)):
return False
else:
return True
def gen_indices_np(x_shape, indices_shapes, index_type, is_all_false):
indices = []
if index_type == np.bool_:
indice = np.zeros(indices_shapes[0], dtype=np.bool_)
if not is_all_false:
indice.flatten()
for i in range(len(indice)):
indice[i] = (i & 1) == 0
indice = indice.reshape(indices_shapes[0])
indices.append(indice)
else:
while True:
indices = []
for i in range(len(indices_shapes)):
np.random.seed()
index_np = np.random.randint(
low=0,
high=x_shape[i],
size=indices_shapes[i],
dtype=index_type,
)
indices.append(index_np)
if not has_duplicate_index(
copy.deepcopy(indices), copy.deepcopy(indices_shapes)
):
break
return tuple(indices)
class TestIndexPutAPIBase(unittest.TestCase):
def setUp(self):
self.mixed_indices = False
self.is_all_false = False
self.init_dtype_type()
self.setPlace()
self.x_np = np.random.random(self.x_shape).astype(self.dtype_np)
self.value_np = np.random.random(self.value_shape).astype(self.dtype_np)
if self.mixed_indices:
tmp_indices_np1 = gen_indices_np(
self.x_shape,
self.indices_shapes,
self.index_type_np,
self.is_all_false,
)
tmp_indices_np2 = gen_indices_np(
self.x_shape,
self.indices_shapes1,
self.index_type_np1,
self.is_all_false,
)
self.indices_np = tuple(
list(tmp_indices_np1) + list(tmp_indices_np2)
)
else:
self.indices_np = gen_indices_np(
self.x_shape,
self.indices_shapes,
self.index_type_np,
self.is_all_false,
)
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.int64
self.x_shape = (100, 110)
self.indices_shapes = [(21,), (21,)]
self.value_shape = (21,)
self.dtype_pd = "float64"
self.index_type_pd = "int64"
self.accumulate = False
def setPlace(self):
self.place = get_devices()
if self.dtype_np is np.float16 and "cpu" in self.place:
self.place.remove("cpu")
def test_dygraph_forward(self):
paddle.disable_static()
for place in self.place:
paddle.device.set_device(place)
self.x_pd = paddle.to_tensor(self.x_np, dtype=self.dtype_pd)
self.value_pd = paddle.to_tensor(self.value_np, dtype=self.dtype_pd)
self.indices_pd = [
paddle.to_tensor(indice) for indice in self.indices_np
]
self.indices_pd = tuple(self.indices_pd)
ref_res = compute_index_put_ref(
self.x_np, self.indices_np, self.value_np, self.accumulate
)
pd_res = paddle.index_put(
self.x_pd, self.indices_pd, self.value_pd, self.accumulate
)
np.testing.assert_allclose(ref_res, pd_res.numpy(), atol=1e-7)
def test_static_forward(self):
paddle.enable_static()
for place in self.place:
with paddle.static.program_guard(paddle.static.Program()):
x = paddle.static.data(
name="x", shape=self.x_shape, dtype=self.dtype_pd
)
if self.mixed_indices:
indices = tuple(
[
paddle.static.data(
name="indice" + str(i),
shape=self.indices_shapes[i],
dtype=self.index_type_pd,
)
for i in range(len(self.indices_shapes))
]
+ [
paddle.static.data(
name="indice"
+ str(i + len(self.indices_shapes)),
shape=self.indices_shapes1[i],
dtype=self.index_type_pd1,
)
for i in range(len(self.indices_shapes1))
]
)
else:
indices = tuple(
[
paddle.static.data(
name="indice" + str(i),
shape=self.indices_shapes[i],
dtype=self.index_type_pd,
)
for i in range(len(self.indices_shapes))
]
)
value = paddle.static.data(
name="value", shape=self.value_shape, dtype=self.dtype_pd
)
out = paddle.index_put(x, indices, value, self.accumulate)
exe = paddle.static.Executor(place=place)
feed_list = {}
feed_list.update({"x": self.x_np})
for i in range(len(indices)):
feed_list.update({"indice" + str(i): self.indices_np[i]})
feed_list.update({"value": self.value_np})
pd_res = exe.run(
feed=feed_list,
fetch_list=[out],
)
ref_res = compute_index_put_ref(
self.x_np, self.indices_np, self.value_np, self.accumulate
)
np.testing.assert_allclose(ref_res, pd_res[0], atol=1e-7)
class TestIndexPutAPI0(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.int64
self.x_shape = (100, 110)
self.indices_shapes = [(21,), (21,)]
self.value_shape = (21,)
self.dtype_pd = "float64"
self.index_type_pd = "int64"
self.accumulate = True
class TestIndexPutAPI1(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.int64
self.x_shape = (110, 42, 56, 56)
self.indices_shapes = ((16, 16), (16, 16), (1, 16), (1, 16))
self.value_shape = (16, 16)
self.dtype_pd = "float64"
self.index_type_pd = "int64"
self.accumulate = False
class TestIndexPutAPI2(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.int64
self.x_shape = (110, 42, 56, 56)
self.indices_shapes = ((16, 16), (16, 16), (1, 16), (1, 16))
self.value_shape = (16, 16)
self.dtype_pd = "float64"
self.index_type_pd = "int64"
self.accumulate = True
class TestIndexPutAPI3(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.bool_
self.x_shape = (110, 94)
self.indices_shapes = [(110, 94)]
self.value_shape = (5170,)
self.dtype_pd = "float64"
self.index_type_pd = "bool"
self.accumulate = False
class TestIndexPutAPI4(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.bool_
self.x_shape = (110, 94)
self.indices_shapes = [(110, 94)]
self.value_shape = (5170,)
self.dtype_pd = "float64"
self.index_type_pd = "bool"
self.accumulate = True
class TestIndexPutAPI5(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.int64
self.x_shape = (110, 42, 56, 56)
self.indices_shapes = ((16, 16), (16, 16), (1, 16))
self.value_shape = (16, 16, 56)
self.dtype_pd = "float64"
self.index_type_pd = "int64"
self.accumulate = False
class TestIndexPutAPI6(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.int64
self.x_shape = (110, 42, 56, 56)
self.indices_shapes = ((16, 16), (16, 16), (1, 16))
self.value_shape = (16, 16, 56)
self.dtype_pd = "float64"
self.index_type_pd = "int64"
self.accumulate = True
class TestIndexPutAPI7(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.bool_
self.x_shape = (110, 94)
self.indices_shapes = [(110,)]
self.value_shape = (55, 94)
self.dtype_pd = "float64"
self.index_type_pd = "bool"
self.accumulate = False
class TestIndexPutAPI8(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.bool_
self.x_shape = (110, 94)
self.indices_shapes = [(110,)]
self.value_shape = (55, 94)
self.dtype_pd = "float64"
self.index_type_pd = "bool"
self.accumulate = True
class TestIndexPutAPI9(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.int64
self.x_shape = (110, 42, 56, 56)
self.indices_shapes = ((16, 16), (16, 16), (1, 16))
self.value_shape = (56,)
self.dtype_pd = "float64"
self.index_type_pd = "int64"
self.accumulate = False
class TestIndexPutAPI10(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.int64
self.x_shape = (110, 42, 56, 56)
self.indices_shapes = ((16, 16), (16, 16), (1, 16))
self.value_shape = (56,)
self.dtype_pd = "float64"
self.index_type_pd = "int64"
self.accumulate = True
class TestIndexPutAPI11(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.int64
self.x_shape = (110, 42, 56, 56)
self.indices_shapes = ((16, 16), (16, 16), (1, 16))
self.value_shape = (1,)
self.dtype_pd = "float64"
self.index_type_pd = "int64"
self.accumulate = False
class TestIndexPutAPI12(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.int64
self.x_shape = (110, 42, 56, 56)
self.indices_shapes = ((16, 16), (16, 16), (1, 16))
self.value_shape = (1,)
self.dtype_pd = "float64"
self.index_type_pd = "int64"
self.accumulate = True
class TestIndexPutAPI13(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.bool_
self.x_shape = (44, 94)
self.indices_shapes = [(44,)]
self.value_shape = (94,)
self.dtype_pd = "float64"
self.index_type_pd = "bool"
self.accumulate = False
class TestIndexPutAPI14(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.bool_
self.x_shape = (44, 94)
self.indices_shapes = [(44,)]
self.value_shape = (94,)
self.dtype_pd = "float64"
self.index_type_pd = "bool"
self.accumulate = True
class TestIndexPutAPI15(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.bool_
self.x_shape = (44, 94)
self.indices_shapes = [(44,)]
self.value_shape = (1,)
self.dtype_pd = "float64"
self.index_type_pd = "bool"
self.accumulate = False
class TestIndexPutAPI16(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.bool_
self.x_shape = (44, 94)
self.indices_shapes = [(44,)]
self.value_shape = (1,)
self.dtype_pd = "float64"
self.index_type_pd = "bool"
self.accumulate = True
class TestIndexPutAPI17(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.int32
self.x_shape = (100, 110)
self.indices_shapes = [(21,), (21,)]
self.value_shape = (21,)
self.dtype_pd = "float64"
self.index_type_pd = "int32"
self.accumulate = False
class TestIndexPutAPI18(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.int32
self.x_shape = (100, 110)
self.indices_shapes = [(21,), (21,)]
self.value_shape = (21,)
self.dtype_pd = "float64"
self.index_type_pd = "int32"
self.accumulate = True
class TestIndexPutAPI19(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float32
self.index_type_np = np.int32
self.x_shape = (100, 110)
self.indices_shapes = [(21,), (21,)]
self.value_shape = (21,)
self.dtype_pd = "float32"
self.index_type_pd = "int32"
self.accumulate = False
class TestIndexPutAPI20(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float32
self.index_type_np = np.int32
self.x_shape = (100, 110)
self.indices_shapes = [(21,), (21,)]
self.value_shape = (21,)
self.dtype_pd = "float32"
self.index_type_pd = "int32"
self.accumulate = True
class TestIndexPutAPI21(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float16
self.index_type_np = np.int32
self.x_shape = (100, 110)
self.indices_shapes = [(21,), (21,)]
self.value_shape = (21,)
self.dtype_pd = "float16"
self.index_type_pd = "int32"
self.accumulate = False
class TestIndexPutAPI22(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float16
self.index_type_np = np.int32
self.x_shape = (100, 110)
self.indices_shapes = [(21,), (21,)]
self.value_shape = (21,)
self.dtype_pd = "float16"
self.index_type_pd = "int32"
self.accumulate = True
class TestIndexPutAPI23(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.int32
self.index_type_np = np.int32
self.x_shape = (100, 110)
self.indices_shapes = [(21,), (21,)]
self.value_shape = (21,)
self.dtype_pd = "int32"
self.index_type_pd = "int32"
self.accumulate = False
class TestIndexPutAPI24(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.int32
self.index_type_np = np.int32
self.x_shape = (100, 110)
self.indices_shapes = [(21,), (21,)]
self.value_shape = (21,)
self.dtype_pd = "int32"
self.index_type_pd = "int32"
self.accumulate = True
class TestIndexPutAPI25(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.int64
self.index_type_np = np.int32
self.x_shape = (100, 110)
self.indices_shapes = [(21,), (21,)]
self.value_shape = (21,)
self.dtype_pd = "int64"
self.index_type_pd = "int32"
self.accumulate = False
class TestIndexPutAPI26(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.int64
self.index_type_np = np.int32
self.x_shape = (100, 110)
self.indices_shapes = [(21,), (21,)]
self.value_shape = (21,)
self.dtype_pd = "int64"
self.index_type_pd = "int32"
self.accumulate = True
class TestIndexPutAPI27(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.bool_
self.index_type_np = np.int32
self.x_shape = (100, 110)
self.indices_shapes = [(21,), (21,)]
self.value_shape = (21,)
self.dtype_pd = "bool"
self.index_type_pd = "int32"
self.accumulate = False
class TestIndexPutAPI28(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.bool_
self.index_type_np = np.int32
self.x_shape = (100, 110)
self.indices_shapes = [(21,), (21,)]
self.value_shape = (21,)
self.dtype_pd = "bool"
self.index_type_pd = "int32"
self.accumulate = True
class TestIndexPutAPI29(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.int32
self.x_shape = (110, 42, 56, 56)
self.indices_shapes = ((16, 16), (16, 16), (1, 16))
self.value_shape = (16, 16, 56)
self.dtype_pd = "float64"
self.index_type_pd = "int32"
self.accumulate = False
class TestIndexPutAPI30(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.int32
self.x_shape = (110, 42, 56, 56)
self.indices_shapes = ((16, 16), (16, 16), (1, 16))
self.value_shape = (16, 16, 56)
self.dtype_pd = "float64"
self.index_type_pd = "int32"
self.accumulate = True
class TestIndexPutAPI31(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.bool_
self.index_type_np = np.int32
self.x_shape = (100, 110)
self.indices_shapes = [(21,), (21,)]
self.value_shape = (21,)
self.dtype_pd = "bool"
self.index_type_pd = "int32"
self.accumulate = False
self.is_all_false = True
class TestIndexPutAPI32(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.bool_
self.index_type_np = np.int32
self.x_shape = (100, 110)
self.indices_shapes = [(21,), (21,)]
self.value_shape = (21,)
self.dtype_pd = "bool"
self.index_type_pd = "int32"
self.accumulate = True
self.is_all_false = True
class TestIndexPutInplaceAPI(unittest.TestCase):
def setUp(self):
self.init_dtype_type()
self.setPlace()
self.x_np = np.random.random(self.x_shape).astype(self.dtype_np)
self.value_np = np.random.random(self.value_shape).astype(self.dtype_np)
self.indices_np = gen_indices_np(
self.x_shape, self.indices_shapes, self.index_type_np, False
)
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.int64
self.x_shape = (100, 110)
self.indices_shapes = [(21,), (21,)]
self.value_shape = (21,)
self.dtype_pd = "float64"
self.index_type_pd = "int64"
self.accumulate = False
def setPlace(self):
self.place = get_devices()
def test_dygraph_forward(self):
paddle.disable_static()
for place in self.place:
paddle.device.set_device(place)
self.x_pd = paddle.to_tensor(self.x_np, dtype=self.dtype_pd)
self.value_pd = paddle.to_tensor(self.value_np, dtype=self.dtype_pd)
self.indices_pd = [
paddle.to_tensor(indice, dtype=self.index_type_pd)
for indice in self.indices_np
]
self.indices_pd = tuple(self.indices_pd)
ref_res = compute_index_put_ref(
self.x_np, self.indices_np, self.value_np, self.accumulate
)
x_pd_bk = self.x_pd.clone()
pd_res = paddle.index_put_(
x_pd_bk, self.indices_pd, self.value_pd, self.accumulate
)
np.testing.assert_allclose(ref_res, pd_res.numpy(), atol=1e-7)
np.testing.assert_allclose(ref_res, x_pd_bk.numpy(), atol=1e-7)
class TestIndexPutInplaceAPI1(TestIndexPutInplaceAPI):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.int64
self.x_shape = (100, 110)
self.indices_shapes = [(21,), (21,)]
self.value_shape = (21,)
self.dtype_pd = "float64"
self.index_type_pd = "int64"
self.accumulate = True
class TestIndexPutAPIBackward(unittest.TestCase):
def setUp(self):
self.setPlace()
def setPlace(self):
self.place = get_devices()
def test_backward(self):
paddle.disable_static()
for place in self.place:
paddle.device.set_device(place)
value = paddle.ones(shape=[4], dtype="float64")
x = paddle.ones(shape=[16, 21], dtype="float64")
ix1 = paddle.to_tensor([0, 1, 2, 3], dtype="int64")
ix2 = paddle.to_tensor([0, 1, 2, 3], dtype="int64")
value.stop_gradient = False
x.stop_gradient = False
out = paddle.index_put(x, (ix1, ix2), value, False)
dx, dvalue = paddle.grad(
outputs=[out],
inputs=[x, value],
create_graph=False,
retain_graph=True,
)
ref_dx = np.ones(shape=[16, 21], dtype=np.float64)
ref_dx[ix1, ix2] = 0
np.testing.assert_allclose(ref_dx, dx.numpy(), atol=1e-7)
np.testing.assert_allclose(
np.array([1.0, 1.0, 1.0, 1.0], dtype=np.float64),
dvalue.numpy(),
atol=1e-7,
)
out = paddle.index_put(x, (ix1, ix2), value, True)
dx, dvalue = paddle.grad(
outputs=[out],
inputs=[x, value],
create_graph=False,
retain_graph=True,
)
ref_dx = np.ones(shape=[16, 21], dtype=np.float64)
np.testing.assert_allclose(ref_dx, dx.numpy(), atol=1e-7)
np.testing.assert_allclose(
np.array([1.0, 1.0, 1.0, 1.0], dtype=np.float64),
dvalue.numpy(),
atol=1e-7,
)
def test_backward_scalarval(self):
paddle.disable_static()
for place in self.place:
paddle.device.set_device(place)
value = paddle.ones(shape=[1], dtype="float64")
x = paddle.ones(shape=[16, 21], dtype="float64")
ix1 = paddle.to_tensor([0, 1, 2, 3], dtype="int64")
ix2 = paddle.to_tensor([0, 1, 2, 3], dtype="int64")
value.stop_gradient = False
x.stop_gradient = False
out = paddle.index_put(x, (ix1, ix2), value, False)
dx, dvalue = paddle.grad(
outputs=[out],
inputs=[x, value],
create_graph=False,
retain_graph=True,
)
ref_dx = np.ones(shape=[16, 21], dtype=np.float64)
ref_dx[ix1, ix2] = 0
np.testing.assert_allclose(ref_dx, dx.numpy(), atol=1e-7)
np.testing.assert_allclose(
np.array([4.0], dtype=np.float64), dvalue.numpy(), atol=1e-7
)
out = paddle.index_put(x, (ix1, ix2), value, True)
dx, dvalue = paddle.grad(
outputs=[out],
inputs=[x, value],
create_graph=False,
retain_graph=True,
)
ref_dx = np.ones(shape=[16, 21], dtype=np.float64)
np.testing.assert_allclose(ref_dx, dx.numpy(), atol=1e-7)
np.testing.assert_allclose(
np.array([4.0], dtype=np.float64), dvalue.numpy(), atol=1e-7
)
def test_backward_broadcastvalue(self):
paddle.disable_static()
for place in self.place:
paddle.device.set_device(place)
value = paddle.ones(shape=[2], dtype="float64")
x = paddle.ones(shape=[16, 21], dtype="float64")
ix1 = paddle.to_tensor([[0, 1], [2, 3]], dtype="int64")
ix2 = paddle.to_tensor([[0, 1], [2, 3]], dtype="int64")
value.stop_gradient = False
x.stop_gradient = False
out = paddle.index_put(x, (ix1, ix2), value, False)
dx, dvalue = paddle.grad(
outputs=[out],
inputs=[x, value],
create_graph=False,
retain_graph=True,
)
ref_dx = np.ones(shape=[16, 21], dtype=np.float64)
ref_dx[ix1, ix2] = 0
np.testing.assert_allclose(ref_dx, dx.numpy(), atol=1e-7)
np.testing.assert_allclose(
np.array([2.0, 2.0], dtype=np.float64),
dvalue.numpy(),
atol=1e-7,
)
out = paddle.index_put(x, (ix1, ix2), value, True)
dx, dvalue = paddle.grad(
outputs=[out],
inputs=[x, value],
create_graph=False,
retain_graph=True,
)
ref_dx = np.ones(shape=[16, 21], dtype=np.float64)
np.testing.assert_allclose(ref_dx, dx.numpy(), atol=1e-7)
np.testing.assert_allclose(
np.array([2.0, 2.0], dtype=np.float64),
dvalue.numpy(),
atol=1e-7,
)
def test_backward_broadcastvalue1(self):
paddle.disable_static()
for place in self.place:
paddle.device.set_device(place)
value = paddle.ones(shape=[1, 2], dtype="float64")
x = paddle.ones(shape=[16, 21], dtype="float64")
ix1 = paddle.to_tensor([[0, 1], [2, 3]], dtype="int64")
ix2 = paddle.to_tensor([[0, 1], [2, 3]], dtype="int64")
value.stop_gradient = False
x.stop_gradient = False
out = paddle.index_put(x, (ix1, ix2), value, False)
dx, dvalue = paddle.grad(
outputs=[out],
inputs=[x, value],
create_graph=False,
retain_graph=True,
)
ref_dx = np.ones(shape=[16, 21], dtype=np.float64)
ref_dx[ix1, ix2] = 0
np.testing.assert_allclose(ref_dx, dx.numpy(), atol=1e-7)
np.testing.assert_allclose(
np.array([[2.0, 2.0]], dtype=np.float64),
dvalue.numpy(),
atol=1e-7,
)
out = paddle.index_put(x, (ix1, ix2), value, True)
dx, dvalue = paddle.grad(
outputs=[out],
inputs=[x, value],
create_graph=False,
retain_graph=True,
)
ref_dx = np.ones(shape=[16, 21], dtype=np.float64)
np.testing.assert_allclose(ref_dx, dx.numpy(), atol=1e-7)
np.testing.assert_allclose(
np.array([[2.0, 2.0]], dtype=np.float64),
dvalue.numpy(),
atol=1e-7,
)
def test_backward_broadcastvalue2(self):
paddle.disable_static()
for place in self.place:
paddle.device.set_device(place)
value = paddle.ones(shape=[2, 1], dtype="float64")
x = paddle.ones(shape=[16, 21], dtype="float64")
ix1 = paddle.to_tensor([[0, 1], [2, 3]], dtype="int64")
ix2 = paddle.to_tensor([[0, 1], [2, 3]], dtype="int64")
value.stop_gradient = False
x.stop_gradient = False
out = paddle.index_put(x, (ix1, ix2), value, False)
dx, dvalue = paddle.grad(
outputs=[out],
inputs=[x, value],
create_graph=False,
retain_graph=True,
)
ref_dx = np.ones(shape=[16, 21], dtype=np.float64)
ref_dx[ix1, ix2] = 0
np.testing.assert_allclose(ref_dx, dx.numpy(), atol=1e-7)
np.testing.assert_allclose(
np.array([[2.0], [2.0]], dtype=np.float64),
dvalue.numpy(),
atol=1e-7,
)
out = paddle.index_put(x, (ix1, ix2), value, True)
dx, dvalue = paddle.grad(
outputs=[out],
inputs=[x, value],
create_graph=False,
retain_graph=True,
)
ref_dx = np.ones(shape=[16, 21], dtype=np.float64)
np.testing.assert_allclose(ref_dx, dx.numpy(), atol=1e-7)
np.testing.assert_allclose(
np.array([[2.0], [2.0]], dtype=np.float64),
dvalue.numpy(),
atol=1e-7,
)
def test_backward_all_false_bool_indice(self):
paddle.disable_static()
for place in self.place:
paddle.device.set_device(place)
value = paddle.ones(shape=[2, 1], dtype="float64")
x = paddle.ones(shape=[16, 21], dtype="float64")
ix = paddle.zeros(shape=[16, 21], dtype="bool")
value.stop_gradient = False
x.stop_gradient = False
out = paddle.index_put(x, (ix,), value, False)
dx, dvalue = paddle.grad(
outputs=[out],
inputs=[x, value],
create_graph=False,
retain_graph=True,
)
ref_dx = np.ones(shape=[16, 21], dtype=np.float64)
np.testing.assert_allclose(ref_dx, dx.numpy(), atol=1e-7)
np.testing.assert_allclose(
np.array([[0.0], [0.0]], dtype=np.float64),
dvalue.numpy(),
atol=1e-7,
)
out = paddle.index_put(x, (ix,), value, True)
dx, dvalue = paddle.grad(
outputs=[out],
inputs=[x, value],
create_graph=False,
retain_graph=True,
)
ref_dx = np.ones(shape=[16, 21], dtype=np.float64)
np.testing.assert_allclose(ref_dx, dx.numpy(), atol=1e-7)
np.testing.assert_allclose(
np.array([[0.0], [0.0]], dtype=np.float64),
dvalue.numpy(),
atol=1e-7,
)
def test_backward_in_static(self):
paddle.enable_static()
exe = paddle.static.Executor()
train_program = paddle.static.Program()
startup_program = paddle.static.Program()
with paddle.static.program_guard(train_program, startup_program):
x = paddle.zeros((4, 2, 5))
x.stop_gradient = False
y = x + 1
index = paddle.to_tensor([0, 1, 3])
value = paddle.ones((5,))
value.stop_gradient = False
z = paddle.index_put(y, (index,), value)
l = z.sum()
if paddle.framework.in_pir_mode():
grads = paddle.autograd.ir_backward.grad(l, [x, value])
x_grad = grads[0]
value_grad = grads[1]
else:
paddle.static.append_backward(l)
x_grad = x.grad_name
value_grad = value.grad_name
res = exe.run(fetch_list=[z, x_grad, value_grad])
expected_z = np.ones((4, 2, 5))
expected_z[[0, 1, 3]] = np.ones((5,))
expected_x_grad = np.ones((4, 2, 5))
expected_x_grad[[0, 1, 3]] = 0
expected_v_grad = np.ones((5,)) * 3 * 2
np.testing.assert_allclose(expected_z, res[0])
np.testing.assert_allclose(expected_x_grad, res[1])
np.testing.assert_allclose(expected_v_grad, res[2])
paddle.disable_static()
class TestIndexPutAPIMixedIndices(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.int32
self.x_shape = (110, 42, 32, 56)
self.indices_shapes = ((16, 16), (16, 16))
self.value_shape = (16, 16, 56)
self.dtype_pd = "float64"
self.index_type_pd = "int32"
self.accumulate = False
self.mixed_indices = True
self.index_type_np1 = np.bool_
self.indices_shapes1 = [(32,)]
self.index_type_pd1 = "bool"
class TestIndexPutAPIMixedIndices1(TestIndexPutAPIBase):
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.int32
self.x_shape = (110, 42, 32, 56)
self.indices_shapes = ((16, 16), (16, 16))
self.value_shape = (16, 16, 56)
self.dtype_pd = "float64"
self.index_type_pd = "int32"
self.accumulate = True
self.mixed_indices = True
self.index_type_np1 = np.bool_
self.indices_shapes1 = [(32,)]
self.index_type_pd1 = "bool"
class TestIndexPutAPI_ZeroSize(unittest.TestCase):
def setUp(self):
self.init_dtype_type()
self.setPlace()
def init_dtype_type(self):
self.dtype_np = np.float32
self.index_type_np = np.int64
self.x_shape = (10, 0)
self.indices_shapes = [[10]]
self.value_shape = [1, 1]
self.dtype_pd = paddle.float32
self.index_type_pd = paddle.int64
def setPlace(self):
self.place = get_devices()
if self.dtype_np is np.float16 and "cpu" in self.place:
self.place.remove("cpu")
def test_dygraph_forward(self):
paddle.disable_static()
for place in self.place:
paddle.device.set_device(place)
x_pd = paddle.randn(self.x_shape, dtype=self.dtype_pd)
x_np = x_pd.numpy()
value_pd = paddle.randn(self.value_shape, dtype=self.dtype_pd)
value_np = value_pd.numpy()
x_pd.stop_gradient = False
value_pd.stop_gradient = False
indices_pd = [
paddle.randn(indices_shape).astype(dtype=self.index_type_pd)
for indices_shape in self.indices_shapes
]
indices_np = [item.numpy() for item in indices_pd]
indices_pd = tuple(indices_pd)
accumulate = False
ref_res = compute_index_put_ref(
x_np, indices_np, value_np, accumulate
)
pd_res = paddle.index_put(x_pd, indices_pd, value_pd, accumulate)
np.testing.assert_allclose(ref_res, pd_res.numpy(), atol=1e-7)
# check grad
pd_res.sum().backward()
np.testing.assert_allclose(x_pd.grad.shape, x_pd.shape)
np.testing.assert_allclose(
value_pd.grad.numpy(), np.zeros(value_pd.shape)
)
class TestIndexPutPrim(unittest.TestCase):
def __int__(self):
self().__init__()
def test_prim(self):
try:
paddle.framework.core._set_prim_all_enabled(True)
for accumulate in [False, True]:
for x_shape, indices_shape, value_shape in [
([16], [10], [10]),
([16, 16], [20, 2], [20]),
([12, 13, 14], [88, 1], [88, 13, 14]),
([12, 13, 14], [88, 2], [88, 14]),
([12, 13, 14], [88, 3], [88]),
([12, 13, 14], [12 * 13 * 14, 3], [12 * 13 * 14]),
]:
n_indices = indices_shape[0]
index_dim_size = (
indices_shape[1] if len(indices_shape) > 1 else 1
)
x_np = np.random.randn(*x_shape)
indices_np = tuple(
[
np.random.randint(
-x_shape[i], x_shape[i], [n_indices]
)
for i in range(max(index_dim_size, 1))
]
)
value_np = np.random.randn(*value_shape).astype("float32")
# run paddle
x_pd = paddle.to_tensor(
x_np.copy(),
"float32",
stop_gradient=False,
)
indices_pd = tuple(
[
paddle.to_tensor(
indice.copy(),
"int64",
stop_gradient=True,
)
for indice in indices_np
]
)
value_pd = paddle.to_tensor(
value_np.copy(),
"float32",
stop_gradient=False,
)
out_pd = paddle.index_put(
x_pd, indices_pd, value_pd, accumulate=accumulate
)
# out_pd = paddle.tanh(out_pd) #
dout_np = np.random.randn(*out_pd.shape)
dout_pd = paddle.to_tensor(
dout_np.copy(),
"float32",
stop_gradient=False,
)
dout_pd.stop_gradient = False
if accumulate:
def compute_dx_dv(x, indices, v, dy, accumulate=True):
y = paddle.index_put(x, indices, v, True)
return paddle.grad(y, [x, v], dy, create_graph=True)
else:
def compute_dx_dv(x, indices, v, dy, accumulate=False):
y = paddle.index_put(x, indices, v, False)
return paddle.grad(y, [x, v], dy, create_graph=True)
# eager
dx_ref, dv_ref = compute_dx_dv(
x_pd, indices_pd, value_pd, dout_pd
)
# static dynamic shape
st_func1 = paddle.jit.to_static(
compute_dx_dv,
input_spec=[
paddle.static.InputSpec(
shape=[-1, -1], dtype='float32'
),
tuple(
paddle.static.InputSpec(
shape=[-1], dtype='int64'
)
for _ in range(len(indices_pd))
),
paddle.static.InputSpec(
shape=[-1, -1], dtype='float32'
),
paddle.static.InputSpec(
shape=[-1, -1], dtype='float32'
),
],
full_graph=True,
backend=None,
)
dx_1, dv_1 = st_func1(x_pd, indices_pd, value_pd, dout_pd)
# static fixed shape
st_func2 = paddle.jit.to_static(
compute_dx_dv,
full_graph=True,
backend=None,
)
dx_2, dv_2 = st_func2(x_pd, indices_pd, value_pd, dout_pd)
np.testing.assert_allclose(
dx_1.numpy(),
dx_ref.numpy(),
err_msg=f"accumulate={accumulate}\nx_np:\n{x_np}\nindices_np:\n{indices_np}\nvalue_np:\n{value_np}\nout_np:{out_pd.numpy()}\n",
)
np.testing.assert_allclose(
dv_1.numpy(),
dv_ref.numpy(),
err_msg=f"accumulate={accumulate}\nx_np:\n{x_np}\nindices_np:\n{indices_np}\nvalue_np:\n{value_np}\nout_np:{out_pd.numpy()}\n",
)
np.testing.assert_allclose(
dx_2.numpy(),
dx_ref.numpy(),
err_msg=f"accumulate={accumulate}\nx_np:\n{x_np}\nindices_np:\n{indices_np}\nvalue_np:\n{value_np}\nout_np:{out_pd.numpy()}\n",
)
np.testing.assert_allclose(
dv_2.numpy(),
dv_ref.numpy(),
err_msg=f"accumulate={accumulate}\nx_np:\n{x_np}\nindices_np:\n{indices_np}\nvalue_np:\n{value_np}\nout_np:{out_pd.numpy()}\n",
)
finally:
paddle.framework.core._set_prim_all_enabled(False)
@unittest.skipIf(
not (core.is_compiled_with_cuda() or is_custom_device()),
"core is not compiled with CUDA",
)
class TestElementwiseMaximumOp_Stride(unittest.TestCase):
def setUp(self):
self.is_all_false = False
self.init_dtype_type()
self.setPlace()
self.x_np = np.random.random(self.x_shape).astype(self.dtype_np)
self.x_trans_np = np.transpose(self.x_np, self.perm)
self.value_np = np.random.random(self.value_shape).astype(self.dtype_np)
self.indices_np = gen_indices_np(
self.x_shape,
self.indices_shapes,
self.index_type_np,
self.is_all_false,
)
def init_dtype_type(self):
self.dtype_np = np.float64
self.index_type_np = np.int64
self.x_shape = (100, 110)
self.indices_shapes = [(21,), (21,)]
self.value_shape = (21,)
self.perm = [1, 0]
self.dtype_pd = "float64"
self.index_type_pd = "int64"
self.accumulate = False
def setPlace(self):
self.place = get_device_place()
def test_dygraph_forward(self):
paddle.disable_static()
paddle.device.set_device(self.place)
self.x_pd = paddle.to_tensor(self.x_np, dtype=self.dtype_pd)
self.x_trans_pd = paddle.to_tensor(self.x_trans_np, dtype=self.dtype_pd)
self.value_pd = paddle.to_tensor(self.value_np, dtype=self.dtype_pd)
self.indices_pd = [
paddle.to_tensor(indice) for indice in self.indices_np
]
self.indices_pd = tuple(self.indices_pd)
self.x_non_conti = paddle.transpose(self.x_trans_pd, self.perm)
ref_res = compute_index_put_ref(
self.x_np, self.indices_np, self.value_np, self.accumulate
)
pd_res = paddle.index_put(
self.x_non_conti, self.indices_pd, self.value_pd, self.accumulate
)
np.testing.assert_allclose(ref_res, pd_res.numpy(), atol=1e-7)
class TestIndexPutAPI_Compatibility(unittest.TestCase):
def setUp(self):
np.random.seed(123)
paddle.enable_static()
self.shape = [5, 6]
self.dtype = 'float32'
self.init_data()
def init_data(self):
self.np_input = np.random.randint(0, 10, self.shape).astype(self.dtype)
self.idx0 = np.array([0, 2], dtype='int64')
self.idx1 = np.array([1, 3], dtype='int64')
self.value = np.array([9.0, 10.0], dtype=self.dtype)
def test_dygraph_Compatibility(self):
paddle.disable_static()
x = paddle.to_tensor(self.np_input, dtype=self.dtype)
idx0_t = paddle.to_tensor(self.idx0, dtype='int64')
idx1_t = paddle.to_tensor(self.idx1, dtype='int64')
indices_t = (idx0_t, idx1_t)
values_t = paddle.to_tensor(self.value, dtype=self.dtype)
paddle_dygraph_out = []
# 1) position args
out1 = paddle.index_put(x, indices_t, value=values_t, accumulate=False)
paddle_dygraph_out.append(out1)
# 2) paddle-style kwargs
out2 = paddle.index_put(
x, indices=indices_t, value=values_t, accumulate=False
)
paddle_dygraph_out.append(out2)
# 3) torch-style kwarg name 'input'
out3 = paddle.index_put(
input=x, indices=indices_t, value=values_t, accumulate=False
)
paddle_dygraph_out.append(out3)
# 4) accumulate=False (position args)
out4 = paddle.index_put(x, indices_t, values_t, accumulate=False)
paddle_dygraph_out.append(out4)
ref_out = compute_index_put_ref(
self.np_input, indices_t, self.value, accumulate=False
)
# test paddle.index_put_
x.index_put_(indices_t, values_t, accumulate=False)
# Check results
np.testing.assert_allclose(ref_out, paddle_dygraph_out[0].numpy())
np.testing.assert_allclose(ref_out, paddle_dygraph_out[1].numpy())
np.testing.assert_allclose(ref_out, paddle_dygraph_out[2].numpy())
np.testing.assert_allclose(ref_out, paddle_dygraph_out[3].numpy())
np.testing.assert_allclose(ref_out, x.numpy())
paddle.enable_static()
def test_static_Compatibility(self):
paddle.enable_static()
with paddle.static.program_guard(paddle.static.Program()):
x = paddle.static.data(name="x", shape=self.shape, dtype=self.dtype)
idx0_t = paddle.static.data(name="idx0", shape=[2], dtype='int64')
idx1_t = paddle.static.data(name="idx1", shape=[2], dtype='int64')
value = paddle.static.data(
name="value", shape=[2], dtype=self.dtype
)
indices_t = (idx0_t, idx1_t)
# position args (accumulate=False)
out1 = paddle.index_put(x, indices_t, value, accumulate=False)
# paddle kwargs
out2 = paddle.index_put(
x=x, indices=indices_t, value=value, accumulate=False
)
# torch-style kwarg name 'input'
out3 = paddle.index_put(
input=x, indices=indices_t, value=value, accumulate=False
)
# accumulate=False
out4 = paddle.index_put(x, indices_t, value, accumulate=False)
exe = paddle.static.Executor(paddle.CPUPlace())
fetches = exe.run(
feed={
"x": self.np_input,
"idx0": self.idx0,
"idx1": self.idx1,
"value": self.value,
},
fetch_list=[out1, out2, out3, out4],
)
ref_out = compute_index_put_ref(
self.np_input,
(self.idx0, self.idx1),
self.value,
accumulate=False,
)
for out in fetches:
np.testing.assert_allclose(out, ref_out)
if __name__ == '__main__':
unittest.main()