【发布时间】:2018-05-02 20:15:32
【问题描述】:
我正在开发一个基于 ROS 的管道,其主要功能是订阅图像主题并连续执行特征检测、匹配等功能。为了使这个管道更快,我尝试使用基于 CUDA 的检测和匹配模块作为我的包的一部分。在这个问题的上下文中,我假设一个简单的管道,我订阅一个图像主题,并且在每次图像可用时调用的订阅者回调中,调用不同类的两个成员函数:一个用于检测,另一个匹配,每个都包含自己的 CUDA 内核。有点类似于循环执行这两个函数。
第一个函数获取图像数据并计算特征关键点和描述符,然后将它们返回给主机。然后我将这些描述符复制回 GPU 内存,我需要将它们与属于参考图像的另一组描述符进行匹配。
例如,独立匹配函数如下所示:
// Detection module returns a struct featureData, containing keypoints and descriptors
// in featureData.kps and featureData.desc
uint64_t* d_desc;
cudaMalloc(&d_desc, 64 * featureData.kps.size());
cudaMemcpy(d_desc, &featureData., 64 * (featureData.kps.size()), cudaMemcpyHostToDevice);
cudaDeviceSetCacheConfig(cudaFuncCachePreferL1);
cudaDeviceSetSharedMemConfig(cudaSharedMemBankSizeEightByte);
// Create texture object for descriptors
struct cudaResourceDesc resDesc;
memset(&resDesc, 0, sizeof(resDesc));
resDesc.resType = cudaResourceTypeLinear;
resDesc.res.linear.devPtr = d_desc;
resDesc.res.linear.desc.f = cudaChannelFormatKindUnsigned;
resDesc.res.linear.desc.x = 32;
resDesc.res.linear.desc.y = 32;
resDesc.res.linear.sizeInBytes = 64 * featureData.kps.size();
struct cudaTextureDesc texDesc;
memset(&texDesc, 0, sizeof(texDesc));
texDesc.addressMode[0] = cudaAddressModeBorder;
texDesc.addressMode[1] = cudaAddressModeBorder;
texDesc.filterMode = cudaFilterModePoint;
texDesc.readMode = cudaReadModeElementType;
texDesc.normalizedCoords = 0;
cudaTextureObject_t tex_q = 0;
cudaCreateTextureObject(&tex_q, &resDesc, &texDesc, nullptr);
// Allocate space for match results
int* d_matches;
cudaMalloc(&d_matches, 4 * featureData.kps.size());
// Launch the matching kernel
CUDAmatch(d_descRef, static_cast<int>(refData.kps.size()), tex_q, static_cast<int>(featureData.kps.size()), d_matches, threshold);
// d_descRef is memory pointed to by a uint64_t* for the reference descriptors.
在这种情况下,我有几个问题,因为这是我第一次涉足基于 GPU 的开发。
- 当需要执行匹配时,描述符等被复制到设备内存中,然后将结果复制回来。我是否应该在每次执行匹配后释放这些设备内存指针并在下一个回调中重新分配(
cudaMalloc())?描述符的长度将根据检测到的特征数量而变化。或者有没有更有效的方法来只分配一次内存并重用它? - 检测和匹配函数还使用
cudaResourceDesc和cudaTextureDesc等对象,这些对象将在每次执行结束时超出范围,因此应该被销毁。我应该以任何其他特定方式处理它们吗? - 我假设在执行这两个函数后我需要
cudaDeviceSynchronize()。我说的对吗? - 我能否安全地将“参考”描述符保留在 GPU 内存中,仅在需要时更新它们?
【问题讨论】: