359 lines
13 KiB
Python
359 lines
13 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 get_device_place, is_custom_device
|
|
|
|
import paddle
|
|
|
|
|
|
def ref_cdist(x, y, p=2.0):
|
|
r1 = x.shape[-2]
|
|
r2 = y.shape[-2]
|
|
c1 = x.shape[-1]
|
|
batch_shape = np.broadcast_shapes(x.shape[:-2], y.shape[:-2])
|
|
if r1 == 0 or r2 == 0:
|
|
return np.empty((*batch_shape, r1, r2), x.dtype)
|
|
if c1 == 0:
|
|
return np.zeros((*batch_shape, r1, r2), x.dtype)
|
|
return np.linalg.norm(x[..., None, :] - y[..., None, :, :], ord=p, axis=-1)
|
|
|
|
|
|
class TestCdistAPI(unittest.TestCase):
|
|
def setUp(self):
|
|
np.random.seed(1024)
|
|
self.x = np.random.rand(10, 20).astype('float32')
|
|
self.y = np.random.rand(11, 20).astype('float32')
|
|
self.p = 2.0
|
|
self.compute_mode = "use_mm_for_euclid_dist_if_necessary"
|
|
self.init_input()
|
|
self.place = (
|
|
get_device_place()
|
|
if (paddle.is_compiled_with_cuda() or is_custom_device())
|
|
else paddle.CPUPlace()
|
|
)
|
|
|
|
def init_input(self):
|
|
pass
|
|
|
|
def test_static_api(self):
|
|
paddle.enable_static()
|
|
with paddle.static.program_guard(paddle.static.Program()):
|
|
x = paddle.static.data('x', self.x.shape, dtype=self.x.dtype)
|
|
y = paddle.static.data('y', self.y.shape, dtype=self.y.dtype)
|
|
out = paddle.cdist(x, y, self.p, self.compute_mode)
|
|
exe = paddle.static.Executor(self.place)
|
|
res = exe.run(feed={'x': self.x, 'y': self.y}, fetch_list=[out])
|
|
out_ref = ref_cdist(self.x, self.y, self.p)
|
|
np.testing.assert_allclose(out_ref, res[0], rtol=1e-5, atol=1e-5)
|
|
|
|
def test_dygraph_api(self):
|
|
paddle.disable_static(self.place)
|
|
x = paddle.to_tensor(self.x)
|
|
y = paddle.to_tensor(self.y)
|
|
out = paddle.cdist(x, y, self.p, self.compute_mode)
|
|
out_ref = ref_cdist(self.x, self.y, self.p)
|
|
np.testing.assert_allclose(out_ref, out.numpy(), rtol=1e-5, atol=1e-5)
|
|
paddle.enable_static()
|
|
|
|
|
|
class TestCdistAPICase1(TestCdistAPI):
|
|
def init_input(self):
|
|
self.p = 0
|
|
|
|
|
|
class TestCdistAPICase2(TestCdistAPI):
|
|
def init_input(self):
|
|
self.p = 1.0
|
|
|
|
|
|
class TestCdistAPICase3(TestCdistAPI):
|
|
def init_input(self):
|
|
self.p = 3.0
|
|
|
|
|
|
class TestCdistAPICase4(TestCdistAPI):
|
|
def init_input(self):
|
|
self.p = 1.5
|
|
|
|
|
|
class TestCdistAPICase5(TestCdistAPI):
|
|
def init_input(self):
|
|
self.p = 2.5
|
|
|
|
|
|
class TestCdistAPICase6(TestCdistAPI):
|
|
def init_input(self):
|
|
self.p = float('inf')
|
|
|
|
|
|
class TestCdistAPICase7(TestCdistAPI):
|
|
def init_input(self):
|
|
self.x = np.random.rand(50, 20).astype('float64')
|
|
self.y = np.random.rand(40, 20).astype('float64')
|
|
self.compute_mode = "use_mm_for_euclid_dist"
|
|
|
|
|
|
class TestCdistAPICase8(TestCdistAPI):
|
|
def init_input(self):
|
|
self.x = np.random.rand(50, 20).astype('float64')
|
|
self.y = np.random.rand(40, 20).astype('float64')
|
|
self.compute_mode = "donot_use_mm_for_euclid_dist"
|
|
|
|
|
|
class TestCdistAPICase9(TestCdistAPI):
|
|
def init_input(self):
|
|
self.x = np.random.rand(500, 100).astype('float64')
|
|
self.y = np.random.rand(400, 100).astype('float64')
|
|
|
|
|
|
class TestCdistAPICase10(TestCdistAPI):
|
|
def init_input(self):
|
|
self.x = np.random.rand(3, 500, 100).astype('float64')
|
|
self.y = np.random.rand(3, 400, 100).astype('float64')
|
|
|
|
|
|
class TestCdistAPICase11(TestCdistAPI):
|
|
def init_input(self):
|
|
self.x = np.random.rand(3, 4, 500, 100).astype('float64')
|
|
self.y = np.random.rand(3, 4, 400, 100).astype('float64')
|
|
|
|
|
|
class TestCdistAPICase12(TestCdistAPI):
|
|
def init_input(self):
|
|
self.x = np.random.rand(3, 4, 500, 100).astype('float64')
|
|
self.y = np.random.rand(3, 4, 400, 100).astype('float64')
|
|
self.p = 3.0
|
|
|
|
|
|
# test for different compute mode output same result
|
|
class TestCdistAPICase13(TestCdistAPI):
|
|
def init_input(self):
|
|
self.x = np.random.rand(3, 4, 500, 100).astype('float64')
|
|
self.y = np.random.rand(3, 4, 400, 100).astype('float64')
|
|
|
|
def test_static_api(self):
|
|
paddle.enable_static()
|
|
with paddle.static.program_guard(paddle.static.Program()):
|
|
x = paddle.static.data('x', self.x.shape, dtype=self.x.dtype)
|
|
y = paddle.static.data('y', self.y.shape, dtype=self.y.dtype)
|
|
out0 = paddle.cdist(x, y, self.p, self.compute_mode)
|
|
out1 = paddle.cdist(x, y, self.p, "donot_use_mm_for_euclid_dist")
|
|
out2 = paddle.cdist(x, y, self.p, "use_mm_for_euclid_dist")
|
|
exe = paddle.static.Executor(self.place)
|
|
res = exe.run(
|
|
feed={'x': self.x, 'y': self.y}, fetch_list=[out0, out1, out2]
|
|
)
|
|
out_ref = ref_cdist(self.x, self.y, self.p)
|
|
np.testing.assert_allclose(out_ref, res[0])
|
|
np.testing.assert_allclose(out_ref, res[2])
|
|
np.testing.assert_allclose(out_ref, res[2])
|
|
|
|
def test_dygraph_api(self):
|
|
paddle.disable_static(self.place)
|
|
x = paddle.to_tensor(self.x)
|
|
y = paddle.to_tensor(self.y)
|
|
out0 = paddle.cdist(x, y, self.p, self.compute_mode)
|
|
out1 = paddle.cdist(x, y, self.p, "donot_use_mm_for_euclid_dist")
|
|
out2 = paddle.cdist(x, y, self.p, "use_mm_for_euclid_dist")
|
|
out_ref = ref_cdist(self.x, self.y, self.p)
|
|
np.testing.assert_allclose(out_ref, out0.numpy())
|
|
np.testing.assert_allclose(out_ref, out1.numpy())
|
|
np.testing.assert_allclose(out_ref, out2.numpy())
|
|
paddle.enable_static()
|
|
|
|
|
|
# test for broadcast
|
|
class TestCdistAPICase14(TestCdistAPI):
|
|
def init_input(self):
|
|
self.x = np.random.rand(3, 4, 500, 100).astype('float64')
|
|
self.y = np.random.rand(1, 4, 400, 100).astype('float64')
|
|
|
|
|
|
# test for broadcast
|
|
class TestCdistAPICase15(TestCdistAPI):
|
|
def init_input(self):
|
|
self.x = np.random.rand(3, 4, 500, 100).astype('float64')
|
|
self.y = np.random.rand(4, 400, 100).astype('float64')
|
|
|
|
|
|
# test for 0-size tensor: r2 == 0, 2D
|
|
class TestCdistZeroSizeR2(TestCdistAPI):
|
|
def init_input(self):
|
|
self.x = np.random.rand(900, 4).astype('float32')
|
|
self.y = np.empty((0, 4), dtype='float32')
|
|
self.p = 1.0
|
|
|
|
def test_dygraph_api(self):
|
|
paddle.disable_static(self.place)
|
|
x = paddle.to_tensor(self.x)
|
|
y = paddle.to_tensor(self.y)
|
|
out = paddle.cdist(x, y, self.p, self.compute_mode)
|
|
self.assertEqual(list(out.shape), [900, 0])
|
|
paddle.enable_static()
|
|
|
|
def test_static_api(self):
|
|
paddle.enable_static()
|
|
with paddle.static.program_guard(paddle.static.Program()):
|
|
x = paddle.static.data('x', self.x.shape, dtype=self.x.dtype)
|
|
y = paddle.static.data('y', self.y.shape, dtype=self.y.dtype)
|
|
out = paddle.cdist(x, y, self.p, self.compute_mode)
|
|
exe = paddle.static.Executor(self.place)
|
|
res = exe.run(feed={'x': self.x, 'y': self.y}, fetch_list=[out])
|
|
self.assertEqual(list(res[0].shape), [900, 0])
|
|
|
|
|
|
# test for 0-size tensor: r1 == 0, 2D
|
|
class TestCdistZeroSizeR1(TestCdistAPI):
|
|
def init_input(self):
|
|
self.x = np.empty((0, 4), dtype='float32')
|
|
self.y = np.random.rand(900, 4).astype('float32')
|
|
self.p = 1.0
|
|
|
|
def test_dygraph_api(self):
|
|
paddle.disable_static(self.place)
|
|
x = paddle.to_tensor(self.x)
|
|
y = paddle.to_tensor(self.y)
|
|
out = paddle.cdist(x, y, self.p, self.compute_mode)
|
|
self.assertEqual(list(out.shape), [0, 900])
|
|
paddle.enable_static()
|
|
|
|
def test_static_api(self):
|
|
paddle.enable_static()
|
|
with paddle.static.program_guard(paddle.static.Program()):
|
|
x = paddle.static.data('x', self.x.shape, dtype=self.x.dtype)
|
|
y = paddle.static.data('y', self.y.shape, dtype=self.y.dtype)
|
|
out = paddle.cdist(x, y, self.p, self.compute_mode)
|
|
exe = paddle.static.Executor(self.place)
|
|
res = exe.run(feed={'x': self.x, 'y': self.y}, fetch_list=[out])
|
|
self.assertEqual(list(res[0].shape), [0, 900])
|
|
|
|
|
|
# test for 0-size tensor: c1 == 0 (feature dim is 0, distance should be 0)
|
|
class TestCdistZeroSizeC1(TestCdistAPI):
|
|
def init_input(self):
|
|
self.x = np.empty((5, 0), dtype='float32')
|
|
self.y = np.empty((3, 0), dtype='float32')
|
|
self.p = 2.0
|
|
|
|
def test_dygraph_api(self):
|
|
paddle.disable_static(self.place)
|
|
x = paddle.to_tensor(self.x)
|
|
y = paddle.to_tensor(self.y)
|
|
out = paddle.cdist(x, y, self.p, self.compute_mode)
|
|
self.assertEqual(list(out.shape), [5, 3])
|
|
np.testing.assert_allclose(
|
|
out.numpy(), np.zeros((5, 3), dtype='float32')
|
|
)
|
|
paddle.enable_static()
|
|
|
|
def test_static_api(self):
|
|
paddle.enable_static()
|
|
with paddle.static.program_guard(paddle.static.Program()):
|
|
x = paddle.static.data('x', self.x.shape, dtype=self.x.dtype)
|
|
y = paddle.static.data('y', self.y.shape, dtype=self.y.dtype)
|
|
out = paddle.cdist(x, y, self.p, self.compute_mode)
|
|
exe = paddle.static.Executor(self.place)
|
|
res = exe.run(feed={'x': self.x, 'y': self.y}, fetch_list=[out])
|
|
self.assertEqual(list(res[0].shape), [5, 3])
|
|
np.testing.assert_allclose(
|
|
res[0], np.zeros((5, 3), dtype='float32')
|
|
)
|
|
|
|
|
|
# test for 0-size tensor: r2 == 0, 3D batched
|
|
class TestCdistZeroSizeBatch3D(TestCdistAPI):
|
|
def init_input(self):
|
|
self.x = np.random.rand(3, 5, 4).astype('float32')
|
|
self.y = np.empty((3, 0, 4), dtype='float32')
|
|
self.p = 1.0
|
|
|
|
def test_dygraph_api(self):
|
|
paddle.disable_static(self.place)
|
|
x = paddle.to_tensor(self.x)
|
|
y = paddle.to_tensor(self.y)
|
|
out = paddle.cdist(x, y, self.p, self.compute_mode)
|
|
self.assertEqual(list(out.shape), [3, 5, 0])
|
|
paddle.enable_static()
|
|
|
|
def test_static_api(self):
|
|
paddle.enable_static()
|
|
with paddle.static.program_guard(paddle.static.Program()):
|
|
x = paddle.static.data('x', self.x.shape, dtype=self.x.dtype)
|
|
y = paddle.static.data('y', self.y.shape, dtype=self.y.dtype)
|
|
out = paddle.cdist(x, y, self.p, self.compute_mode)
|
|
exe = paddle.static.Executor(self.place)
|
|
res = exe.run(feed={'x': self.x, 'y': self.y}, fetch_list=[out])
|
|
self.assertEqual(list(res[0].shape), [3, 5, 0])
|
|
|
|
|
|
# test for 0-size tensor: r2 == 0, 4D batched
|
|
class TestCdistZeroSizeBatch4D(TestCdistAPI):
|
|
def init_input(self):
|
|
self.x = np.random.rand(2, 3, 5, 4).astype('float32')
|
|
self.y = np.empty((2, 3, 0, 4), dtype='float32')
|
|
self.p = 2.0
|
|
|
|
def test_dygraph_api(self):
|
|
paddle.disable_static(self.place)
|
|
x = paddle.to_tensor(self.x)
|
|
y = paddle.to_tensor(self.y)
|
|
out = paddle.cdist(x, y, self.p, self.compute_mode)
|
|
self.assertEqual(list(out.shape), [2, 3, 5, 0])
|
|
paddle.enable_static()
|
|
|
|
def test_static_api(self):
|
|
paddle.enable_static()
|
|
with paddle.static.program_guard(paddle.static.Program()):
|
|
x = paddle.static.data('x', self.x.shape, dtype=self.x.dtype)
|
|
y = paddle.static.data('y', self.y.shape, dtype=self.y.dtype)
|
|
out = paddle.cdist(x, y, self.p, self.compute_mode)
|
|
exe = paddle.static.Executor(self.place)
|
|
res = exe.run(feed={'x': self.x, 'y': self.y}, fetch_list=[out])
|
|
self.assertEqual(list(res[0].shape), [2, 3, 5, 0])
|
|
|
|
|
|
# test for 0-size tensor: stop_gradient propagation
|
|
class TestCdistZeroSizeGrad(unittest.TestCase):
|
|
def test_stop_gradient_false(self):
|
|
paddle.disable_static()
|
|
x = paddle.randn([10, 4], dtype='float32')
|
|
x.stop_gradient = False
|
|
y = paddle.to_tensor(np.empty((0, 4), dtype='float32'))
|
|
y.stop_gradient = False
|
|
out = paddle.cdist(x, y, p=1.0)
|
|
self.assertEqual(out.stop_gradient, False)
|
|
grads = paddle.grad(
|
|
[out],
|
|
[x, y],
|
|
grad_outputs=[paddle.ones_like(out)],
|
|
allow_unused=True,
|
|
)
|
|
self.assertIsNotNone(grads)
|
|
paddle.enable_static()
|
|
|
|
def test_stop_gradient_true(self):
|
|
paddle.disable_static()
|
|
x = paddle.randn([10, 4], dtype='float32')
|
|
y = paddle.to_tensor(np.empty((0, 4), dtype='float32'))
|
|
out = paddle.cdist(x, y, p=1.0)
|
|
self.assertEqual(out.stop_gradient, True)
|
|
paddle.enable_static()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
paddle.enable_static()
|
|
unittest.main()
|