如何解决PyTorch中使用F1 Score作评估指标时的张量维度不匹配问题
错误原因与解决方案
第一次报错(形状不匹配)原因
- 你的模型当前是单分类任务实现:使用了
LogSoftmax激活+F.nll_loss损失,输入标签形状为[batch_size](每个样本仅对应一个类别)。 - 你最初写的
F_score是多标签任务逻辑:要求标签形状为[batch_size, 类别数](每个样本可对应多个类别),二者维度不匹配因此报错。
第二次报错(维度越界)原因
- 修改后你通过
torch.max(output, dim = 1)得到的预测结果prob是形状为[batch_size]的1维张量,但后续代码仍使用.sum(1)在第1维度求和,1维张量仅存在第0维度,因此触发索引越界。 - 额外逻辑问题:单分类任务的F1计算逻辑和多标签完全不同,不能直接沿用多标签按类别维度求和的逻辑。
修正方案
方案1:确认是单分类任务(每个样本仅对应1个类别)
直接替换为单分类加权F1的实现即可,纯PyTorch实现代码如下:
def F_score(output, label, beta=1): # 取概率最高的类别作为预测结果 pred = torch.argmax(output, dim=1) num_classes = output.shape[1] # 初始化每个类别的混淆矩阵指标 class_tp = torch.zeros(num_classes, device=output.device) class_fp = torch.zeros(num_classes, device=output.device) class_fn = torch.zeros(num_classes, device=output.device) class_counts = torch.bincount(label, minlength=num_classes) for c in range(num_classes): class_tp[c] = ((pred == c) & (label == c)).sum() class_fp[c] = ((pred == c) & (label != c)).sum() class_fn[c] = ((pred != c) & (label == c)).sum() # 计算每个类别的precision、recall、F1 precision = class_tp / (class_tp + class_fp + 1e-12) recall = class_tp / (class_tp + class_fn + 1e-12) class_f1 = (1 + beta**2) * precision * recall / (beta**2 * precision + recall + 1e-12) # 按类别样本数加权得到最终加权F1 weighted_f1 = (class_f1 * class_counts / class_counts.sum()).sum() return weighted_f1
方案2:确认是多标签任务(每个样本可对应多个类别)
需要修改三处代码适配多标签逻辑:
- 模型最后一层的
nn.LogSoftmax(dim = 1)替换为nn.Sigmoid() - 验证步骤的损失函数从
F.nll_loss(out, targets)替换为F.binary_cross_entropy(out, targets) - 数据集的标签处理为
[batch_size, 258]形状,每个位置用0/1表示样本是否属于对应类别
修改完成后你最初写的多标签版本F_score即可正常运行。
内容的提问来源于stack exchange,提问作者harry r
相关产品推荐
相关产品推荐

