如何使 numpy 剪辑跑得更快?

mmvthczy  于 2023-03-02  发布在  其他
关注(0)|答案(1)|浏览(127)

我有一个自定义的机器学习目标函数,它是一种线性有界函数,主要使用numpy.clip。在训练过程中,目标函数会运行很多次。因此训练时间取决于numpy.clip的运行速度。
所以,我的问题是“我能做些什么让numpy.clip跑得更快吗?”
到目前为止,我尝试了numba,但我基本上没有得到任何改善(下面的例子)。

import timeit
from numba import jit
import numpy as np

def clip(x, l, u):
    return x.clip(l, u)

@jit(nopython=True, parallel=True, fastmath=True)
def clip2(x, l, u):
    return x.clip(l, u)

x = np.random.rand(1000)
l = -np.random.rand(1000)
u = np.random.rand(1000)

timeit.timeit(lambda: clip(x, l, u))
>>> 7.600710524711758
timeit.timeit(lambda: clip2(x, l, u))
>>> 23.19934402871877

我使用numba的方式有什么问题吗?或者在这种情况下它真的帮不上忙?
有没有其他方法值得一试?
需要注意的是,对于我的用例,clip中x、l和u的向量长度(上面定义的)主要在1000左右。因此,我确实希望针对这种特定情况进行优化。
非常感谢你的帮助。

rkue9o1l

rkue9o1l1#

正如在评论中指出的,Numba在第一次调用函数时引入了一些编译开销(对于特定的数据类型签名),根据您所分享的有限信息,很难回答是否应该将其包括在基准测试中。
Numba支持的Numpy函数既方便又健壮,但是通常可以通过为应用程序实现特定函数来获得额外的性能。
parallel=True不执行警告所示的任何操作。
使用np.clip时,如果您愿意修改输入(在适当的位置),那么使用out=关键字可能会有所收获。
总的来说,我使用numba.vectorize获得了最好的性能,在我的经验中经常出现这种情况。

from numba import njit, vectorize
import numpy as np

def clip1(x, l, u):
    return x.clip(l, u)

@njit(fastmath=True)
def clip2(x, l, u):
    return x.clip(l, u)
    
@njit(fastmath=True)
def clip3(x, l, u):
    return np.clip(x, l, u, out=x)
    
@vectorize
def clip4(x, l, u):
    return max(min(x, u), l)

在我的机器上,经过预热(不包括编译),这将导致:

clip1: 7.19 µs ± 546   ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
clip2: 2.88 µs ±  35.9 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
clip3: 2.54 µs ± 177   ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
clip4: 1.2  µs ±  39.3 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

相关问题