{"id":2247,"library":"pytorch-metric-learning","title":"PyTorch Metric Learning","description":"PyTorch Metric Learning is a Python library (version 2.9.0) that simplifies the use of deep metric learning in applications. It offers a modular, flexible, and extensible framework built on PyTorch, providing a wide array of loss functions, miners, samplers, trainers, and testers. The library maintains an active release cadence, with frequent updates introducing new features and improvements.","status":"active","version":"2.9.0","language":"en","source_language":"en","source_url":"https://github.com/KevinMusgrave/pytorch-metric-learning","tags":["pytorch","deep-learning","metric-learning","embedding","similarity-learning","computer-vision"],"install":[{"cmd":"pip install pytorch-metric-learning","lang":"bash","label":"Standard Install"},{"cmd":"pip install pytorch-metric-learning[with-hooks]","lang":"bash","label":"Install with evaluation & logging (Faiss-GPU, Record-Keeper, TensorBoard)"}],"dependencies":[{"reason":"Core deep learning framework. Requires >= 1.6 for pytorch-metric-learning >= v0.9.90.","package":"torch","optional":false},{"reason":"Numerical operations.","package":"numpy","optional":false},{"reason":"Utility functions, e.g., for data splitting or metrics.","package":"scikit-learn","optional":false},{"reason":"Progress bars.","package":"tqdm","optional":false},{"reason":"Efficient similarity search, part of `[with-hooks]` extra.","package":"faiss-cpu","optional":true},{"reason":"GPU-accelerated efficient similarity search, part of `[with-hooks]` extra.","package":"faiss-gpu","optional":true},{"reason":"Logging and experiment tracking, part of `[with-hooks]` extra.","package":"record-keeper","optional":true},{"reason":"Visualization tools, part of `[with-hooks]` extra.","package":"tensorboard","optional":true}],"imports":[{"symbol":"TripletMarginLoss","correct":"from pytorch_metric_learning.losses import TripletMarginLoss"},{"symbol":"MultiSimilarityMiner","correct":"from pytorch_metric_learning.miners import MultiSimilarityMiner"},{"note":"The `trainers` module is plural.","wrong":"from pytorch_metric_learning.trainer import MetricLossOnly","symbol":"MetricLossOnly","correct":"from pytorch_metric_learning.trainers import MetricLossOnly"},{"symbol":"AccuracyCalculator","correct":"from pytorch_metric_learning.utils.accuracy_calculator import AccuracyCalculator"},{"note":"Wrappers are in their own submodule.","wrong":"from pytorch_metric_learning.losses import DistributedLossWrapper","symbol":"DistributedLossWrapper","correct":"from pytorch_metric_learning.wrappers import DistributedLossWrapper"}],"quickstart":{"code":"import torch\nimport torch.nn as nn\nfrom torch.utils.data import DataLoader, Dataset\nfrom pytorch_metric_learning import losses, miners\n\n# 1. Dummy Dataset for demonstration\nclass DummyDataset(Dataset):\n    def __init__(self, num_samples=100, embedding_dim=64, num_classes=10):\n        self.data = torch.randn(num_samples, embedding_dim)\n        self.labels = torch.randint(0, num_classes, (num_samples,))\n\n    def __len__(self):\n        return len(self.labels)\n\n    def __getitem__(self, idx):\n        return self.data[idx], self.labels[idx]\n\n# 2. Dummy Model (e.g., identity for pre-computed embeddings)\nclass DummyModel(nn.Module):\n    def __init__(self, embedding_dim):\n        super().__init__()\n        self.linear = nn.Linear(embedding_dim, embedding_dim) # Simple linear layer\n\n    def forward(self, x):\n        return self.linear(x)\n\n# Configuration\nembedding_dim = 64\nnum_classes = 10\nbatch_size = 32\nnum_epochs = 2\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n# Initialize dataset and dataloader\ndataset = DummyDataset(embedding_dim=embedding_dim, num_classes=num_classes)\ndataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)\n\n# Initialize model, loss, and miner\nmodel = DummyModel(embedding_dim).to(device)\nloss_func = losses.TripletMarginLoss(margin=0.1).to(device)\nminer = miners.MultiSimilarityMiner(epsilon=0.1)\noptimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n\n# Training loop\nprint(f\"Training on {device}...\")\nfor epoch in range(num_epochs):\n    for i, (data, labels) in enumerate(dataloader):\n        data, labels = data.to(device), labels.to(device)\n\n        optimizer.zero_grad()\n        embeddings = model(data)\n\n        # Mine for hard triplets\n        hard_triplets = miner(embeddings, labels)\n\n        # Compute loss using mined triplets\n        loss = loss_func(embeddings, labels, hard_triplets)\n\n        loss.backward()\n        optimizer.step()\n\n        if i % 10 == 0:\n            print(f\"Epoch {epoch+1}/{num_epochs}, Batch {i+1}/{len(dataloader)}, Loss: {loss.item():.4f}\")\n\nprint(\"Training complete.\")","lang":"python","description":"This quickstart demonstrates a basic training loop using PyTorch Metric Learning. It defines a dummy dataset and model, then initializes a `TripletMarginLoss` and `MultiSimilarityMiner`. The training loop moves data and model to the appropriate device, generates embeddings, mines for hard triplets, computes the loss, and performs backpropagation."},"warnings":[{"fix":"Update calls to `DistributedLossWrapper.forward` to use `embeddings` instead of `emb`.","message":"The `emb` argument of `DistributedLossWrapper.forward` was renamed to `embeddings` for consistency with the rest of the library.","severity":"breaking","affected_versions":">=2.6.0"},{"fix":"Explicitly set `symmetric=False` in `SelfSupervisedLoss` initialization if you need the old behavior. Otherwise, be aware of the change in anchor selection.","message":"The default value of the `symmetric` flag in `SelfSupervisedLoss` changed from `False` to `True`. If `False`, only `embeddings` are used as anchors. If `True`, `embeddings` and `ref_emb` are both used as anchors.","severity":"breaking","affected_versions":">=2.2.0"},{"fix":"Wrap your loss and miner functions with `DistributedLossWrapper` and `DistributedMinerWrapper` respectively when using `DistributedDataParallel`. Ensure `efficient` parameter is consistent between wrappers if used.","message":"When using `PyTorch's DistributedDataParallel`, `DistributedLossWrapper` and `DistributedMinerWrapper` are essential. Without them, losses and miners in each process will only see a fraction of the global batch, leading to incorrect calculations.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Reduce your batch size if you encounter `INT_MAX` errors during loss or mining computation.","message":"Very large batch sizes can lead to `INT_MAX` errors within `loss_and_miner_utils` due to an extremely high number of pairs/triplets being processed.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Explicitly move models (`model.to(device)`), data (`data.to(device)`, `labels.to(device)`), and loss/miner functions (`loss_func.to(device)`, `miner.to(device)`) to the target device.","message":"Device mismatches (CPU/GPU) are a common PyTorch error. Ensure your model, input data, and loss/miner functions are all on the same device (e.g., 'cuda') to avoid `RuntimeError: Expected all tensors to be on the same device...`.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-09T00:00:00.000Z","next_check":"2026-07-08T00:00:00.000Z"}