由于读研期间需要用并行实现图像预处理,然后用深度学习的模型进行进一步处理,所以需要实现python和cuda的交互,就会用到一个很重要的库pycuda。
大部分内容参考 https://zhuanlan.zhihu.com/p/32062796?utm_source=qq&utm_medium=social
共享存储器:每个线程块(block)都有独立的共享内存,block与Block之间不能相互通信,同一个block中的threads可以通过共享内存进行通信。使用pycuda将数据放进共享内存时,格式如 __shared__ float gpu[64];,需要提前计算好共享内存的大小,相当于为该block中的每个thread都创建了一个64维的矩阵,然后计算机就会将该线程所需要的数据提前放进该矩阵中。
在使用PyCuda的时候,原始数据都是以NumPy数组的形式存储在宿主系统(host)中的。大多数常用的NVIDIA显卡只支持单精度浮点数,输入的数组必须是float32型,输入全局存储器中的变量必须是int32型的。
PyCuda提供了pycuda.driver.In, pycuda.driver.Out, 以及pycuda.driver.InOut 这三个参数处理器(argument handlers),能用来简化内存和显存之间的数据拷贝。例如,咱们可以不去创建一个a_gpu,而是直接把a移动过去,下面的代码就可以实现:
func(cuda.InOut(a), block=(4, 4, 1))
使用内置的 pycuda.driver.Function.call() 方法来进行的函数调用,会增加类型识别的资源开销(参考显卡接口)。 要实现跟上面代码同样的效果,又不造成这种开销,这个函数就需要设定好参数类型(如Python的标准库中的结构体模块struct所示),然后再去调用该函数。这样也就不用需要再使用numpy.number类去制定参数的规模了:
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