我有一些 CUDA 代码可以执行一些线性代数来反转一种特殊类型的结构化矩阵。我使用算法的序列化版本的结果来计算 RMS 误差。错误随着问题的大小而增长,其程度超出了我的预期。任何人都可以提供有关为什么会这样的见解吗?
GPU 代码非常幼稚。这是故意的,我很快就会优化它——我只想要一个简单的基线内核,它可以给出正确的结果。
__global__ void levinson_durbin_gpu(TYPE *h0_d, TYPE *h_d, TYPE *v_d, TYPE *x_d, TYPE *y_d, int N) //Naive kernel
{
int j = threadIdx.x;
int i;
__shared__ TYPE hn_1[512];
hn_1[j] = h_d[j];
for(i=1; i<N; i++)
{
if(j < i)
{
TYPE hn = h_d[i];
TYPE yn = y_d[i];
__syncthreads();
//Set up temporary arrays, compute inner products
__shared__ TYPE temp[512]; //Temp for hn_1_J_v
__shared__ TYPE temp2[512]; //Temp for hn_1_J_x
__shared__ TYPE temp3[512]; //Temp for hn_1_v
temp[j] = hn_1[j]*v_d[i-j-1];
temp2[j] = hn_1[j]*x_d[i-j-1];
temp3[j] = hn_1[j]*v_d[j];
__syncthreads();
//Three reductions at once
for(unsigned int s=1; s<i; s*=2)
{
int index = 2*s*j;
if((index+s) < i)
{
temp[index] += temp[index+s];
temp2[index] += temp2[index+s];
temp3[index] += temp3[index+s];
}
__syncthreads();
}
TYPE hn_1_J_v = temp[0];
TYPE hn_1_J_x = temp2[0];
TYPE hn_1_v = temp3[0];
TYPE alpha_v = (hn - hn_1_J_v)/(h0_d[0] - hn_1_v);
TYPE alpha_x = (yn - hn_1_J_x)/(h0_d[0] - hn_1_v);
__shared__ TYPE w_v[512];
w_v[j] = v_d[j] - alpha_v*v_d[i-j-1];
__shared__ TYPE w_x[512];
w_x[j] = x_d[j] - alpha_x*v_d[i-j-1];
v_d[j] = w_v[j];
x_d[j] = w_x[j];
if(j == 0)
{
v_d[i] = alpha_v;
x_d[i] = alpha_x;
}
}
__syncthreads();
}
}
标识符TYPE
是浮点数或双精度数,具体取决于我编译代码的方式。我正在使用 1 个带有 N 个线程的块(再次,在这里保持天真和简单)。使用单精度,我看到以下结果:
N=4:RMS 误差 = 0.0000000027
N=8:RMS 误差 = 0.0000001127
N=16:RMS 误差 = 0.0000008832
N=32:RMS 误差 = 0.0000009233
N=64:RMS 误差 = 42.0136776452
N=80:RMS 误差 = 281438717。
我不知道这是我的算法错误还是某种精度问题。如果有帮助,我可以使用双精度、算法的 CPU 版本或计算 RMS 误差的代码来显示上述结果。我正在使用 GeForce GTX 660 Ti (cc 3.0) GPU。变量x_d
包含最终结果。