PyTorch C++ 损失函数(Loss Functions)完全指南:从回归到度量学习的 nn 模块选型与实践
PyTorch C 损失函数Loss Functions完全指南从回归到度量学习的 nn 模块选型与实践【免费下载链接】pytorchTensors and Dynamic neural networks in Python with strong GPU acceleration项目地址: https://gitcode.com/GitHub_Trending/py/pytorch损失函数Loss Function用来衡量模型预测输出与真实目标之间的差异程度是训练循环中梯度回传的起点。本文以 PyTorch C 前端torch::nn的损失函数 API 为主题系统梳理回归、分类、序列建模与度量学习四类任务下的常用损失模块覆盖其数学语义、构造参数、调用方式与源码实现位置帮助你在 LibTorch/C 项目中快速完成损失层的选型、实例化与正确接入反向传播。读完本文你将能根据任务类型与数据特征为分类网络、回归网络、Embedding 检索等场景写出正确的torch::nn损失函数代码并能顺着源码深入理解其底层实现。本文对应的 API 参考文档位于 docs/cpp/source/api/nn/loss.md其中每个模块均由doxygenclass/doxygenstruct自动从头文件抽取完整成员与用法。损失模块的头文件实现集中在 loss.h构造选项options在 options/loss.h具体转发逻辑在 modules/loss.cpp底层算子统一收敛到函数式接口 functional/loss.h。选型总览先按任务类型分类损失函数的选择取决于任务类型与数据特性。PyTorch C 沿用了 Pythontorch.nn的分层语义参考文档把常用损失划分为三大类回归损失Regression lossesL1Loss / MSELoss基础回归损失对应 MAE平均绝对误差与 MSE均方误差SmoothL1Loss / HuberLoss对离群点outlier更鲁棒的平滑回归损失。分类损失Classification lossesCrossEntropyLoss多分类标准损失内部组合 LogSoftmax NLLLossNLLLoss负对数似然损失需配合 LogSoftmax 输出的概率对数使用BCELoss / BCEWithLogitsLoss二分类二元交叉熵二者区别在于输入是否为未过 Sigmoid 的 logits。专用损失Specialized lossesCTCLoss无需逐帧对齐的序列到序列损失语音识别等场景TripletMarginLoss度量学习损失相似度 / Embedding 任务CosineEmbeddingLoss基于余弦距离的相似性学习。此外torch::nn还提供KLDivLoss分布差异度量、PoissonNLLLoss泊松计数回归、MarginRankingLoss / HingeEmbeddingLoss / MultiMarginLoss / MultiLabelMarginLoss / MultiLabelSoftMarginLoss / SoftMarginLoss、以及可自定义距离函数的TripletMarginWithDistanceLoss等本文会逐一给出语义与使用要点。统一的调用约定模块化损失函数的使用范式在 PyTorch C 前端中所有损失函数都遵循统一的ImplModuleHolder二段式设计头文件先定义XXXLossImpl继承CloneableXXXLossImpl再通过TORCH_MODULE(XXXLoss)宏生成持有智能指针的XXXLoss外壳参见 loss.h。因此torch::nn::MSELoss是外壳类型构造后得到的是一个模块持有者holder调用前向传播需使用-forward(input, target)箭头解引用这与普通Module的持有语义一致外壳与Impl具有值语义可像普通对象一样拷贝、移动clone()后共享同一份 options 配置。参考文档给出的最小示例即这一范式// MSELoss平均平方误差 auto loss_fn torch::nn::MSELoss(); auto loss loss_fn-forward(predictions, targets);前向计算最终在 loss.cpp 中被转发到函数式接口例如L1LossImpl::forward实际执行F::detail::l1_loss(input, target, options.reduction())。这意味着模块层只是对底层torch::nn::functional函数的薄封装——你可以选择“构造模块”的风格也可以直接调用F::l1_loss(input, target, F::L1LossFuncOptions(...))的函数式风格。二者共享同一份 options/loss.h 中定义的XXXLossOptions。关于 reduction 的统一约定多数回归与分类损失如 L1Loss、MSELoss、BCELoss的 options 都以std::variantkNone, kMean, kSum声明 reduction默认取torch::kMean见 options/loss.h。三种取值含义为reduction 取值行为torch::kNone不降维逐元素返回 loss 张量形状与输入一致torch::kMean对 batch 求平均得到标量默认torch::kSum对所有元素求和得到标量少数损失有特殊取值KLDivLoss 额外支持torch::kBatchMean按 batch 维度取平均是文档约定下近似“真 KL 散度”的正确用法。构造时既可以直接传入枚举构造器L1LossOptions(torch::kNone)也可以通过链式方法MSELossOptions().reduction(torch::kSum)覆盖默认值。回归损失L1Loss平均绝对误差L1Loss 度量输入x与目标y逐元素之差的绝对值的平均对异常样本的惩罚是线性的因此对离群点不像 MSE 那样敏感常用于 MAE 指标对齐或对稀疏噪声鲁棒的回归任务。头文件对其语义的描述是 measures the mean absolute error (MAE) between each element in the input x and target yloss.h。// 例逐元素 loss不降维 auto loss_fn torch::nn::L1Loss(torch::nn::L1LossOptions(torch::kNone)); auto loss loss_fn-forward(input, target); // shape input.shape()MSELoss均方误差MSELoss 度量输入与目标逐元素差平方的均值squared L2 norm。由于对误差取平方它对大误差施以更强惩罚训练初期梯度也更大是回归任务最常用的默认损失。参考文档给出的示例auto loss_fn torch::nn::MSELoss(); auto loss loss_fn-forward(predictions, targets);其底层 forward 同样只携带options.reduction()一个参数转发到F::detail::mse_lossloss.cppoptions 默认 reduction 为torch::kMean。需要逐像素 loss 用于后续加权或可视化时用MSELossOptions(torch::kNone)。SmoothL1Loss 与 HuberLoss抗离群点回归SmoothL1Loss平滑 L1在误差较小时表现为二次函数、误差较大时退化为线性既保留 L1 对离群点的鲁棒性又避免了 L1 在零点附近不可导的问题因此被 Faster R-CNN 等目标检测框架广泛用于边框回归。其阈值切换点即beta超参数。HuberLoss 是 SmoothL1Loss 的更一般形式当beta取 1 时二者数学上等价HuberLoss 允许你显式调节该阈值。二者均继承回归损失的 reduction 约定。分类损失CrossEntropyLoss多分类交叉熵CrossEntropyLoss 是多分类任务图像分类、文本分类等的默认选择。它在内部把LogSoftmax 与 NLLLoss 组合为一个算子因此输入应为未归一化的原始 logits形状[batch, num_classes]目标为类别索引形状[batch]取值为0 ~ num_classes-1的整数张量。不要把 logits 手动过 Softmax 后再喂给它也不要把 one-hot 向量当目标否则语义会被破坏。参考文档示例auto loss_fn torch::nn::CrossEntropyLoss(); auto logits torch::randn({32, 10}); // [batch, num_classes] auto targets torch::randint(0, 10, {32}); // [batch] auto loss loss_fn-forward(logits, targets);NLLLoss负对数似然NLLLoss 计算-log(prob)形式的目标损失。它的输入必须是对数概率空间的值即要求模型输出已经过LogSoftmax或等价的log_softmax。CrossEntropyLoss 之所以能“吃”原始 logits本质就是因为它内部先替你执行了 LogSoftmax 再接 NLLLoss。当你自定义网络结构、需要显式分离LogSoftmax层时再直接使用 NLLLoss也可通过 options 配置weight类别加权缓解类别不均衡与ignore_index忽略某个索引的目标如填充符。BCELoss二元交叉熵BCELoss 计算二元交叉熵loss -[ y * log(x) (1 - y) * log(1 - x) ]约束是输入 x 必须落在 (0,1) 区间即要求模型输出已经过 Sigmoid。它的 options 除 reduction 外还支持逐样本/逐类别weight张量做加权。实现上需要注意一点BCELossImpl 的reset()会把options.weight()注册为模块 buffer源码见 loss.cpp 中BCELossImpl::reset()的register_buffer(weight, options.weight())从而在state_dict中与模块一并保存/加载而 L1Loss、KLDivLoss、MSELoss 等无参损失的reset()为空实现这也解释了为何头文件里会区分这两类实现。BCEWithLogitsLoss数值稳定的二分类BCEWithLogitsLoss 与 BCELoss 的唯一区别是它接受未经 Sigmoid 的 logits 作为输入并在算子内部以数值稳定的方式同时完成 Sigmoid 与交叉熵计算避免log在接近 0/1 处出现数值下溢。因此在实践中几乎总是优先使用 BCEWithLogitsLoss只有当你确实已经在上游显式做了 Sigmoid例如与 BN 等结构耦合时才使用 BCELoss。它还额外提供pos_weight选项可对正样本加权常用于正负样本极不均衡的二分类与多标签任务。分布度量与生成式损失KLDivLossKL 散度KLDivLoss 度量两个概率分布间的 Kullback-Leibler 散度。它的语义约定常被误解输入应为对数概率log-probabilities目标为真实概率分布。options 中 reduction 的取值枚举是四种——kNone / kBatchMean / kSum / kMean默认kMean同时还提供log_target(bool)开关默认false用于声明目标本身是否已经位于对数空间options/loss.hauto loss_fn torch::nn::KLDivLoss( torch::nn::KLDivLossOptions().reduction(torch::kBatchMean).log_target(false));注意文档级约定当目标是真实概率分布而非对数概率时应使用torch::kBatchMean而非torch::kMean以得到数学意义上正确的分布散度值。PoissonNLLLoss泊松负对数似然PoissonNLLLoss 面向计数型数据如事件计数、点击率等泊松分布假设下的回归在内部对输入施加指数变换后计算泊松分布的负对数似然。适用于输出为非负期望值 τ 的计数回归模型常配合 log-input 模式使用。CTCLoss序列到序列免对齐CTCLoss 面向输入与输出长度不一致且没有逐帧对齐标注的序列任务最典型的应用是语音识别、手写识别。它通过动态规划在所有可能的对齐路径上求和来计算损失从而无需人工标注每一帧对应哪个字符。CTCLoss 通常需要传入输入序列长度与目标长度使用前请务必确认 batch 内序列按长度排序等约定并合理配置blank索引。度量学习与排序损失度量学习的目标是让同类样本的表示在度量空间中靠近、异类远离。以下损失通常在训练完分类头之外的 Embedding 网络后使用输入均为样本对/三元组的特征向量。TripletMarginLoss三元组边际损失TripletMarginLoss 是最经典的度量学习损失。输入为anchor锚点、positive正样本、negative负样本三组特征训练目标是让anchor与positive的距离比anchor与negative的距离至少小一个marginloss max(d(anchor, positive) - d(anchor, negative) margin, 0)它常用于人脸识别、ReID、句子相似度等 Embedding 检索场景。除margin、reduction外还可配置p距离范数阶数与swap是否采用交换技巧以收紧约束等选项。TripletMarginWithDistanceLoss自定义距离的三元组损失TripletMarginWithDistanceLoss 是 TripletMarginLoss 的泛化版本前者把距离函数固定为p范数而后者允许你传入任意可微的距离函数distance_function例如余弦距离1 - cosine_similarity、自定义的度量等从而支持更灵活的样本对距离建模。当你需要非欧氏度量或更复杂的距离定义时选用它。CosineEmbeddingLoss余弦相似度学习CosineEmbeddingLoss 基于两个输入间的余弦相似度进行学习对正样本对希望相似度尽量高对负样本对希望相似度低于某个边际。与 Triplet 系列不同它接收的是样本对而非三元组适合二分类形式的相似性判断任务如判断两个句子/两张图是否语义相关。相关选项包括margin与reduction。MarginRankingLoss、HingeEmbeddingLoss 与多标签系列MarginRankingLoss输入为样本对x1、x2与标签yy1表示 x1 应排在 x2 前用于学习排序关系HingeEmbeddingLoss用于判断样本对是否属于同一类是 SVM/铰链损失在 Embedding 学习中的形式支持marginMultiMarginLoss多分类合页损失对每类的 margin 求和与 MultiMargin/结构化 SVM 思想一致MultiLabelMarginLoss面向多标签排序的合页损失目标由正标签索引列表给出MultiLabelSoftMarginLoss将多标签问题拆成多个独立二元分类并以 Sigmoid 多标签交叉熵求解是“one-vs-all”思想在损失层的体现SoftMarginLoss二元版本的 soft-marginlogistic损失输入为样本对与 ±1 标签。在训练循环中的接入方式与 Python 端一致C 训练循环中损失函数只需放在前向传播之后、backward()之前torch::nn::CrossEntropyLoss criterion; // ... 得到 logits 与 targets 后 auto loss criterion-forward(logits, targets); loss.backward(); // 通过 autograd 图回传梯度 optimizer.step(); // 更新模型参数 optimizer.zero_grad();由于所有XXXLossImpl都继承自Cloneableloss.h它们与其它torch::nn模块保持一致的模块语义可以存进torch::nn::ModuleList、随模型一起to(device)与序列化带权重参数的损失如 BCELoss 的weightbuffer会自动进入模块状态。小结PyTorch C 的损失函数家族与 Python 版torch.nn保持严格对齐可按下表快速选型任务类型推荐损失关键约束数值回归MSELoss / L1Loss输入输出同为连续张量抗离群点回归SmoothL1Loss / HuberLoss用beta调节平滑阈值多分类CrossEntropyLoss输入 logits目标为类别索引概率对数输出 / 自定义NLLLoss输入必须为 LogSoftmax 输出二分类BCEWithLogitsLoss / BCELoss前者吃 logits后者吃 Sigmoid 输出分布散度KLDivLoss输入为对数概率注意batchmean免对齐序列CTCLoss语音识别、手写识别Embedding 检索TripletMarginLoss / TripletMarginWithDistanceLoss / CosineEmbeddingLoss特征向量间的距离建模排序 / 多标签MarginRankingLoss / HingeEmbeddingLoss / MultiMargin / MultiLabel*样本对与索引式目标需要逐元素控制的训练技巧如 masked loss、样本加权时将 reduction 设为torch::kNone再自行降维即可。动手实验时可以随时对照 loss.h 查看每个类的成员声明、对照 options/loss.h 确认可配置项与默认值并回到 modules/loss.cpp 查看模块到函数式算子的转发路径从而彻底弄清每个损失从“构造”到“前向”再到“底层算子”的完整链路。【免费下载链接】pytorchTensors and Dynamic neural networks in Python with strong GPU acceleration项目地址: https://gitcode.com/GitHub_Trending/py/pytorch创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

最新新闻

日新闻

周新闻

月新闻