与CUDA上的GPU上的简单算法并行
Paralleling a simple algorithm on GPU with CUDA
i具有一个CUDA函数,可以计算GPU上的局部二进制模式。基本上LBP是对图像像素的计算,其中任何给定像素(I,J)的值取决于它的8个邻居的强度。
到目前为止很好,代码如下:
//The kernel
__global__ void LBP(unsigned char *in, unsigned char *out, const int w, const int h)
{
const unsigned int i = (blockIdx.x * blockDim.x) + threadIdx.x;
//Don't do edges!
if(
i < w //first row
|| i >= (w * (h - 1)) // last row
|| !(i % w) // first column
|| (i % w + 1 == w) // last column
)
{
out[i] = 0;
return;
}
unsigned char
code = 0,
center = in[i];
code |= (in[i-w-1] > center) << 7;
code |= (in[i-w ] > center) << 6;
code |= (in[i-w+1] > center) << 5;
code |= (in[i +1] > center) << 4;
code |= (in[i+w+1] > center) << 3;
code |= (in[i+w ] > center) << 2;
code |= (in[i+w-1] > center) << 1;
code |= (in[i -1] > center) << 0;
out[i] = code;
}
// A proxi function
void DoLBP(unsigned char *in, unsigned char *out, const int w, const int h)
{
const int
sz = w * h * sizeof(unsigned char);
unsigned char
*in_gpu,
*out_gpu;
cudaMalloc((void**)&in_gpu, sz);
cudaMalloc((void**)&out_gpu, sz);
cudaMemcpy(in_gpu, in, sz, cudaMemcpyHostToDevice);
cudaMemcpy(out_gpu, out, sz, cudaMemcpyHostToDevice);
dim3 threadsPerBlock(1024); //Max
dim3 numBlocks(w*h/threadsPerBlock.x + 1);
LBP<<<numBlocks,threadsPerBlock>>>(in_gpu, out_gpu, w, h);
cudaMemcpy(out, out_gpu, sz, cudaMemcpyDeviceToHost);
cudaFree(in_gpu);
cudaFree(out_gpu);
}
//The caller
int main()
{
printf("Startingn");
const int
w = 4000,
h = 2000;
unsigned char
in[w*h],
out[w*h];
// Fill [in] with some data
DoLBP(in, out, w, h);
// Use [out] data
return 0;
}
这些图像作为 * unsigned char *s( array = [[row 1] [row 2] [row 3] ... [row n]]
)的单维数组传递给GPU(从OpenCV的垫子中提取)
问题
此代码在相对较小的图像中正常工作,它返回带有正确值的输出数组,但是当图像大小增长时,输出数组全部为零!
我的怀疑是,图像数据溢出了一些GPU缓冲区或类似的东西。
我也不清楚 numberfblocks 和 threadspersperblock part的工作!如果你们中的任何一个可以对此提供一些基本的见解,那将不胜感激。
(我在Cuda中像1天大,所以可能有太多方法可以改善此代码段!)
- 我建议在您的代码中添加适当的CUDA错误检查。我相信您的内核正在访问和失败。
- 使用
cuda-memcheck
运行代码,因为它将有助于确定内核为何失败。 -
这些是在堆栈上进行的相当大的分配:
const int w = 4000, h = 2000; unsigned char in[w*h], out[w*h];
每个大约8MB。这可能是一个问题;它可能依赖于系统。通常最好通过动态分配进行大规模分配,例如
malloc
。在我的特定系统上,由于这些大型堆栈变量未正确分配,因此我得到了SEG错误。 -
您的内核缺少适当的"线程检查"。起初,我以为您对此做得很好:
if( i < w //first row || i >= (w * (h - 1)) // last row || !(i % w) // first column || (i % w + 1 == w) // last column )
但这是一个问题:
out[i] = 0; return;
如果您评论
out[i] = 0;
行,您将有更好的运气。另外,如果您不喜欢发表评论,则可以这样做:if (i < (w*h)) out[i] = 0;
问题是您的网格启动参数必定会创建"额外线程":
dim3 threadsPerBlock(1024); //Max dim3 numBlocks(w*h/threadsPerBlock.x + 1);
如果您有适当的线程检查(几乎可以做...),那不是问题。但是您不能让这些额外的线程写入无效的位置。
要解释每个块螺纹和通过算术工作的块数量可能是有用的。CUDA内核发射具有关联的网格。网格只是与内核启动相关联的所有线程。线程将分为块。因此,网格等于启动的块数量,每块线程。那是多少?这条线说您每块要求1024个线程:
dim3 threadsPerBlock(1024); //Max
您要启动的块数量由:
给出 dim3 numBlocks(w*h/threadsPerBlock.x + 1);
算术是:
(w=4000)*(h=2000)/1024 = 7812.5 = 7812 (note this is an *integer* divide)
然后我们添加1。因此您启动了7813个块。那是几个线程?
(7813 blocks)*(1024 threads per block) = 8000512 threads
,但是您只需要(只需要)8000000螺纹(= w * h),因此您需要进行线程检查即可防止额外的512线程尝试访问out[i]
。但是您的线程检查在这方面被打破了。
作为最后的注意,让我更快地运行此代码的最明显方法是通过共享内存利用相邻操作中的数据重新使用。但请先让您的代码正常工作。
- 对多个(可能)重叠范围进行分区的最简单算法
- 学习数据结构和算法的简单方法
- 使用简单的暴力算法找到数组中最大的4个元素
- 使用 Prim 算法计算最小生成树:如何使其简单?
- 使用 c++17 算法并行化简单循环
- 与CUDA上的GPU上的简单算法并行
- 在C 中编写一个简单的排序算法以及伪代码版本
- 为什么对于简单的 StereoBM 算法,我的代码比 opencv 慢得多
- C++简单的凯撒密码算法
- 用于简单 2D 自上而下的车辆碰撞物理的算法
- 简单过程生成2D城市的算法
- 如何进一步优化这个简单的算法
- 简单的三角函数算法,用于计算定点数的 sin() 和 cos()
- 从文本文件中简单读取算法不起作用
- 无锁简单隔离存储算法
- c++中简单的通配符搜索算法
- OpenGL中粒子发射器的简单三维烟雾算法
- 简单的拼写检查算法
- 调试使用广度优先搜索(BFS)的简单图算法
- 帮助我理解这个算法(简单)