Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[内部 review] add paddle.nn.functional.pairwise_distance #273

Merged
merged 14 commits into from
Jul 7, 2022
266 changes: 228 additions & 38 deletions python/paddle/fluid/tests/unittests/test_pairwise_distance.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,74 @@
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
# (Tensors of shape () , 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):
SigureMo marked this conversation as resolved.
Show resolved Hide resolved

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


def call_pairwise_distance_functional(x,
y,
p=2.,
epsilon=1e-6,
keepdim='False',
name='name'):
distance = paddle.nn.functional.pairwise_distance(x=x,
y=y,
p=p,
epsilon=epsilon,
keepdim=keepdim,
name=name)
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,70 +96,210 @@ 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()
Ainavo marked this conversation as resolved.
Show resolved Hide resolved
return static_ret


def test_dygraph(x_np, y_np, p=2.0, epsilon=1e-6, keepdim=False):
def test_dygraph(place,
x_np,
y_np,
p=2.0,
epsilon=1e-6,
keepdim=False,
functional=False):
paddle.disable_static()
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()
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()
paddle.enable_static()
return dygraph_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], [4, 5, 6, 7]]
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)
excepted_value = np_pairwise_distance(
x_np, y_np, p, epsilon=epsilon, keepdim=keepdim)
self.assertEqual(static_ret.shape,
dygraph_ret.shape)
self.assertEqual(static_ret.shape,
excepted_value.shape)
self.assertEqual(dygraph_ret.shape,
excepted_value.shape)
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.assertTrue(np.allclose(static_ret, dygraph_ret))
self.assertTrue(np.allclose(static_ret, excepted_value))
self.assertTrue(np.allclose(dygraph_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)
self.assertEqual(static_ret.shape,
dygraph_ret.shape)
self.assertEqual(static_ret.shape,
excepted_value.shape)
self.assertEqual(dygraph_ret.shape,
excepted_value.shape)
self.assertTrue(
np.allclose(static_functional_ret,
dygraph_functional_ret))
self.assertTrue(
np.allclose(static_functional_ret,
excepted_value))
self.assertTrue(
np.allclose(dygraph_functional_ret,
excepted_value))

def test_pairwise_distance_broadcast(self):
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)
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)
excepted_value = np_pairwise_distance(x_np,
y_np,
epsilon=epsilon,
keepdim=keepdim)
self.assertEqual(static_ret.shape, dygraph_ret.shape)
self.assertEqual(static_ret.shape, excepted_value.shape)
self.assertEqual(dygraph_ret.shape, excepted_value.shape)
self.assertTrue(np.allclose(static_ret, dygraph_ret))
self.assertTrue(np.allclose(static_ret, excepted_value))
self.assertTrue(np.allclose(dygraph_ret, excepted_value))
SigureMo marked this conversation as resolved.
Show resolved Hide resolved

def test_pairwise_distance_different_p(self):
shape = [100, 100]
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)
self.assertEqual(static_ret.shape, dygraph_ret.shape)
self.assertEqual(static_ret.shape, excepted_value.shape)
self.assertEqual(dygraph_ret.shape, excepted_value.shape)
self.assertTrue(
np.allclose(static_functional_ret, dygraph_functional_ret))
self.assertTrue(np.allclose(static_functional_ret, excepted_value))
self.assertTrue(np.allclose(dygraph_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)
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)
excepted_value = np_pairwise_distance(x_np,
y_np,
epsilon=epsilon,
keepdim=keepdim)
self.assertEqual(static_ret.shape, dygraph_ret.shape)
self.assertEqual(static_ret.shape, excepted_value.shape)
self.assertEqual(dygraph_ret.shape, excepted_value.shape)
self.assertTrue(np.allclose(static_ret, dygraph_ret))
self.assertTrue(np.allclose(static_ret, excepted_value))
self.assertTrue(np.allclose(dygraph_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)
self.assertEqual(static_ret.shape, dygraph_ret.shape)
self.assertEqual(static_ret.shape, excepted_value.shape)
self.assertEqual(dygraph_ret.shape, excepted_value.shape)
self.assertTrue(
np.allclose(static_functional_ret, dygraph_functional_ret))
self.assertTrue(np.allclose(static_functional_ret, excepted_value))
self.assertTrue(np.allclose(dygraph_functional_ret, excepted_value))


if __name__ == "__main__":
unittest.main()
2 changes: 2 additions & 0 deletions python/paddle/nn/functional/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
from .conv import conv2d_transpose # noqa: F401
from .conv import conv3d # noqa: F401
from .conv import conv3d_transpose # noqa: F401
from .distance import pairwise_distance # noqa: F401
from .extension import diag_embed # noqa: F401
from .extension import sequence_mask
from .loss import binary_cross_entropy # noqa: F401
Expand Down Expand Up @@ -136,6 +137,7 @@
'conv2d_transpose',
'conv3d',
'conv3d_transpose',
'pairwise_distance',
'elu',
'elu_',
'gelu',
Expand Down
Loading