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

686 lines
24 KiB
Python

# Copyright (c) 2020 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, is_custom_device
import paddle
from paddle.base import core
DELTA = 1e-6
def np_medain_min(data, keepdims=False):
shape = data.shape
data_flat = data.flatten()
data_cnt = len(data_flat)
if data.dtype != 'int32' and data.dtype != 'int64':
data_flat[np.isnan(data_flat)] = np.inf
data_sort = np.sort(data_flat)
if data.dtype != 'int32' and data.dtype != 'int64':
data_sort[np.isinf(data_sort)] = np.nan
if data_cnt % 2:
is_odd = False
else:
is_odd = True
i = int(data_cnt / 2)
if is_odd:
np_res = min(data_sort[i - 1], data_sort[i])
else:
np_res = data_sort[i]
if keepdims:
new_shape = [1] * len(shape)
np_res = np_res.reshape(new_shape)
return np_res + np.sum(np.isnan(data).astype(data.dtype) * data)
def np_median_min_axis(data, axis=None, keepdims=False):
data = copy.deepcopy(data)
if axis is None:
return np_medain_min(data, keepdims)
axis = axis + len(data.shape) if axis < 0 else axis
trans_shape = []
reshape = []
for i in range(len(data.shape)):
if i != axis:
trans_shape.append(i)
reshape.append(data.shape[i])
trans_shape.append(axis)
last_shape = data.shape[axis]
reshape.append(last_shape)
data_flat = np.transpose(data, trans_shape)
data_flat = np.reshape(data_flat, (-1, reshape[-1]))
data_cnt = np.full(
shape=data_flat.shape[:-1], fill_value=data_flat.shape[-1]
)
if data.dtype != 'int32' and data.dtype != 'int64':
data_flat[np.isnan(data_flat)] = np.inf
data_sort = np.sort(data_flat, axis=-1)
if data.dtype != 'int32' and data.dtype != 'int64':
data_sort[np.isinf(data_sort)] = np.nan
is_odd = data_cnt % 2
np_res = np.zeros(len(is_odd), dtype=data.dtype)
for j in range(len(is_odd)):
if data_cnt[j] == 0:
np_res[j] = np.nan
continue
i = int(data_cnt[j] / 2)
if is_odd[j]:
np_res[j] = data_sort[j, i]
else:
np_res[j] = min(data_sort[j, i - 1], data_sort[j, i])
if keepdims:
shape = list(data.shape)
shape[axis] = 1
np_res = np.reshape(np_res, shape)
else:
np_res = np.reshape(np_res, reshape[:-1])
return np_res + np.sum(
np.isnan(data).astype(data.dtype) * data, axis=axis, keepdims=keepdims
)
class TestMedianAvg(unittest.TestCase):
def check_numpy_res(self, np1, np2):
self.assertEqual(np1.shape, np2.shape)
np1_isnan = np.isnan(np1)
np2_isnan = np.isnan(np2)
nan_mismatch = np.sum(
(np1_isnan.astype('int32') - np2_isnan.astype('int32'))
* (np1_isnan.astype('int32') - np2_isnan.astype('int32'))
)
self.assertEqual(nan_mismatch, 0)
np1 = np.where(np.isnan(np1), 0.0, np1)
np2 = np.where(np.isnan(np2), 0.0, np2)
mismatch = np.sum((np1 - np2) * (np1 - np2))
self.assertAlmostEqual(mismatch, 0, delta=DELTA)
def static_single_test_median(self, lis_test):
paddle.enable_static()
x, axis, keepdims = lis_test
res_np = np.median(x, axis=axis, keepdims=keepdims)
main_program = paddle.static.Program()
startup_program = paddle.static.Program()
exe = paddle.static.Executor()
with paddle.static.program_guard(main_program, startup_program):
x_in = paddle.static.data(shape=x.shape, dtype=x.dtype, name='x')
y = paddle.median(x_in, axis, keepdims)
[res_pd] = exe.run(feed={'x': x}, fetch_list=[y])
self.check_numpy_res(res_pd, res_np)
paddle.disable_static()
def dygraph_single_test_median(self, lis_test):
x, axis, keepdims = lis_test
res_np = np.median(x, axis=axis, keepdims=keepdims)
res_pd = paddle.median(paddle.to_tensor(x), axis, keepdims)
self.check_numpy_res(res_pd.numpy(False), res_np)
def dygraph_single_test_median_cpu(self, lis_test):
x, axis, keepdims = lis_test
res_np = np.median(x, axis=axis, keepdims=keepdims)
res_pd = paddle.median(paddle.to_tensor(x).to('cpu'), axis, keepdims)
self.check_numpy_res(res_pd.numpy(False), res_np)
def test_median_static(self):
h = 3
w = 4
l = 2
x = np.arange(h * w * l).reshape([h, w, l])
lis_tests = [
[x.astype(dtype), axis, keepdims]
for axis in [-1, 0, 1, 2, None]
for keepdims in [False, True]
for dtype in ['float32', 'float64', 'int32', 'int64']
]
for lis_test in lis_tests:
self.static_single_test_median(lis_test)
def test_median_dygraph(self):
paddle.disable_static()
h = 3
w = 4
l = 2
x = np.arange(h * w * l).reshape([h, w, l])
lis_tests = [
[x.astype(dtype), axis, keepdims]
for axis in [-1, 0, 1, 2, None]
for keepdims in [False, True]
for dtype in ['float32', 'float64', 'int32', 'int64']
]
for lis_test in lis_tests:
self.dygraph_single_test_median(lis_test)
def test_median_exception(self):
paddle.disable_static()
x = [1, 2, 3, 4]
self.assertRaises(TypeError, paddle.median, x)
x = paddle.arange(12).reshape([3, 4])
self.assertRaises(ValueError, paddle.median, x, 1.0)
self.assertRaises(ValueError, paddle.median, x, 2)
self.assertRaises(ValueError, paddle.median, x, 2, False, 'max')
self.assertRaises(ValueError, paddle.median, x, [], False, 'max')
def test_nan(self):
paddle.disable_static()
x = np.array(
[[1, 2, 3, float('nan')], [1, 2, 3, 4], [float('nan'), 1, 2, 3]]
)
lis_tests = [
[x.astype(dtype), axis, keepdims]
for axis in [-1, 0, 1, None]
for keepdims in [False, True]
for dtype in ['float32', 'float64']
]
for lis_test in lis_tests:
self.dygraph_single_test_median(lis_test)
self.dygraph_single_test_median_cpu(lis_test)
def test_all_nan(self):
paddle.disable_static()
x = np.array(
[
[float('nan'), float('nan'), float('nan'), float('nan')],
[float('nan'), float('nan'), float('nan'), float('nan')],
[float('nan'), float('nan'), float('nan'), float('nan')],
]
)
lis_tests = [
[x.astype(dtype), axis, keepdims]
for axis in [-1, 0, 1, None]
for keepdims in [False, True]
for dtype in ['float32', 'float64']
]
for lis_test in lis_tests:
self.dygraph_single_test_median(lis_test)
self.dygraph_single_test_median_cpu(lis_test)
@unittest.skipIf(
not (core.is_compiled_with_cuda() or is_custom_device())
or not core.is_float16_supported(get_device_place()),
"core is not compiled with CUDA and do not support float16",
)
def test_float16(self):
paddle.disable_static(get_device_place())
x = np.array(
[[1, 2, 3, float('nan')], [1, 2, 3, 4], [float('nan'), 1, 2, 3]]
).astype('float16')
lis_tests = [
[axis, keepdims]
for axis in [-1, 0, 1, None]
for keepdims in [False, True]
]
for axis, keepdims in lis_tests:
res_np = np.median(x, axis=axis, keepdims=keepdims)
res_pd = paddle.median(paddle.to_tensor(x), axis, keepdims)
self.check_numpy_res(res_pd.numpy(False), res_np.astype('float64'))
np.testing.assert_equal(res_pd.numpy(False).dtype, np.float32)
def test_output_dtype(self):
supported_dypes = ['float32', 'float64', 'int32', 'int64']
for inp_dtype in supported_dypes:
x = np.random.randint(low=-100, high=100, size=[2, 4, 5]).astype(
inp_dtype
)
res = paddle.median(paddle.to_tensor(x), mode='avg')
if inp_dtype == 'float64':
np.testing.assert_equal(res.numpy().dtype, np.float64)
else:
np.testing.assert_equal(res.numpy().dtype, np.float32)
class TestMedianMin(unittest.TestCase):
def static_single_test_median(self, lis_test):
paddle.enable_static()
x, axis, keepdims = lis_test
res_np = np_median_min_axis(x, axis=axis, keepdims=keepdims)
main_program = paddle.static.Program()
startup_program = paddle.static.Program()
exe = paddle.static.Executor()
with paddle.static.program_guard(main_program, startup_program):
x_in = paddle.static.data(shape=x.shape, dtype=x.dtype, name='x')
y = paddle.median(x_in, axis, keepdims, mode='min')
[res_pd, _] = exe.run(feed={'x': x}, fetch_list=[y])
np.testing.assert_allclose(res_pd, res_np)
paddle.disable_static()
def dygraph_single_test_median(self, lis_test):
x, axis, keepdims = lis_test
res_np = np_median_min_axis(x, axis=axis, keepdims=keepdims)
if axis is None:
res_pd = paddle.median(
paddle.to_tensor(x), axis, keepdims, mode='min'
)
else:
res_pd, _ = paddle.median(
paddle.to_tensor(x), axis, keepdims, mode='min'
)
np.testing.assert_allclose(res_pd.numpy(False), res_np)
def test_median_static(self):
h = 3
w = 4
l = 2
x = np.arange(h * w * l).reshape([h, w, l]).astype("float32")
lis_tests = [
[x.astype(dtype), axis, keepdims]
for axis in [-1, 0, 1, 2]
for keepdims in [False, True]
for dtype in ['float32', 'float64', 'int32', 'int64']
]
for lis_test in lis_tests:
self.static_single_test_median(lis_test)
def test_median_dygraph(self):
paddle.disable_static()
h = 3
w = 4
l = 2
x = np.arange(h * w * l).reshape([h, w, l]).astype("float32")
lis_tests = [
[x.astype(dtype), axis, keepdims]
for axis in [-1, 0, 1, 2]
for keepdims in [False, True]
for dtype in ['float32', 'float64', 'int32', 'int64']
]
for lis_test in lis_tests:
self.dygraph_single_test_median(lis_test)
def test_index_even_case(self):
paddle.disable_static()
x = paddle.arange(2 * 100).reshape((2, 100)).astype(paddle.float32)
out, index = paddle.median(x, axis=1, mode='min')
np.testing.assert_allclose(out.numpy(), [49.0, 149.0])
np.testing.assert_equal(index.numpy(), [49, 49])
def test_index_odd_case(self):
paddle.disable_static()
x = paddle.arange(30).reshape((3, 10)).astype(paddle.float32)
out, index = paddle.median(x, axis=1, mode='min')
np.testing.assert_allclose(out.numpy(), [4.0, 14.0, 24.0])
np.testing.assert_equal(index.numpy(), [4, 4, 4])
def test_nan(self):
paddle.disable_static()
x = np.array(
[
[1, 2, 3, float('nan')],
[1, 2, 3, 4],
[float('nan'), 1, 2, 3],
[1, float('nan'), 3, float('nan')],
[float('nan'), float('nan'), 3, float('nan')],
]
)
lis_tests = [
[x.astype(dtype), axis, keepdims]
for axis in [-1, 0, 1, None]
for keepdims in [False, True]
for dtype in ['float32', 'float64']
]
for lis_test in lis_tests:
self.dygraph_single_test_median(lis_test)
@unittest.skipIf(
not (core.is_compiled_with_cuda() or is_custom_device())
or not core.is_float16_supported(get_device_place()),
"core is not compiled with CUDA and do not support float16",
)
def test_float16(self):
paddle.disable_static(get_device_place())
x = np.array(
[[1, 2, 3, float('nan')], [1, 2, 3, 4], [float('nan'), 1, 2, 3]]
).astype('float16')
lis_tests = [
[axis, keepdims]
for axis in [-1, 0, 1, None]
for keepdims in [False, True]
]
for axis, keepdims in lis_tests:
res_np = np_median_min_axis(x, axis=axis, keepdims=keepdims)
if axis is None:
res_pd = paddle.median(
paddle.to_tensor(x), axis, keepdims, mode='min'
)
else:
res_pd, _ = paddle.median(
paddle.to_tensor(x), axis, keepdims, mode='min'
)
np.testing.assert_allclose(res_pd.numpy(False), res_np)
np.testing.assert_equal(res_pd.numpy(False).dtype, np.float16)
def test_output_dtype(self):
supported_dypes = ['float32', 'float64', 'int32', 'int64']
for inp_dtype in supported_dypes:
x = np.random.randint(low=-100, high=100, size=[2, 4, 5]).astype(
inp_dtype
)
res = paddle.median(paddle.to_tensor(x), mode='min')
np.testing.assert_equal(res.numpy().dtype, np.dtype(inp_dtype))
class TestMedianAvg_ZeroSize(unittest.TestCase):
def dygraph_single_test_median(self, lis_test):
x, axis, keepdims = lis_test
res_np = np.median(x, axis=axis, keepdims=keepdims)
x_pd = paddle.to_tensor(x)
x_pd.stop_gradient = False
res_pd = paddle.median(x_pd, axis, keepdims)
np.testing.assert_allclose(res_pd.numpy(), res_np)
paddle.sum(res_pd).backward()
np.testing.assert_allclose(x_pd.grad.shape, x_pd.shape)
def test_median_dygraph(self):
paddle.disable_static()
h = 0
w = 4
l = 2
x = np.arange(h * w * l).reshape([h, w, l])
self.dygraph_single_test_median([x, 1, False])
class TestMedianMin_ZeroSize(unittest.TestCase):
def dygraph_single_test_median(self, lis_test):
x, axis, keepdims = lis_test
res_np = np_median_min_axis(x, axis=axis, keepdims=keepdims)
x_pd = paddle.to_tensor(x)
x_pd.stop_gradient = False
if axis is None:
res_pd = paddle.median(x_pd, axis, keepdims, mode='min')
else:
res_pd, _ = paddle.median(x_pd, axis, keepdims, mode='min')
np.testing.assert_allclose(res_pd.numpy(), res_np)
paddle.sum(res_pd).backward()
np.testing.assert_allclose(x_pd.grad.shape, x_pd.shape)
def test_median_dygraph(self):
paddle.disable_static()
h = 0
w = 4
l = 2
x = np.arange(h * w * l).reshape([h, w, l]).astype("float32")
self.dygraph_single_test_median([x, 1, False])
class TestMedianSort(unittest.TestCase):
def dygraph_single_test_median(self, lis_test):
x, axis, keepdims = lis_test
res_np = np.median(x, axis=axis, keepdims=keepdims)
x_pd = paddle.to_tensor(x)
x_pd.stop_gradient = False
res_pd = paddle.median(x_pd, axis, keepdims)
np.testing.assert_allclose(res_pd.numpy(), res_np)
def test_median_dygraph(self):
paddle.disable_static()
h = 2
w = 20000
l = 2
x = np.arange(h * w * l).reshape([h, w, l])
self.dygraph_single_test_median([x, 1, False])
class TestMedianAlias(unittest.TestCase):
def static_single_test_median(self, lis_test):
paddle.enable_static()
x, axis, keepdims = lis_test
res_np = np_median_min_axis(x, axis=axis, keepdims=keepdims)
main_program = paddle.static.Program()
startup_program = paddle.static.Program()
exe = paddle.static.Executor()
with paddle.static.program_guard(main_program, startup_program):
x_in = paddle.static.data(shape=x.shape, dtype=x.dtype, name='x')
y = paddle.median(x_in, dim=axis, keepdim=keepdims)
[res_pd, _] = exe.run(feed={'x': x}, fetch_list=[y])
np.testing.assert_allclose(res_pd, res_np)
paddle.disable_static()
def dygraph_single_test_median(self, lis_test):
x, axis, keepdims = lis_test
res_np = np_median_min_axis(x, axis=axis, keepdims=keepdims)
if axis is None:
res_pd = paddle.median(
paddle.to_tensor(x), dim=axis, keepdim=keepdims
)
else:
res_pd, _ = paddle.median(
paddle.to_tensor(x), dim=axis, keepdim=keepdims
)
np.testing.assert_allclose(res_pd.numpy(False), res_np)
def test_median_static(self):
h = 3
w = 4
l = 2
x = np.arange(h * w * l).reshape([h, w, l]).astype("float32")
lis_tests = [
[x.astype(dtype), axis, keepdims]
for axis in [-1, 0, 1, 2]
for keepdims in [False, True]
for dtype in ['float32', 'float64', 'int32', 'int64']
]
for lis_test in lis_tests:
self.static_single_test_median(lis_test)
def test_median_dygraph(self):
paddle.disable_static()
h = 3
w = 4
l = 2
x = np.arange(h * w * l).reshape([h, w, l]).astype("float32")
lis_tests = [
[x.astype(dtype), axis, keepdims]
for axis in [-1, 0, 1, 2]
for keepdims in [False, True]
for dtype in ['float32', 'float64', 'int32', 'int64']
]
for lis_test in lis_tests:
self.dygraph_single_test_median(lis_test)
def test_cpu(self):
paddle.disable_static(place=paddle.CPUPlace())
x_np = np.array(
[
[1.0, 2.0, 3.0, np.nan],
[5.0, 6.0, 7.0, 8.0],
[1.0, 3.0, 3.0, 5.0],
]
)
np_grad = np.array(
[[0.0, 0.0, 0.0, 1.0], [0, 0.5, 0.5, 0], [0, 0.5, 0.5, 0]]
)
x_tensor = paddle.to_tensor(x_np, stop_gradient=False).to('cpu')
y = paddle.median(x_tensor, axis=-1)
dx = paddle.grad(y, x_tensor)[0].numpy()
np.testing.assert_allclose(np_grad, dx, rtol=1e-05, equal_nan=True)
def test_all_nan_cpu(self):
paddle.disable_static(place=paddle.CPUPlace())
x_np = np.array([np.nan, np.nan, np.nan, np.nan])
np_grad = np.array([1, 0, 0, 0])
x_tensor = paddle.to_tensor(x_np, stop_gradient=False).to('cpu')
y = paddle.median(x_tensor, axis=0, mode="min")
dx = paddle.grad(y[0], x_tensor)[0].numpy()
np.testing.assert_allclose(np_grad, dx, rtol=1e-05, equal_nan=True)
def test_none_dim_cpu(self):
paddle.disable_static(place=paddle.CPUPlace())
x_np = np.array([[1.0, 1.0, 1.0, 1.0], [1.0, 0.0, 2.0, 0.0]])
np_grad = np.array([[0.2, 0.2, 0.2, 0.2], [0.2, 0, 0, 0]])
x_tensor = paddle.to_tensor(x_np, stop_gradient=False).to('cpu')
y = paddle.median(x_tensor)
dx = paddle.grad(y, x_tensor)[0].numpy()
np.testing.assert_allclose(np_grad, dx, rtol=1e-05, equal_nan=True)
def test_zero_size_cpu(self):
paddle.disable_static(place=paddle.CPUPlace())
x_np = np.array([])
x_tensor = paddle.to_tensor(x_np, stop_gradient=False).to('cpu')
y = paddle.median(x_tensor)
np_y = np.array([np.nan])
np.testing.assert_allclose(np_y, y, rtol=1e-05, equal_nan=True)
class MedianOutTest(unittest.TestCase):
def setUp(self):
paddle.disable_static()
if core.is_compiled_with_cuda():
self.place = core.CUDAPlace(0)
else:
self.place = core.CPUPlace()
def test_median_api(self):
def run_median(test_type):
x = paddle.to_tensor(
[[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype='float32'
)
a = paddle.ones([3], dtype="float32")
b = paddle.ones([3], dtype="int64")
x.stop_gradient = False
a.stop_gradient = False
b.stop_gradient = False
input = x + x
values = a + a
indices = b + b
out = (values, indices)
if test_type == "return":
out = paddle.median(input, dim=0, keepdim=False, mode='min')
elif test_type == "input_out":
paddle.median(input, dim=0, keepdim=False, mode='min', out=out)
elif test_type == "both_return":
out = paddle.median(
input, dim=0, keepdim=False, mode='min', out=out
)
elif test_type == "both_input_out":
tmp = paddle.median(
input, dim=0, keepdim=False, mode='min', out=out
)
ref_out = paddle._C_ops.median(input, 0, False, 'min')
np.testing.assert_allclose(
ref_out[0].numpy(),
out[0].numpy(),
1e-20,
1e-20,
)
np.testing.assert_allclose(
ref_out[1].numpy(),
out[1].numpy(),
1e-20,
1e-20,
)
out_0 = out[0] + out[0]
out_1 = out[1] + out[1]
(
paddle.sum(paddle.abs(out_0)) + paddle.sum(paddle.abs(out_1))
).backward()
return out[0], out[1], x.grad, a.grad, b.grad
paddle.disable_static()
v1, i1, gx1, ga1, gb1 = run_median("return")
v2, i2, gx2, ga2, gb2 = run_median("input_out")
v3, i3, gx3, ga3, gb3 = run_median("both_return")
v4, i4, gx4, ga4, gb4 = run_median("both_input_out")
np.testing.assert_allclose(
v1.numpy(),
v2.numpy(),
1e-20,
1e-20,
)
np.testing.assert_allclose(
v1.numpy(),
v3.numpy(),
1e-20,
1e-20,
)
np.testing.assert_allclose(
v1.numpy(),
v4.numpy(),
1e-20,
1e-20,
)
np.testing.assert_allclose(
i1.numpy(),
i2.numpy(),
1e-20,
1e-20,
)
np.testing.assert_allclose(
i1.numpy(),
i3.numpy(),
1e-20,
1e-20,
)
np.testing.assert_allclose(
i1.numpy(),
i4.numpy(),
1e-20,
1e-20,
)
np.testing.assert_allclose(
gx1.numpy(),
gx2.numpy(),
1e-20,
1e-20,
)
np.testing.assert_allclose(
gx1.numpy(),
gx3.numpy(),
1e-20,
1e-20,
)
np.testing.assert_allclose(
gx1.numpy(),
gx4.numpy(),
1e-20,
1e-20,
)
np.testing.assert_equal(ga1, None)
np.testing.assert_equal(ga2, None)
np.testing.assert_equal(ga3, None)
np.testing.assert_equal(ga4, None)
np.testing.assert_equal(gb1, None)
np.testing.assert_equal(gb2, None)
np.testing.assert_equal(gb3, None)
np.testing.assert_equal(gb4, None)
if __name__ == '__main__':
unittest.main()