【问题标题】:Numpy tensor implementation slower than loopNumpy张量实现比循环慢
【发布时间】:2019-03-21 14:06:57
【问题描述】:

我有两个计算相同指标的函数。一个最终使用列表推导来循环计算,另一个只使用 numpy 张量操作。这些函数采用 (N, 3) 数组,其中 N 是 3D 空间中的点数。当 N ~ 3000 时,列表理解更快。就 N 而言,两者似乎都具有线性时间复杂度,即两条时间 N 线在 N=~3000 处交叉。

def approximate_area_loop(section, num_area_divisions):        
    n_a_d = num_area_divisions
    interp_vectors = get_section_interp_(section)

    a1 = section[:-1]
    b1 = section[1:]
    a2 = interp_vectors[:-1]
    b2 = interp_vectors[1:]

    c = lambda u: (1 - u) * a1 + u * a2
    d = lambda u: (1 - u) * b1 + u * b2
    x = lambda u, v: (1 - v) * c(u) + v * d(u)

    area = np.sum([np.linalg.norm(np.cross((x((i + 1)/n_a_d, j/n_a_d) - x(i/n_a_d, j/n_a_d)),\
                                           (x(i/n_a_d, (j +1)/n_a_d) - x(i/n_a_d, j/n_a_d))), axis = 1)\
                   for i in range(n_a_d) for j in range(n_a_d)])

    Dt = section[-1, 0] - section[0, 0]
    return area, Dt

def approximate_area_tensor(section, num_area_divisions):
    divisors = np.linspace(0, 1, num_area_divisions + 1)
    interp_vectors = get_section_interp_(section)
    a1 = section[:-1]
    b1 = section[1:]
    a2 = interp_vectors[:-1]
    b2 = interp_vectors[1:]
    c = np.multiply.outer(a1, (1 - divisors)) + np.multiply.outer(a2, divisors) # c_areas_vecs_divs
    d = np.multiply.outer(b1, (1 - divisors)) + np.multiply.outer(b2, divisors) # d_areas_vecs_divs
    x = np.multiply.outer(c, (1 - divisors)) + np.multiply.outer(d, divisors) # x_areas_vecs_Divs_divs
    u = x[:, :, 1:, :-1] - x[:, :, :-1, :-1] # u_areas_vecs_Divs_divs
    v = x[:, :, :-1, 1:] - x[:, :, :-1, :-1] # v_areas_vecs_Divs_divs
    sub_area_norm_vecs = np.cross(u, v, axis = 1) # areas_crosses_Divs_divs
    sub_areas = np.linalg.norm(sub_area_norm_vecs, axis = 1) # areas_Divs_divs (values are now sub areas)
    area = np.sum(sub_areas)
    Dt = section[-1, 0] - section[0, 0]
    return area, Dt

为什么列表推导版本在大 N 时工作得更快?当然张量版本应该更快?我想知道这是否与计算的大小有关,这意味着它太大而无法在缓存中完成?请问我是否没有提供足够的信息,我真的很想深入了解这一点。

【问题讨论】:

  • 我不确定您使用的是什么算法以及近似面积张量的意思,但是您在 numpy 函数中大量使用的外部产品使 3d 数组对于大 Ns 可以真正增长制作大而耗时。您的列表理解似乎不会生成它们。可能有更简单的方法来计算这些面积,或者有人已经这样做了。
  • u的形状是什么?您的代码足够复杂,难以一目了然。许多 SO 问题已经观察到,对于非常大的数组,内存管理复杂性和迭代时间之间存在权衡。我想知道部分循环情况将如何执行 - 您仅在 i 上循环。
  • 总体而言,您的代码非常复杂,使用了crossnorm 等复杂函数。所以很难区分大内存情况在哪里变慢。您可能需要做一些更集中的时间安排。

标签: python-3.x numpy numpy-ndarray array-broadcasting


【解决方案1】:

正如@hpauljs 评论所建议的那样,完全矢量化函数的瓶颈确实在 np.linalg.norm 中。 Norm 仅用于获取轴 1 中包含的所有向量的大小。一种更简单、更快速的方法是:

sub_areas = np.sqrt((sub_area_norm_vecs*sub_area_norm_vecs).sum(axis = 1))

这给出了完全相同的结果,并且代码速度比循环实现快了 25 倍(即使循环也不使用 linalg.norm)。

【讨论】:

    猜你喜欢
    • 2021-01-16
    • 2019-09-10
    • 2017-11-09
    • 2017-01-22
    • 1970-01-01
    • 2017-12-17
    • 1970-01-01
    • 2017-10-13
    • 1970-01-01
    相关资源
    最近更新 更多