我可以使用PyOpenCL与Scipy集成来与GPU并行执行差分进化吗?

wlzqhblo  于 2022-11-10  发布在  其他
关注(0)|答案(1)|浏览(190)

我使用Differential Evolution来模拟多元回归模型,甚至还使用了多处理选项来帮助减少运行时间。然而,对于7个自变量(每个自变量有10个值)和21个100+元素矩阵的矩阵运算,在24个内核上运行需要花费一些时间。我在PyOpenCL的多处理方面没有太多经验,因此,我想问一下,是否值得尝试将这两种方法集成到GPU上。我附上了包含3个变量和3个值的代码片段,以供参考:

import scipy.optimize as op
import numpy as np

def func(vars, *args):
    res = []
    x = []
    for i in args[1:]:
        if len(res) + 1 > len(args)//2:
            x.append(i)
            continue
        res.append(np.array(i).T)

    f1 = 0
    for i in range(len(x[0])):
        for j in range(len(x[1])):
            diff = (vars[0]*x[0][i] + vars[1])*(vars[2]*x[1][j]*x[1][j] + vars[3]*x[1][j] + vars[4])*(vars[5]*50*50 + vars[6]*50 + vars[7])
            f1 = f1 + abs(res[0][i][j] - diff) # ID-Pitch

    f2 = 0
    for i in range(len(x[0])):
        for j in range(len(x[2])):
            diff = (vars[0]*x[0][i] + vars[1])*(vars[5]*x[2][j]*x[2][j] + vars[6]*x[2][j] + vars[7])*(vars[2]*10*10 + vars[3]*10 + vars[4])
            f2 = f2 + abs(res[1][i][j] - diff) # ID-Depth

    f3 = 0
    for i in range(len(x[1])):
        for j in range(len(x[2])):
            diff = (vars[2]*x[1][i]*x[1][i] + vars[3]*x[1][i] + vars[4])*(vars[5]*x[2][j]*x[2][j] + vars[6]*x[2][j] + vars[7])*(vars[0]*3.860424005 + vars[1])
            f3 = f3 + abs(res[2][i][j] - diff) # Pitch-Depth
    return f1 + f2 + f3

def main():
    res1 = [[134.3213274,104.8030828,75.28483813],[151.3351445,118.07797,84.82079556],[135.8343927,105.9836392,76.1328857]]
    res2 = [[131.0645086,109.1574174,91.1952225],[54.74920444,30.31300092,17.36537062],[51.8931954,26.45139822,17.28693162]]
    res3 = [[131.0645086,141.2210331,133.3192429],[54.74920444,61.75898314,56.52756593],[51.8931954,52.8191817,52.66531712]]
    x1 = np.array([3.860424005,7.72084801,11.58127201])
    x2 = np.array([10,20,30])
    x3 = np.array([50,300,500])
    interval = (-20,20)
    bds = [interval,interval,interval,interval,interval,interval,interval,interval]
    res = op.differential_evolution(func, bounds=bds, workers=-1, maxiter=100000, tol=0.01, popsize=15, args=([1,2,2], res1, res2, res3, x1, x2, x3))
    print(res)

if __name__ == '__main__':
    main()
vfwfrxfs

vfwfrxfs1#

首先,是的,这是可能的,func可以是一个函数,该函数将数据发送到GPU,然后等待计算完成,然后将数据传输回RAM并返回到scipy。
将计算从CPU端更改为GPU端并不总是有益的,因为从GPU来回传输数据需要时间,因此,对于中等的笔记本电脑GPU(例如),您根本不会获得任何加速,您的代码可能会更慢。减少GPU和RAM之间的数据传输可以使GPU比普通CPU快2-4倍,但您的代码需要数据传输,因此这是不可能的。
对于具有高带宽的强大GPU(如RTX 2070或RTX 3070或APU),您可以期望更快的计算,因此GPU上的计算速度将比CPU快几倍,即使是数据传输,但这取决于CPU和GPU代码的代码实现。
最后,您的代码可以在不使用GPU的情况下加速,这可能是您在进行GPU计算之前应该做的第一件事,主要是通过使用代码编译器(如cythonnumba),这些编译器可以在不进行重大修改的情况下将代码速度提高近100倍,但您应该将代码转换为仅使用固定大小的预分配numpy数组,而不是列表,因为代码会快得多,您甚至可以禁用GIL并使代码多线程化,而且其中有很好的多线程循环实现。

相关问题