Skip to content

Commit

Permalink
【PaddlePaddle Hackathon 3 No.12】为 Paddle 新增 pairwise_distance (#44161)
Browse files Browse the repository at this point in the history
* add paddle.nn.functional.pairwise_distance (cattidea#273)
* remove the test case for undefined behavior

Co-authored-by: SigureMo <sigure.qaq@gmail.com>
  • Loading branch information
Ainavo and SigureMo committed Jul 29, 2022
1 parent 8849056 commit 46be685
Show file tree
Hide file tree
Showing 4 changed files with 424 additions and 102 deletions.
334 changes: 292 additions & 42 deletions python/paddle/fluid/tests/unittests/test_pairwise_distance.py
Expand Up @@ -20,24 +20,64 @@
import unittest


def pairwise_distance(x, y, p=2.0, epsilon=1e-6, keepdim=False):
return np.linalg.norm(x - y, ord=p, axis=1, keepdims=keepdim)
def np_pairwise_distance(x, y, p=2.0, epsilon=1e-6, keepdim=False):
distance = np.linalg.norm(x - y + epsilon, ord=p, axis=-1, keepdims=keepdim)
# Paddle currently has not supported for 0-d Tensors, so even if keep_dim is False,
# and neither x nor y is batched, a Tensor of shape (1, ) is returned
if distance.ndim == 0:
distance = np.expand_dims(distance, axis=0)
return distance


def test_static(x_np, y_np, p=2.0, epsilon=1e-6, keepdim=False):
def call_pairwise_distance_layer(x, y, p=2., epsilon=1e-6, keepdim='False'):
pairwise_distance = paddle.nn.PairwiseDistance(p=p,
epsilon=epsilon,
keepdim=keepdim)
distance = pairwise_distance(x=x, y=y)
return distance


def call_pairwise_distance_functional(x,
y,
p=2.,
epsilon=1e-6,
keepdim='False'):
distance = paddle.nn.functional.pairwise_distance(x=x,
y=y,
p=p,
epsilon=epsilon,
keepdim=keepdim)
return distance


def test_static(place,
x_np,
y_np,
p=2.0,
epsilon=1e-6,
keepdim=False,
functional=False):
prog = paddle.static.Program()
startup_prog = paddle.static.Program()

place = fluid.CUDAPlace(
0) if paddle.fluid.core.is_compiled_with_cuda() else fluid.CPUPlace()

paddle.enable_static()
with paddle.static.program_guard(prog, startup_prog):
x = paddle.fluid.data(name='x', shape=x_np.shape, dtype=x_np.dtype)
y = paddle.fluid.data(name='y', shape=y_np.shape, dtype=x_np.dtype)
dist = paddle.nn.layer.distance.PairwiseDistance(p=p,

if functional:
distance = call_pairwise_distance_functional(x=x,
y=y,
p=p,
epsilon=epsilon,
keepdim=keepdim)
distance = dist(x, y)
else:
distance = call_pairwise_distance_layer(x=x,
y=y,
p=p,
epsilon=epsilon,
keepdim=keepdim)
exe = paddle.static.Executor(place)
static_ret = exe.run(prog,
feed={
Expand All @@ -46,69 +86,279 @@ def test_static(x_np, y_np, p=2.0, epsilon=1e-6, keepdim=False):
},
fetch_list=[distance])
static_ret = static_ret[0]
paddle.disable_static()
return static_ret


def test_dygraph(x_np, y_np, p=2.0, epsilon=1e-6, keepdim=False):
paddle.disable_static()
def test_dygraph(place,
x_np,
y_np,
p=2.0,
epsilon=1e-6,
keepdim=False,
functional=False):
x = paddle.to_tensor(x_np)
y = paddle.to_tensor(y_np)
dist = paddle.nn.layer.distance.PairwiseDistance(p=p,
epsilon=epsilon,
keepdim=keepdim)
distance = dist(x, y)
dygraph_ret = distance.numpy()
paddle.enable_static()
if functional:
dy_distance = call_pairwise_distance_functional(x=x,
y=y,
p=p,
epsilon=epsilon,
keepdim=keepdim)
else:
dy_distance = call_pairwise_distance_layer(x=x,
y=y,
p=p,
epsilon=epsilon,
keepdim=keepdim)
dygraph_ret = dy_distance.numpy()
return dygraph_ret


def test_legacy_dygraph(place,
x_np,
y_np,
p=2.0,
epsilon=1e-6,
keepdim=False,
functional=False):
paddle.fluid.framework._enable_legacy_dygraph()
x = paddle.to_tensor(x_np)
y = paddle.to_tensor(y_np)
if functional:
legacy_distance = call_pairwise_distance_functional(x=x,
y=y,
p=p,
epsilon=epsilon,
keepdim=keepdim)
else:
legacy_distance = call_pairwise_distance_layer(x=x,
y=y,
p=p,
epsilon=epsilon,
keepdim=keepdim)
legacy_ret = legacy_distance.numpy()
paddle.fluid.framework._disable_legacy_dygraph()
return legacy_ret


class TestPairwiseDistance(unittest.TestCase):

def test_pairwise_distance(self):
all_shape = [[100, 100], [4, 5, 6, 7]]
epsilon = 1e-6
all_shape = [[5], [100, 100]]
dtypes = ['float32', 'float64']
p_list = [-1, 0, 1, 2, np.inf, -np.inf]
places = [paddle.CPUPlace()]
if paddle.device.is_compiled_with_cuda():
places.append(paddle.CUDAPlace(0))
keeps = [False, True]
for shape in all_shape:
for dtype in dtypes:
for keepdim in keeps:
x_np = np.random.random(shape).astype(dtype)
y_np = np.random.random(shape).astype(dtype)

static_ret = test_static(x_np, y_np, keepdim=keepdim)
dygraph_ret = test_dygraph(x_np, y_np, keepdim=keepdim)
excepted_value = pairwise_distance(x_np,
for place in places:
for shape in all_shape:
for dtype in dtypes:
for p in p_list:
for keepdim in keeps:
x_np = np.random.random(shape).astype(dtype)
y_np = np.random.random(shape).astype(dtype)

static_ret = test_static(place,
x_np,
y_np,
p,
epsilon=epsilon,
keepdim=keepdim)
dygraph_ret = test_dygraph(place,
x_np,
y_np,
p,
epsilon=epsilon,
keepdim=keepdim)
legacy_ret = test_legacy_dygraph(place,
x_np,
y_np,
p,
epsilon=epsilon,
keepdim=keepdim)
excepted_value = np_pairwise_distance(
x_np, y_np, p, epsilon=epsilon, keepdim=keepdim)

self.assertEqual(static_ret.shape,
excepted_value.shape)
self.assertEqual(dygraph_ret.shape,
excepted_value.shape)
self.assertEqual(legacy_ret.shape,
excepted_value.shape)

self.assertTrue(
np.allclose(static_ret, excepted_value))
self.assertTrue(
np.allclose(dygraph_ret, excepted_value))
self.assertTrue(
np.allclose(legacy_ret, excepted_value))

static_functional_ret = test_static(place,
x_np,
y_np,
p,
epsilon=epsilon,
keepdim=keepdim)
dygraph_functional_ret = test_dygraph(
place,
x_np,
y_np,
p,
epsilon=epsilon,
keepdim=keepdim)
legacy_functional_ret = test_legacy_dygraph(
place,
x_np,
y_np,
p,
epsilon=epsilon,
keepdim=keepdim)

self.assertTrue(np.allclose(static_ret, dygraph_ret))
self.assertTrue(np.allclose(static_ret, excepted_value))
self.assertTrue(np.allclose(dygraph_ret, excepted_value))
self.assertEqual(static_functional_ret.shape,
excepted_value.shape)
self.assertEqual(dygraph_functional_ret.shape,
excepted_value.shape)
self.assertEqual(legacy_functional_ret.shape,
excepted_value.shape)

def test_pairwise_distance_broadcast(self):
self.assertTrue(
np.allclose(static_functional_ret,
excepted_value))
self.assertTrue(
np.allclose(dygraph_functional_ret,
excepted_value))
self.assertTrue(
np.allclose(legacy_functional_ret,
excepted_value))

def test_pairwise_distance_broadcast_1(self):
shape_x = [100, 100]
shape_y = [100, 1]
epsilon = 1e-6
keepdim = False
place = paddle.CPUPlace()
x_np = np.random.random(shape_x).astype('float32')
y_np = np.random.random(shape_y).astype('float32')
static_ret = test_static(x_np, y_np, keepdim=keepdim)
dygraph_ret = test_dygraph(x_np, y_np, keepdim=keepdim)
excepted_value = pairwise_distance(x_np, y_np, keepdim=keepdim)
self.assertTrue(np.allclose(static_ret, dygraph_ret))
static_ret = test_static(place=place,
x_np=x_np,
y_np=y_np,
epsilon=epsilon,
keepdim=keepdim)
dygraph_ret = test_dygraph(place=place,
x_np=x_np,
y_np=y_np,
epsilon=epsilon,
keepdim=keepdim)
legacy_ret = test_legacy_dygraph(place=place,
x_np=x_np,
y_np=y_np,
epsilon=epsilon,
keepdim=keepdim)
excepted_value = np_pairwise_distance(x_np,
y_np,
epsilon=epsilon,
keepdim=keepdim)

self.assertEqual(static_ret.shape, excepted_value.shape)
self.assertEqual(dygraph_ret.shape, excepted_value.shape)
self.assertEqual(legacy_ret.shape, excepted_value.shape)

self.assertTrue(np.allclose(static_ret, excepted_value))
self.assertTrue(np.allclose(dygraph_ret, excepted_value))
self.assertTrue(np.allclose(legacy_ret, excepted_value))

static_functional_ret = test_static(place=place,
x_np=x_np,
y_np=y_np,
epsilon=epsilon,
keepdim=keepdim,
functional=True)
dygraph_functional_ret = test_dygraph(place=place,
x_np=x_np,
y_np=y_np,
epsilon=epsilon,
keepdim=keepdim,
functional=True)
legacy_functional_ret = test_legacy_dygraph(place=place,
x_np=x_np,
y_np=y_np,
epsilon=epsilon,
keepdim=keepdim,
functional=True)

self.assertEqual(static_functional_ret.shape, excepted_value.shape)
self.assertEqual(dygraph_functional_ret.shape, excepted_value.shape)
self.assertEqual(legacy_functional_ret.shape, excepted_value.shape)

def test_pairwise_distance_different_p(self):
shape = [100, 100]
self.assertTrue(np.allclose(static_functional_ret, excepted_value))
self.assertTrue(np.allclose(dygraph_functional_ret, excepted_value))
self.assertTrue(np.allclose(legacy_functional_ret, excepted_value))

def test_pairwise_distance_broadcast_2(self):
shape_x = [100, 100]
shape_y = [100]
epsilon = 1e-6
keepdim = False
p = 3.0
x_np = np.random.random(shape).astype('float32')
y_np = np.random.random(shape).astype('float32')
static_ret = test_static(x_np, y_np, p=p, keepdim=keepdim)
dygraph_ret = test_dygraph(x_np, y_np, p=p, keepdim=keepdim)
excepted_value = pairwise_distance(x_np, y_np, p=p, keepdim=keepdim)
self.assertTrue(np.allclose(static_ret, dygraph_ret))
place = paddle.CPUPlace()
x_np = np.random.random(shape_x).astype('float32')
y_np = np.random.random(shape_y).astype('float32')
static_ret = test_static(place=place,
x_np=x_np,
y_np=y_np,
epsilon=epsilon,
keepdim=keepdim)
dygraph_ret = test_dygraph(place=place,
x_np=x_np,
y_np=y_np,
epsilon=epsilon,
keepdim=keepdim)
legacy_ret = test_legacy_dygraph(place=place,
x_np=x_np,
y_np=y_np,
epsilon=epsilon,
keepdim=keepdim)
excepted_value = np_pairwise_distance(x_np,
y_np,
epsilon=epsilon,
keepdim=keepdim)

self.assertEqual(static_ret.shape, excepted_value.shape)
self.assertEqual(dygraph_ret.shape, excepted_value.shape)
self.assertEqual(legacy_ret.shape, excepted_value.shape)

self.assertTrue(np.allclose(static_ret, excepted_value))
self.assertTrue(np.allclose(dygraph_ret, excepted_value))
self.assertTrue(np.allclose(legacy_ret, excepted_value))

static_functional_ret = test_static(place=place,
x_np=x_np,
y_np=y_np,
epsilon=epsilon,
keepdim=keepdim,
functional=True)
dygraph_functional_ret = test_dygraph(place=place,
x_np=x_np,
y_np=y_np,
epsilon=epsilon,
keepdim=keepdim,
functional=True)
legacy_functional_ret = test_legacy_dygraph(place=place,
x_np=x_np,
y_np=y_np,
epsilon=epsilon,
keepdim=keepdim,
functional=True)

self.assertEqual(static_functional_ret.shape, excepted_value.shape)
self.assertEqual(dygraph_functional_ret.shape, excepted_value.shape)
self.assertEqual(legacy_functional_ret.shape, excepted_value.shape)

self.assertTrue(np.allclose(static_functional_ret, excepted_value))
self.assertTrue(np.allclose(dygraph_functional_ret, excepted_value))
self.assertTrue(np.allclose(legacy_functional_ret, excepted_value))


if __name__ == "__main__":
Expand Down

0 comments on commit 46be685

Please sign in to comment.