查找CUDA中线程大小的总和缩减问题
在上一篇文章中,我询问了如何计算具有约化的数组的和。现在我有一个新问题,图像变大了,结果不正确,每次运行时都会发生变化。 我测试了96*96的图像大小 第一次成绩:28169.046875 第二次结果:28169.048828 预期结果:28169.031250 这是我的密码:查找CUDA中线程大小的总和缩减问题,cuda,reduction,Cuda,Reduction,在上一篇文章中,我询问了如何计算具有约化的数组的和。现在我有一个新问题,图像变大了,结果不正确,每次运行时都会发生变化。 我测试了96*96的图像大小 第一次成绩:28169.046875 第二次结果:28169.048828 预期结果:28169.031250 这是我的密码: #include <stdio.h> #include <cuda.h> __global__ void calculate_threshold_kernel(float * input, f
#include <stdio.h>
#include <cuda.h>
__global__ void calculate_threshold_kernel(float * input, float * output)
{
int idx = blockIdx.x * blockDim.x + threadIdx.x;
int t = threadIdx.x;
__shared__ float partialSum[256];
partialSum[t] = input[idx];
__syncthreads();
for (int stride = 1; stride < blockDim.x; stride *= 2)
{
if (t % (2 * stride) == 0)
partialSum[t] += partialSum[t + stride];
__syncthreads();
}
if (t == 0)
{
atomicAdd(output,partialSum[0]);
}
}
int main( void )
{
float *d_array, *d_output,*h_input, *h_output;
int img_height = 96;
int img_width = 96;
int input_elements = img_height * img_width;
h_input = (float*) malloc(sizeof(float) * input_elements);
cudaMalloc((void**)&d_output, sizeof(float));
cudaMemset(d_output, 0, sizeof(float));
h_output = (float*)malloc(sizeof(float));
cudaMalloc((void**)&d_array, input_elements*sizeof(float));
float array[] = {[array sample]};
for (int i = 0; i < input_elements; i++)
{
h_input[i] = array[i];
}
cudaMemcpy(d_array, h_input, input_elements*sizeof(float), cudaMemcpyHostToDevice);
dim3 blocksize(256);
dim3 gridsize(input_elements/blocksize.x);
calculate_threshold_kernel<<<gridsize,blocksize>>>(d_array, d_output);
cudaMemcpy(h_output, d_output, sizeof(float), cudaMemcpyDeviceToHost);
printf("Sum from GPU = %f\n", *h_output);
return 0;
}
#包括
#包括
__全局无效计算阈值内核(浮点*输入,浮点*输出)
{
int idx=blockIdx.x*blockDim.x+threadIdx.x;
int t=threadIdx.x;
__共享_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu;
partialSum[t]=输入[idx];
__同步线程();
对于(整数步长=1;步长
浮点数
的精度限制在7位左右,如下所述
结果会发生变化,因为float
上的操作是非交换的,并且您正在使用并行归约
由于float
上的操作是非交换的,并且您使用的是atomicAdd()
,无法保持加法顺序,因此结果会发生变化
如果您想得到更准确的结果,可以使用
double
虽然康世音关于浮点精度和浮点运算的非交换性的回答是正确的,但他对于结果不同的原因并不正确
- 浮点运算是非交换的,这意味着按不同顺序执行的运算可以返回不同的结果。例如,
对于((a+b)+c)+d)
、a
、b
和c
的某些值,可能与d
略有不同。但这两个结果不应因运行而异
- 您的结果在不同的运行之间有所不同,因为
的添加顺序不同。使用double也不能保证不同运行之间的结果相同atomicAdd
- 有一些方法可以实现并行缩减,而不将atomicAdd作为最后一步(例如:使用第二次内核启动来添加第一次启动的部分和),这可以提供一致的(但与CPU略有不同)结果
atomicCAS()
。你可以用它。谢谢你澄清这一点。我会改变我的答案。