【问题标题】:CUDA Zeropadding 3D matrixCUDA Zeropadding 3D 矩阵
【发布时间】:2021-11-30 19:08:44
【问题描述】:

我有一个大小为 100x200x800 的整数矩阵,它以 100*200*800 的平面向量存储在主机上,也就是说,我有

int* h_data = (int*)malloc(sizeof(int)*100*200*800);

在设备 (GPU) 上,我想用零填充每个维度,以便获得大小为 128x256x1024 的矩阵,分配如下:

int *d_data;
cudaMalloc((void**)&d_data, sizeof(int)*128*256*1024);

获得零填充矩阵的最佳方法是什么?我有两个想法:

  1. 遍历主机上的各个子矩阵并将它们直接复制到设备上的正确位置。
    • 这种方法需要多次cudaMemcpy 调用,因此可能非常慢
  2. 在设备上,为 100x200x800 矩阵和 128x256x1024 矩阵分配内存,并编写一个内核,将样本复制到正确的内存空间
    • 这种方法可能要快得多,但需要为设备上的两个矩阵分配内存

有没有类似于 MATLAB 的三维矩阵索引的可能性?在 MATLAB 中,我可以简单地执行以下操作:

h_data = rand(100, 200, 800);
d_data = zeros(128, 256, 1024);
d_data(1:100, 1:200, 1:800) = h_data;

或者,如果我使用cudaMemcpy(d_data, h_data, sizeof(int)*100*200*800, cudaMemcpyHostToDevice); 将数据复制到设备,是否可以重新排序数据,这样我就不必为第二个矩阵分配内存,也许使用cudaMemcpy3DcudaMemset3D

【问题讨论】:

  • 第一个问题的答案完全取决于GPU上的计划使用:你将如何寻址数组(稀疏、线性等),你将读取和写入多少次等等。
  • 我想使用 cuFFT 库对零填充矩阵执行 FFT 并将数据复制回主机。这应该在流上连续执行,即,一旦计算出 FFT,就应该处理下一个矩阵。我是 CUDA 新手,找不到任何有关稀疏或线性内存的信息。矩阵本身并不稀疏。我希望这些信息对您有所帮助。
  • 对于我能想到的大多数考虑因素,第二种方法是首选。此处的额外分配大小为 64MB。那是个问题?不,您不能使用 matlab 样式的矩阵切片表示法来引用或填充 C++ 中的矩阵,这是 CUDA 所基于的。

标签: c++ matrix cuda zero-padding


【解决方案1】:

根据您的假设,您可以使用cudaMemcpy3D 进行此操作。基本上:

  1. 正常分配设备阵列
  2. 使用cudaMemset 将其归零
  3. 使用cudaMemcpy3D 对从主机源到设备目标阵列的选定子阵列执行从主机到设备的线性内存复制。

cudaMemcpy3D API 有点巴洛克式的,神秘的文档记录,并且为初学者提供了一些常见的陷阱。基本上,线性内存传输需要一个指向源和目标的指针,以及一个表示传输大小的范围。令人困惑的部分是参数含义会根据源和/或目标内存是 CUDA 数组还是倾斜线性内存而改变。在代码中你会想要这样的东西:

int hw = 100, hh = 200, hd = 800; 
size_t hpitch = hw * sizeof(int);
int* h_data = (int*)malloc(hpitch * hh * hd);

int dw = 128, dh = 256, dd = 1024;
size_t dpitch = dw * sizeof(int);
int *d_data; 
cudaMalloc((void**)&d_data, dpitch * dh * dd);
cudaMemset(d_data, 0, dpitch * dh * dd);

cudaPitchedPtr src = make_cudaPitchedPtr(h_data, hpitch, hw, hh);    ​
​cudaPitchedPtr dst = make_cudaPitchedPtr(d_data, dpitch, dw, dh);

cudaExtent copyext = make_cudaExtent(hpitch, hh, hd);

​‎cudaMemcpy3DParms copyparms = {0};
​copyparms.srcPtr = src;
​copyparms.dstPtr = dest;
copyparms.extent = copyext;
copyparms.kind = cudaMemcpyHostToDevice;

cudaMemcpy3D(&copyparms);

[注意:全部在浏览器中完成,绝不编译或运行使用风险自负]

【讨论】:

  • 非常感谢。这正是我想要的。您可以编辑您的答案并将copyparms.desPtr 更改为copyparms.dstPtr。其他一切都立即生效。
【解决方案2】:

有没有类似MATLAB的三维矩阵索引的可能性?

这可以使用更高级别的库来实现,例如libtorch。例如,

    d_data(1:100, 1:200, 1:800) = h_data

libtorch 变成类似

    d_data.index_put_({Slice(0, 100), Slice(0, 200), Slice(0, 800)}, h_data)

(MATLAB 使用从 1 开始的索引)。

可能还有其他 C++ 库可以执行此操作,但这是我所知道的。


另一方面,如果创建一个 0 填充的 3D 数组是您的唯一目标,那么添加对另一个库的依赖项可能不值得。这个狭窄的目标可以通过主机上的三重循环或设备上的等效内核来实现。

【讨论】:

  • 请解释一下dv。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-16
  • 2013-12-27
  • 1970-01-01
  • 2022-06-30
  • 1970-01-01
  • 2012-04-12
相关资源
最近更新 更多