Math 从全局点读取时对CUDA矩阵执行操作

Math 从全局点读取时对CUDA矩阵执行操作,math,optimization,cuda,Math,Optimization,Cuda,嘿,那里, 我有一个数学函数(多维的,这意味着有一个索引,我传递给C++函数,我想返回一个数学函数。例如,假设我有一个这样的数学函数: f = Vector(x^2*y^2 / y^2 / x^2*z^2) double myFunc(int function_index) { switch(function_index) { case 1: return PNT[0]*PNT[0]*PNT[1]*PNT[1];

嘿,那里, 我有一个数学函数(多维的,这意味着有一个索引,我传递给C++函数,我想返回一个数学函数。例如,假设我有一个这样的数学函数:

f = Vector(x^2*y^2 / y^2 / x^2*z^2)
double myFunc(int function_index)
{       
    switch(function_index)
    {
        case 1:
            return PNT[0]*PNT[0]*PNT[1]*PNT[1];
        case 2:
            return PNT[1]*PNT[1];
        case 3:
            return PNT[2]*PNT[2]*PNT[1]*PNT[1];
    }
}
我会这样实施:

f = Vector(x^2*y^2 / y^2 / x^2*z^2)
double myFunc(int function_index)
{       
    switch(function_index)
    {
        case 1:
            return PNT[0]*PNT[0]*PNT[1]*PNT[1];
        case 2:
            return PNT[1]*PNT[1];
        case 3:
            return PNT[2]*PNT[2]*PNT[1]*PNT[1];
    }
}
然而,
PNT
是这样全局定义的:
double PNT[NUM_COORDINATES]
。现在我想为每个坐标实现每个函数的导数,从而生成导数矩阵(列=坐标;行=单个函数)。我已经编写了我的内核,到目前为止它可以工作,并且调用了myFunc()

问题是:为了计算关于坐标j的数学子函数i的导数,我将在顺序模式下(例如在CPU上)使用以下代码(然而这是简化的,因为通常会减小h,直到达到导数的某个精度):

现在,当我想在GPU上并行执行此操作时,问题出现了:如何处理PNT?因为我必须将某些坐标增加h,计算值,然后再次减少它,所以出现了一个问题:如何在不“干扰”其他线程的情况下执行此操作?我无法修改
PNT
,因为其他线程需要“原始”'指向以修改自己的坐标

我的第二个想法是为每个线程保存一个修改点,但我很快就放弃了这个想法,因为当并行使用数千个线程时,这是一个非常糟糕而且可能很慢的想法(可能因为内存限制根本无法实现)

最终解决方案 因此,我目前的做法是,在运行时通过预处理器宏将值“add”添加到由
coord_index
标识的坐标中(不将其存储在某处)

#define X(n) ((coordinate_index == n) ? (PNT[n]+add) : PNT[n])
__device__ double myFunc(int function_index, int coordinate_index, double add)
{           
    //*// Example: f[i] = x[i]^3
    return (X(function_index)*X(function_index)*X(function_index));
    // */
}
这很好,速度也很快。当使用具有10000个函数和10000个坐标的导数矩阵时,它只需要0.5sek。
PNT
是全局定义的,或者是像
\uuuu constant\uuuuuuuuu double PNT[NUM\u coordinates];
一样的常量内存,具体取决于预处理器变量
USE\u CONST
。 行
返回(X(函数索引)*X(函数索引)*X(函数索引));
只是一个示例,其中每个子函数看起来都是相同的方案,从数学上讲:

f = Vector(x0^3 / x1^3 / ... / xN^3)
现在大问题出现了

myFunc
是一个数学函数,用户应该能够根据自己的喜好实现。例如,他还可以实现以下数学函数:

f = Vector(x0^2*x1^2*...*xN^2 / x0^2*x1^2*...*xN^2 / ... / x0^2*x1^2*...*xN^2)
<> p>因此每个函数看起来都一样。作为程序员,你只需要编码一次,而不依赖于实现的数学函数。因此,当上面的函数在C++中实现时,它看起来像下面这样:

__device__ double myFunc(int function_index, int coordinate_index, double add)
{           
    double ret = 1.0;
    for(int i = 0; i < NUM_COORDINATES; i++)
        ret *= X(i)*X(i);
    return ret; 
}
\uuuuuuu设备\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuifunc(整型函数索引、整型坐标索引、双加)
{           
双ret=1.0;
对于(int i=0;i
现在,内存访问非常“怪异”,对性能问题不利,因为每个线程都需要访问
PNT
的每个元素两次。当然,在每个函数看起来都一样的情况下,我可以重写围绕
myFunc
调用的完整算法,但正如我已经说过的:我不想编码根据用户实现的函数
myFunc

有谁能想出一个解决这个问题的办法吗??
谢谢!

回到开头,从一张干净的纸开始,你似乎想做两件事

  • 计算任意标量值 输入数组上的函数
  • 近似任意标量的偏导数 输入数组上的有值函数 使用一阶精确有限差分法
虽然该函数是标量值和任意函数,但实际上,该函数似乎有两种明确的形式:

  • 具有标量参数的标量值函数
  • 具有向量参数的标量值函数
  • 您似乎从第一类函数开始,编写了处理函数和近似导数计算的代码,现在正在努力解决如何使用相同代码处理第二种情况的问题

    如果这是对问题的合理总结,那么请在评论中注明,我将继续用一些代码示例和概念对其进行扩展。如果不是,我将在几天后删除它


    在评论中,我一直试图指出,将第一种类型的函数与第二种类型的函数混为一谈不是一个好方法。并行执行的正确性要求,以及在GPU上提取并行性和性能的最佳方法是非常不同的。分开处理这两种类型的函数会更好在两个不同的代码框架中,使用不同的使用模型。当需要实现给定的数学表达式时,“用户”应该对表达式进行基本分类,确定它是第一类函数的模型,还是第二类函数的模型。分类行为是驱动代码中算法选择的因素。这种类型的“按算法分类”在设计良好的库中几乎是通用的——你可以在像Boost和STL这样的C++模板库中找到它,你可以在BLASS之类的传统Fortran代码中找到它。

    当然,第一个代码片段不是你如何定义一个函数来作为矢量化方案的一部分吗?对不起,我真的不明白你的意思?!这和我要解决的最后一个问题有关吗?我的意思是,函子在这么多层次上都没有意义。因为它是后面的一切的基本前提,因为所有的函数都是共轴的