PycUDA --入门

PycUDA --入门

导入并初始化

import pycuda.driver as cuda
import pycuda.autoinit
from pycuda.compiler import SourceModule`

示例:

传输数据

import numpy
a = numpy.random.randn(4,4)

a 由双精度数字组成,但大多数nvidia设备只支持单精度:

a = a.astype(numpy.float32)

在设备上分配内存:

a_gpu = cuda.mem_alloc(a.nbytes)

将数据传输到GPU:

cuda.memcpy_htod(a_gpu, a)

执行内核

编写相应的CUDAC代码,并将其输入pycuda.compiler.SourceModule ::

mod = SourceModule("""
  __global__ void doublify(float *a)
  {
    int idx = threadIdx.x + threadIdx.y*4;
    a[idx] *= 2;
  }
  """)

编译并加载到设备上,pycuda.driver.Function 调用它,指定 a_gpu 作为参数,块大小为4x4::

func = mod.get_function("doublify")
func(a_gpu, block=(4,4,1))

从gpu取回数据并将其与原始数据一起显示 a

a_doubled = numpy.empty_like(a)
cuda.memcpy_dtoh(a_doubled, a_gpu)

显式内存副本的快捷方式
pycuda.driver.In , pycuda.driver.Out 和 pycuda.driver.InOut 参数处理程序可以简化一些内存传输
例如,不是 a_gpu ,直接替换 a

func(cuda.InOut(a), block=(4, 4, 1))

使用内置的函数调用 pycuda.driver.Function.__call__() 方法导致类型标识的开销(请参见 设备接口 )为了获得与上面相同的效果而不产生这种开销,函数被绑定到参数类型(由python的标准库指定 struct 模块),然后调用。

grid = (1, 1)
block = (4, 4, 1)
func.prepare("P")
func.prepared_call(grid, block, a_gpu)

使用 pycuda.gpuarray.GPUArray 同样的效果可以用更少的代码来实现:

import pycuda.gpuarray as gpuarray
import pycuda.driver as cuda
import pycuda.autoinit
import numpy

a_gpu = gpuarray.to_gpu(numpy.random.randn(4,4).astype(numpy.float32))
a_doubled = (2*a_gpu).get()
print a_doubled
print a_gpu

struct

假设我们有以下struct:

mod = SourceModule("""
    struct DoubleOperation {
        int datalen, __padding; // so 64-bit ptrs can be aligned
        float *ptr;
    };

    __global__ void double_array(DoubleOperation *a) {
        a = &a[blockIdx.x];
        for (int idx = threadIdx.x; idx < a->datalen; idx += blockDim.x) {
            a->ptr[idx] *= 2;
        }
    }
    """)

网格中的每个块(参见CUDA文档)将使其中一个数组加倍。这个 for 循环允许更多的数据元素比线程加倍,虽然效率不高,如果可以保证有足够数量的线程。接下来,创建结构的包装类,并实例化两个数组:

class DoubleOpStruct:
    mem_size = 8 + numpy.intp(0).nbytes
    def __init__(self, array, struct_arr_ptr):
        self.data = cuda.to_device(array)
        self.shape, self.dtype = array.shape, array.dtype
        cuda.memcpy_htod(int(struct_arr_ptr), numpy.getbuffer(numpy.int32(array.size)))
        cuda.memcpy_htod(int(struct_arr_ptr) + 8, numpy.getbuffer(numpy.intp(int(self.data))))
    def __str__(self):
        return str(cuda.from_device(self.data, self.shape, self.dtype))

struct_arr = cuda.mem_alloc(2 * DoubleOpStruct.mem_size)
do2_ptr = int(struct_arr) + DoubleOpStruct.mem_size

array1 = DoubleOpStruct(numpy.array([1, 2, 3], dtype=numpy.float32), struct_arr)
array2 = DoubleOpStruct(numpy.array([0, 4], dtype=numpy.float32), do2_ptr)
print("original arrays", array1, array2)

此代码使用 pycuda.driver.to_device() 和 pycuda.driver.from_device() 分配和复制值的功能,并演示如何使用分配内存块的偏移量。最后,代码可以被执行;下面演示了将两个数组加倍,然后只有第二个:

func = mod.get_function("double_array")
func(struct_arr, block = (32, 1, 1), grid=(2, 1))
print("doubled arrays", array1, array2)

func(numpy.intp(do2_ptr), block = (32, 1, 1), grid=(1, 1))
print("doubled second only", array1, array2, "\n")

参考:https://www.osgeo.cn/pycuda/tutorial.html

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值