Tensor Metrics
导言
在AI训练流程中,明明一个tensor就是一个shape下的数值,但是竟然有一堆指标来处理和解释其含义:
- l1 norm
- entropy
- log_prob
- logistics
这些指标代表什么,用途为何?如何计算(标量?什么shape),计算前后值域/shape变化如何,在比较精度的场景下是否为合适的典型指标(有代表性,且能比较)
Tensor 指标说明¶
Tensor 本身只是一个带 shape 的数值数组。
L1 norm、entropy、log_prob、logits/logistic 的含义取决于这个 tensor 表示什么,以及在哪个维度上计算。
常见分类模型输出:
| 名称 | Shape | 含义 |
|---|---|---|
logits |
[B, K] |
模型原始输出分数 |
probs |
[B, K] |
softmax 后的概率分布 |
target |
[B] |
每个样本的真实类别 |
loss |
scalar |
batch 归约后的训练目标 |
其中:
B:batch sizeK:类别数、词表大小或动作数- 最后一维通常是概率分布维度
总览¶
| 指标 | 本质 | 常见输入 | 常见输出 | 值域 | 是否适合比较精度 |
|---|---|---|---|---|---|
L1 norm |
数值大小或差异 | 任意 tensor | scalar / 按维度归约 | [0, +∞) |
适合数值误差、回归 |
entropy |
分布不确定性 | 概率分布 | 去掉分布维度 | [0, log K] |
不适合单独代表准确率 |
log_prob |
样本的对数概率 | 概率模型输出 | [B] 或 scalar |
离散时 (-∞, 0] |
适合概率模型评价 |
logits |
未归一化分数 | 模型原始输出 | shape 通常不变 | (-∞, +∞) |
不适合作为最终精度指标 |
logistic/sigmoid |
logit 到概率的映射 | 二分类或多标签 logits | shape 不变 | (0, 1) |
本身不是指标 |
L1 norm¶
L1 norm 衡量 tensor 的绝对大小:
比较两个 tensor 时,通常用 L1 distance:
如果取平均,就是 MAE:
用途¶
- 比较两个 tensor 的数值差异
- 回归任务 loss
- 模型量化、推理框架转换、不同精度计算的误差检查
- L1 正则化,鼓励参数稀疏
Shape 变化¶
假设:
整体 L1:
输出:
按样本计算:
输出:
计算平均绝对误差:
输出:
精度比较¶
如果比较数值误差,L1/MAE 是合适指标。
但原始 L1=sum(abs(diff)) 会受 tensor 大小影响,shape 越大,L1 往往越大。
更推荐:
Entropy¶
entropy 衡量概率分布的不确定性。
对于概率分布:
要求:
熵定义为:
如果分布很集中,熵低。 如果分布很平均,熵高。
用途¶
- 判断分类模型是否自信
- 强化学习中鼓励探索
- 半监督学习中筛选高置信度样本
- 分析 attention 分布是否集中
Shape 变化¶
分类任务:
计算:
输出:
语言模型:
对词表维度计算:
输出:
值域¶
如果有 K 个类别:
其中:
H(p) = 0:完全确定H(p) = log(K):完全均匀
也可以归一化:
值域变为:
精度比较¶
entropy 不适合单独作为准确率指标。
原因是:
例如模型对错误类别给出 0.99 概率,它的熵很低,但预测是错的。
因此,熵适合分析不确定性,不适合单独比较预测精度。
log_prob¶
log_prob 表示模型给某个样本或标签分配的对数概率:
分类任务中,如果:
则:
概率越大,log_prob 越接近 0。
概率越小,log_prob 越负。
与 loss 的关系¶
负对数概率就是 NLL:
对于 one-hot 分类任务,NLL 等价于 cross entropy loss:
Shape 变化¶
分类任务:
计算:
log_probs = torch.log_softmax(logits, dim=-1)
target_log_probs = log_probs.gather(
dim=-1,
index=target[:, None]
).squeeze(-1)
nll = -target_log_probs
loss = nll.mean()
Shape:
语言模型:
Shape:
值域¶
离散分类中:
注意:连续分布中的 log_prob 是 log density,不一定小于 0。
精度比较¶
log_prob/NLL/cross entropy 是概率模型中非常典型的评价指标。
优点是它不仅关心是否预测正确,还关心模型给正确答案的概率有多高。
例如两个模型都预测正确:
accuracy 一样,但 NLL 会认为模型 B 更好。
比较时需要保证:
- 同一数据集
- 同一标签空间
- 同一 tokenization
- 同一长度归一化方式
- 同一概率建模方式
语言模型中不宜直接比较整句 log_prob,因为句子越长,总 log_prob 越低。
更常用:
Logits 与 logistic¶
logits 是模型输出的未归一化分数:
它不是概率,因为:
- 可以为负数
- 不要求和为
1 - 没有固定范围
分类任务中通过 softmax 转成概率:
Shape 通常不变:
值域变化:
logistic/sigmoid¶
logistic 通常指 sigmoid 函数:
用于二分类或多标签分类:
值域:
二分类中:
训练时常用:
它将 sigmoid 和 binary cross entropy 合并,数值更稳定。
精度比较¶
raw logits 不适合作为最终精度指标。
原因:
- logits 没有固定值域
- softmax 对整体平移不敏感
- 不同模型的 logit scale 可能不同
- logit 大不一定代表预测更准确,只可能代表更自信
更推荐从 logits 派生指标:
比较数值一致性¶
适用于:
- FP32 vs FP16
- PyTorch vs ONNX
- 原模型 vs 量化模型
- 不同推理后端输出对齐
推荐指标:
如果比较的是概率分布,可以补充:
Tensor 差异比较指标:KL、JS、Argmax、Top-k¶
在模型训练、蒸馏、推理对齐、量化评估中,经常需要比较两个 tensor 的差异。例如:
其中:
B:batch 维度...:可选的空间维、序列维,例如[T]、[H, W]C:类别数、词表大小或特征分布维度- 通常沿最后一维
C比较两个 tensor 的分布或预测结果
下面讨论四类常用指标:
它们关注的差异不同:
| 指标 | 比较对象 | 是否需要概率分布 | 越大越好 | 典型值域 |
|---|---|---|---|---|
| KL divergence | 完整分布差异 | 是 | 否 | [0, +∞) |
| JS divergence | 对称分布差异 | 是 | 否 | [0, ln 2] 或 [0, 1] |
| argmax agreement | 第一预测是否一致 | 否 | 是 | [0, 1] |
| top-k agreement | 前 k 个候选是否一致 | 否 | 是 | [0, 1] |
基本设定¶
假设有两个 tensor:
如果 x 和 y 是 logits,需要先转成概率分布:
此时:
其中每个位置上的最后一维满足:
KL divergence 和 JS divergence 比较的是完整概率分布,因此要求输入是概率分布。
argmax agreement 和 top-k agreement 比较的是排序或预测类别,不要求归一化,所以可以直接用于 logits。
KL divergence¶
KL divergence,全称 Kullback-Leibler divergence,用来衡量一个概率分布 Q 相对于参考分布 P 的差异。
公式为:
如果比较的是:
则沿类别维 C 求和:
如果再做平均:
即得到一个标量。
KL divergence 的值域是:
含义:
0表示两个分布完全相同- 值越大,说明两个分布差异越大
- KL 不对称:
这点非常重要。
例如:
表示以 P 为参考,衡量 Q 对 P 的拟合程度。
在知识蒸馏中,如果 P 是 teacher 分布,Q 是 student 分布,那么常用:
它会惩罚 student 在 teacher 高概率类别上给出过低概率的情况。
KL divergence 的计算示例:
import torch
import torch.nn.functional as F
log_p = F.log_softmax(x, dim=-1)
log_q = F.log_softmax(y, dim=-1)
p = log_p.exp()
q = log_q.exp()
kl_pq = (p * (log_p - log_q)).sum(dim=-1)
kl_mean = kl_pq.mean()
shape 变化:
需要注意:
- KL 对小概率位置较敏感
- 如果
P_i > 0但Q_i = 0,KL 会趋向无穷 - 实际计算时通常使用
log_softmax或加eps保持数值稳定
JS divergence¶
JS divergence,全称 Jensen-Shannon divergence,可以看作 KL divergence 的对称、平滑版本。
定义中先构造中间分布:
然后:
它的特点是:
- 对称:
- 有界
- 比 KL 更稳定
- 可以衡量两个分布整体上的差异
如果使用自然对数 ln,值域为:
即:
如果使用以 2 为底的对数,值域为:
JS divergence 的计算示例:
log_p = F.log_softmax(x, dim=-1)
log_q = F.log_softmax(y, dim=-1)
p = log_p.exp()
q = log_q.exp()
m = 0.5 * (p + q)
log_m = torch.log(m.clamp_min(1e-8))
js = 0.5 * (p * (log_p - log_m)).sum(dim=-1) \
+ 0.5 * (q * (log_q - log_m)).sum(dim=-1)
js_mean = js.mean()
shape 变化:
如果希望将 JS divergence 归一化到 [0, 1],可以除以 ln 2:
含义:
0表示两个分布完全相同- 越接近上界,表示两个分布差异越大
- 相比 KL,JS 更适合做两个模型输出分布的对称比较
Argmax agreement¶
Argmax agreement 比较两个 tensor 在每个位置上预测的最大类别是否一致。
它不关心完整概率分布,只关心:
计算方式:
idx_x = torch.argmax(x, dim=-1)
idx_y = torch.argmax(y, dim=-1)
argmax_agree = (idx_x == idx_y).float()
argmax_agree_mean = argmax_agree.mean()
shape 变化:
值域:
含义:
1表示所有位置的 top-1 预测完全一致0表示所有位置的 top-1 预测完全不一致0.9表示 90% 的位置 top-1 预测一致
Argmax agreement 的特点:
- 只看最终预测类别
- 不看置信度
- 不看非最大类别的分布
- 对 logits 和 softmax 后的概率结果相同,因为 softmax 不改变排序
例如:
二者 argmax 都是第 0 类,因此 argmax agreement 为 1。
但两个分布的置信度差异很大,KL/JS 可能不小。
Top-k agreement¶
Top-k agreement 比较两个 tensor 的前 k 个预测类别是否一致。
常见定义有几种,最常用的是 top-k overlap ratio:
即两个 top-k 集合的交集占比。
例如:
则:
计算示例:
k = 5
topk_x = torch.topk(x, k=k, dim=-1).indices
topk_y = torch.topk(y, k=k, dim=-1).indices
overlap = (
topk_x.unsqueeze(-1) == topk_y.unsqueeze(-2)
).any(dim=-1).float().mean(dim=-1)
topk_agree_mean = overlap.mean()
shape 变化:
值域:
含义:
1表示两个 tensor 的 top-k 集合完全一致0表示两个 tensor 的 top-k 集合完全没有交集0.6表示平均有 60% 的 top-k 候选相同
Top-k agreement 比 argmax agreement 更宽松。
例如:
但如果两个模型的高分候选集合接近,那么:
这在大词表语言模型、检索系统、推荐系统中很常见。
还可以定义更严格的 top-k 指标。
第一种是 top-k exact set agreement:
第二种是 ordered top-k agreement:
ordered_topk_agree = (topk_x == topk_y).all(dim=-1).float()
ordered_topk_agree_mean = ordered_topk_agree.mean()
严格程度如下:
其中 ordered top-k agreement 最严格,top-k overlap ratio 最平滑。
四类指标的对比¶
假设:
整体 shape 变化如下:
| 指标 | 输入 shape | 中间 shape | 输出 shape | 标量汇总 |
|---|---|---|---|---|
| KL divergence | [B, ..., C] |
[B, ..., C] |
[B, ...] |
mean/sum |
| JS divergence | [B, ..., C] |
[B, ..., C] |
[B, ...] |
mean/sum |
| argmax agreement | [B, ..., C] |
[B, ...] |
[B, ...] |
mean |
| top-k agreement | [B, ..., C] |
[B, ..., k] |
[B, ...] |
mean |
值域对比:
| 指标 | 值域 | 最优值 | 方向 |
|---|---|---|---|
| KL divergence | [0, +∞) |
0 |
越小越相似 |
| JS divergence | [0, ln 2] |
0 |
越小越相似 |
| JS normalized | [0, 1] |
0 |
越小越相似 |
| argmax agreement | [0, 1] |
1 |
越大越相似 |
| top-k agreement | [0, 1] |
1 |
越大越相似 |
该如何解读¶
KL divergence 适合回答:
它关注概率质量的偏移,尤其关注参考分布中高概率位置是否被另一个分布正确覆盖。
适用于:
- 知识蒸馏
- teacher/student 分布对齐
- 语言模型 logits 分布比较
- 量化前后概率分布偏移分析
JS divergence 适合回答:
它比 KL 更稳定、更对称,适合做模型间输出分布差异的通用度量。
适用于:
- 两个模型输出分布比较
- 量化前后分布漂移
- 不希望区分参考方和被比较方的场景
Argmax agreement 适合回答:
它不关心置信度,只关心最终预测类别。
适用于:
- 分类结果一致性
- 量化模型和原模型 top-1 是否一致
- 推理优化前后预测类别是否改变
Top-k agreement 适合回答:
它比 argmax 更宽松,能够反映候选排序的稳定性。
适用于:
- 语言模型 top-k token 对齐
- 检索候选集一致性
- 推荐系统候选集稳定性
- 大类别分类中 top-k 预测对齐
参考实现¶
下面给出一个统一实现,假设类别维在最后一维:
import torch
import torch.nn.functional as F
def compare_tensors(x, y, k=5, from_logits=True, eps=1e-8):
"""
x, y: [B, ..., C]
return:
kl: [B, ...]
js: [B, ...]
argmax_agree: [B, ...]
topk_overlap: [B, ...]
"""
assert x.shape == y.shape
C = x.shape[-1]
k = min(k, C)
if from_logits:
log_p = F.log_softmax(x, dim=-1)
log_q = F.log_softmax(y, dim=-1)
p = log_p.exp()
q = log_q.exp()
else:
p = x.clamp_min(eps)
q = y.clamp_min(eps)
p = p / p.sum(dim=-1, keepdim=True)
q = q / q.sum(dim=-1, keepdim=True)
log_p = torch.log(p)
log_q = torch.log(q)
# KL(P || Q)
kl = (p * (log_p - log_q)).sum(dim=-1)
# JS(P || Q)
m = 0.5 * (p + q)
log_m = torch.log(m.clamp_min(eps))
js = 0.5 * (p * (log_p - log_m)).sum(dim=-1) \
+ 0.5 * (q * (log_q - log_m)).sum(dim=-1)
# Argmax agreement
idx_x = torch.argmax(x, dim=-1)
idx_y = torch.argmax(y, dim=-1)
argmax_agree = (idx_x == idx_y).float()
# Top-k overlap ratio
topk_x = torch.topk(x, k=k, dim=-1).indices
topk_y = torch.topk(y, k=k, dim=-1).indices
topk_overlap = (
topk_x.unsqueeze(-1) == topk_y.unsqueeze(-2)
).any(dim=-1).float().mean(dim=-1)
return {
"kl": kl,
"kl_mean": kl.mean(),
"js": js,
"js_mean": js.mean(),
"argmax_agree": argmax_agree,
"argmax_agree_mean": argmax_agree.mean(),
"topk_overlap": topk_overlap,
"topk_overlap_mean": topk_overlap.mean(),
}
总结¶
这四个指标不是互相替代关系,而是观察差异的角度不同。
如果关心完整分布差异,使用:
如果关心最终决策是否一致,使用:
如果关心候选集合是否稳定,使用:
通常建议组合使用:
原因是:
- JS divergence 反映整体分布漂移
- argmax agreement 反映最终 top-1 决策一致性
- top-k agreement 反映高分候选集合稳定性
例如在量化模型评估中:
说明量化后模型输出基本保持一致。
如果:
说明最终预测类别没变,但置信度或非 top-1 分布发生了明显变化。
如果:
说明两个分布整体很接近,但 top-1 位置可能经常发生细微交换,常见于多个类别分数非常接近的情况。
比较分类效果¶
推荐:
如果关注概率校准:
比较回归效果¶
推荐:
比较语言模型¶
推荐:
任务型评价可以补充:
常见误区¶
L1越小只说明数值更接近,不一定说明任务效果更好。entropy低只说明模型更自信,不一定说明模型更正确。log_prob适合概率模型,但比较时必须保证数据和归一化方式一致。logits不是概率,也不是最终精度指标。- 任何指标都要先明确计算维度和 reduction 方式。
- 标量指标通常来自对 batch、类别、序列或空间维度的归约。
- 比较语言模型时,不要直接比较不同长度文本的总 log_prob。
简要结论¶
L1 norm:看数值差异,适合数值误差和回归。entropy:看分布不确定性,不适合单独代表准确率。log_prob:看模型给目标的概率,是 NLL 和 cross entropy 的基础。logits:模型原始分数,需要经过 softmax 或 sigmoid 才能解释为概率。- 比较精度前,必须先明确 tensor 的语义、计算维度和归约方式。