输出层的数字、标签格式与损失函数要形成一致约定。看见分类任务就先加 Softmax,可能反而重复了损失函数内部已经做的操作。
常见约定
| 任务形式 | 典型模型输出 | 标签约定 |
|---|---|---|
| 多分类、每样本一个类别 | 每类一个 Logit | 类别索引,或满足要求的类别概率分布 |
| 二分类单输出 | 一个 Logit | 与输出对应的 0/1 浮点目标 |
| 多标签分类 | 每个标签一个 Logit | 各标签独立的目标向量 |
PyTorch 的 CrossEntropyLoss 接收未归一化的 Logits;BCEWithLogitsLoss 将 Sigmoid 与二元交叉熵结合,以改善数值稳定性。使用它们时不要先重复做相应激活。CrossEntropyLoss、BCEWithLogitsLoss
一个稳定的多分类算术检查
以下例子只覆盖“一行一个样本、一列一个类别、标签为类别索引”的情况,未实现权重、掩码与复杂维度。
import numpy as np
def cross_entropy_demo(logits, labels):
logits = np.asarray(logits, dtype=float)
labels = np.asarray(labels, dtype=int)
if logits.ndim != 2 or labels.shape != (len(logits),):
raise ValueError("expected batch-by-class logits and one label per sample")
if (labels < 0).any() or (labels >= logits.shape[1]).any():
raise ValueError("class index is outside the class range")
shifted = logits - logits.max(axis=1, keepdims=True)
log_probabilities = shifted - np.log(np.exp(shifted).sum(axis=1, keepdims=True))
return -log_probabilities[np.arange(len(labels)), labels].mean()
scores = np.array([[1000., 1001., 999.], [-1000., -999., -998.]])
target = np.array([1, 2])
value = cross_entropy_demo(scores, target)
assert np.isfinite(value)
assert np.isclose(value, cross_entropy_demo(scores + 12345., target))
assert cross_entropy_demo([[10., 0.]], [0]) < cross_entropy_demo([[0., 10.]], [0])
print("stable logits and class-index checks passed")
平移不变性说明:每个样本所有类别分数同时加一个常数,不改变其 Softmax 概率。数值稳定不等于模型有用;验证准确率、校准、类别表现和数据划分仍需单独评估。
广播可能把错误藏起来
回归中 [B,1] 的预测与 [B] 的标签若意外广播,可能形成并非预期的误差矩阵。不要只依赖“代码没有报错”,应断言预期形状、标签范围和损失是否有限。
分类索引、独热标签、多标签目标的含义不同,不要为了凑形状随意转换。具体实现还需核对所用版本支持的目标格式、类型及归约方式。
来源与核验边界
本篇结合疏锦行机器学习基础班《神经网络》的输出、激活与训练部分,补充输入输出约定和独立数值检查。NumPy 示例已运行,没有训练课程神经网络。视频尚未逐节核验,原课件不公开。
原创
神经网络基础:先对齐标签和Logits,再选择损失函数
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法