From 10f202ee90b876ad964dcb05ec5d5eb8ba1e609d Mon Sep 17 00:00:00 2001 From: Vinayak Date: Sun, 30 Oct 2022 08:33:50 +0530 Subject: [PATCH 1/5] Modified arcface loss to keep cost function monotonically decreasing --- src/pytorch_metric_learning/losses/arcface_loss.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/pytorch_metric_learning/losses/arcface_loss.py b/src/pytorch_metric_learning/losses/arcface_loss.py index b9d6f819..b18e553c 100644 --- a/src/pytorch_metric_learning/losses/arcface_loss.py +++ b/src/pytorch_metric_learning/losses/arcface_loss.py @@ -21,7 +21,19 @@ def cast_types(self, dtype, device): def modify_cosine_of_target_classes(self, cosine_of_target_classes): angles = self.get_angles(cosine_of_target_classes) - return torch.cos(angles + self.margin) + + # Compute cos of (theta + margin) and cos of theta + cos_theta_plus_margin = torch.cos(angles + self.margin) + cos_theta = torch.cos(angles) + + # Keep the cost function monotonically decreasing + unscaled_logits = torch.where( + angles <= np.deg2rad(180) - self.margin, + cos_theta_plus_margin, + cos_theta - self.margin * np.sin(self.margin) + ) + + return unscaled_logits def scale_logits(self, logits, *_): return logits * self.scale From c0cc5de16134704d6b14ccf5ac866e134121e032 Mon Sep 17 00:00:00 2001 From: Vinayak Date: Sun, 6 Nov 2022 12:04:07 +0530 Subject: [PATCH 2/5] Modified test_arcface_loss.py to pass conditional margin addition --- tests/losses/test_arcface_loss.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/losses/test_arcface_loss.py b/tests/losses/test_arcface_loss.py index 85d6ab8a..cb9aff11 100644 --- a/tests/losses/test_arcface_loss.py +++ b/tests/losses/test_arcface_loss.py @@ -36,9 +36,14 @@ def test_arcface_loss(self): for i, c in enumerate(labels): acos = torch.acos(torch.clamp(logits[i, c], -1, 1)) - logits[i, c] = torch.cos( - acos + torch.tensor(np.radians(margin), dtype=dtype).to(TEST_DEVICE) - ) + if acos <= (np.pi - np.radians(margin)): + logits[i, c] = torch.cos( + acos + torch.tensor(np.radians(margin), dtype=dtype).to(TEST_DEVICE) + ) + else: + mg = np.radians(margin) + logits[i, c] -= torch.tensor(mg * np.sin(mg), dtype=dtype).to(TEST_DEVICE) + correct_loss = F.cross_entropy(logits * scale, labels.to(TEST_DEVICE)) From 5da3c0cd729c45d455aba6d10773c812d3d60f83 Mon Sep 17 00:00:00 2001 From: KevinMusgrave Date: Mon, 16 Jan 2023 14:27:47 -0500 Subject: [PATCH 3/5] Formatted the code --- src/pytorch_metric_learning/losses/arcface_loss.py | 8 ++++---- tests/losses/test_arcface_loss.py | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/pytorch_metric_learning/losses/arcface_loss.py b/src/pytorch_metric_learning/losses/arcface_loss.py index b18e553c..0bbe479c 100644 --- a/src/pytorch_metric_learning/losses/arcface_loss.py +++ b/src/pytorch_metric_learning/losses/arcface_loss.py @@ -28,10 +28,10 @@ def modify_cosine_of_target_classes(self, cosine_of_target_classes): # Keep the cost function monotonically decreasing unscaled_logits = torch.where( - angles <= np.deg2rad(180) - self.margin, - cos_theta_plus_margin, - cos_theta - self.margin * np.sin(self.margin) - ) + angles <= np.deg2rad(180) - self.margin, + cos_theta_plus_margin, + cos_theta - self.margin * np.sin(self.margin), + ) return unscaled_logits diff --git a/tests/losses/test_arcface_loss.py b/tests/losses/test_arcface_loss.py index cb9aff11..3c32962d 100644 --- a/tests/losses/test_arcface_loss.py +++ b/tests/losses/test_arcface_loss.py @@ -38,12 +38,14 @@ def test_arcface_loss(self): acos = torch.acos(torch.clamp(logits[i, c], -1, 1)) if acos <= (np.pi - np.radians(margin)): logits[i, c] = torch.cos( - acos + torch.tensor(np.radians(margin), dtype=dtype).to(TEST_DEVICE) + acos + + torch.tensor(np.radians(margin), dtype=dtype).to(TEST_DEVICE) ) else: mg = np.radians(margin) - logits[i, c] -= torch.tensor(mg * np.sin(mg), dtype=dtype).to(TEST_DEVICE) - + logits[i, c] -= torch.tensor(mg * np.sin(mg), dtype=dtype).to( + TEST_DEVICE + ) correct_loss = F.cross_entropy(logits * scale, labels.to(TEST_DEVICE)) From 51a29e1b74a3b429949b7fdf01caac483933834a Mon Sep 17 00:00:00 2001 From: KevinMusgrave Date: Mon, 16 Jan 2023 14:34:06 -0500 Subject: [PATCH 4/5] Updated version --- src/pytorch_metric_learning/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pytorch_metric_learning/__init__.py b/src/pytorch_metric_learning/__init__.py index 31e744e4..14d9d2f5 100644 --- a/src/pytorch_metric_learning/__init__.py +++ b/src/pytorch_metric_learning/__init__.py @@ -1 +1 @@ -__version__ = "1.6.3" +__version__ = "1.7.0" From 774df7861772f03b5a6b0fe6fb717a135b3215f2 Mon Sep 17 00:00:00 2001 From: KevinMusgrave Date: Mon, 16 Jan 2023 14:36:32 -0500 Subject: [PATCH 5/5] Fixed .flake8 file --- .flake8 | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/.flake8 b/.flake8 index 8e7514b4..23df87ab 100644 --- a/.flake8 +++ b/.flake8 @@ -1,12 +1,18 @@ [flake8] extend-ignore = - E266 # too many leading '#' for block comment - E203 # whitespace before ':' - E402 # module level import not at top of file - E501 # line too long - E741 # ambiguous variable names - E265 # block comment should start with # + # too many leading '#' for block comment + E266 + # whitespace before ':' + E203 + # module level import not at top of file + E402 + # line too long + E501 + # ambiguous variable names + E741 + # block comment should start with # + E265 per-file-ignores = __init__.py:F401 \ No newline at end of file