3.0.0rc1¶
This is the first release candidate for version 3.0.0.
Version 3 focuses the library on composable metric-learning components used from ordinary PyTorch code. It removes training and evaluation orchestration, makes tensor and extension contracts explicit and typed, and corrects numerical, distributed, and retrieval behavior. It is a clean break: there are no compatibility aliases. Look up any version 2 name in the migration guide.
Requirements¶
- Python 3.12 or newer.
- PyTorch 2.14.0 and NumPy 2.5.3 are the tested minimums; newer versions are permitted.
- Optional extras:
faiss(Faiss 1.15.1 or newer) for the Faiss retrieval backends, andclustering(scikit-learn 1.9.1 or newer) for NMI and AMI. - The
with-hooks,with-hooks-cpu,docs, anddevextras are removed, so record-keeper and TensorBoard are no longer installed. tqdm is no longer a dependency, and scikit-learn moves to theclusteringextra. - The package is typed and ships
py.typed. Read the installed version withimportlib.metadata.version("pytorch-metric-learning");pytorch_metric_learning.__version__is removed.
Breaking changes¶
Package layout¶
- Retrieval metrics and backends live in
pytorch_metric_learning.evaluation(AccuracyCalculator,CustomKNN,FaissKNN,FaissKMeans,MatchFinder), replacingutils.accuracy_calculator,utils.inference, andutils.retrieval. - Distributed wrappers live in
pytorch_metric_learning.distributed. utils.loss_and_miner_utilsis replaced byutils.indexing. Everything else underutils, including the former common functions, is private.- The public API is the
__all__ofdistances,losses,miners,reducers,regularizers,samplers,evaluation,distributed,types, andutils.indexing; see versioning. Implementation submodules, such aslosses.pnp_lossorevaluation.retrieval, are not public import paths, and their helpers are private, includingremove_self_comparisons,add_to_index_and_search, andreturn_results. typesexports the aliases and result tuples used in public signatures:PNPVariant,AnchorAggregation,DistributedObjective,SubCenterOutliers,ArrayLike,NeighborLimit,MetricNeighbors, andDatasetLabels.evaluationexports the built-in retrieval metric functionsprecision_at_k,precision_at_1,r_precision,mean_average_precision,mean_average_precision_at_r, andmean_reciprocal_rankfor reuse in custom metrics.
Tensor contracts¶
ref_emb=Nonemeans the query set is its own reference set, and self-comparisons are excluded. Passingref_emb, even the same tensor, describes a separate set. Withref_emb, supply bothlabelsandref_labelsor neither.- Labels must be on the embeddings' device; a mismatch raises
ValueError. Losses, miners, reducers, and memory never move or cast their parameters and buffers duringforward; place modules with.to(device, dtype). Under autocast, parameters keep their configured precision. - Miners return
types.PairIndicesortypes.TripletIndicesnamed tuples. Losses, miners, andutils.indexingaccept these or plain 3- or 4-tuples. utils.indexing.pairs_to_tripletsvalidates its input likeindices_tuple; a triplet tuple raisesValueError.- A loss term is
{"losses": tensor, "indices": ..., "divisor": optional}. The kind follows fromindices:Nonefor an already reduced value, one tensor for per-element losses, an(anchor, other)pair, or a triplet. Thereduction_typekey is removed. - Index tensors in
indices_tuple, miner output, and loss terms must beint64orint32; other dtypes raiseTypeError. A loss term'sindicesisNone, one tensor, a pair, or a triplet; 1-tuples are rejected. - A supplied
indices_tuplewith no indices selects nothing. Miner-weighted losses (ArcFace, CosFace, FastAP, LargeMarginSoftmax, NCA, NormalizedSoftmax, ProxyAnchor, ProxyNCA, SmoothAP, SoftTriple, SphereFace, SubCenterArcFace) then return a differentiable zero; passNonefor no restriction. - Invalid arguments raise
TypeErrorfor the wrong type andValueErrorfor an invalid value, also underpython -O.HistogramLoss(num_bins=...),LargeMarginSoftmaxLossandSphereFaceLossmargins, andSoftTripleLossorRegularFaceRegularizerwith a distance that is not a similarity now raiseTypeError. - Losses that return one already-reduced value (
DynamicSoftMarginLoss,HistogramLoss,ManifoldLoss,P2SGradLoss,PNPLoss,ThresholdConsistentMarginLoss) take noreducer, andP2SGradLosstakes nodistance; both were ignored and now raiseTypeError.LpRegularizerandZeroMeanRegularizerlikewise take nodistance. VICRegLossrequires at least two rows; a one-row batch raisesValueErrorinstead of returning NaN.
Composition and extension¶
BaseMetricLossFunction,BaseMiner, andBaseRegularizerextendtorch.nn.Moduledirectly and take keyword-only options typed bytypes.LossOptionsandtypes.RegularizerOptions. The mixins and composition bases are removed. A reducer is used as given, never copied.- Losses with class weights store one row per class or center in a parameter
named
weight. Except forP2SGradLoss, they derive from the newlosses.BaseProxyLossand take keyword-onlyweight_regularizer,weight_reg_weight, andweight_init_func. - Custom losses implement
compute_loss(embeddings, labels, indices_tuple, ref_emb, ref_labels). A custom loss may return{}when nothing is valid; reducers turn an empty dictionary or empty terms into a differentiable zero.sub_loss_namesandzero_lossesare removed.GenericPairLosssubclasses implementpair_loss(mat, pairs). - Custom reducers implement
element_reduction(losses, anchors, embeddings, labels); the pair and triplet hooks are removed. Terms with adivisor(ProxyAnchorLoss,MarginLoss,SparseCentersRegularizer) requireDivisorReducer, alone or insideMultipleReducers; other reducers raiseValueErrorinstead of ignoring the divisor. - Regularization penalties are added after reduction.
loss_terms(...)returns the unreduced objective and penalty terms. - Miners take
forward(embeddings, labels, indices_tuple=None, ref_emb=None, ref_labels=None)and restrict their search to optional candidate tuples. This argument replacesHDCMiner.set_idx_externallyandreset_idx. The third positional argument of miners andDistributedMinerWrapperis nowindices_tuple, so pass references by keyword. - Distance options are keyword-only.
BaseDistance.is_invertedis a class attribute.BaseDistance.pairwise(query, ref)computes normalized, powered row-wise values;smallest_distandlargest_distare removed. DistributedLossWrapperandDistributedMinerWrappertakeobjective="global"or"local_anchor"instead ofefficient.
Renamed or changed arguments¶
ArcFaceLossandSubCenterArcFaceLossmargins are in radians (default 0.5).LargeMarginSoftmaxLossrequires an integer margin.CircleLoss(margin=...)replacesm;HistogramLoss(num_bins=...)replacesn_binsanddelta;RankedListLoss(neg_temperature=..., pos_temperature=...)replacesTnandTp;AngularMiner(alpha=...)replacesangle;PerAnchorReducer(aggregation="mean")oraggregation="sum"replacesaggregation_func.ManifoldLoss(embedding_size, num_proxies, lambda_c, ...)replacesl,K, andlambdaC; proxy assignments are passed aslabels.P2SGradLoss(num_classes, embedding_size)matches the other classification losses.MultipleLossestakes mappings for losses, miners, and weights, accepts onlyBaseMetricLossFunctionorMultipleLossesvalues, and has the sameforwardsignature as a loss, includingref_embandref_labels.CrossBatchMemory,SelfSupervisedLoss, andDistributedLossWrapperaccept it (types.MetricLoss). Its per-loss miners select from a suppliedindices_tupleas candidates.CosineSimilarity()takes no options; useDotProductSimilarity(normalize_embeddings=True, ...)for other norms or powers.LiftedStructureLossandGeneralizedLiftedStructureLosstake(pos_margin, neg_margin)positionally, likeContrastiveLoss.MarginLossnames its main term"loss";DynamicSoftMarginLoss.hist_ishist.SubCenterArcFaceLoss.get_outliers(embeddings, labels, threshold_radians=...)takes its threshold in radians and always returnsSubCenterOutliers(outliers, dominant_centers).MPerClassSampler(num_samples=...)replaceslength_before_new_iter.MatchFinder.get_matching_pairsis replaced byget_match_matrix(a boolean matrix) andget_match_indices(an(num_matches, 2)index tensor).AccuracyCalculatorno longer takesreturn_per_class.get_accuracyreturnsdict[str, float];get_accuracy_per_classreturns values keyed by class label, with NaN for classes without relevant references. Custom metrics are passed ascustom_metrics={name: RetrievalMetric(function, neighbors=...)}orClusteringMetric(function); a retrieval metric returns one value per query and the calculator owns all reduction.metric_functions(),requires_knn(),requires_clustering(),aggregate(), and thecalculate_*methods are removed. Naming a clustering metric inget_accuracy_per_class(include=...)raisesValueError.- Samplers draw from PyTorch generators and accept a keyword-only
generator; seeded sequences differ from version 2.
Removed¶
- Trainers, testers, logging presets,
InferenceModel,run_pca, and thedatasetspackage. The training and evaluation recipes show the equivalent PyTorch code, including classifier, proxy, two-stream, cascaded, adversarial, and memory-warmup training, split composition, and parent-conditioned metrics. - Recorded statistics (
collect_stats,COLLECT_STATS, and attributes such asminer.pos_pair_dist). Compute diagnostics from returned tensors or with forward hooks. Recording forced host synchronization insideforward. DoNothingReducer(useloss_terms),EmbeddingsAlreadyPackagedAsTriplets,TuplesToWeightsSampler,BaseLossWrapper, thecommon_functionslogging, tensor-conversion, checkpoint, and label-mapping helpers, and Jupyter notebooks.
Changed defaults¶
AccuracyCalculatorsearches with exact PyTorch squared Euclidean distance (CustomKNN) on the input device instead of Faiss, and selects a device only when given one. NMI and AMI are computed only when included with akmeans_func.- A fixed
kis capped at the neighbors available in each call. - R-precision with an integer
kbelow a query's relevant count divides by the relevant count instead of byk. That configuration still logs a warning; usek="max_bin_count". utils.indexing.convert_to_tripletsdefaults to all triplets.ProxyAnchorLossapplies miner weights as multiplicative weights on the exponential terms; version 2 addedw - 1to the exponent. Results without a miner are unchanged.ProxyNCALossminer weights count every position in the mined tuples, like the other classification losses; version 2 counted only anchors. A mined triplet now also weights its positive and negative rows.PerAnchorReducer(aggregation="mean")averages over anchors that have losses; version 2 averaged over every row of the batch.CircleLoss,GeneralizedLiftedStructureLoss,MultiSimilarityLoss,SupConLoss,SmoothAPLoss, andPNPLossexclude anchors that lack the pairs their term needs, so means average only anchors that have them, asNCALossandFastAPLossalready did.SupConLossfollows the paper when a batch has positives but no negatives, instead of returning zero.
Fixed¶
NCALossandProxyNCALosscompute the objective in log space. A single query with valid separate references no longer returns zero, and largesoftmax_scalevalues no longer underflow hard examples to zero loss and gradient. Queries without a positive reference are excluded.NTXentLosscomputes per-anchor log-sum-exp directly; float16 hard positives keep their loss and gradients.AccuracyCalculatorrelevance counts, lone-query detection, andk="max_bin_count"honor custom label comparators, so a comparator that rejects self-matches no longer produces infinite MAP or NaN R-precision.CrossBatchMemoryrejects labels that change value when converted tolabel_dtype, and validates inputs and runs the wrapped miner and loss before modifying its queue. Its miner no longer sees each anchor's own enqueued copy, which an easy-positive miner used to select and then lose, leaving no positive.PerAnchorReduceraggregates the supplied losses by anchor, supports references larger than the query batch and duplicate pairs, and no longer builds a dense matrix.AngularMinermeasures angles on normalized embeddings, matchingAngularLoss.LiftedStructureLosspositive pairs without negatives contribute zero, as in the paper; the loss rejectsref_emb, which it mishandled.SmoothAPLossderives positives from labels instead of positional blocks.ThresholdConsistentMarginLossusesref_emband its configured similarity.TupletMarginLossno longer returns NaN for identical anchors and positives, andAngularLossnormalizes negatives.RankedListLosscomputes exact weighted means without a1e-5offset and cannot overflow for large temperatures.TripletMarginLoss(swap=True)measures positive-negative distances on the reference set.FaissKNNuses a GPU only with a GPU build of Faiss.BatchHardMiner,BatchEasyHardMiner,DistanceWeightedMiner, andMultiSimilarityMinerreturn empty tuples for an empty query or reference set instead of raisingIndexError.AccuracyCalculatorruns undertorch.no_grad()and builds no autograd graph. Aknn_funcreturning indices outside the reference set, such as aFaissKNN(reset_before=False)whose index has grown, raisesValueErrorinstead ofIndexError, and so do indices not shaped(len(query), k).- float16 and bfloat16 normalization runs in float32, including in
P2SGradLoss, so zero and tiny rows no longer give NaN values or gradients.ThresholdConsistentMarginLosssums its penalties andDynamicSoftMarginLosscounts its histogram in float32, so large half-precision batches no longer overflow.LpDistance.pairwiseno longer adds1e-6, so identical rows give 0, matching the distance matrix. - Distributed wrappers raise invalid-input errors on every rank instead of leaving other ranks waiting in a collective.
AngularLosstakes negatives from labels even when a miner supplies only positives, instead of returning zero.GeneralizedLiftedStructureLossno longer adds a hinge for anchors missing positives or negatives.PNPLoss, labeledManifoldLoss, andP2SGradLossgive a differentiable zero for empty batches instead of NaN.- Miner weights normalize occurrence counts before casting, so float16 counts above 65504 no longer become infinite.
DistanceWeightedMinernormalizes weights per anchor over eligible negatives, so default cutoffs no longer underflow to an empty output.LpDistancepreserves small float16 and bfloat16 distances and their gradients.- Losses never move or cast learnable parameters during
forward; one float64 call previously converted a float32 proxy matrix permanently. AccuracyCalculatorkeeps label dtypes, so large integer identifiers no longer collide (reported and fixed by Akshit Khokhani in #763).MPerClassSampleryields exactlylen(sampler)indices.MatchFinder.is_matchapplies the configured normalization and power.
Performance¶
- Pair-to-triplet conversion and all-triplet enumeration group negatives by anchor; memory scales with the emitted triplets instead of a positives-by-negatives boolean matrix.
NTXentLoss,TupletMarginLoss, andLiftedStructureLossreduce negatives per anchor instead of materializing positive-by-negative matrices.- Default reducers, self-comparison removal, and random triplet sampling avoid data-dependent host synchronization where the output shape allows it.
AccuracyCalculatorretrieves only the neighbors the selected metrics need, and counts relevant references from label counts with the default comparator. With onlyprecision_at_1andk=None, 2000 queries against 20000 references took 0.10 s instead of 2.9 s on one CPU thread.LpDistancecomputes half-precision matrices withtorch.cdistin float32 instead of expanding every row pair.
See performance measurements for the measured workloads.