使用 Python 写 CUDA 程序有两种方式:
现在已经不推荐使用了,功能被拆分并分别被集成到和 Numba 了。
Numba 通过及时编译机制(JIT)优化 Python 代码,Numba 可以针对本机的硬件环境进行优化,同时支持 CPU 和 GPU 的优化,并且可以和 Numpy 集成,使 Python 代码可以在 GPU 上运行,只需在函数上方加上相关的指令标记,如下所示:
- import numpy as np from timeit import default_timer as timer from numba import vectorize@vectorize(["float32(float32, float32)"], target = 'cuda') def vectorAdd(a, b) : return a + b def main() : N = 320000000 A = np.ones(N, dtype = np.float32) B = np.ones(N, dtype = np.float32) C = np.zeros(N, dtype = np.float32) start = timer() C = vectorAdd(A, B) vectorAdd_time = timer() - start print("c[:5] = " + str(C[: 5])) print("c[-5:] = " + str(C[ - 5 : ])) print("vectorAdd took %f seconds " % vectorAdd_time) if __name__ == '__main__': main()
PyCUDA 的内核函数(kernel)其实就是使用 C/C++ 编写的,通过动态编译为 GPU 微码,Python 代码与 GPU 代码进行交互,如下所示:
- import pycuda.autoinit import pycuda.driver as drv import numpy as np from timeit import default_timer as timer from pycuda.compiler import SourceModule mod = SourceModule("""
- __global__ void func(float *a, float *b, size_t N)
- {
- const int i = blockIdx.x * blockDim.x + threadIdx.x;
- if (i >= N)
- {
- return;
- }
- float temp_a = a[i];
- float temp_b = b[i];
- a[i] = (temp_a * 10 + 2 ) * ((temp_b + 2) * 10 - 5 ) * 5;
- // a[i] = a[i] + b[i];
- }
- """) func = mod.get_function("func") def test(N) : #N = 1024 * 1024 * 90#float: 4M = 1024 * 1024 print("N = %d" % N) N = np.int32(N)
- a = np.random.randn(N).astype(np.float32) b = np.random.randn(N).astype(np.float32)#copy a to aa aa = np.empty_like(a) aa[: ] = a#GPU run nTheads = 256 nBlocks = int((N + nTheads - 1) / nTheads) start = timer() func(drv.InOut(a), drv.In(b), N, block = (nTheads, 1, 1), grid = (nBlocks, 1)) run_time = timer() - start print("gpu run time %f seconds " % run_time)#cpu run start = timer() aa = (aa * 10 + 2) * ((b + 2) * 10 - 5) * 5 run_time = timer() - start print("cpu run time %f seconds " % run_time)#check result r = a - aa print(min(r), max(r)) def main() : for n in range(1, 10) : N = 1024 * 1024 * (n * 10) print("------------%d---------------" % n) test(N) if __name__ == '__main__': main()
numba 使用一些指令标记某些函数进行加速(也可以使用 Python 编写内核函数),这一点类似于 OpenACC,而 PyCUDA 需要自己写 kernel,在运行时进行编译,底层是基于 C/C++ 实现的。通过测试,这两种方式的加速比基本差不多。但是,numba 更像是一个黑盒,不知道内部到底做了什么,而 PyCUDA 就显得很直观。因此,这两种方式具有不同的应用:
来源: http://www.cnblogs.com/5long/p/python-cuda.html