缩放时间以numpy广播3D数组上的操作 [英] Scaling of time to broadcast an operation on 3D arrays in numpy

查看:133
本文介绍了缩放时间以numpy广播3D数组上的操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在两个3D阵列上广播>"的简单操作.一个具有尺寸(m,1,n),另一个具有尺寸(m,1,n).如果更改第三维(n)的值,我会天真地希望计算速度将缩放为n.

I am trying to broadcast a simple operation of ">" over two 3D arrays. One has dimensions (m, 1, n) the other (1, m, n). If I change the value of the third dimension (n), I would naively expect that the speed of the computation would scale as n.

但是,当我尝试明确地进行测量时,我发现将n从1增加到2时,计算时间增加了大约10倍,此后缩放是线性的.

However, when I try to measure this explicitly I find that there is an increase in computation time of about factor 10 when increasing n from 1 to 2, after which the scaling is linear.

为什么从n = 1到n = 2时计算时间会急剧增加?我假设它是numpy中的内存管理工件,但是我正在寻找更多细节.

Why does the computation time increase so drastically when going from n=1 to n=2? I'm assuming that it is an artifact of memory management in numpy but I'm looking for more specifics.

代码附在下面,并带有结果图.

The code is attached below with the resulting plot.

import numpy as np
import time
import matplotlib.pyplot as plt

def compute_time(n):

    x, y = (np.random.uniform(size=(1, 1000, n)), 
            np.random.uniform(size=(1000, 1, n)))

    t = time.time()
    x > y 
    return time.time() - t

a = [
        [
            n, np.asarray([compute_time(n) 
            for _ in range(100)]).mean()
        ]
        for n in range(1, 30, 1)
    ]

a = np.asarray(a)
plt.plot(a[:, 0], a[:, 1])
plt.xlabel('n')
plt.ylabel('time(ms)')
plt.show()

广播操作的时间段

推荐答案

我无法证明这一点,但我可以肯定,这是由于仅在n == 1时才可用的一种简单优化.

I can't prove it but I am pretty certain that this is due to one simple optimization that is only available at n==1.

当前,numpy ufunc实现基于计算机生成的最内层循环的代码,该代码映射到简单的C循环.封闭的循环要求使用完全成熟的迭代器对象,这取决于有效负载,即最里面的循环的大小和原子操作的开销可能是相当大的开销.

Currently, the numpy ufunc implementation is based on computergenerated code for the innermost loop which is mapped to a simple C loop. Enclosing loops require the use of a fully fledged iterator object which depending on the payload i.e. the size of the innermost loop and the cost of the atomic operation can be a significant overhead.

现在,在n == 1时,问题本质上是2D(numpy足够聪明以检测到该问题),并且最里面的循环的大小为1000,因此迭代器对象的步数为1000.从n == 2开始,最里面的循环的大小为n,我们有1,000,000步的迭代器对象,这说明了您正在观察的跳转.

Now, at n==1 the problem is essentially 2D (numpy is smart enough to detect that), with innermost loop of size 1000, hence 1000 steps of the iterator object. From n==2 upwards the innermost loop has size n and we have 1,000,000 steps of the iterator object which accounts for the jump you are observing.

正如我说的那样,我无法证明它,但我可以使它看起来合理:如果将变量尺寸移到最前面,则最内层的循环将具有1000的恒定大小,而外层的循环将以1000个迭代步长线性增长.确实,这使跳远消失了.

As I said I can't prove it but I can make it look plausible: If we move the variable dimension to the front, then the innermost loop has constant size of 1000, and the outer loop grows linearly in 1000 iteration steps. And indeed that makes the jump go away.

代码:

import numpy as np
import time
import matplotlib.pyplot as plt

def compute_time(n, axis=2):
    xs, ys = [1, 10], [10, 1]
    xs.insert(axis, n)
    ys.insert(axis, n)
    x, y = (np.random.uniform(size=xs),
            np.random.uniform(size=ys))

    t = time.perf_counter()
    x > y
    return time.perf_counter() - t

a = [
        [
            n,
            np.asarray([compute_time(n) for _ in range(100)]).mean(),
            np.asarray([compute_time(n, 0) for _ in range(100)]).mean()
        ]
        for n in range(0, 10, 1)
     ]

a = np.asarray(a)
plt.plot(a[:, 0], a[:, 1:])
plt.xlabel('n')
plt.ylabel('time(ms)')
plt.show()

相关: https://stackoverflow.com/a/48257213/7207392

这篇关于缩放时间以numpy广播3D数组上的操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆