1、对于python的基础介绍python
Python是一种高效的动态编程语言,普遍用于科学,工程和数据分析应用程序。。影响python普及的因素有不少,包括干净,富有表现力的语法和标准数据结构,全面的“电池包含”标准库,优秀的文档,普遍的图书馆和工具生态系统,专业支持的可用性以及大而开放社区。但也许最重要的是,像Python这样的动态类型化解释语言可以实现高效率。Python灵活灵活,使其成为快速原型设计的理想语言,同时也是构建完整系统的理想语言。
可是Python的最大优点也多是它最大的弱点:它的灵活性和无类型的高级语法可能致使数据和计算密集型程序的性能不佳。git
2、numba--高性能高效率的计算程序员
在这篇文章中,我将向您介绍Numba,一个来自Anaconda的Python编译器,能够编译Python代码,以便在支持CUDA的GPU或多核CPU上执行。因为Python一般不是编译语言,您可能想知道为何要使用Python编译器。答案固然是运行本机编译代码比运行动态解释代码快许多倍。 Numba容许您为Python函数指定类型签名,它能够在运行时进行编译(这是“即时”或JIT编译)。 Numba动态编译代码的能力意味着您不会放弃Python的灵活性。这是向高效率编程和高性能计算提供理想组合的重要一步。 github
使用Numba,如今能够编写标准的Python函数并在支持CUDA的GPU上运行它们。 Numba专为面向阵列的计算任务而设计,就像普遍使用的NumPy库同样。面向阵列的计算任务中的数据并行性很是适合GPU等加速器。 Numba了解NumPy数组类型,并使用它们生成有效的编译代码,以便在GPU或多核CPU上执行。所需的编程工做能够像添加函数装饰器同样简单,以指示Numba为GPU编译。例如,如下代码中的@vectorize装饰器在运行时生成标量函数Add的已编译矢量化版本,以便它可用于在GPU上并行处理数据数组编程
imort numpy as np from numba import vectorize @vectorize(['float32(float32, float32)'], target='cuda') def Add(a, b): return a + b # Initialize arrays N = 100000 A = np.ones(N, dtype=np.float32) B = np.ones(A.shape, dtype=A.dtype) C = np.empty_like(A, dtype=A.dtype) # Add arrays on GPU C = Add(A, B)
要在CPU上编译和运行相同的函数,咱们只需将目标更改成“cpu”,从而在CPU上编译的矢量化C代码级别上产生性能。 这种灵活性可帮助您生成更多可重用的代码,并容许您在没有GPU的计算机上进行开发。 后端
3、用于Python的GPU加速库
CUDA并行计算平台的优点之一是其普遍的GPU加速库。 Numba团队的另外一个名为pyculib的项目为CUDA cuBLAS(密集线性代数),cuFFT(快速傅立叶变换)和cuRAND(随机数生成)库提供了Python接口。 许多应用程序只需使用这些库就能够得到显着的加速,而无需编写任何特定于GPU的代码。 例如,如下代码使用“XORWOW”伪随机数生成器在GPU上生成一百万个均匀分布的随机数。数组
import numpy as np from pyculib import rand as curand prng = curand.PRNG(rndtype=curand.PRNG.XORWOW) rand = np.empty(100000) prng.uniform(rand) print rand[:10]
4、与CUDA Python的大规模并行性
Anaconda(前身为Continuum Analytics)认识到,在某些计算上实现大幅加速须要一个更具表现力的编程接口,对并行性的控制要比库和自动循环矢量化所能提供的更详细。 所以,Numba具备另外一组重要功能,能够构成非正式名称为“CUDA Python”的功能。 Numba公开CUDA编程模型,就像在CUDA C / C ++中同样,可是使用纯python语法,这样程序员就能够建立自定义的,调优的并行内核,而不会留下Python的温馨和优点。 Numba的CUDA JIT(可经过装饰器或函数调用得到)在运行时编译CUDA Python函数,专门针对您使用的类型,而且其CUDA Python API提供对数据传输和CUDA流的显式控制,以及其余功能服务器
下面的代码示例使用简单的Mandelbrot设置内核演示了这一点。 请注意,mandel_kernel函数使用Numba提供的cuda.threadIdx,cuda.blockIdx,cuda.blockDim和cuda.gridDim结构来计算当前线程的全局X和Y像素索引。 与其余CUDA语言同样,咱们经过在函数名称和参数列表之间插入一个“执行配置”(CUDA-表明用于运行内核的线程数和线程数)来启动内核:mandel_kernel [griddim,blockdim]( - 2.0,1.0,-1.0,1.0,d_image,20)。 您还能够看到使用to_host和to_device API函数将数据复制到GPU或从GPU复制数据。数据结构
@cuda.jit(device=True) def mandel(x, y, max_iters): """ Given the real and imaginary parts of a complex number, determine if it is a candidate for membership in the Mandelbrot set given a fixed number of iterations. """ c = complex(x, y) z = 0.0j for i in range(max_iters): z = z*z + c if (z.real*z.real + z.imag*z.imag) >= 4: return i return max_iters @cuda.jit def mandel_kernel(min_x, max_x, min_y, max_y, image, iters): height = image.shape[0] width = image.shape[1] pixel_size_x = (max_x - min_x) / width pixel_size_y = (max_y - min_y) / height startX = cuda.blockDim.x * cuda.blockIdx.x + cuda.threadIdx.x startY = cuda.blockDim.y * cuda.blockIdx.y + cuda.threadIdx.y gridX = cuda.gridDim.x * cuda.blockDim.x; gridY = cuda.gridDim.y * cuda.blockDim.y; for x in range(startX, width, gridX): real = min_x + x * pixel_size_x for y in range(startY, height, gridY): imag = min_y + y * pixel_size_y image[y, x] = mandel(real, imag, iters) gimage = np.zeros((1024, 1536), dtype = np.uint8) blockdim = (32, 8) griddim = (32,16) start = timer() d_image = cuda.to_device(gimage) mandel_kernel[griddim, blockdim](-2.0, 1.0, -1.0, 1.0, d_image, 20) d_image.to_host() dt = timer() - start print "Mandelbrot created on GPU in %f s" % dt imshow(gimage) On a server with an NVIDIA Tesla P100 GPU and an Intel Xeon E5-2698 v3 CPU, this CUDA Python Mandelbrot code runs nearly 1700 times faster than the pure Python version. 1700x may seem an unrealistic speedup, but keep in mind that we are comparing compiled, parallel, GPU-accelerated Python code to interpreted, single-threaded Py
在配备NVIDIA Tesla P100 GPU和Intel Xeon E5-2698 v3 CPU的服务器上,此CUDA Python Mandelbrot代码的运行速度比纯Python版快近1700倍。 1700x可能看起来不切实际,但请记住,咱们正在将编译的,并行的,GPU加速的Python代码与CPU上的解释的单线程Python代码进行比较。、编程语言
4、 当即开始使用Numba Numba为Python开发人员提供了一种轻松进入GPU加速计算的途径,以及使用日益复杂的CUDA代码并使用最少的新语法和术语的途径。您能够从简单的函数装饰器开始,自动编译您的函数,或使用pyculib公开的强大的CUDA库。随着您对并行编程概念的理解以及当您须要对并行线程进行表达和灵活控制时,CUDA可用,而无需您在第一天进入。 Numba是一个得到BSD许可的开源项目,它自己在很大程度上依赖于LLVM编译器的功能。 Numba的GPU后端使用基于LLVM的NVIDIA编译器SDK。 CUDA库周围的pyculib包装器也是开源和BSD许可的。 要开始使用Numba,第一步是下载并安装Anaconda Python发行版,这是一个“彻底免费的企业级Python发行版,用于大规模数据处理,预测分析和科学计算”,其中包括许多流行的软件包(Numpy, Scipy,Matplotlib,iPython等)和“conda”,一个强大的包管理器。安装Anaconda后,键入conda install numba cudatoolkit pyculib安装所需的CUDA软件包。而后在ContinuumIO github存储库上查看CumbA的Numba教程。我还建议您查看Anaconda博客上的Numba帖子。