【问题标题】:Creating a matrix of validation results with correct counts创建具有正确计数的验证结果矩阵
【发布时间】:2019-11-28 21:05:10
【问题描述】:

我有一个经过训练的 10 类机器学习模型,类似于 MNIST 数字分类器。我想确定每个数字类别的正确频率,如果出现错误,它会混淆哪个类别。我想用它来创建一个混淆矩阵等等。

无论如何,每个 pass 的输入是来自验证集的一批图片(形状 (32,3,224,224),其中 3、224 和 224 是图片尺寸,32 是批量大小)和标签(形状 32 ,1) 这些图片匹配的班级编号。模型输出是(形状 32,1),并列出了模型认为最匹配的类号。通过比较标签和输出张量,我可以轻松找到有多少匹配项,但我很难告诉 如何 错过了错误分类。这是主验证循环中的一个 sn-p

# Main validation loop
valid_accuracy = 0.0
model.eval()
device = 'cuda'
raw_counts = torch.zeros((11,11)) # leave room for totals in the last row and column
with torch.no_grad():
    for inputs, labels in validloader:
        # Run each image through the network to get log probabilities of each class
        inputs, labels = inputs.to(device), labels.to(device)
        logps = model.forward(inputs)  

        # Calculate accuracy
        ps = torch.exp(logps) # 32 X 10: probability of each label in every case
        top_p, top_class = ps.topk(1, dim=1)
        equals = top_class == labels.view(*top_class.shape)
        valid_accuracy += torch.mean(equals.type(torch.FloatTensor)).item()

        # Count confusions
        raw_counts[labels[:],top_class[:,0]] += 1  # <<<<---- This is the problem!

        # Accumulate letter-by-letter certainties
        for i in range(ll):
            sum_ps[i,] += sum(ps[labels==i])
            letter_counts[i] += len(ps[labels==i])

# Print validation accuracy
valid_accuracy = valid_accuracy/len(validloader)
print(f"Validation accuracy: {valid_accuracy:.3f}")

问题是我试图计算混乱的地方。只有 10 个类和 32 个批量大小,我保证有重复的标签。但是说raw_counts[labels[:],top_class[:,0]] += 1 只会将raw_counts 矩阵的每一行增加一个。例如,在此行之前的调试器中:

(Pdb) top_class[:,0]
tensor([5, 9, 5, 0, 2, 3, 3, 8, 2, 9, 6, 3, 0, 3, 1, 3, 3, 4, 0, 1, 5, 2, 8, 4,
        5, 3, 6, 5, 0, 3, 2, 1], device='cuda:0')
(Pdb) labels[:]
tensor([5, 9, 5, 0, 2, 3, 3, 8, 2, 9, 6, 3, 0, 3, 1, 3, 3, 4, 0, 1, 5, 2, 8, 4,
        5, 3, 8, 5, 0, 3, 2, 1], device='cuda:0')
(Pdb) raw_counts
tensor([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])

一切都如预期的那样。但是在执行该行之后:

(Pdb) n
> /home/model.py(219)main()
-> for i in range(10):
(Pdb) raw_counts
tensor([[1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 1., 0., 1., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])

即使这批中的五个标签是 5 并且模型得到了它们,仍然是 raw_counts[4,4] == 1。有没有什么 Pythonic 方法可以计算所有五个正确答案而不会出现混乱的 for 循环等?

【问题讨论】:

    标签: python numpy pytorch


    【解决方案1】:

    没有足够的声誉来发表评论,所以我将复制my answer


    我使用这两个函数来计算混淆矩阵(在sklearn 中定义):

    # rewrite sklearn method to torch
    def confusion_matrix_1(y_true, y_pred):
        N = max(max(y_true), max(y_pred)) + 1
        y_true = torch.tensor(y_true, dtype=torch.long)
        y_pred = torch.tensor(y_pred, dtype=torch.long)
        return torch.sparse.LongTensor(
            torch.stack([y_true, y_pred]), 
            torch.ones_like(y_true, dtype=torch.long),
            torch.Size([N, N])).to_dense()
    
    # weird trick with bincount
    def confusion_matrix_2(y_true, y_pred):
        N = max(max(y_true), max(y_pred)) + 1
        y_true = torch.tensor(y_true, dtype=torch.long)
        y_pred = torch.tensor(y_pred, dtype=torch.long)
        y = N * y_true + y_pred
        y = torch.bincount(y)
        if len(y) < N * N:
            y = torch.cat(y, torch.zeros(N * N - len(y), dtype=torch.long))
        y = y.reshape(N, N)
        return T
    
    y_true = [2, 0, 2, 2, 0, 1]
    y_pred = [0, 0, 2, 2, 0, 2]
    
    confusion_matrix_1(y_true, y_pred)
    # tensor([[2, 0, 0],
    #         [0, 0, 1],
    #         [1, 0, 2]])
    
    

    在类数较少的情况下,第二个函数更快。

    %%timeit
    confusion_matrix_1(y_true, y_pred)
    # 102 µs ± 30.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    
    %%timeit
    confusion_matrix_2(y_true, y_pred)
    # 25 µs ± 149 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
    

    【讨论】:

    • 如果你可以复制另一个问题的答案来回答这个问题,那么这个问题是重复的,应该关闭。或者,如果它们是不同的问题,您的答案并不能真正回答其中之一。
    猜你喜欢
    • 1970-01-01
    • 2021-09-13
    • 1970-01-01
    • 2013-04-15
    • 2022-01-25
    • 2023-03-19
    • 1970-01-01
    • 2016-11-01
    • 1970-01-01
    相关资源
    最近更新 更多