Python 为什么numpy数组元素的随机写入比随机读取慢得多?

Python 为什么numpy数组元素的随机写入比随机读取慢得多?,python,numpy,numba,Python,Numpy,Numba,以下代码是图像二值化算法的一部分。我正试图提高这个算法的性能,但我发现瓶颈在一个奇怪的地方。(省略了算法中不相关的部分。) 上述代码的运行时为: 539 ns ± 12.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 这很好。这意味着,在循环中获取/访问bucket[g]一点要求都不高。让我们看看如果我取消注释这一行会发生什么:bucket[g]=1 for h in range(height):

以下代码是图像二值化算法的一部分。我正试图提高这个算法的性能,但我发现瓶颈在一个奇怪的地方。(省略了算法中不相关的部分。)

上述代码的运行时为:

539 ns ± 12.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
这很好。这意味着,在循环中获取/访问
bucket[g]
一点要求都不高。让我们看看如果我取消注释这一行会发生什么:
bucket[g]=1

    for h in range(height):
        for w in range(width):  
            g = img[h, w]
            a = buckets[g] + 1
            buckets[g]  = 1
            # buckets[g]  = a
运行时是

27.8 µs ± 865 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
这意味着在循环中设置
bucket[g]
可以显著提高运行时间

现在,如果我取消注释
bucket[g]=a
行,如下所示:

    for h in range(height):
        for w in range(width):  
            g = img[h, w]
            a = buckets[g] + 1
            # buckets[g]  = 1
            buckets[g]  = a
运行时间增加到:

37.8 µs ± 1.09 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
此运行时间增量是一致的,并且取决于
img
矩阵,它可能需要>100µs。这也意味着将矩阵元素设置为变量要比将其设置为常量慢得多。有人能解释为什么将矩阵元素设置为循环中的变量会显著增加运行时间吗?另外,您能建议fs有什么方法可以提高性能吗


我正在用数百万张图像(手写文档)进行机器学习,所以我的数据生成器应该足够快,这样就不会使GPU出现瓶颈。在datagenerator管道中,有多个图像操作,因此我希望尽可能优化每个操作。这种二值化是在每个图像上完成的,因此我想将运行时间缩短到几微秒。

我认为您可以用以下代码替换代码:

def make_buckets(img):
    return np.bincount(img.reshape(-1), minlength=256)
请尝试一下,让我们知道时间安排


Ref:

我认为您可以用以下代码替换您的代码:

def make_buckets(img):
    return np.bincount(img.reshape(-1), minlength=256)
请尝试一下,让我们知道时间安排


Ref:

请记住,numpy数组使用静态数据类型,与python列表或变量不同。因此,从python变量中设置元素需要进行安全检查/转换,因此我们希望这比读取已经具有强制类型的元素花费更多的时间。然而,我不知道这是否解释了你在这里看到的全部差异,或者是否有其他因素在起作用。如果你所做的只是阅读,那么这些阅读可以被优化。试着用你正在读取的数据做一些实际的事情,这是不能被优化掉的。@HymnsForDisco,事实上,当我尝试使用python list
buckets=[0 for uuuu in range(256)]
而不是
buckets=np.zeros(256)
,性能稍好一些,有时高达20%。存在死代码消除。在第一个示例中,您没有执行任何影响函数输出的操作->代码被检测为无用并被忽略。请记住,numpy数组使用静态数据类型,而不是python列表或变量。因此,从python变量中设置元素需要进行安全检查/转换,因此我们希望这比读取已经具有强制类型的元素花费更多的时间。然而,我不知道这是否解释了你在这里看到的全部差异,或者是否有其他因素在起作用。如果你所做的只是阅读,那么这些阅读可以被优化。试着用你正在读取的数据做一些实际的事情,这是不能被优化掉的。@HymnsForDisco,事实上,当我尝试使用python list
buckets=[0 for uuuu in range(256)]
而不是
buckets=np.zeros(256)
,性能稍好一些,有时高达20%。存在死代码消除。在第一个示例中,您没有做任何影响函数输出的事情->代码被检测为无用并被忽略。感谢您的快速回答。不幸的是,它比我正在使用的要慢得多。此循环的运行时间为每循环133µs±1.42µs(7次运行的平均值±标准偏差,每个循环10000次)运行时间徘徊在130µs到150µs之间。感谢快速回答。不幸的是,它比我正在使用的要慢得多。此循环的运行时间为每循环133µs±1.42µs(7次循环的平均值±标准偏差,每个循环10000次)运行时间徘徊在130µs到150µs之间。