【问题标题】:numpy.vectorize: Why so slow?numpy.vectorize:为什么这么慢?
【发布时间】:2016-12-04 05:00:16
【问题描述】:

scipy.special 中的 expit 函数是一个向量化的 sigmoid 函数。它计算 1 / (1+e^(-x)),这很复杂,可能涉及泰勒级数。

我了解了“快速 sigmoid”1 / (1 + abs(x)),它应该更快——但内置的 expit 函数大大优于它,即使我将它作为 lambda 表达式交给numpy.vectorize。

这是测试它们的一种方法:

from scipy.special import expit
data = np.random.rand(1000000)

内置的复杂 sigmoid 速度很快:

%prun expit(data)

3 function calls in 0.064 seconds

Ordered by: internal time

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1    0.064    0.064    0.064    0.064 <string>:1(<module>)
     1    0.000    0.000    0.064    0.064 {built-in method builtins.exec}
     1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

更简单的 sigmoid 大约慢 20 倍:

%prun np.vectorize( lambda x: (x / (1 + abs(x)) + 1) / 2 )(data)

2000023 function calls in 1.992 seconds

Ordered by: internal time

 ncalls  tottime  percall  cumtime  percall filename:lineno(function)
1000001    1.123    0.000    1.294    0.000 <string>:1(<lambda>)
      1    0.558    0.558    1.950    1.950 function_base.py:2276(_vectorize_call)
1000001    0.170    0.000    0.170    0.000 {built-in method builtins.abs}
      4    0.098    0.025    0.098    0.025 {built-in method numpy.core.multiarray.array}
      1    0.041    0.041    1.991    1.991 function_base.py:2190(__call__)
      1    0.000    0.000    0.068    0.068 function_base.py:2284(<listcomp>)
      1    0.000    0.000    1.992    1.992 {built-in method builtins.exec}
      1    0.000    0.000    1.991    1.991 <string>:1(<module>)
      1    0.000    0.000    0.000    0.000 function_base.py:2220(_get_ufunc_and_otypes)
      1    0.000    0.000    0.000    0.000 function_base.py:2162(__init__)
      1    0.000    0.000    0.000    0.000 function_base.py:2242(<listcomp>)
      2    0.000    0.000    0.000    0.000 numeric.py:414(asarray)
      1    0.000    0.000    0.000    0.000 {built-in method numpy.core.umath.frompyfunc}
      1    0.000    0.000    0.000    0.000 function_base.py:2266(<listcomp>)
      2    0.000    0.000    0.000    0.000 {built-in method builtins.isinstance}
      1    0.000    0.000    0.000    0.000 {built-in method builtins.len}
      1    0.000    0.000    0.000    0.000 {method 'join' of 'str' objects}
      1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

【问题讨论】:

    标签: python numpy scipy ipython vectorization


    【解决方案1】:

    我只是引用vectorize docstring:“提供vectorize 函数主要是为了方便,而不是为了性能。实现本质上是一个for 循环。”

    你想让1/(1 + abs(x)) 快点。 numpy 有一个名为numpy.abs 的函数(也称为numpy.absolute——它们是同一对象的不同名称)。它计算其参数的每个元素的绝对值,并在 C 代码中执行此操作,因此速度很快。此外,Python 内置函数 abs 知道如何将参数分派给具有方法 __abs__ 的对象,而 numpy 数组就是这样做的,因此您还可以使用 Python 的 abs() 来计算 a 的逐元素绝对值numpy 数组。不过,在下文中,我将使用np.abs

    这里是np.abs的使用示例:

    In [25]: x = np.array([-2, -1.5, 0, 5, 10])
    
    In [26]: np.abs(x)
    Out[26]: array([  2. ,   1.5,   0. ,   5. ,  10. ])
    

    下面是scipy.special.expit1.0/(1 + np.abs(x)) 对于大型数组x 的性能对比:

    In [34]: from scipy.special import expit
    
    In [35]: x = np.random.randn(100000)
    
    In [36]: %timeit expit(x)
    1000 loops, best of 3: 771 µs per loop
    
    In [37]: %timeit 1.0/(1 + np.abs(x))
    1000 loops, best of 3: 279 µs per loop
    

    所以1.0/(1 + np.abs(x))expit(x) 快很多。

    【讨论】:

    • 我测试过;这绝对解决了我的问题。谢谢,沃伦!
    猜你喜欢
    • 2021-09-03
    • 2016-09-28
    • 2020-02-08
    • 2012-07-17
    • 2011-11-07
    • 2015-08-24
    • 2013-08-06
    • 2014-07-16
    • 2011-01-02
    相关资源
    最近更新 更多