【问题标题】:Faster iteration on for loop with 2d arrays使用 2d 数组对 for 循环进行更快的迭代
【发布时间】:2021-03-08 13:03:23
【问题描述】:

我在计算视差图估计误差时遇到了优化问题。

为了计算错误,我为每个错误创建了一个带有调用方法的类。我需要对每个像素进行迭代以获得错误。 这个数组很重要,因为我正在迭代 1937 x 1217 图像的大小。你知道怎么优化吗?

这是我的方法的代码:

编辑:

def mreError(self):
    s_gt = self.ref_disp_norm
    s_all = self.disp_bin
    s_r = self.disp_norm 

    s_gt = s_gt.astype(np.float32)
    s_r = s_r.astype(np.float32)
    n, m = s_gt.shape
    all_arr = []

    for i in range(0, n):
        for j in range(0, m):

            if s_all[i,j] == 255:
                if s_gt[i,j] == 0:
                    sub_mre = 0
                else:   
                    sub_mre = np.abs(s_gt[i,j] - s_r[i,j]) / s_gt[i,j]
                all_arr.append(sub_mre)

    mre_all = np.mean(all_arr)
    return mre_all

【问题讨论】:

  • 您可以直接对整个数组进行减法和差分,而不是在循环中进行。用精美的索引替换一个数组为 0 的所有实例。
  • 请阅读FAQ,了解如何使用该网站。这不是一个有大量帖子的论坛。如果您对某人的帖子有评论,请在下方评论,不要发布答案。任何与所有人相关的信息都应在您的问题中进行编辑。您声称某些答案提供了错误的结果,但您没有提供自己的输入。我们生成了合成数据,它工作得很好。请阅读如何创建minimal, reproducible example

标签: python numpy opencv disparity-mapping depth-testing


【解决方案1】:

您的方法的直接矢量化将是

def method_1(self):
    # get s_gt, s_all, s_r
    sub_mre = np.zeros((s_gt.shape), dtype=np.float32)
    idx = s_gt != 0
    sub_mre[idx] = np.abs((s_gt[idx] - s_r[idx]) / s_gt[idx])
    return np.mean(sub_mre[s_all == 255])

但由于您只对 s_all 为 255 的像素进行平均,您也可以先过滤这些像素,然后再进行其余操作

def method_2(self):
    idx = s_all == 255
    s_gt = s_gt[idx].astype(np.float32)
    s_r = s_r[idx].astype(np.float32)
    sub_mre = np.zeros_like(s_gt)
    idx = s_gt != 0
    sub_mre[idx] = np.abs((s_gt[idx] - s_r[idx]) / s_gt[idx])
    return np.mean(sub_mre)

就我个人而言,我更喜欢第一种方法,除非第二种方法的结果要快得多。只调用一次函数并花费,例如 40 ms vs 5 ms 并不明显,函数的可读性更重要。

【讨论】:

  • 很好,您的 method_2 是正确的。我得到了预期的价值! Reti43: 1.0188183 | Sagocz:0.11468831-method_1 Reti43:0.11468831 | Sagocz:0.11468831 - method_2
  • @Sagocz 在您关于提供相关输入预期输出的问题下阅读我的评论。我看不出为什么我的两种方法中的任何一种应该彼此不同。我已经和你一起对随机数据进行了测试,他们都同意。除非您提供他们的答案不同的输入,否则我无法调查为什么会发生这种情况。
  • 对不起。我再次编写了代码,第一种方法也是正确的。另外我想为保持沉默而道歉,但我不想在再次测试第一种方法之前写下你的问题的答案。
【解决方案2】:

您可以简单地使用数组运算符,而不是将它们应用于 for 循环中的每个元素:

import numpy as np

# Creating 2000x2000 Test-Data
s_gt = np.random.randint(0,2,(2000,2000)).astype(np.float32)
s_r = np.random.randint(0,2,(2000,2000)).astype(np.float32)
s_all = np.random.randint(0,256,(2000,2000)).astype(np.float32)


def calc(s_gt, s_r, s_all):
    n, m = s_gt.shape
    all_arr = []
    for i in range(0, n):
        for j in range(0, m):
            if s_gt[i,j] == 0:
                sub_mre = 0
            else:   
                sub_mre = np.abs(s_gt[i,j] - s_r[i,j]) / s_gt[i,j]
    
            if s_all[i,j] == 255:
                all_arr.append(sub_mre)
    
    mre_all = np.mean(all_arr)
    return mre_all

def calc_optimized(s_gt, s_r, s_all):
    sub_mre = np.abs((s_gt-s_r)/s_gt)
    sub_mre[s_gt==0] = 0
    return np.mean(sub_mre[s_all == 255])

当我测试两种不同方法的速度时:

%time calc(s_gt, s_r, s_all)
Wall time: 27.6 s
Out[53]: 0.24686379928315413

%time calc_optimized(s_gt, s_r, s_all)
Wall time: 63.3 ms
__main__:34: RuntimeWarning: divide by zero encountered in true_divide
__main__:34: RuntimeWarning: invalid value encountered in true_divide
Out[54]: 0.2468638

【讨论】:

  • 是的,您的优化要快得多,但根据我的数据,优化结果是错误的。我不知道我做错了什么。
【解决方案3】:

您可以将图像设置为灰色(这将大大加快计算速度)去查看link 怎么做。

【讨论】:

  • 问题中没有任何内容表明计算是在 3 个颜色通道上完成的。问题在于使用 python 级循环而不是 numpy 矢量化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-11
  • 1970-01-01
  • 2020-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多