【问题标题】:Why doesn't Numba improve this iteration ...?为什么 Numba 不改进此迭代...?
【发布时间】:2014-05-16 05:42:57
【问题描述】:

我正在尝试使用 Numba 来加速计算联合发生的最小条件概率的函数。

    import numpy as np
    from numba import double
    from numba.decorators import jit, autojit

    X = np.random.random((100,2))

    def cooccurance_probability(X):
        P = X.shape[1]      
        CS = np.sum(X, axis=0)                  #Column Sums
        D = np.empty((P, P), dtype=np.float)    #Return Matrix
        for i in range(P):
            for j in range(P):
                D[i, j] = (X[:,i] * X[:,j]).sum() / max(CS[i], CS[j])
        return D 

    cooccurance_probability_numba = autojit(cooccurance_probability)

但是我发现cooccurance_probabilitycooccurance_probability_numba 的性能几乎相同。

%timeit cooccurance_probability(X)
1 loops, best of 3: 302 ms per loop

%timeit cooccurance_probability_numba(X)
1 loops, best of 3: 307 ms per loop

这是为什么?会不会是numpy逐个元素操作的原因?

我以以下为例: http://nbviewer.ipython.org/github/ellisonbg/talk-sicm2-2013/blob/master/NumbaCython.ipynb

[注意:由于问题的对称性,我可以将执行时间减半——但这不是我主要关心的问题]

【问题讨论】:

    标签: python numpy ipython numba


    【解决方案1】:

    以下是使用 Josh 建议的解决方案,该建议是正确的。但是看起来 max() 在下面的实现中工作正常。如果有一个 "safe" python / numpy 函数列表,那就太好了。

    注意:我将原始矩阵的维数降低到100 x 200]

    import numpy as np
    from numba import double
    from numba.decorators import jit, autojit
    
    X = np.random.random((100,200))
    
    def cooccurance_probability_explicit(X):
        C = X.shape[0]
        P = X.shape[1]      
        # - Column Sums - #
        CS = np.zeros((P,), dtype=np.float)
        for p in range(P):
            for c in range(C):
                CS[p] += X[c,p]
        D = np.empty((P, P), dtype=np.float)    #Return Matrix
        for i in range(P):
            for j in range(P):
                # - Compute Elemental Pairwise Sums over each Product Vector - #
                pws = 0
                for c in range(C):
                    pws += (X[c,i] * X[c,j])
                D[i,j] = pws / max(CS[i], CS[j])
        return D 
    
    cooccurance_probability_explicit_numba = autojit(cooccurance_probability_explicit)
    

    %timeit 结果:

    %timeit cooccurance_probability(X)
    10 loops, best of 3: 83 ms per loop
    
    
    %timeit cooccurance_probability_explicit(X)
    1 loops, best of 3: 2.55s per loop
    
    %timeit cooccurance_probability_explicit_numba(X)
    100 loops, best of 3: 7.72 ms per loop
    

    结果的有趣之处在于,由于类型检查开销很大,python 执行的显式编写版本非常慢。但是通过 Numba 很神奇。 (Numba 比使用 Numpy 的 python 解决方案快约 11.5 倍)。


    更新:添加了用于比较的 Cython 函数(感谢 moarningsun:Cython function with variable sized matrix input

    %load_ext cythonmagic
    %%cython
    import numpy as np
    cimport numpy as np
    
    def cooccurance_probability_cy(double[:,:] X):
        cdef int C, P, i, j, k
        C = X.shape[0]
        P = X.shape[1]
        cdef double pws
        cdef double [:] CS = np.sum(X, axis=0)
        cdef double [:,:] D = np.empty((P,P), dtype=np.float)
    
        for i in range(P):
            for j in range(P):
                pws = 0.0
                for c in range(C):
                    pws += (X[c, i] * X[c, j])
                D[i,j] = pws / max(CS[i], CS[j]) 
        return D
    

    %timeit 结果:

    %timeit cooccurance_probability_cy(X)
    100 loops, best of 3: 12 ms per loop
    

    【讨论】:

    • 如果X 的形状为[m, n],您需要结果为[m, m] 还是[n, n]?你的问题和你的答案是不同的。
    • 原始问题已得到纠正...谢谢...X 的形状为[m,n],为了计算共现,我比较了所有可能的列向量组合,因此得到了[n,n] 矩阵。
    • 我问是因为现在您的代码运行速度足够快,因此优化缓存友好性是明智的。目前您正在非顺序访问X,假设X 是连续的并且是C 顺序的,这会导致RAM 访问不理想。要查看性能差异,请将X 设为一个方阵,并使用XX.T 作为参数对函数进行计时。
    • 您可以通过禁用边界检查和负索引处理来加速 cython。
    【解决方案2】:

    我的猜测是,由于对sum 的调用,您正在访问对象层而不是生成本机代码,这意味着 Numba 不会显着加快速度。它只是不知道如何优化/翻译sum(此时)。此外,通常最好使用 Numba 将矢量化操作展开为显式循环。请注意,您链接到的 ipynb 只调用np.sqrt,我相信它确实会被翻译成机器代码,并且它对元素而不是切片进行操作。我会尝试将内部循环中的总和扩展为对元素的显式附加循环,而不是采用切片并使用sum 方法。

    我的经验是,Numba 有时可以创造奇迹,但它不能加速任意 python 代码。您需要了解限制以及它可以有效优化的内容。另请注意,由于 Numba 在这些版本之间进行了重大重构,v0.11 在这方面与 0.12 和 0.13 相比有些不同。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-03
      • 2018-07-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-09
      • 1970-01-01
      • 2011-02-05
      相关资源
      最近更新 更多