输出层与损失函数搭配
根据回归、二分类、多分类和多标签选择输出形状、标签格式与损失。
学习目标
- 相同三个零 logits 的两种语义
- CrossEntropyLoss 的索引目标为什么通常是 long?
- 说明:损失较小不等于任务更简单或模型更准确,不同损失的尺度不能直接比较。
为什么需要这个概念
输出层规定预测张量的形状与语义,损失函数规定预测和目标如何比较。回归、二分类、互斥多分类和多标签分类各有不同的契约。
学习前需要掌握
背景与问题
同样是输出三个数字,它们可以表示三个互斥类别,也可以表示三个独立标签。输出层和损失必须一起设计,否则网络会被迫学习错误的概率关系。
概念定义
输出层规定预测张量的形状与语义,损失函数规定预测和目标如何比较。回归、二分类、互斥多分类和多标签分类各有不同的契约。
直观理解
互斥分类像只投一张票,多标签像每个选项独立勾选。softmax 让票数总和为 1,sigmoid 则不要求不同标签互相排斥。
核心原理
回归常输出实数并配 MSE 或 L1;二分类可输出一个 logit,配 BCEWithLogitsLoss,浮点目标与预测同形状。互斥多分类输出 logits,常用 CrossEntropyLoss 与 的 long 类别索引。
多标签同样可输出 ,但每格是独立二元目标,因此使用浮点的 目标和 BCEWithLogitsLoss。若错误地使用 softmax,一个标签概率升高会强制挤压其他标签,即使它们可以同时出现。
组合损失内部以稳定方式完成概率和对数计算,训练前不必先 softmax 或 sigmoid。推理时才按需要转换概率、选择阈值;argmax 只适合互斥标签,不能自动给多标签选择集合。
数学表达
核心公式
输出层规定预测张量的形状与语义,损失函数规定预测和目标如何比较。回归、二分类、互斥多分类和多标签分类各有不同的契约。
变量含义
C类别或标签数z原始 logits
计算步骤
- 1互斥 softmax 给每类 1/3,交叉熵为 log(3)。
- 2独立 sigmoid 给每格 1/2,平均二元损失为 log(2)。
代码对应位置
示例 1相同三个零 logits 的两种语义的最小验证:使用完整构造输入核对相同三个零 logits 的两种语义,输出只表示本例计算。
变量解释
| 变量 | 含义 |
|---|---|
C | 类别或标签数 |
z | 原始 logits |
完整数值示例
相同三个零 logits 的两种语义
已知条件
- logits 为 (0,0,0)
- 互斥目标类别为 1
- 多标签目标为 (1,0,1)
计算步骤
- 互斥 softmax 给每类 1/3,交叉熵为 log(3)。
- 独立 sigmoid 给每格 1/2,平均二元损失为 log(2)。
计算结果
互斥损失约为 1.098612;多标签平均损失约为 0.693147。
处理前后对比
- 损失较小不等于任务更简单或模型更准确,不同损失的尺度不能直接比较。
案例推演与判断
对一张既有猫又有狗的图像,多标签目标可以同时激活两个位置。此时 argmax 只能选一个,不符合标注任务。若标签是“猫、狗、其他三选一”,则相反,需要互斥建模。
两个损失的数值来自不同目标和归一化定义,不能因为 0.693 比 1.099 小就判断多标签模型更好。必须在相同任务、相同计算口径下比较。
计算与实现步骤
- 互斥 softmax 给每类 1/3,交叉熵为 log(3)。
- 独立 sigmoid 给每格 1/2,平均二元损失为 log(2)。
代码实现
示例 1
相同三个零 logits 的两种语义的最小验证
example_01.py用途:使用完整构造输入核对相同三个零 logits 的两种语义,输出只表示本例计算。
import torch
from torch import nn
logits = torch.zeros(1, 3)
single = nn.CrossEntropyLoss()(logits, torch.tensor([1]))
multi = nn.BCEWithLogitsLoss()(logits, torch.tensor([[1., 0., 1.]]))
print(f"single={single.item():.6f} multi={multi.item():.6f}")
print("softmax:", [round(v, 6) for v in logits.softmax(-1)[0].tolist()])
print("sigmoid:", logits.sigmoid()[0].tolist())代码解析
解析始终位于完整代码下方,并按实际代码段逐项对应。
输入数据与任务
使用完整构造输入核对相同三个零 logits 的两种语义,输出只表示本例计算。
Step 1 · 1–8 行
导入当前步骤需要的数值计算、预处理、模型或评价工具。依赖集中写在代码开头,便于复现。
import torch
from torch import nn
logits = torch.zeros(1, 3)
single = nn.CrossEntropyLoss()(logits, torch.tensor([1]))
multi = nn.BCEWithLogitsLoss()(logits, torch.tensor([[1., 0., 1.]]))
print(f"single={single.item():.6f} multi={multi.item():.6f}")
print("softmax:", [round(v, 6) for v in logits.softmax(-1)[0].tolist()])
print("sigmoid:", logits.sigmoid()[0].tolist())预期输出或运行结果
single=1.098612 multi=0.693147 softmax: [0.333333, 0.333333, 0.333333] sigmoid: [0.5, 0.5, 0.5]
常见错误 · 4 条
- CE 前 Softmax
- BCEWithLogits 前 Sigmoid
- 类别回归成单数
- target dtype 错
实际应用
- 设计分类和多标签任务头
- 避免推理阈值与训练目标错配
常见错误
- CE 前 Softmax
- BCEWithLogits 前 Sigmoid
- 类别回归成单数
- target dtype 错
常见问题
CrossEntropyLoss 的索引目标为什么通常是 long?
索引目标表示类别编号,框架按编号选取正确类的对数概率;它不是需要插值的连续数值。概率目标是另一种受支持的契约,不能与索引接口混用。
这个示例能说明什么边界?
损失较小不等于任务更简单或模型更准确,不同损失的尺度不能直接比较。
推荐学习资料
参考库不会生成虚假资源或无效外部链接。