【问题标题】:No result obtained from calculation计算没有结果
【发布时间】:2021-04-16 08:38:39
【问题描述】:

我正在尝试使用 CUDA 对图像进行卷积,但无法得到结果。 cuda-gdb 在我的系统上无法正常工作,所以我无法判断 CUDA 内核内部发生了什么。我使用的CUDA内核如下:

__global__
void
convolve_component_EXTEND_kern(const JSAMPLE *data, // image data
                           ssize_t data_width, // image width
                           ssize_t data_height, // image height
                           const float *kern, // convolution kernel data
                           ssize_t kern_w_f, // convolution kernel has a width of 2 * kern_w_f + 1
                           ssize_t kern_h_f, // convolution_kernel has a height of 2 * kern_h_f + 1
                           JSAMPLE *res) // array to store the result
{
ssize_t i = ::blockIdx.x * ::blockDim.x + ::threadIdx.x;
ssize_t j = ::blockIdx.y * ::blockDim.y + ::threadIdx.y;

float value = 0;

for (ssize_t m = 0; m < 2 * kern_w_f + 1; m++) {
    for (ssize_t n = 0; n < 2 * kern_h_f + 1; n++) {
            ssize_t x = i + m - kern_w_f; // column index for this contribution to convolution sum for (i, j)
            ssize_t y = j + n - kern_h_f; // row index for ...
            x = x < 0 ? 0 : (x >= data_width ? data_width - 1 : x);
            y = y < 0 ? 0 : (y >= data_height ? data_height - 1 : y);
            value += ((float) data[data_width * y + x]) * kern[(2 * kern_w_f + 1) * n + m];
    }
}

res[data_width * j + i] = (JSAMPLE) value;
}

我在这个函数中调用它

void
convolve_component_EXTEND_cuda(const JSAMPLE *data,
                           ssize_t data_width,
                           ssize_t data_height,
                           const float *kern,
                           ssize_t kern_w_f,
                           ssize_t kern_h_f,
                           JSAMPLE *res)
{
JSAMPLE *d_data;
cudaMallocManaged(&d_data,
                  data_width * data_height * sizeof(JSAMPLE));
cudaMemcpy(d_data,
           data,
           data_width * data_height * sizeof(JSAMPLE),
           cudaMemcpyHostToDevice);

float *d_kern;
cudaMallocManaged(&d_kern,
                  (2 * kern_w_f + 1) * (2 * kern_h_f + 1) * sizeof(float));
cudaMemcpy(d_kern,
           kern,
           (2 * kern_w_f + 1) * (2 * kern_h_f + 1) * sizeof(float),
           cudaMemcpyHostToDevice);

JSAMPLE *d_res;
cudaMallocManaged(&d_res,
                  data_width * data_height * sizeof(JSAMPLE));

dim3 threadsPerBlock(16, 16);  // can be adjusted to 32, 32 (1024 threads per block is the maximum)
dim3 numBlocks(data_width / threadsPerBlock.x,
               data_height / threadsPerBlock.y);
convolve_component_EXTEND_kern<<<numBlocks, threadsPerBlock>>>(d_data,
                                                               data_width,
                                                               data_height,
                                                               d_kern,
                                                               kern_w_f,
                                                               kern_h_f,
                                                               d_res);

cudaDeviceSynchronize();

cudaMemcpy(d_res,
           res,
           data_width * data_height * sizeof(JSAMPLE),
           cudaMemcpyDeviceToHost);
cudaFree(d_data);
cudaFree(d_kern);
cudaFree(d_res);
}

在这种情况下,图像数据包含在名为 data 的数组中,通过在 data_width * j + i 处对数组进行索引来访问 (i, j) 处的像素。内核数据位于名为 kern 的数组中,其宽度为 2 * kern_w_f + 1,高度为 2 * kern_h_f + 1。 (i, j) 处的元素通过在 (2 * w_f + 1) * j + i,就像数据数组一样。数组 res 用于存储卷积的结果,在传递给函数之前使用 calloc() 分配。

当我对图像数据调用第二个函数时,图像的所有像素都将转换为 0,而不是应用卷积。谁能指出问题所在?

【问题讨论】:

  • 您确定 CUDA 确实在您的系统上运行吗?您使用的是什么 CUDA 版本和什么 GPU?你为什么将 cudamallocManaged() 与 cudamempy() 一起使用?
  • 我使用的是 Cuda V10.1.243。 GPU是GTX1060移动版。至于 CUDA 是否真的在工作,我不确定。当我运行它时,它不会以任何方式向我表明出现问题。 CUDA 可以静默失败吗?
  • 如果您的 cuda 版本和驱动程序不能正常协同工作,您很可能不会收到关于找不到 CUDA 设备的警告(因为您没有检查 cuda 错误),然后内核什么都不做。所以这更多的是关于你是否可以运行 cuda 样本,并在那里获得结果。
  • 再观察...在使用 GPU 处理数据后,您调用 cudaMemcpy(d_res,res, ..),这应该是 cudaMemcpy(res, d_res, ..),因为您必须翻转 dest 和 src。

标签: c++ image-processing cuda convolution


【解决方案1】:

在调用内核并执行卷积之后,您尝试将数据复制回 res 数组。

cudaDeviceSynchronize();

cudaMemcpy(d_res,
       res,
       data_width * data_height * sizeof(JSAMPLE),
       cudaMemcpyDeviceToHost); 

这应该是

cudaDeviceSynchronize();

cudaMemcpy(res,
       d_res,
       data_width * data_height * sizeof(JSAMPLE),
       cudaMemcpyDeviceToHost);

因为 cudaMemcpy 的第一个参数是目标指针。

cudaError_t cudaMemcpy  ( void *dst, const void *src, size_t count, enum cudaMemcpyKind kind)

【讨论】:

  • 是的,你是对的。感谢您的观察。
猜你喜欢
  • 2022-10-23
  • 1970-01-01
  • 1970-01-01
  • 2023-02-07
  • 2017-10-19
  • 2022-09-29
  • 1970-01-01
  • 2023-01-04
  • 2017-07-05
相关资源
最近更新 更多