python - PyCuda 中 3D 数组的就地转置

标签 python numpy multidimensional-array cuda pycuda

我有一个 3D 数组,想要转置它的前两个维度 (x 和 y),但不想转置第三个维度 (z)。在 3D 数组 A 上,我想要与 numpy 的 A.transpose((1,0,2)) 相同的结果。具体来说,我想获取“转置”全局threadIdx。下面的代码应该在 3D 数组 A 中的未转置位置写入转置索引。但事实并非如此。

有什么建议吗?

import numpy as np
from pycuda import compiler, gpuarray
import pycuda.driver as cuda
import pycuda.autoinit

kernel_code = """
__global__ void test_indexTranspose(uint*A){
    const size_t size_x = 4;
    const size_t size_y = 4;
    const size_t size_z = 3;

    // Thread position in each dimension
    const size_t tx = blockDim.x * blockIdx.x + threadIdx.x;
    const size_t ty = blockDim.y * blockIdx.y + threadIdx.y;
    const size_t tz = blockDim.z * blockIdx.z + threadIdx.z;

    if(tx < size_x && ty < size_y && tz < size_z){
        // Flat index
        const size_t ti = tz * size_x * size_y + ty * size_x + tx;
        // Transposed flat index
        const size_t tiT = tz * size_x * size_y + tx * size_x + ty;
        A[ti] = tiT;
    }
}
"""

A = np.zeros((4,4,3),dtype=np.uint32)
mod = compiler.SourceModule(kernel_code)
test_indexTranspose = mod.get_function('test_indexTranspose')
A_gpu = gpuarray.to_gpu(A)
test_indexTranspose(A_gpu, block=(2, 2, 1), grid=(2,2,3))

这是返回的内容(不是我期望的):

A_gpu.get()[:,:,0]
array([[ 0, 12,  9,  6],
       [ 3, 15, 24, 21],
       [18, 30, 27, 36],
       [33, 45, 42, 39]], dtype=uint32)

A_gpu.get()[:,:,1]
array([[ 4,  1, 13, 10],
       [ 7, 16, 28, 25],
       [22, 19, 31, 40],
       [37, 34, 46, 43]], dtype=uint32)

A_gpu.get()[:,:,2]
array([[ 8,  5,  2, 14],
       [11, 20, 17, 29],
       [26, 23, 32, 44],
       [41, 38, 35, 47]], dtype=uint32)

这是我所期望的(但没有返回):

A_gpu.get()[:,:,0]
array([[0, 4, 8,  12],
       [1, 5, 9,  13],
       [2, 6, 10, 14],
       [3, 7, 11, 15]], dtype=uint32)

A_gpu.get()[:,:,1]
array([[16, 20, 24, 28],
       [17, 21, 25, 29],
       [18, 22, 26, 30],
       [19, 23, 27, 31]], dtype=uint32)

A_gpu.get()[:,:,2]
...

谢谢

最佳答案

使用与 CUDA 内核代码一致的步幅创建 numpy 数组可以解决该问题。 numpy 数组的默认布局不是我的内核假设的行、列、深度。但是,可以在创建数组时设置步幅。
如果像这样创建数组,上面的内核可以正常工作:

nRows = 4
nCols = 4
nSlices = 3
nBytes = np.dtype(np.uint32).itemsize
A = np.ndarray(shape=(nRows, nCols, nSlices), 
               dtype=np.uint32, 
               strides=(nCols*nBytes, 1*nBytes, nCols*nRows*nBytes))

步幅是每个维度(以字节为单位)所需的内存连续索引的跳转。例如。从第 1 行第一个元素到第 2 行第一个元素有 nCols * nBytes,即 16 个字节。

关于python - PyCuda 中 3D 数组的就地转置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32127536/

相关文章:

python - 如何聚合 pandas 系列的值

Python:矩阵的非对角线元素为0

arrays - 寻找所有最大的序列

c# - 调整和初始化二维数组 C#

JQuery 多维数组或对象或其他方法?

python - 如何从 pandas 的列中删除列表中的字符串

python - 在 Pytorch 中计算 4D 张量的一个特定维度的平均值

python - 如果存在空白值,如何从两个文件中读入、插入新列以及计算平均值等函数?

python - 使用 numpy 数组和元组保持每个元素出现一次的快速方法

python - 使用python处理和创建外部软件的输入文件