更快地估计对数运算

Faster estimation of logarithm operation

我有一个相当简单的函数,涉及以 10 为底的对数(f1 如下所示)。我需要它尽快 运行 因为它作为较大代码的一部分被调用了数百万次。

我尝试使用 Taylor approximation(下面的 f2),但即使扩展很大,准确性也很差,更糟,它结束了花费更多时间。

我是否达到了 numpy 的性能极限?

import time
import numpy as np

def f1(m1, m2):
    return m1 - 2.5 * np.log10(1. + 10 ** (-.4 * (m2 - m1)))


def f2(m1, m2):
    """
    Taylor expansion of 'f1'.
    """
    x = -.4 * (m2 - m1)
    return m1 - 2.5 * (
        0.30102999 + .5 * x + 0.2878231366 * x ** 2 -
        0.0635837 * x ** 4 + 0.0224742887 * x ** 6 -
        0.00904311879 * x ** 8 + 0.00388579 * x ** 10)


# The data I actually use has more or less this range.
N = 1000
m1 = np.random.uniform(5., 30., N)
m2 = np.random.uniform(.7 * m1, m1)

# Test both functions
M = 5000
s = time.clock()
for _ in range(M):
    mc1 = f1(m1, m2)
t1 = time.clock() - s
s = time.clock()
for _ in range(M):
    mc2 = f2(m1, m2)
t2 = time.clock() - s

print(t1, t2, np.allclose(mc1, mc2, 0.01))

用乘法替换f2中的所有幂:

def f2(m1, m2):
    """
    Taylor expansion of 'f1'.
    """
    x = -0.4 * (m2 - m1)
    x2 = x * x
    x4 = x2 * x2
    x6 = x4 * x2
    return m1 - 2.5 * (
        0.30102999 + .5 * x + 0.2878231366 * x2 -
        0.0635837 * x4 + 0.0224742887 * x6 -
        0.00904311879 * x4 * x4 + 0.00388579 * x4 * x6)

有了这个代码片段,我不确定你是否应该优化日志,但更多的是整个向量表达式本身

您可以尝试 numexpr(Python、NumPy 等的快速数值数组表达式求值器),它可能对您有很大帮助。

尝试这个的想法来自 Ignacio 的评论,这让我想到他的加速来自哪里(我敢肯定,它不是来自对数计算本身)。

我对你的代码进行了简单的修改:

import numexpr as ne
def f1(m1, m2):
   return ne.evaluate("m1 - 2.5 * log10( 1.0 + 10 ** (-0.4 * (m2-m1)))")

上面的结果似乎是(未优化的)f2(近似值) 的 5 - 6 倍,同时仍提供原始精度。

速度几乎是原始 numpy 方法 f1 的两倍。

这些数字可能会根据 numexpr 的设置而改变,例如也可以使用 Intels MKL。由于我懒得检查我基于 anaconda 的设置,所以我将其作为技术演示提供,每个人都可以尝试。

虽然我过去曾几次使用 numexpr 来处理简单的事情,但我可能会补充说,它也在 pandas 中使用,只是提一下取决于它的正确工作原理的真实世界项目。

免责声明:我使用您的基准作为模板(并希望缓存和 co 不会发挥作用)。