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

408 lines
12 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 unittest
import numpy as np
from op_test import (
convert_float_to_uint16,
get_device,
get_device_place,
get_places,
is_custom_device,
)
import paddle
from paddle import base
from paddle.base import core
def np_masked_fill(x, mask, value):
if not np.isscalar(value):
value = value[0]
x, mask = np.broadcast_arrays(x, mask)
result = np.copy(x)
for idx, m in np.ndenumerate(mask):
if m:
result[idx] = value
return result
paddle.enable_static()
class TestMaskedFillAPI(unittest.TestCase):
def setUp(self):
self.init()
self.x_np = np.random.random(self.x_shape).astype(self.dtype)
self.mask_np = np.array(
np.random.randint(2, size=self.mask_shape), dtype="bool"
)
self.value_np = np.random.randn(1).astype(self.dtype)
self.out_np = np_masked_fill(self.x_np, self.mask_np, self.value_np)
def init(self):
self.x_shape = (50, 3)
self.mask_shape = self.x_shape
self.dtype = "float32"
self.scalar_value = False
def test_static_graph(self):
paddle.enable_static()
startup_program = base.Program()
train_program = base.Program()
with base.program_guard(startup_program, train_program):
x = paddle.static.data(
name='x', dtype=self.dtype, shape=self.x_shape
)
mask = paddle.static.data(
name='mask', dtype='bool', shape=self.mask_shape
)
value = paddle.static.data(
name='value', dtype=self.dtype, shape=self.value_np.shape
)
out = paddle.masked_fill(x, mask, value)
place = get_device_place()
exe = base.Executor(place)
res = exe.run(
base.default_main_program(),
feed={
'x': self.x_np,
'mask': self.mask_np,
'value': self.value_np,
},
fetch_list=[out],
)
np.testing.assert_allclose(
res[0], self.out_np, atol=1e-5, rtol=1e-5
)
paddle.disable_static()
def test_dygraph(self):
paddle.disable_static()
x = paddle.to_tensor(self.x_np, dtype=self.dtype)
mask = paddle.to_tensor(self.mask_np).astype('bool')
if self.scalar_value:
value = self.value_np[0]
else:
value = paddle.to_tensor(self.value_np, dtype=self.dtype)
result = paddle.masked_fill(x, mask, value)
np.testing.assert_allclose(self.out_np, result.numpy(), rtol=1e-05)
paddle.enable_static()
class TestMaskedFillAPI1(TestMaskedFillAPI):
def init(self):
self.x_shape = (6, 8, 9, 18)
self.mask_shape = self.x_shape
self.dtype = "float32"
self.scalar_value = False
class TestMaskedFillAPI2(TestMaskedFillAPI):
def init(self):
self.x_shape = (168,)
self.mask_shape = self.x_shape
self.dtype = "float32"
self.scalar_value = False
class TestMaskedFillAPI3(TestMaskedFillAPI):
def init(self):
self.x_shape = (6, 8, 9, 18)
self.mask_shape = self.x_shape
self.dtype = "float32"
self.scalar_value = True
class TestMaskedFillGrad(unittest.TestCase):
def setUp(self):
self.typelist = ['float32', 'float64', 'int32', 'int64']
self.places = get_places()
self.dtype = "float32"
def test_backward(self):
paddle.disable_static()
expected_np = np.array(
[[2, 1, 1], [2, 1, 1], [2, 1, 1], [2, 1, 1]]
).astype('float32')
expected_y_grad = np.array(
[[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]]
).astype('float32')
expected_v_grad = np.array(8).astype('float32')
for idx, p in enumerate(self.places):
if idx == 0:
paddle.set_device('cpu')
else:
paddle.set_device(get_device())
for dtype in self.typelist:
v = paddle.to_tensor(np.array(1).astype(self.dtype))
x = paddle.ones((4, 3), dtype=self.dtype)
mask = paddle.to_tensor(np.array([0, 1, 1]).astype("bool"))
x.stop_gradient = False
v.stop_gradient = False
y = x * 2
y.retain_grads()
ny = y.masked_fill(mask=mask, value=v)
ny.retain_grads() # if ny grad is none, v_grad should be 0
loss = ny.sum()
loss.backward()
self.assertEqual(
(ny.numpy().astype('float32') == expected_np).all(), True
)
self.assertEqual(
(y.grad.numpy().astype('float32') == expected_y_grad).all(),
True,
)
self.assertEqual(
(v.grad.numpy().astype('float32') == expected_v_grad).all(),
True,
)
@unittest.skipIf(
not (core.is_compiled_with_cuda() or is_custom_device()),
"core is not compiled with CUDA",
)
class TestMaskedFillFP16API1(TestMaskedFillAPI):
def init(self):
self.x_shape = (6, 8, 9, 18)
self.mask_shape = self.x_shape
self.dtype = "float16"
self.scalar_value = False
@unittest.skipIf(
not (core.is_compiled_with_cuda() or is_custom_device()),
"core is not compiled with CUDA",
)
class TestMaskedFillFP16API2(TestMaskedFillAPI):
def init(self):
self.x_shape = (168,)
self.mask_shape = self.x_shape
self.dtype = "float16"
self.scalar_value = False
@unittest.skipIf(
not (core.is_compiled_with_cuda() or is_custom_device()),
"core is not compiled with CUDA",
)
class TestMaskedFillFP16API3(TestMaskedFillAPI):
def init(self):
self.x_shape = (168,)
self.mask_shape = self.x_shape
self.dtype = "float16"
self.scalar_value = True
class TestMaskedFillAPIBroadcast(TestMaskedFillAPI):
def init(self):
self.x_shape = (3, 40)
self.mask_shape = (3, 1)
self.dtype = "float32"
self.scalar_value = False
class TestMaskedFillAPIBroadcast2(TestMaskedFillAPI):
def init(self):
self.x_shape = (3, 3)
self.mask_shape = (1, 3)
self.dtype = "float32"
self.scalar_value = False
class TestMaskedFillAPIBroadcast3(TestMaskedFillAPI):
def init(self):
self.x_shape = (120,)
self.mask_shape = (300, 120)
self.dtype = "float32"
self.scalar_value = False
class TestMaskedFillAPIBroadcast4(TestMaskedFillAPI):
def init(self):
self.x_shape = (300, 40)
self.mask_shape = (40,)
self.dtype = "float32"
self.scalar_value = False
class TestMaskedFillAPIBroadcast5(TestMaskedFillAPI):
def init(self):
self.x_shape = (300, 40)
self.mask_shape = (40,)
self.dtype = "float32"
self.scalar_value = True
class TestMaskedFillAPIBroadcast6(TestMaskedFillAPI):
def init(self):
self.x_shape = (1, 1)
self.mask_shape = (40, 40)
self.dtype = "float32"
self.scalar_value = True
class TestMaskedFillAPIBroadcast7(TestMaskedFillAPI):
def init(self):
self.x_shape = (15,)
self.mask_shape = (40, 1)
self.dtype = "float32"
self.scalar_value = True
class TestMaskedFillAPIBroadcast8(TestMaskedFillAPI):
def init(self):
self.x_shape = (3, 1, 1)
self.mask_shape = (
120,
40,
)
self.dtype = "float32"
self.scalar_value = True
@unittest.skipIf(
not (core.is_compiled_with_cuda() or is_custom_device()),
"core is not compiled with CUDA",
)
class TestMaskedFillFP16APIBroadcast(TestMaskedFillAPI):
def init(self):
self.x_shape = (3, 40)
self.mask_shape = (3, 1)
self.dtype = "float16"
self.scalar_value = False
@unittest.skipIf(
not (core.is_compiled_with_cuda() or is_custom_device()),
"core is not compiled with CUDA",
)
class TestMaskedFillFP16APIBroadcast2(TestMaskedFillAPI):
def init(self):
self.x_shape = (300, 1)
self.mask_shape = (300, 40)
self.dtype = "float16"
self.scalar_value = False
@unittest.skipIf(
not (core.is_compiled_with_cuda() or is_custom_device()),
"core is not compiled with CUDA",
)
class TestMaskedFillFP16APIBroadcast3(TestMaskedFillAPI):
def init(self):
self.x_shape = (300, 1)
self.mask_shape = (300, 40)
self.dtype = "float16"
self.scalar_value = True
@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 or not support bfloat16",
)
class TestMaskedFillBF16(TestMaskedFillAPI):
def init(self):
self.x_shape = (300, 1)
self.mask_shape = (300, 1)
self.dtype = "uint16"
self.scalar_value = False
def setUp(self):
self.init()
self.x_np = convert_float_to_uint16(
np.random.random(self.x_shape).astype("float32")
)
self.mask_np = np.array(
np.random.randint(2, size=self.mask_shape), dtype="bool"
)
self.value_np = convert_float_to_uint16(
np.random.randn(1).astype("float32")
)
self.out_np = np_masked_fill(self.x_np, self.mask_np, self.value_np)
@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 or not support bfloat16",
)
class TestMaskedFillBF16APIBroadcast2(TestMaskedFillBF16):
def init(self):
self.x_shape = (300, 1)
self.mask_shape = (300, 3)
self.dtype = "uint16"
self.scalar_value = False
class TestMaskedFillAPI_ZeroSize(unittest.TestCase):
def setUp(self):
self.init()
self.x_np = np.random.random(self.x_shape).astype(self.dtype)
self.mask_np = np.array(
np.random.randint(2, size=self.mask_shape), dtype="bool"
)
self.value_np = np.random.randn(1).astype(self.dtype)
self.out_np = np_masked_fill(self.x_np, self.mask_np, self.value_np)
def init(self):
self.x_shape = (0, 3)
self.mask_shape = self.x_shape
self.dtype = "float32"
self.scalar_value = False
def test_dygraph(self):
paddle.disable_static()
x = paddle.to_tensor(self.x_np, dtype=self.dtype)
x.stop_gradient = False
mask = paddle.to_tensor(self.mask_np).astype('bool')
if self.scalar_value:
value = self.value_np[0]
else:
value = paddle.to_tensor(self.value_np, dtype=self.dtype)
result = paddle.masked_fill(x, mask, value)
np.testing.assert_allclose(self.out_np, result.numpy(), rtol=1e-05)
paddle.sum(result).backward()
np.testing.assert_allclose(x.grad.shape, x.shape)
np.testing.assert_allclose(x.grad.numpy(), np.zeros(x.shape))
class TestMaskedFillAPI_ZeroSize2(TestMaskedFillAPI_ZeroSize):
# x_grad shape [2, 3], filled with 0.
def init(self):
self.x_shape = (1, 3)
self.mask_shape = (0, 3)
self.dtype = "float32"
self.scalar_value = False
if __name__ == '__main__':
paddle.enable_static()
unittest.main()