使用GPU加速Python应用
1. APU性能概述
APU在提升程序性能方面具有巨大潜力。随着数组元素数量线性增长,使用HSA(异构系统架构)的性能提升几乎呈指数级,直到达到约11倍加速比,之后增速变为线性,最终稳定在15 - 18倍加速比。
2. Anaconda的Accelerate包
Anaconda的Accelerate包可让我们充分利用英特尔CPU和英伟达GPU的卓越性能。它是Anaconda包的附加组件,具有以下特点:
- 绑定多个CUDA库,如DV#-“4、DV’‘5等。
- 使用英特尔数学核心库加速/VN1Z、4DJ1Z、TDJLJUMFBSO和/VN&YQS库中的线性代数运算。
- 加速NumPy内置通用函数(UFuncs)的变体。
- 提高NumPy中快速傅里叶变换(FFT)的速度。
该包专为处理大型数据集而设计,但其官方文档目前较为简略,可查看 文档链接 。
3. Theano库
Theano是一个Python库,非常适合处理多维数组,如NumPy的ndarrays,并且在这方面表现出色。它依赖GPU提供远超典型CPU上C语言的性能。
3.1 安装要求
- Python版本为2.7或大于3.3且小于3.6。
- 安装NumPy和SciPy。
完整的要求列表可查看 官方文档 。
3.2 入门示例
以下是一些简单的示例代码,展示了Theano的基本用法。
简单加法示例 :
from theano import *
import numpy
import theano.tensor as T
x = T.dscalar('x')
y = T.dscalar('y')
z = x + y
f = function([x, y], z)
print(f(2, 3))
运行上述代码,输出结果为 5.0 。
矩阵相加示例 :
from theano import *
import numpy
import theano.tensor as T
x = T.dmatrix('x')
y = T.dmatrix('y')
z = x + y
f = function([x, y], z)
print(f([[2, 3], [4, 5]], [[2, 3], [4, 5]]))
运行该代码,输出结果为:
[[ 4. 6.]
[ 8. 10.]]
3.3 全类型构造函数
Theano库有丰富的 TensorType ,从表示最基本单位的标量到向量、矩阵、行和列以及张量对象等。完整列表可查看 官方文档 ,这对计算建模很有帮助。
3.4 在GPU上使用Theano
Theano旨在让开发者无需关注计算模型的复杂细节,可编写依赖强大硬件的简单代码。目前,它提供两种启用GPU的方法:
- 更开放的方法:设置 device 配置标志为 CUDA ,示例命令如下:
$ THEANO_FLAGS='device=cuda' python3.6 04_gpu.py
- 较旧且兼容性较低的方法:设置
device=gpu,示例命令如下:
$ THEANO_FLAGS='device=gpu’ python3.6 04_gpu.py
GPU使用示例代码 :
from theano import function, config, shared, tensor
import numpy
import time
wl = 20 * 30 * 784 # 20 cores * 30 threads per core
iters = 1000
rng = numpy.random.RandomState(11)
x = shared(numpy.asarray(rng.rand(wl), config.floatX))
f = function([], tensor.exp(x))
print(f.maker.fgraph.toposort())
t0 = time.time()
for i in range(iters):
r = f()
t1 = time.time()
print("Looping %d times took %f seconds" % (iters, t1 - t0))
print("Result is %s" % (r,))
if numpy.any([isinstance(x.op, tensor.Elemwise) and ('Gpu' not in type(x.op).__name__) for x in f.maker.fgraph.toposort()]):
print('Used the cpu')
else:
print('Used the gpu')
直接运行上述代码,默认使用CPU,若要使用GPU,可按上述方法设置 THEANO_FLAGS 。
3.5 利用多个GPU
Theano支持并行使用多个GPU,但这是该库的实验性功能,可能会导致程序结果出现异常。
定义上下文映射 :
需要先映射每个设备,格式为上下文名称加上 和设备名称,如 cuda0 等。示例命令如下:
$ THEANO_FLAGS='contexts=dev1, cuda1;dev2, cuda2' python -c 'import theano'
简单图形示例 :
import numpy
import theano
w12 = theano.shared(numpy.random.random((2016, 2016)).astype('float32'), target='dev1')
w11 = theano.shared(numpy.random.random((2016, 2016)).astype('float32'), target='dev1')
w22 = theano.shared(numpy.random.random((2016, 2016)).astype('float32'), target='dev2')
w21 = theano.shared(numpy.random.random((2016, 2016)).astype('float32'), target='dev2')
f = theano.function([], [theano.tensor.dot(w12, w11), theano.tensor.dot(w22, w21)])
f()
使用两个不同设备运行此代码,执行速度会有线性提升。若没有多个显卡,也可将多个上下文映射到一个设备,使用以下命令:
THEANO_FLAGS=”contexts=dev0->cuda0;dev1->cuda0” python myApp.py
4. PyOpenCL库
OpenCL是一种用于异构计算的低级API,运行在CUDA驱动的GPU上。PyOpenCL是该API的Python实现,可让我们编写利用CPU、GPU、DSP和FPGA等多种平台的Python应用程序。
4.1 示例代码
from __future__ import absolute_import, print_function
import numpy as np
import pyopencl as cl
a_np = np.random.rand(40000).astype(np.float32)
b_np = np.random.rand(40000).astype(np.float32)
ctx = cl.create_some_context()
queue = cl.CommandQueue(ctx)
mf = cl.mem_flags
a_g = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=a_np)
b_g = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=b_np)
prg = cl.Program(ctx, """
__kernel void sum(
__global const float *a_g, __global const float *b_g, __global float *res_g) {
int gid = get_global_id(0);
res_g[gid] = a_g[gid] + b_g[gid];
}
""").build()
res_g = cl.Buffer(ctx, mf.WRITE_ONLY, a_np.nbytes)
prg.sum(queue, a_np.shape, None, a_g, b_g, res_g)
res_np = np.empty_like(a_np)
cl.enqueue_copy(queue, res_np, res_g)
# Check on CPU with Numpy:
print(res_np - (a_np + b_np))
print(np.linalg.norm(res_np - (a_np + b_np)))
运行上述代码时,程序会提示选择运行代码的平台和设备。例如:
$ python3.6 06_example.py
Choose platform:
[0] <pyopencl.Platform 'Apple' at 0x7fff0000>
Choice [0]:0
Choose device(s):
[0] <pyopencl.Device 'Intel(R) Core(TM) i5-4288U CPU @ 2.60GHz' on 'Apple' at 0xffffffff>
[1] <pyopencl.Device 'Iris' on 'Apple' at 0x1024500>
Choice, comma-separated [0]:1
Set the environment variable PYOPENCL_CTX='0:1' to avoid being asked again.
[ 0. 0. 0. ..., 0. 0. 0.]
0.0
以下是使用Theano和PyOpenCL的流程对比表格:
| 库 | 安装要求 | 使用步骤 | 特点 |
| — | — | — | — |
| Theano | Python 2.7或3.3 - 3.6,NumPy和SciPy | 定义变量、构建函数、设置设备标志 | 抽象计算模型,支持多GPU |
| PyOpenCL | 无特殊Python版本要求 | 创建上下文、命令队列、程序对象 | 支持多种计算平台 |
mermaid流程图展示使用Theano在GPU上运行程序的流程:
graph TD;
A[开始] --> B[安装Theano及依赖];
B --> C[编写Theano代码];
C --> D{是否使用GPU};
D -- 是 --> E[设置THEANO_FLAGS];
D -- 否 --> F[直接运行代码];
E --> F;
F --> G[输出结果];
G --> H[结束];
5. 未详细介绍的库
5.1 PyGPU
PyGPU是一个值得深入研究的库,它专为图像处理需求而设计。与其他基于GPU的库一样,它抽象了处理底层GPU API的复杂性,以实现极高的速度。它是Python中的嵌入式语言,具备Python的大多数核心特性,如高阶函数、迭代器和列表推导式,专门为方便构建GPU算法而设计。
官方文档可查看: PyGPU官方文档
5.2 事件驱动和响应式库
- Tornado
Tornado是一个Python Web框架和异步网络库,它利用非阻塞网络I/O,能够扩展到数万个连接。其官方文档可查看: Tornado官方文档
一个简单的Hello World应用示例代码如下:
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
- Flask
Flask与Tornado类似,但它自认为是一个微框架,其API更简单易用。使用Flask实现相同功能只需五行代码。
一个简单的Flask应用示例代码如下:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello World!'
官方文档可查看: Flask官方文档
以下是Tornado和Flask的对比表格:
| 库 | 类型 | 特点 | 示例代码复杂度 |
| — | — | — | — |
| Tornado | Web框架和异步网络库 | 利用非阻塞I/O,可扩展到大量连接 | 相对复杂 |
| Flask | 微框架 | API简单易用 | 非常简单 |
mermaid流程图展示选择合适库的流程:
graph TD;
A[开始] --> B{需求类型};
B -- 图像处理 --> C[考虑PyGPU];
B -- Web开发 --> D{性能需求};
D -- 高并发 --> E[Tornado];
D -- 简单开发 --> F[Flask];
C --> G[查看文档并使用];
E --> G;
F --> G;
G --> H[结束];
总结
本文介绍了多种使用GPU加速Python应用的方法和相关库。从APU的性能特点,到Anaconda的Accelerate包对英特尔CPU和英伟达GPU性能的利用,再到Theano库在处理多维数组和利用GPU方面的强大功能,以及PyOpenCL对多种计算平台的支持。同时,还提及了未详细介绍的PyGPU、Tornado和Flask等库。通过这些库和方法,开发者可以根据不同的需求和场景,选择合适的工具来加速Python应用,提高程序性能。在实际应用中,需要根据具体的任务和硬件环境,综合考虑各库的特点和优势,以达到最佳的加速效果。
超级会员免费看

被折叠的 条评论
为什么被折叠?



