MediumLoss Functions

Implement Triplet Loss

Loss Functions

Medium

Problem

Compute triplet loss using squared Euclidean distance:

d(x,y) = \sum_{j=1}^{D}(x_j-y_j)^2

For each anchor, positive, and negative triplet:

L_i = \max\left(0, d(a_i,p_i)-d(a_i,n_i)+m\right)

Here, D is embedding width and m is margin. Support one triplet with shape (D,) or a batch with shape (N,D). Return the mean loss as a Python float.

Theory

Triplet loss learns embeddings by comparing three samples at a time:

The goal: learn embeddings where anchor is closer to positive than to negative.

d(a, p) < d(a, n)

Where d is a distance function (usually L2/Euclidean distance).


The Triplet Loss Formula

L = \max(0, d(a, p) - d(a, n) + m)

Where:

The loss is zero when: d(a, n) > d(a, p) + m

This means the negative must be farther than the positive by at least margin m.


Understanding the Margin

The margin m prevents trivial solutions:

Without margin (m = 0):

With margin (e.g., m = 0.2):


Numerical Examples

Let margin m = 0.5.

Example 1: Good triplet (satisfied)

Example 2: Violated triplet

Example 3: Badly violated triplet


Types of Triplets

Easy triplets: d(a, n) > d(a, p) + m

Semi-hard triplets: d(a, p) < d(a, n) < d(a, p) + m

Hard triplets: d(a, n) < d(a, p)


Triplet Mining Strategies

Random triplet sampling is inefficient because most triplets are easy:

Batch-hard mining:

Batch-semi-hard mining:

Offline mining:


The Gradient

For a violated triplet:

\frac{\partial L}{\partial f(a)} = \frac{f(a) - f(p)}{d(a, p)} - \frac{f(a) - f(n)}{d(a, n)}

This pushes the anchor:

Similar gradients apply to the positive and negative embeddings:


Triplet Loss vs. Contrastive Loss

Contrastive loss:

Triplet loss:

Triplet loss is often preferred because:


Batch All Triplet Loss

Computing loss over all valid triplets in a batch:

For a batch with P identities and K samples per identity:

Total triplets per batch: P \times K \times (K-1) \times (P-1) \times K

This can be thousands of triplets, but most are easy. Filtering to semi-hard or hard triplets is essential.


Squared Distance Variant

Some implementations use squared distances:

L = \max(0, d(a, p)^2 - d(a, n)^2 + m)

Advantages:

Disadvantage:


Where Triplet Loss Is Used

Best practices:

Examples

Example 1

Input
anchor = [[1, 0]], positive = [[2, 0]], negative = [[5, 0]], margin = 1.0
Output
0.0
Explanation
The positive squared distance is 1 and the negative squared distance is 16, so the margin is already satisfied.

Example 2

Input
anchor = [[0, 0]], positive = [[3, 0]], negative = [[1, 0]], margin = 1.0
Output
9.0

Example 3

Input
anchor = [1, 0], positive = [2, 0], negative = [5, 0], margin = 1.0
Output
0.0

Hints

  1. Use np.atleast_2d so one vector and a batch share the same computation.
  2. Sum squared coordinate differences along axis=1.
  3. Apply np.maximum(0.0, positive_distance - negative_distance + margin).

Requirements

Constraints

Starter Code

import numpy as np

def triplet_loss(anchor: list, positive: list, negative: list, margin: float = 1.0) -> float:
    """
    Returns the loss as a float.
    """
    # Write code here
    pass

Test Cases

CaseMatches
Basic single tripletpublic
Positive farther than negativepublic
1D vector inputpublic