解释numpy向量化函数应用VS python for循环的速度差异

Posted

技术标签:

【中文标题】解释numpy向量化函数应用VS python for循环的速度差异【英文标题】:Explain the speed difference between numpy's vectorized function application VS python's for loop 【发布时间】:2013-07-03 05:05:22 【问题描述】:

我在一组 42000 张图像上实现了一个称为 TF-IDF 的加权系统,每张图像由 784 个像素组成。这基本上是一个 42000 x 784 矩阵。

我尝试的第一种方法是使用显式循环,耗时超过 2 小时

def tfidf(color,img_pix,img_total):
    if img_pix==0:
        return 0
    else:
        return color * np.log(img_total/img_pix)

...

result = np.array([])
for img_vec in data_matrix:
    double_vec = zip(img_vec,img_pix_vec)
    result_row = np.array([tfidf(x[0],x[1],img_total) for x in double_vec])
    try:
        result = np.vstack((result,result_row))
    # first row will throw a ValueError since vstack accepts rows of same len
    except ValueError:
        result = result_row

我尝试的第二种方法使用了 numpy 矩阵,耗时不到 5 分钟。请注意,data_matrix、img_pix_mat 都是 42000 x 784 矩阵,而 img_total 是标量。

result = data_matrix * np.log(np.divide(img_total,img_pix_mat))

我希望有人能解释速度上的巨大差异

以下题为“NumPy 数组:一种用于高效数值计算的结构”(http://arxiv.org/pdf/1102.1523.pdf) 论文的作者在第 4 页顶部指出,由于矢量化计算,他们观察到速度提高了 500 倍。我假设我看到的大部分速度增加都是由于这个原因。但是,我想更进一步,问为什么 numpy 向量化计算比标准 python 循环快得多?

另外,也许你们知道第一种方法速度慢的其他原因。 try/except 结构是否有高开销?或者可能为每个循环形成一个新的 np.array 需要很长时间?

谢谢。

【问题讨论】:

这充实了 numpy 使用 C 更快的原因:***.com/questions/8385602/…. 【参考方案1】:

由于 numpy 的内部工作原理,(据我所知,numpy 在内部与 C 一起工作,所以你下推到 numpy 的所有内容实际上要快得多,因为它使用不同的语言)

编辑: 取出 zip 并用 vstack 替换它也应该更快,(如果参数非常大,zip 往往会变慢,而 vstack 更快),(但这也是将它放入 numpy 的东西(因此进入C),而 zip 是 python)

是的,如果我理解正确 - 不确定 - 你正在执行 42k 次 try/except 块,这肯定不利于速度,

测试:

T=numpy.ndarray((5,10))
for t in T:
print t.shape

导致 (10,)

这意味着是的,如果您的矩阵是 42kx784 矩阵,那么您将尝试 42k 次 try-except 块,我假设这应该会影响计算时间,以及每次执行 zip 时,但不确定这是否是主要原因,

(所以每次运行 42k 次都需要 0.17 秒,我很确定 try/except 块不需要 0.17 秒,但它可能导致的开销左右,确实有助于它吗?

尝试更改以下内容:

double_vec = zip(img_vec,img_pix_vec)
result_row = np.array([tfidf(x[0],x[1],img_total) for x in double_vec])

result_row=np.array([tfidf(img_vec[i],img_pix_vec[i],img_total) for i in xrange(len(img_vec))])

这至少摆脱了 zip 语句,但不确定 zip 语句是否会占用您一分钟或近两个小时的时间(我知道 zip 与 numpy vstack 相比很慢,但不知道是否这样会给你两个小时的时间增益)

【讨论】:

这能回答问题吗?还是您想要更技术性的答案? (一般来说,python 不是为了快速运行,存在其他语言,但是对于那些想要使用 python 但仍然获得至少与 C 或 FORTRAN 中的速度相当的速度的人来说,存在 numpy,它们是专为数字运算应用而设计) 是拉链导致的吗??? (只是为了知道将来使用,如果是 42k 次调用导致它的 zip?)因为很高兴知道这是否会产生 2 小时的差异,或者这只会改善 30 分钟左右,【参考方案2】:

您看到的差异并不是由于像 SSE 矢量化这样的花哨的东西。有两个主要原因。首先是 NumPy 是用 C 编写的,C 实现不必像 Python 实现那样经历大量的运行时方法分派和异常检查等。

第二个原因是即使对于 Python 代码,基于循环的实现也是低效的。您在循环中使用vstack,每次调用vstack,它都必须完全复制您传递给它的所有数组。这为您的渐近复杂度增加了额外的 len(data_matrix) 因子。

【讨论】:

以上是关于解释numpy向量化函数应用VS python for循环的速度差异的主要内容,如果未能解决你的问题,请参考以下文章

为什么内置函数abs()不能用于Python列表,但却能正确地用于NumPy数组和pandas数列(因为它会被向量化)?

假设有许多重复项,使用 numpy 对“纯”函数进行矢量化

python学习随笔-向量化

python中numpy对函数进行矢量化转换

NumPy基础-数组与向量化计算

在python中为依赖于索引的函数向量化嵌套的for循环