Pyopencl用法

基本上没有资料,实践了很长时间才掌握基本用法。

官网示例

#! /usr/bin/env python3

import pyopencl as cl
import numpy as np

a_np = np.random.rand(10**7).astype(np.float32)
b_np = np.random.rand(10**7).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, r"""
__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)
knl = prg.sum  # Use this Kernel object for repeated calls
knl(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)))
assert np.allclose(res_np, a_np + b_np)

解析

Pyopencl程序的大概流程为:

1.通过pyopencl.create_some_context构建一个类似会话的对象ctx

2.基于ctx构建queue对象

3.以ctx为参数,用pyopencl.Buffer拷贝Python数据到显卡缓存中

4.以ctx为参数,通过pyopencl.Program(script).build()编译c语言,通过编译对象的属性获取c函数(如示例的prg.sum)

5.以queue为参数,运行c函数

6.以queue为参数,将结果从显存拷贝到Python数据结构中

 

参数含义

运行c函数时,需要在前面额外传入三个参数,如示例中的knl(prg.sum)函数,它们分别为:

  1. queue对象
  2. 需要启动的线程大小(一个元组,代表各维度的大小,最小为一维,如(100,))
  3. 未知

其中第二个参数如果大于实际使用的数量,会报错,因为后面的线程根据gid取的数据地址不存在,然而这不影响最终结果。

报错:找不到平台

在Windows下没安装任何平台,没有遇见过报错,然而在没有显卡的linux平台上,遇见了下面的报错:

pyopencl._cl.LogicError: clGetPlatformIDs failed: PLATFORM_NOT_FOUND_KHR

意思是找不到OpenCL能运行的环境。

有的机器能用python的oclgrind包作为虚拟环境,有的却不能,可能要安装英特尔的官方opencl驱动才能用。

 

posted @ 2023-01-30 13:35  小鱼圆又圆  阅读(801)  评论(0)    收藏  举报