单标签多分类任务的自定义损失函数设计咨询
损失函数设计方案
核心思路
针对「允许预测多个指定类别、仅严厉惩罚预测非允许类别」的需求,我们可以基于负对数似然变种设计损失:只要模型在任意一个允许类别上的预测概率足够高,损失就会很低;只有当高概率集中在非允许类别时,才会产生较高损失,完全贴合你「预测任意允许类别即可」的要求。
具体实现步骤(以PyTorch为例)
假设输入张量:
preds: 模型输出的logits,形状为(bs, n, nc),未经过softmaxtargets: 标签张量,形状与preds一致,targets[i,j,k]=1表示第i个batch point的第j个vector point允许预测类别k,0表示不允许
步骤1:转换为概率分布
对preds在类别维度(nc)做softmax,得到每个类别的预测概率:
probs = torch.softmax(preds, dim=-1) # 形状保持(bs, n, nc)
步骤2:计算单个vector point的损失
将非允许类别的概率置0,只保留允许类别的概率,再取每个vector point允许类别中的最大概率,最后取其负对数作为该样本的损失(负对数越大,说明模型在允许类别上的最高概率越低,损失越高):
# 过滤出允许类别的概率,非允许类别置为0 allowed_probs = probs * targets # 提取每个vector point在允许类别上的最大概率,维度变为(bs, n) max_allowed_probs = torch.max(allowed_probs, dim=-1)[0] # 计算损失,加1e-8避免log(0)导致数值报错 loss_per_vector = -torch.log(max_allowed_probs + 1e-8) # 形状(bs, n)
步骤3:按要求聚合损失
- 先对每个batch point内的
n个vector point损失取平均,得到单个batch point的损失(维度变为(bs)) - 再对所有
bs个batch point的损失取平均,得到最终总损失:
# 单个batch point内的损失平均(n维度取平均) loss_per_batch_point = torch.mean(loss_per_vector, dim=1) # 形状(bs) # 总损失(所有batch point取平均) total_loss = torch.mean(loss_per_batch_point)
变种方案:加权允许类别
如果需要对不同允许类别设置优先级(比如某些允许类别更接近真实类别),可以修改步骤2,用加权求和代替最大概率:
# 假设targets中的数值为对应类别的权重(如1表示完全允许,0.7表示次要允许) weighted_probs = probs * targets # 计算加权后的概率和 sum_weighted_probs = torch.sum(weighted_probs, dim=-1) # 计算损失 loss_per_vector = -torch.log(sum_weighted_probs + 1e-8)
注意事项
- 若模型输出已经是经过softmax的概率,可直接跳过步骤1
1e-8用于避免数值不稳定,可根据实际精度需求调整- 聚合损失时,也可根据任务需求用「求和」代替「平均」,比如样本不均衡时对不同batch point设置权重
内容的提问来源于stack exchange,提问作者helloworld
相关产品推荐
相关产品推荐

