Python 3.x Numpy张量实现比循环慢

Python 3.x Numpy张量实现比循环慢,python-3.x,numpy,numpy-ndarray,array-broadcasting,Python 3.x,Numpy,Numpy Ndarray,Array Broadcasting,我有两个计算相同度量的函数。一个使用列表理解循环计算,另一个只使用numpy张量运算。函数采用(N,3)数组,其中N是三维空间中的点数。当N~3000时,列表理解速度更快。两者似乎都具有N的线性时间复杂度,即两条时间-N线在N=~3000处交叉 def approximate_area_loop(section, num_area_divisions): n_a_d = num_area_divisions interp_vectors = get_section

我有两个计算相同度量的函数。一个使用列表理解循环计算,另一个只使用numpy张量运算。函数采用(N,3)数组,其中N是三维空间中的点数。当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

为什么列表理解版本总体上工作得更快?张量版本应该更快吗?我想知道这是否和计算的大小有关,这意味着它太大而无法在缓存中完成?请询问我是否还没有包含足够的信息,我真的很想弄清这一点。

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

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

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

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

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

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

我不确定您使用的算法是什么,以及近似面积张量是什么意思,但是,您在numpy函数中大量使用的外部产品可以制作3d阵列,对于大型Ns来说,这种阵列可能会变得非常大,而且制作起来非常耗时。您的列表理解似乎无法生成它们。也许有更简单的方法来计算这些面积,或者有人已经做了。u的形状是什么?您的代码非常复杂,很难一目了然。许多这样的问题已经观察到,对于非常大的阵列,内存管理复杂性和迭代时间之间存在权衡。我想知道部分循环的情况会如何执行-您只在
I
上循环。总体而言,您的代码相当复杂,使用了复杂的函数,如
cross
norm
。因此,很难找出大内存箱速度减慢的地方。你可能需要做一些更有针对性的计时。我不确定你使用的是什么算法,也不确定你所说的近似面积张量是什么意思,但是你在numpy函数中大量使用的外部产品可以制作3d阵列,对于大N,这种阵列可能会变得非常大,而且制作起来非常耗时。您的列表理解似乎无法生成它们。也许有更简单的方法来计算这些面积,或者有人已经做了。u的形状是什么?您的代码非常复杂,很难一目了然。许多这样的问题已经观察到,对于非常大的阵列,内存管理复杂性和迭代时间之间存在权衡。我想知道部分循环的情况会如何执行-您只在
I
上循环。总体而言,您的代码相当复杂,使用了复杂的函数,如
cross
norm
。因此,很难找出大内存箱速度减慢的地方。你可能需要做一些更有针对性的计时。