带扰动的逐元素向量反演的优化方法
Optimized way of element wise vector inverse with perturbations
我有一个大向量,我想每次都用一个小的扰动计算元素的逆向。例如,对于大 N
,我有 y
及其元素的逆 y_inv
y = np.random.rand(1, N)
y_inv = 1. / y
y_inv[y_inv == np.inf] = 0 # y may contain zeros
我想计算
p = 0.01
z = y + p
z_inv = 1./ z = 1./ (y + p)
多次不同 p
和固定 y
。因为 N
非常大,有没有一种有效的方法或近似值,可以在 z_inv
的计算中使用已经计算出的 y_inv
?非常感谢任何提高反转速度的建议 z
。
浮点除法很慢,尤其是 double-precision 浮点数。 Simple-precision 更快(relative 错误可能小于 2.5e-07),如果你这样做,它可以变得更快不需要 high-precision 通过计算 近似倒数 (此近似值的最大 相对 误差小于 3.66e-4 x86-64 处理器)。
假设您可以降低结果的精度,以下是不同方法在 Skylake 处理器上的性能(假设 Numpy 是在 AVX SIMD 指令集的支持下编译的):
Double-precision division: 8 operation/cycle/core
Simple-precision division: 5 operation/cycle/core
Simple-precision approximate reciprocal: 1 operation/cycle/core
您可以通过指定数组的 dtype
轻松切换到 Numpy 的 simple-precision。对于倒数,您需要使用配置为使用 fastmath
模型(njit
的标志)的 Numba(或 Cython)。
另一种解决方案是使用多线程 简单地执行此操作。这可以通过 Numba 使用 njit
标志 parallel=True
和循环遍历 nb.prange
轻松完成。该解决方案可以与前一个解决方案(关于精度)相结合,从而与最初基于 Numpy double-precision 的代码相比,计算速度要快得多。
此外,计算数组 in-place 应该更快(尤其是在使用多线程时)。或者,您可以预分配输出数组并重用它(比 in-place 方法慢但比原始方法快)。 Numpy 函数的参数 out
(如 np.divide
)可用于执行此操作。
这是一个(未经测试的)并行 Numba 代码示例:
import numba as nb
# See fastmath=True and float32 types for faster performance of approximate results
# Assume `out` is already preallocated
@njit('void(float64[::1], float64[::1], float64)', parallel=True)
def compute(out, y, p):
assert(out.size == y.size)
for i in nb.prange(y.size):
out[i] = 1.0 / (y[i] + p)
我有一个大向量,我想每次都用一个小的扰动计算元素的逆向。例如,对于大 N
,我有 y
及其元素的逆 y_inv
y = np.random.rand(1, N)
y_inv = 1. / y
y_inv[y_inv == np.inf] = 0 # y may contain zeros
我想计算
p = 0.01
z = y + p
z_inv = 1./ z = 1./ (y + p)
多次不同 p
和固定 y
。因为 N
非常大,有没有一种有效的方法或近似值,可以在 z_inv
的计算中使用已经计算出的 y_inv
?非常感谢任何提高反转速度的建议 z
。
浮点除法很慢,尤其是 double-precision 浮点数。 Simple-precision 更快(relative 错误可能小于 2.5e-07),如果你这样做,它可以变得更快不需要 high-precision 通过计算 近似倒数 (此近似值的最大 相对 误差小于 3.66e-4 x86-64 处理器)。
假设您可以降低结果的精度,以下是不同方法在 Skylake 处理器上的性能(假设 Numpy 是在 AVX SIMD 指令集的支持下编译的):
Double-precision division: 8 operation/cycle/core
Simple-precision division: 5 operation/cycle/core
Simple-precision approximate reciprocal: 1 operation/cycle/core
您可以通过指定数组的 dtype
轻松切换到 Numpy 的 simple-precision。对于倒数,您需要使用配置为使用 fastmath
模型(njit
的标志)的 Numba(或 Cython)。
另一种解决方案是使用多线程 简单地执行此操作。这可以通过 Numba 使用 njit
标志 parallel=True
和循环遍历 nb.prange
轻松完成。该解决方案可以与前一个解决方案(关于精度)相结合,从而与最初基于 Numpy double-precision 的代码相比,计算速度要快得多。
此外,计算数组 in-place 应该更快(尤其是在使用多线程时)。或者,您可以预分配输出数组并重用它(比 in-place 方法慢但比原始方法快)。 Numpy 函数的参数 out
(如 np.divide
)可用于执行此操作。
这是一个(未经测试的)并行 Numba 代码示例:
import numba as nb
# See fastmath=True and float32 types for faster performance of approximate results
# Assume `out` is already preallocated
@njit('void(float64[::1], float64[::1], float64)', parallel=True)
def compute(out, y, p):
assert(out.size == y.size)
for i in nb.prange(y.size):
out[i] = 1.0 / (y[i] + p)