Skip to content

Commit

Permalink
[Hackathon No.26] (PaddlePaddle#40487)
Browse files Browse the repository at this point in the history
* 'triplet_margin_loss'

* 'test_file_corret'

* '2022_03_27'

* 2022_04_05

* 2022-04-17_1

* 2022-04-17

* 2022-04-17_2

* 2022-04-25

* 2022-05-02_V1

* 2022-05-06_V1

* 2022-05-07_V1

* Update loss.py

* Update loss.py

* Update loss.py

* Update loss.py

* Update loss.py

* Update loss.py

* Update loss.py

* Update loss.py

* Update loss.py

* Update test_triplet_margin_loss.py

* Update loss.py

* 2022-06-01_pre-commit

* 2022-06-05

* 2022-06-06

* 2022-06-06

* code_style_check

* code_style_check

* Update loss.py

* 2022-06-07_V2

* Update loss.py

* Update loss.py
  • Loading branch information
yangguohao authored and sneaxiy committed Jun 27, 2022
1 parent 3e88726 commit 752487b
Show file tree
Hide file tree
Showing 6 changed files with 628 additions and 1 deletion.
395 changes: 395 additions & 0 deletions python/paddle/fluid/tests/unittests/test_triplet_margin_loss.py
@@ -0,0 +1,395 @@
# Copyright (c) 2022 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 paddle
import numpy as np
import unittest


def call_TripletMarginLoss_layer(
input,
positive,
negative,
p=2,
margin=0.3,
swap=False,
eps=1e-6,
reduction='mean',
):
triplet_margin_loss = paddle.nn.TripletMarginLoss(p=p,
epsilon=eps,
margin=margin,
swap=swap,
reduction=reduction)
res = triplet_margin_loss(
input=input,
positive=positive,
negative=negative,
)
return res


def call_TripletMarginLoss_functional(
input,
positive,
negative,
p=2,
margin=0.3,
swap=False,
eps=1e-6,
reduction='mean',
):
res = paddle.nn.functional.triplet_margin_loss(input=input,
positive=positive,
negative=negative,
p=p,
epsilon=eps,
margin=margin,
swap=swap,
reduction=reduction)
return res


def test_static(place,
input_np,
positive_np,
negative_np,
p=2,
margin=0.3,
swap=False,
eps=1e-6,
reduction='mean',
functional=False):
prog = paddle.static.Program()
startup_prog = paddle.static.Program()
with paddle.static.program_guard(prog, startup_prog):
input = paddle.static.data(name='input',
shape=input_np.shape,
dtype='float64')
positive = paddle.static.data(name='positive',
shape=positive_np.shape,
dtype='float64')
negative = paddle.static.data(name='negative',
shape=negative_np.shape,
dtype='float64')
feed_dict = {
"input": input_np,
"positive": positive_np,
"negative": negative_np
}

if functional:
res = call_TripletMarginLoss_functional(input=input,
positive=positive,
negative=negative,
p=p,
eps=eps,
margin=margin,
swap=swap,
reduction=reduction)
else:
res = call_TripletMarginLoss_layer(input=input,
positive=positive,
negative=negative,
p=p,
eps=eps,
margin=margin,
swap=swap,
reduction=reduction)

exe = paddle.static.Executor(place)
static_result = exe.run(prog, feed=feed_dict, fetch_list=[res])
return static_result


def test_dygraph(place,
input,
positive,
negative,
p=2,
margin=0.3,
swap=False,
eps=1e-6,
reduction='mean',
functional=False):
paddle.disable_static()
input = paddle.to_tensor(input)
positive = paddle.to_tensor(positive)
negative = paddle.to_tensor(negative)

if functional:
dy_res = call_TripletMarginLoss_functional(input=input,
positive=positive,
negative=negative,
p=p,
eps=eps,
margin=margin,
swap=swap,
reduction=reduction)
else:
dy_res = call_TripletMarginLoss_layer(input=input,
positive=positive,
negative=negative,
p=p,
eps=eps,
margin=margin,
swap=swap,
reduction=reduction)
dy_result = dy_res.numpy()
paddle.enable_static()
return dy_result


def calc_triplet_margin_loss(
input,
positive,
negative,
p=2,
margin=0.3,
swap=False,
reduction='mean',
):
positive_dist = np.linalg.norm((input - positive), p, axis=1)
negative_dist = np.linalg.norm((input - negative), p, axis=1)

if swap:
swap_dist = np.linalg.norm((positive - negative), p, axis=1)
negative_dist = np.minimum(negative_dist, swap_dist)
expected = np.maximum(positive_dist - negative_dist + margin, 0)

if reduction == 'mean':
expected = np.mean(expected)
elif reduction == 'sum':
expected = np.sum(expected)
else:
expected = expected

return expected


class TestTripletMarginLoss(unittest.TestCase):

def test_TripletMarginLoss(self):
shape = (2, 2)
input = np.random.uniform(0.1, 0.8, size=shape).astype(np.float64)
positive = np.random.uniform(0, 2, size=shape).astype(np.float64)
negative = np.random.uniform(0, 2, size=shape).astype(np.float64)

places = [paddle.CPUPlace()]
if paddle.device.is_compiled_with_cuda():
places.append(paddle.CUDAPlace(0))
reductions = ['sum', 'mean', 'none']
for place in places:
for reduction in reductions:
expected = calc_triplet_margin_loss(input=input,
positive=positive,
negative=negative,
reduction=reduction)

dy_result = test_dygraph(
place=place,
input=input,
positive=positive,
negative=negative,
reduction=reduction,
)

static_result = test_static(
place=place,
input_np=input,
positive_np=positive,
negative_np=negative,
reduction=reduction,
)
self.assertTrue(np.allclose(static_result, expected))
self.assertTrue(np.allclose(static_result, dy_result))
self.assertTrue(np.allclose(dy_result, expected))
static_functional = test_static(place=place,
input_np=input,
positive_np=positive,
negative_np=negative,
reduction=reduction,
functional=True)
dy_functional = test_dygraph(place=place,
input=input,
positive=positive,
negative=negative,
reduction=reduction,
functional=True)
self.assertTrue(np.allclose(static_functional, expected))
self.assertTrue(np.allclose(static_functional, dy_functional))
self.assertTrue(np.allclose(dy_functional, expected))

def test_TripletMarginLoss_error(self):
paddle.disable_static()
self.assertRaises(ValueError,
paddle.nn.loss.TripletMarginLoss,
reduction="unsupport reduction")
input = paddle.to_tensor([[0.1, 0.3]], dtype='float32')
positive = paddle.to_tensor([[0.0, 1.0]], dtype='float32')
negative = paddle.to_tensor([[0.2, 0.1]], dtype='float32')
self.assertRaises(ValueError,
paddle.nn.functional.triplet_margin_loss,
input=input,
positive=positive,
negative=negative,
reduction="unsupport reduction")
paddle.enable_static()

def test_TripletMarginLoss_dimension(self):
paddle.disable_static()

input = paddle.to_tensor([[0.1, 0.3], [1, 2]], dtype='float32')
positive = paddle.to_tensor([[0.0, 1.0]], dtype='float32')
negative = paddle.to_tensor([[0.2, 0.1]], dtype='float32')
self.assertRaises(
ValueError,
paddle.nn.functional.triplet_margin_loss,
input=input,
positive=positive,
negative=negative,
)
TMLoss = paddle.nn.loss.TripletMarginLoss()
self.assertRaises(
ValueError,
TMLoss,
input=input,
positive=positive,
negative=negative,
)
paddle.enable_static()

def test_TripletMarginLoss_swap(self):
reduction = 'mean'
place = paddle.CPUPlace()
shape = (2, 2)
input = np.random.uniform(0.1, 0.8, size=shape).astype(np.float64)
positive = np.random.uniform(0, 2, size=shape).astype(np.float64)
negative = np.random.uniform(0, 2, size=shape).astype(np.float64)
expected = calc_triplet_margin_loss(input=input,
swap=True,
positive=positive,
negative=negative,
reduction=reduction)

dy_result = test_dygraph(
place=place,
swap=True,
input=input,
positive=positive,
negative=negative,
reduction=reduction,
)

static_result = test_static(
place=place,
swap=True,
input_np=input,
positive_np=positive,
negative_np=negative,
reduction=reduction,
)
self.assertTrue(np.allclose(static_result, expected))
self.assertTrue(np.allclose(static_result, dy_result))
self.assertTrue(np.allclose(dy_result, expected))
static_functional = test_static(place=place,
swap=True,
input_np=input,
positive_np=positive,
negative_np=negative,
reduction=reduction,
functional=True)
dy_functional = test_dygraph(place=place,
swap=True,
input=input,
positive=positive,
negative=negative,
reduction=reduction,
functional=True)
self.assertTrue(np.allclose(static_functional, expected))
self.assertTrue(np.allclose(static_functional, dy_functional))
self.assertTrue(np.allclose(dy_functional, expected))

def test_TripletMarginLoss_margin(self):
paddle.disable_static()

input = paddle.to_tensor([[0.1, 0.3]], dtype='float32')
positive = paddle.to_tensor([[0.0, 1.0]], dtype='float32')
negative = paddle.to_tensor([[0.2, 0.1]], dtype='float32')
margin = -0.5
self.assertRaises(
ValueError,
paddle.nn.functional.triplet_margin_loss,
margin=margin,
input=input,
positive=positive,
negative=negative,
)
paddle.enable_static()

def test_TripletMarginLoss_p(self):
p = 3
shape = (2, 2)
reduction = 'mean'
place = paddle.CPUPlace()
input = np.random.uniform(0.1, 0.8, size=shape).astype(np.float64)
positive = np.random.uniform(0, 2, size=shape).astype(np.float64)
negative = np.random.uniform(0, 2, size=shape).astype(np.float64)
expected = calc_triplet_margin_loss(input=input,
p=p,
positive=positive,
negative=negative,
reduction=reduction)

dy_result = test_dygraph(
place=place,
p=p,
input=input,
positive=positive,
negative=negative,
reduction=reduction,
)

static_result = test_static(
place=place,
p=p,
input_np=input,
positive_np=positive,
negative_np=negative,
reduction=reduction,
)
self.assertTrue(np.allclose(static_result, expected))
self.assertTrue(np.allclose(static_result, dy_result))
self.assertTrue(np.allclose(dy_result, expected))
static_functional = test_static(place=place,
p=p,
input_np=input,
positive_np=positive,
negative_np=negative,
reduction=reduction,
functional=True)
dy_functional = test_dygraph(place=place,
p=p,
input=input,
positive=positive,
negative=negative,
reduction=reduction,
functional=True)
self.assertTrue(np.allclose(static_functional, expected))
self.assertTrue(np.allclose(static_functional, dy_functional))
self.assertTrue(np.allclose(dy_functional, expected))


if __name__ == "__main__":
unittest.main()

0 comments on commit 752487b

Please sign in to comment.