Python 3D插值加速

标签 python performance numpy interpolation cython

我有以下用于插入 3D 体积数据的代码。

Y, X, Z = np.shape(volume)
xs = np.arange(0, X)
ys = np.arange(0, Y)
zs = np.arange(0, Z)

points = list(zip(np.ravel(result[:, :, :, 1]), np.ravel(result[:, :, :, 0]), np.ravel(result[:, :, :, 2])))
interp = interpolate.RegularGridInterpolator((ys, xs, zs), volume,
                                             bounds_error=False, fill_value=0, method='linear')
new_volume = interp(points)
new_volume = np.reshape(new_volume, (Y, X, Z))

此代码在 512x512x110 体积(约 2900 万个点)上执行大约需要 37 秒,这导致每个体素超过 1 微秒(这对我来说是 Not Acceptable 时间——更重要的是它使用 4 个内核)。调用 new_volume=interp(points) 占用了大约 80% 的程序时间,列表创建几乎占用了全部剩余时间。

是否有任何简单(或什至更复杂)的方法可以加快计算速度?或者是否有任何好的 Python 库可以提供更快的插值?每次调用此程序时,我的音量和积分都会发生变化。

最佳答案

这是您的 cython 解决方案的略微修改版本:

import numpy as np
cimport numpy as np
from libc.math cimport floor
from cython cimport boundscheck, wraparound, nonecheck, cdivision

DTYPE = np.float
ctypedef np.float_t DTYPE_t

@boundscheck(False)
@wraparound(False)
@nonecheck(False)
def interp3D(DTYPE_t[:,:,::1] v, DTYPE_t[:,:,::1] xs, DTYPE_t[:,:,::1] ys, DTYPE_t[:,:,::1] zs):

    cdef int X, Y, Z
    X,Y,Z = v.shape[0], v.shape[1], v.shape[2]
    cdef np.ndarray[DTYPE_t, ndim=3] interpolated = np.zeros((X, Y, Z), dtype=DTYPE)

    _interp3D(&v[0,0,0], &xs[0,0,0], &ys[0,0,0], &zs[0,0,0], &interpolated[0,0,0], X, Y, Z)
    return interpolated


@cdivision(True)
cdef inline void _interp3D(DTYPE_t *v, DTYPE_t *x_points, DTYPE_t *y_points, DTYPE_t *z_points, 
               DTYPE_t *result, int X, int Y, int Z):

    cdef:
        int i, x0, x1, y0, y1, z0, z1, dim
        DTYPE_t x, y, z, xd, yd, zd, c00, c01, c10, c11, c0, c1, c

    dim = X*Y*Z

    for i in range(dim):
        x = x_points[i]
        y = y_points[i]
        z = z_points[i]

        x0 = <int>floor(x)
        x1 = x0 + 1
        y0 = <int>floor(y)
        y1 = y0 + 1
        z0 = <int>floor(z)
        z1 = z0 + 1

        xd = (x-x0)/(x1-x0)
        yd = (y-y0)/(y1-y0)
        zd = (z-z0)/(z1-z0)

        if x0 >= 0 and y0 >= 0 and z0 >= 0:
            c00 = v[Y*Z*x0+Z*y0+z0]*(1-xd) + v[Y*Z*x1+Z*y0+z0]*xd
            c01 = v[Y*Z*x0+Z*y0+z1]*(1-xd) + v[Y*Z*x1+Z*y0+z1]*xd
            c10 = v[Y*Z*x0+Z*y1+z0]*(1-xd) + v[Y*Z*x1+Z*y1+z0]*xd
            c11 = v[Y*Z*x0+Z*y1+z1]*(1-xd) + v[Y*Z*x1+Z*y1+z1]*xd

            c0 = c00*(1-yd) + c10*yd
            c1 = c01*(1-yd) + c11*yd

            c = c0*(1-zd) + c1*zd

        else:
            c = 0

        result[i] = c 

结果仍然与您的相同。使用 60x60x60 的随机网格数据,我获得以下时间:

SciPy's solution:                982ms
Your cython solution:            24.7ms
Above modified cython solution:  8.17ms

所以它比您的 cython 解决方案快将近 4 倍。注意

  1. Cython 默认对数组执行边界检查,如果您需要该功能,请打开边界检查并删除 @boundscheck(False)
  2. 在上面的解决方案中,数组需要是 C 连续的
  3. 如果您想要上述代码的并行变体,请在您的for 循环 中替换range 而不是prange

希望这对您有所帮助。

关于Python 3D插值加速,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41220617/

相关文章:

python - 学习Python中的内存分配

python - python一次遍历两个字符串

performance - 在 neo4j 中检索时如何避免最近更新的节点?

python - 二维数组中每个对角线的最大值

python - 无法导入qiskit,numpy : "' numpy. random'中的属性错误没有属性 'default_rng'“

python - 如何找到 Pypi 包的最新*兼容*版本?

python - 从 pandas 的 DataFrame 中删除所有 NaN 的行

java - JSF 真的准备好迎接高性能社交网络项目了吗?

c# - StackTrace 构造函数和获取方法名称对性能的影响

python - Matrix (scipy sparse) - Matrix (dense; numpy array) 乘法效率