You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用nll_loss计算损失与混淆矩阵时遇维度错误求助

问题根源与解决方案

错误原因

RuntimeError: 0D or 1D target tensor expected, multi-target not supported 本质是因为你用的nll_loss(包括依赖它的交叉熵损失)要求目标是1D整数类别索引(每个样本对应0~10的一个标签),但你的y是2D独热编码(每个样本是11维向量,仅一个位置为1),属于多目标格式,不符合损失函数的输入要求。同时你的混淆矩阵计算也犯了同样的错误——直接传入独热编码的y会导致每个样本被解析成多个类别,完全无法生成正确的混淆矩阵。


分步修正方案

1. 把独热编码的y转成类别索引

不管是计算损失还是混淆矩阵,都需要先将2D的独热y转换成1D的类别索引:

# 从独热编码中提取类别索引,得到形状为[batch_size]的1D张量
y_label = torch.argmax(y, dim=1)

2. 修正损失计算

  • 如果你的模型最后一层是LogSoftmax,直接用nll_loss:
    import torch.nn.functional as F
    loss = F.nll_loss(output, y_label)
    
  • 如果模型最后一层是普通Linear层(没有加LogSoftmax),用cross_entropy(它内部会自动完成LogSoftmax+NLLLoss的计算):
    loss = F.cross_entropy(output, y_label)
    

3. 修正混淆矩阵计算

必须传入类别索引而非独热编码,同时要把张量转到CPU并转成numpy数组(sklearn的混淆矩阵只认numpy格式):

from sklearn.metrics import confusion_matrix

# 转CPU+转numpy
y_np = y_label.cpu().numpy()
pred_np = torch.argmax(output, dim=1).cpu().numpy()
# 生成正确的混淆矩阵
cm = confusion_matrix(y_np, pred_np)

完整修改后的代码

def test_persionalized_model(self):
    self.model.eval()
    cTC = 0
    cP = []
    total_loss = 0.0  # 新增:累计损失
    self.update_parameters(self.persionalized_model_bar)
    
    with torch.no_grad():  # 评估阶段禁用梯度计算,省内存
        for x, y in self.testloaderfull:
            x, y = x.to(self.device), y.to(self.device)
            output = self.model(x)
            
            # 转换独热y为类别索引
            y_label = torch.argmax(y, dim=1)
            
            # 计算损失(根据模型最后一层选择下面其中一种)
            # loss = F.nll_loss(output, y_label)  # 模型最后是LogSoftmax时用
            loss = F.cross_entropy(output, y_label)  # 模型最后是Linear时用
            total_loss += loss.item() * x.size(0)  # 按样本数累计损失
            
            # 计算混淆矩阵
            y_np = y_label.cpu().numpy()
            pred_np = torch.argmax(output, dim=1).cpu().numpy()
            cm = confusion_matrix(y_np, pred_np)
            
            TC = np.diag(cm)
            cTC += np.sum(TC)
            for i in range(len(cm[0])):
                cP.append(cm[i][i] / (np.sum(cm[i]) + 1e-7))
    
    self.update_parameters(self.local_model)
    avg_loss = total_loss / len(self.testloaderfull.dataset)  # 计算平均损失
    return cTC, np.sum(cm), cP, avg_loss

额外提醒

  • 如果你的任务是多标签分类(每个样本可以属于多个类别),那nll_loss确实不适用,需要改用BCEWithLogitsLoss,但从你输出和y的形状以及混淆矩阵的需求来看,应该是单标签多分类任务,上面的方案完全适用。
  • 评估阶段一定要加with torch.no_grad(),避免不必要的内存占用和计算开销。

内容的提问来源于stack exchange,提问作者Anwar As'ad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 00:05:25