Python 我如何知道我令人尴尬的并行任务是否适合GPU?

Python 我如何知道我令人尴尬的并行任务是否适合GPU?,python,parallel-processing,gpu,numba,Python,Parallel Processing,Gpu,Numba,我们是说,一个任务,需要相当轻的计算每行在大量的行是根本不适合的GPU 我需要对一个表进行一些数据处理,其中的行是独立的。因此,这是令人尴尬的平行。我有一个GPU所以…天作之合?这与本例非常相似,本例计算每行每个条目的移动平均数(行是独立的) 像这个例子一样,我对每一行的处理都不是严格的数学处理。相反,它是在行中循环,并使用一些条件逻辑进行一些求和、赋值和其他比特和片段 我曾尝试使用Numba库中的guVectorize将其分配给Nvidia GPU。它工作正常,但我没有加速 这类任务原则上适合

我们是说,一个任务,需要相当轻的计算每行在大量的行是根本不适合的GPU

我需要对一个表进行一些数据处理,其中的行是独立的。因此,这是令人尴尬的平行。我有一个GPU所以…天作之合?这与本例非常相似,本例计算每行每个条目的移动平均数(行是独立的)

像这个例子一样,我对每一行的处理都不是严格的数学处理。相反,它是在行中循环,并使用一些条件逻辑进行一些求和、赋值和其他比特和片段

我曾尝试使用Numba库中的guVectorize将其分配给Nvidia GPU。它工作正常,但我没有加速

这类任务原则上适合GPU吗?i、 e.如果我深入到Numba,开始调整线程、块和内存管理或算法实现,理论上,我应该加快速度。或者,这种问题根本不适合体系结构

下面的答案似乎表明这是不合适的,但我还不太确信


而且

您的任务显然是内存受限的,但这并不意味着您不能从GPU中获益,但是它可能没有CPU受限的任务那么直接

让我们看一下常见的配置并做一些计算:

  • CPU-RAM内存带宽约为24GB/s
  • CPU-GPU传输带宽约为8GB/s
  • GPU-RAM内存带宽约为180GB/s
  • 让我们假设我们需要传输24 GB的数据来完成任务,因此我们将有以下最佳时间(是否以及如何实现这些时间是另一个问题!):

  • 场景:仅CPU时间=24GB/24GB/s=1秒
  • 场景:数据必须从CPU传输到GPU(24GB/8GB/s=3秒),并在那里进行处理(24GB/180GB/s=0.13秒)到3.1秒
  • 场景:数据已经在设备上,因此只需要24GB/180GB/s=0.13秒
  • 正如人们所看到的,有可能加速,但只有在3。场景-当您的数据已经在GPU设备上时

    然而,实现最大带宽是一项极具挑战性的任务

    例如,在CPU上按行处理矩阵时,您希望数据按行主顺序(C顺序)排列,以便最大限度地利用一级缓存:在读取一个双精度数据时,您实际上会将8个双精度数据加载到缓存中,并且您不希望在处理剩余的7个数据之前将其从缓存中逐出

    另一方面,在GPU上,您希望内存访问为,例如线程
    0
    应该访问地址
    0
    ,线程
    1
    -地址
    1
    等等。要使其工作,数据必须按列主顺序(Fortran顺序)排列


    还有一件事需要考虑:测试性能的方式。您的测试阵列只有大约2MB大,因此对于三级缓存来说足够小。L3缓存的带宽取决于用于计算的内核数量,但至少在100GB/s左右-不比GPU慢多少,在CPU上并行时可能快很多

    您需要一个更大的数据集,以避免被缓存行为愚弄


    有点离题的评论:从数值的角度来看,你的算法不是很稳健

    如果窗口宽度为3,如您的示例所示,但一行中大约有
    10**4
    个元素。因此,对于最后一个元素,该值是大约
    10**4
    加法和减法的结果,每个加法和减法都会给该值增加一个舍入误差-相比之下,如果“天真地”进行,则只有三个加法,这是相当大的差异


    当然,它可能并不重要(如您的示例中,一行10个元素),但也可能有一天会咬到您

    如果您的数据尚未在gpu上,您将无法从gpu获得任何加速,因为数据传输cpugpu非常昂贵,这对我来说很有意义。如果每行有更多的顺序指令要执行,也就是说,没有什么数学上的复杂,只是每行要做更多的事情,那该怎么办?这会不会开始更有效地利用GPU的处理能力?只要您的任务是内存受限的,GPU/cpu内存带宽就是您可以实现的加速。只有在算法执行期间必须多次读取数据时,才值得将数据传输到gpu。
    import numpy as np
    
    from numba import guvectorize
    
    @guvectorize(['void(float64[:], intp[:], float64[:])'], '(n),()->(n)')
    def move_mean(a, window_arr, out):
        window_width = window_arr[0]
        asum = 0.0
        count = 0
        for i in range(window_width):
            asum += a[i]
            count += 1
            out[i] = asum / count
        for i in range(window_width, len(a)):
            asum += a[i] - a[i - window_width]
            out[i] = asum / count
    
    arr = np.arange(2000000, dtype=np.float64).reshape(200000, 10)
    print(arr)
    print(move_mean(arr, 3))