В результате вычислений результат не получен

#c #image-processing #cuda #convolution

#c #обработка изображений #cuda #свертка

Вопрос:

Я пытаюсь свернуть изображение с помощью 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(amp;d_data,
                  data_width * data_height * sizeof(JSAMPLE));
cudaMemcpy(d_data,
           data,
           data_width * data_height * sizeof(JSAMPLE),
           cudaMemcpyHostToDevice);

float *d_kern;
cudaMallocManaged(amp;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(amp;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, таким образом, что доступ к пикселю в (i, j) осуществляется путем индексации в массив по адресу data_width * j i. данные ядра находятся в массиве с именем kern, и его ширина равна 2 * kern_w_f 1 и высота 2 * kern_h_f 1. Доступ к элементу в (i, j) осуществляется путем индексации в массив kern по адресу (2 * w_f 1) * j i, точно так же, как и к массиву данных. Массив res используется для хранения результата свертки и выделяется с помощью calloc() перед передачей функции.

Когда я вызываю вторую функцию для данных изображения, все пиксели изображения преобразуются в 0 вместо применения свертки. Кто-нибудь может указать на проблему?

Комментарии:

1. вы уверены, что CUDA действительно работает в вашей системе? Какую версию CUDA и какой графический процессор вы используете? Почему вы используете cudaMallocManaged() с cudamempy()?

2. Я использую Cuda версии 10.1.243. Графический процессор представляет собой мобильную версию GTX1060. Что касается того, действительно ли CUDA работает, я не уверен. Когда я запускаю его, это никоим образом не указывает мне, что что-то пошло не так. Может ли CUDA автоматически завершиться сбоем?

3. Если ваша версия cuda и драйвер не работают вместе должным образом, вполне возможно, что вы не получите предупреждение о том, что не найдено CUDA-устройство (поскольку вы не проверяете наличие ошибок cuda), и тогда ядро ничего не сделает. Итак, это больше о том, можете ли вы, например, запускать образцы cuda и получать там результаты.

4. еще одно наблюдение … после обработки данных с помощью графического процессора вы вызываете cudaMemcpy(d_res,res, ..), это должно быть cudaMemcpy(res, d_res, ..), Так как вам нужно перевернуть dest и src.

Ответ №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)
 

Комментарии:

1. Да, вы правы. Спасибо за замечание.