
人工智能机器学习深度学习计算机视觉【免费下载链接】pytorch-metric-learningThe easiest way to use deep metric learning in your application. Modular, flexible, and extensible. Written in PyTorch.项目地址https://gitcode.com/gh_mirrors/py/pytorch-metric-learning点击查看免费下载本文围绕 pytorch-metric-learning 仓库中的官方扩展文档 docs/extend/losses.md 展开系统讲解如何编写自定义度量学习损失函数从最简实现出发逐步接入距离度量distance与归约器reducer两大基础设施并深入indices_tuple、reduction_type等核心机制。读完本文你将掌握自定义损失函数的完整范式能够写出与内置TripletMarginLoss、ContrastiveLoss等同样健壮、可组合、可被 Miner 驱动的自定义 Loss。一、整体框架损失函数在训练循环中的角色在深入编写代码之前先理解 pytorch-metric-learning 中损失函数所处的框架位置。所有内置损失函数如 triplet_margin_loss.py、contrastive_loss.py都继承自 BaseMetricLossFunction。该类本身又由EmbeddingRegularizerMixin与ModuleWithRecordsReducerAndDistance组合而成后者提供了两个关键默认设施见 module_with_records_and_reducer.py默认归约器MeanReducerget_default_reducer()返回默认距离LpDistance(p2)get_default_distance()返回。从源码看BaseMetricLossFunction.forwardbase_metric_loss_function.py的调用链非常清晰这也是任何自定义损失函数最终都会经历的流程reset_stats()重置统计记录check_shapes(embeddings, labels)校验输入形状set_ref_emb(...)处理参考集ref_emb/ref_labels为空时的回退逻辑调用你唯一需要实现的方法compute_loss(embeddings, labels, indices_tuple, ref_emb, ref_labels)add_embedding_regularization_to_loss_dict(...)自动追加嵌入正则化项将整个 loss 字典交给self.reducer(loss_dict, embeddings, labels)完成最终归约返回标量。因此编写自定义损失函数的本质工作只有一个实现compute_loss方法并返回符合约定的字典。二、最简单的损失函数官方文档给出的最简实现如下只需继承BaseMetricLossFunction并返回一个loss子键from pytorch_metric_learning.losses import BaseMetricLossFunction import torch class BarebonesLoss(BaseMetricLossFunction): def compute_loss(self, embeddings, labels, indices_tuple, ref_emb, ref_labels): # perform some calculation # some_loss torch.mean(embeddings) # put into dictionary # return { loss: { losses: some_loss, indices: None, reduction_type: already_reduced, } }这段代码虽然简短却包含了自定义损失函数必须遵守的全部契约compute_loss必须存在父类的实现直接raise NotImplementedErrorbase_metric_loss_function.py返回值必须是字典字典的每个键对应一个子损失每个子损失又必须包含losses、indices、reduction_type三个字段reduction_typealready_reduced表示losses本身已经是标量无需 reducer 再做归约。对应地BaseReducer.already_reduced_reductionbase_reducer.py会直接断言其为 0 维或单元素张量并原样返回。注意由于该类没有重写_sub_loss_names默认子损失名即[loss]base_metric_loss_function.py。三、接入距离与归约器功能完备的自定义 Loss仅返回一个already_reduced标量的损失无法利用框架的 miner、distance、reducer 生态。官方文档展示了一个完整范例FullFeaturedLoss它演示了如何让自定义损失兼容三元组采样、距离矩阵和多子损失归约from pytorch_metric_learning.losses import BaseMetricLossFunction from pytorch_metric_learning.reducers import AvgNonZeroReducer from pytorch_metric_learning.distances import CosineSimilarity from pytorch_metric_learning.utils import loss_and_miner_utils as lmu import torch class FullFeaturedLoss(BaseMetricLossFunction): def compute_loss(self, embeddings, labels, indices_tuple, ref_emb, ref_labels): indices_tuple lmu.convert_to_triplets(indices_tuple, labels) anchors, positives, negatives indices_tuple if len(anchors) 0: return self.zero_losses() mat self.distance(embeddings) ap_dists mat[anchors, positives] an_dists mat[anchors, negatives] # perform some calculations # losses1 ap_dists - an_dists losses2 ap_dists * 5 losses3 torch.mean(embeddings) # put into dictionary # return { loss1: { losses: losses1, indices: indices_tuple, reduction_type: triplet, }, loss2: { losses: losses2, indices: (anchors, positives), reduction_type: pos_pair, }, loss3: { losses: losses3, indices: None, reduction_type: already_reduced, }, } def get_default_reducer(self): return AvgNonZeroReducer() def get_default_distance(self): return CosineSimilarity() def _sub_loss_names(self): return [loss1, loss2, loss3]围绕该示例官方文档补充了 5 条关键细节结合源码可以进一步展开基于三元组计算convert_to_triplets把外部传入的indices_tuple统一转换成(anchors, positives, negatives)三元组形式。当传入的indices_tuple为None时该函数会按标签自动生成随机三元组默认t_per_anchor100传all则生成全部三元组见 loss_and_miner_utils.py当传入的是 4 元组pair 形式时它也会转换为三元组。空三元组守卫当 batch 中不存在任何有效三元组例如indices_tuple为 None 且标签类别不足时返回self.zero_losses()。父类实现base_metric_loss_function.py会为sub_loss_names()中每个子损失生成{losses: 0, indices: None, reduction_type: already_reduced}随后BaseReducer.input_is_zero_lossbase_reducer.py会识别该情况并返回零损失避免梯度异常。内置的TripletMarginLoss同样采用这一模式triplet_margin_loss.py。self.distance返回成对距离矩阵self.distance(embeddings)本质是BaseDistance.forwardbase_distance.py的调用它会按需对嵌入做 L2 归一化normalize_embeddingsTrue时、计算矩阵并在power ! 1时施加幂次变换最终返回形状为(batch_size, batch_size)的矩阵随后用mat[anchors, positives]之类的索引取出成对距离。这也意味着你的自定义损失天然支持ref_emb参考集场景。多子损失需要重写_sub_loss_names当返回多个子损失时必须重写该方法告知框架子损失名称。这直接影响 reducer 的组装ModuleWithRecordsAndReducer.set_reducermodule_with_records_and_reducer.py会在子损失数量大于 1 时自动为每个子损失创建独立的 reducer并用MultipleReducers打包保证loss1/loss2/loss3各自按AvgNonZeroReducer归约后再相加。重写默认 reducer 与 distanceget_default_reducer默认返回MeanReducer此处改为AvgNonZeroReducer——它继承自ThresholdReducer(low0)avg_non_zero_reducer.py即只对大于 0未满足条件的损失取平均这一语义与 hinge 类损失天然契合get_default_distance默认返回LpDistance(p2)此处改为CosineSimilarity。注意这两个方法只在用户未显式传入reducer/distance参数时生效——ModuleWithRecordsAndReducer.__init__的逻辑是外部传入则使用传入值否则取默认值。关于AvgNonZeroReducer与MeanReducer的选择两者都实现对每个元素取平均区别在于MeanReducermean_reducer.py对全部元素直接torch.mean而AvgNonZeroReducer只统计非零元素。对三元组/成对损失来说零值通常代表没有违反 margin 的样本不参与平均可以避免噪声稀释这是内置TripletMarginLoss、ContrastiveLoss都选择它作为默认 reducer 的原因contrastive_loss.py。建议在编写 hinge 类自定义损失时沿用此选择。四、距离对象的进阶用法处理倒置距离距离度量的一个重要抽象是is_inverted标志。CosineSimilarity这类相似度度量中距离越小越好的语义与欧氏距离相反因此它是倒置距离is_invertedTrue。为了让你的自定义损失同时兼容两种语义官方文档建议检查self.distance.is_inverted并据此编写逻辑。与其手写分支更推荐直接使用BaseDistance内置的三个语义化方法base_distance.py它们的定义非常直观| 方法 | 非倒置距离如 LpDistance | 倒置距离如 CosineSimilarity | |--|--|--| |smallest_dist(x)|torch.min(x)|torch.max(x)| |largest_dist(x)|torch.max(x)|torch.min(x)| |margin(x, y)|x - y|y - x|以margin为例对距离度量margin 语义是x与y的差距通常x是待惩罚的项对倒置的相似度度量则取反从而保证越相似、margin 越小的语义一致。内置TripletMarginLoss正是通过self.distance.margin(ap_dists, an_dists)来计算三元组 margin并通过self.distance.smallest_dist(an_dists, pn_dists)实现swap逻辑triplet_margin_loss.pyContrastiveLoss则用self.distance.margin在正对/负对上分别计算 hinge 项contrastive_loss.py。编写自定义损失时应优先使用这三个方法而非直接比较大小这样切换到倒置距离后损失语义仍正确。五、处理indices_tuple三种输入形态与转换函数indices_tuple是外部通常是 Miner传入的可选参数在训练循环中由 miner 生成参见官方 docs/index.md 中关于 losses 和 miners 使用的说明。它当前共有 3 种可能形态None没有传入任何采样索引此时损失函数需要自行根据标签构造 pairs/triplets4 元组(anchor1, positives, anchor2, negatives)表示被挖掘出的成对索引前两个构成正对后两个构成负对3 元组(anchors, positives, negatives)表示被挖掘出的三元组索引。官方文档强调你不必在损失函数里判断传入的是哪种形态交给loss_and_miner_utils提供的转换函数即可from pytorch_metric_learning.utils import loss_and_miner_utils as lmu # For a pair based loss # After conversion, indices_tuple will be a tuple of size 4 indices_tuple lmu.convert_to_pairs(indices_tuple, labels) # For a triplet based loss # After conversion, indices_tuple will be a tuple of size 3 indices_tuple lmu.convert_to_triplets(indices_tuple, labels) # For a classification based loss # miner_weights.shape labels.shape # You can use these to weight your loss miner_weights lmu.convert_to_weights(indices_tuple, labels, dtypetorch.float32)从源码看loss_and_miner_utils.pyconvert_to_pairs的规则是传入None时调用get_all_pairs_indices生成全部正负对传入 4 元组时原样返回传入 3 元组时把三元组拆成(a, p, a, n)补齐为 4 元组。convert_to_triplets则相反传入None时按t_per_anchor生成随机三元组或全部三元组传入 3 元组时原样返回传入 4 元组时通过torch.where(a1.unsqueeze(1) a2)将成对索引重组为三元组loss_and_miner_utils.py。convert_to_weights专为分类式损失设计它统计每个 batch 元素在indices_tuple中出现的次数归一化后返回一个与labels等长的权重向量用于加权每个样本的交叉熵。内置NormalizedSoftmaxLoss正是这样使用的normalized_softmax_loss.py。注意convert_to_weights的 dtype 参数需要显式指定如torch.float32因为权重张量默认按torch.float16之外的通用逻辑创建。六、Reduction type 对照表给 reducer 的语义声明reduction_type是损失字典中每个子损失必须提供的字段它向 reducer 声明losses中每个元素代表什么以及indices的形状应如何校验。官方文档给出了完整对照表| Reduction type | 含义 |indices的形状 | |--|--|--| |triplet|losses中每个元素代表一个三元组 | 3 个张量组成的元组(anchors, positives, negatives)每个形状(N,)| |pos_pair|losses中每个元素代表一个正对 | 2 个张量组成的元组(anchors, positives)每个形状(N,)| |neg_pair|losses中每个元素代表一个负对 | 2 个张量组成的元组(anchors, negatives)每个形状(N,)| |element|losses中每个元素代表 batch 中的某个元素 | 形状为(N,)的张量 | |already_reduced|losses已是标量即损失已归约完成 | 应为None|对照 base_reducer.py 的assert_sizes_*系列校验方法可以理解这些约定的底层约束assert_sizes_triplet要求losses是张量indices是包含 3 个张量的元组且三者长度都与losses相等assert_sizes_pair供 pos_pair/neg_pair 共用要求indices是包含 2 个张量的元组且两个索引张量与losses等长assert_sizes_element要求losses与indices都是张量且长度相等assert_sizes_already_reduced不做任何断言pass。reducer 随后根据reduction_type通过get_reduction_func动态分发到对应的*_reduction方法base_reducer.py。这意味着你甚至可以编写一个根据 reduction_type 行为不同的自定义 reducer——这正是该机制的设计目的reduction_type是损失函数与归约器之间的语义协议。七、参考实现向仓库内置损失学习官方文档推荐了三个可参考的内置损失实现它们分别覆盖了三种典型的自定义需求是学习的最佳范本ContrastiveLoss基于成对pair的损失。它继承GenericPairLoss返回pos_loss与neg_loss两个子损失reduction_type分别为pos_pair与neg_pair并通过self.distance.margin实现与距离类型无关的 hinge 计算。如果你的自定义损失是 pair 型建议以它为模板。MultiSimilarityLoss基于全矩阵mat_based的损失。它在_compute_loss中直接接收距离矩阵与正/负掩码利用lmu.logsumexp计算 softmax 式加权返回reduction_typeelement的子损失并把默认距离覆盖为CosineSimilaritymulti_similarity_loss.py。如果你的损失需要对整个 batch 矩阵做全局运算如 NCA、MS-Loss 类参考它最合适。NormalizedSoftmaxLoss基于分类头的损失。它直接继承BaseMetricLossFunction通过lmu.convert_to_weights把 miner 权重注入逐样本交叉熵normalized_softmax_loss.py并使用DotProductSimilarity计算 logits、用self.distance.is_inverted判断是否取负号normalized_softmax_loss.py。如果你的损失是分类/代理proxy型参考它的权重接入方式。此外还有几个值得阅读的模式TripletMarginLoss展示了先convert_to_triplets→ 空守卫zero_losses()→ 索引距离矩阵 →margin计算 →triplet归约的完整三元组损失范式triplet_margin_loss.pyBaseMetricLossFunction中sub_loss_names()会动态拼接所有正则化损失名称base_metric_loss_function.py因此如果你的自定义损失类混入了*RegularizerMixincompute_loss返回的字典无需手动包含正则化项——forward中的add_embedding_regularization_to_loss_dict会自动补全。八、小结自定义损失函数的检查清单综合官方文档与仓库实现编写一个健壮的自定义损失函数可以按以下清单自查继承BaseMetricLossFunction并实现compute_loss返回以子损失名为键的字典每个子损失都包含losses、indices、reduction_type三要素且reduction_type与indices形状严格对应对照第六节表格需要外部索引时调用lmu.convert_to_pairs/lmu.convert_to_triplets/lmu.convert_to_weights不自行判断indices_tuple形态对空索引情况返回self.zero_losses()避免空张量引发数值问题使用self.distance获取距离矩阵并优先用smallest_dist/largest_dist/margin替代裸的大小比较保证倒置距离兼容性多子损失时重写_sub_loss_names让框架自动组装MultipleReducers按需重写get_default_reducer与get_default_distancehinge 类建议AvgNonZeroReducer相似度类建议CosineSimilarity编写测试仓库tests/losses/目录下为每个内置损失都配了对应的单元测试如 test_triplet_margin_loss.py测试工具类tests/zzz_testing_utils/testing_utils.py提供了test_losses等通用测试入口可直接复用来验证自定义损失在indices_tupleNone、三元组、成对、ref 集等多种输入下的行为。按照以上范式实现的自定义损失将与框架内置损失具有完全一致的能力可以被任何 Miner 驱动、可自由切换 distance/reducer、可参与MultipleLosses组合、可与EmbeddingRegularizerMixin系列正则器协同工作。赞分享人工智能机器学习深度学习计算机视觉【免费下载链接】pytorch-metric-learningThe easiest way to use deep metric learning in your application. Modular, flexible, and extensible. Written in PyTorch.项目地址https://gitcode.com/gh_mirrors/py/pytorch-metric-learning点击查看免费下载相关推荐PyTorch Metric Learning损失函数自定义距离、约简器与正则化器完全指南PyTorch Metric Learning损失函数自定义距离、约简器与正则化器完全指南 想要在深度度量学习中实现最佳性能PyTorch Metric L人工智能机器学习深度学习计算机视觉MXNet Gluon 损失函数实战指南内置 Loss、KL 散度与自定义损失MXNet Gluon 损失函数实战指南内置 Loss、KL 散度与自定义损失 损失函数Loss Function是神经网络训练的核心环节它定量刻画模型深度学习人工智能机器学习分布式训练PyTorch C 损失函数Loss Functions完全指南从回归到度量学习的 nn 模块选型与实践PyTorch C 损失函数Loss Functions完全指南从回归到度量学习的 nn 模块选型与实践 损失函数Loss Function用来衡人工智能机器学习深度学习分布式训练模型编译上一篇本地任务消息组件让数据库事务与外部消息推送HTTP/RabbitMQ达成最终一致性的通用组件方案下一篇rknn_model_zoo 中的 YOLOv7 部署实战ONNX 转换、量化与 RKNN C/Python 双端推理创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考