PyOpenCL Installation on Windows

Windows系统下安装PyOpenCL

挣脱CUDA

两年多以前,我翻译了PyCUDA Tutorial 的中文版,还建立了一个Github Repo.但后来一直忙其他事情,也没跟得上更新进度.

CUDA确实很美好,但从Titan X开始就眼看着老黄将双精度浮点数(Float Point 64bit,缩写为FP64)砍到没法用,让我这样买不起Tesla的人很无奈.虽然还有初代白泰坦的1.3 ~ 1.5 TFLOPS的FP64,但毕竟显卡核心时代久远,目前存世的良品有限,且功耗感人.

反观AMD阵营,根据维基百科上面的AMD显卡核心页面的数据,RX580 有385.9GFLOPS的FP64, 而 Vega64 有792GFLOPS的FP64,虽然不是很高,但总算能用.

为了双精度,只能尝试挣脱CUDA的束缚,试试OpenCL了.

PyOpenCL

由于我这种外行人没有雄厚的代码实力,只会一点基础的 Python,就只能选择 PyOpenCL 了.

PyOpenCL 的官网在 https://mathema.tician.de/software/pyopencl/. 其安装指南内容非常繁多,新人看上去可能会一时半会摸不着头脑.至少我是懵了好一阵.

最近在外远游,随身用的是一台Windows工作站,我就尝试在Windows下安装一下,将安装过程记录下来供参考.

根据硬件平台查询支持的OpenCL版本

我这台机器上用的是NVIDIA 1050显卡,本来我想着这既然是比较新世代的10系卡,肯定是支持最新版本的OpenCL2.2,结果下载了二进制文件之后才发现不兼容.所以大家一定要先查清楚自己所用的设备支持的OpenCL版本!

Intel 核显

访问维基百科上面的Intel显示核心页面可以根据处理器或者核显型号来搜索到在对应的操作系统上所支持的OpenCL版本,有的设备在Windows下支持到2.0,Linux却只支持到1.2;有的设备则反过来,在Linux支持到2.0,在Windows下支持到1.2.

如果你同时也使用另外一个独立显卡,建议选择二者中更低版本的,似乎是高版本兼容的设备应该能够支持低版本的OpenCL.

AMD 用户

如果你使用的是AMD的核显或者独显,可以参考维基百科上面的AMD显卡核心页面上面列出的OpenCL版本支持信息,或者可以从AMD官网查一查.

NVIDIA 用户

访问NVIDIA OpenCL这个站点,下载OpenCL Device Query:

Win64 版本下载链接

Win32 版本下载链接

下载之后解压缩,从中找到任意的一个名字叫做oclDeviceQuery.exe的可执行文件,双击运行,会在同一目录下生成一个名为oclDeviceQuery.txt的文件.用记事本等编辑器打开这个文件,从其中查找关键词CL_PLATFORM_VERSION,后面就会有版本信息.

我的这台机器上的版本信息为:

OpenCL SW Info:

 CL_PLATFORM_NAME:  NVIDIA CUDA
 CL_PLATFORM_VERSION:   OpenCL 1.2 CUDA 10.0.132
 OpenCL SDK Revision:   7027912


OpenCL Device Info:

 1 devices found supporting OpenCL:

 ---------------------------------
 Device GeForce GTX 1050
 ---------------------------------
  CL_DEVICE_NAME:           GeForce GTX 1050
  CL_DEVICE_VENDOR:             NVIDIA Corporation
  CL_DRIVER_VERSION:            417.71
  CL_DEVICE_VERSION:            OpenCL 1.2 CUDA
  CL_DEVICE_OPENCL_C_VERSION:       OpenCL C 1.2 
  CL_DEVICE_TYPE:           CL_DEVICE_TYPE_GPU
  CL_DEVICE_MAX_COMPUTE_UNITS:      5
  CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS:   3
  CL_DEVICE_MAX_WORK_ITEM_SIZES:    1024 / 1024 / 64 
  CL_DEVICE_MAX_WORK_GROUP_SIZE:    1024
  CL_DEVICE_MAX_CLOCK_FREQUENCY:    1493 MHz
  CL_DEVICE_ADDRESS_BITS:       64
  CL_DEVICE_MAX_MEM_ALLOC_SIZE:     1024 MByte
  CL_DEVICE_GLOBAL_MEM_SIZE:        4096 MByte

很明显,只支持OpenCL1.2,这么悲剧.

下载编译好的二进制安装文件

在确定了所用显卡支持的OpenCL版本后,到https://www.lfd.uci.edu/~gohlke/pythonlibs下载和OpenCL版本以及Python版本/操作系统版本都对应的whl文件.

例如,如上文所述,我的1050显卡支持的OpenCL版本是1.2,我的Python版本是3.7,我的操作系统是64bit的Windows,那么就下载pyopencl-2018.2.2+cl12-cp37-cp37m-win_amd64.whl.

这里面的cl12的意思就是OpenCL1.2,cp37表示的应该是Python3.7,win_amd64表示是64位Windows.

大家一定要先确定你的OpenCL版本/Python版本/Windows版本,然后找好对应的whl文件下载.

安装和测试

下载好了之后,通过 powershell 或者 cmd 到达刚刚下载的 whl 文件所在目录,用 pip 来安装就可以了. 例如我这里的pyopencl-2018.2.2+cl12-cp37-cp37m-win_amd64.whl文件在D:\TMP\这个目录下:

cd D:\TMP\
pip install pyopencl-2018.2.2+cl12-cp37-cp37m-win_amd64.whl

这样如果没有报错,应该就是安装成功了.

然后在Python中运行下面的来自PyOpenCL官网的代码来测试是否能够在Python下调用CL:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import absolute_import, print_function
import numpy as np
import pyopencl as cl

a_np = np.random.rand(50000).astype(np.float32)
b_np = np.random.rand(50000).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)))
# 代码来自 https://documen.tician.de/pyopencl/index.html

如果你的机器上有多个支持OpenCL的设备,比如同时有核显和独显或者多块独显,就会遇到一个提问界面,询问你用哪个设备执行上述OpenCL操作.比如我就遇到了:

Choose platform:
[0] <pyopencl.Platform 'NVIDIA CUDA' at 0x184befb97a0>
[1] <pyopencl.Platform 'Intel(R) OpenCL' at 0x184bf0fe500>
Choice [0]:
#这里我输入了回车键就是直接用默认的设备0
Set the environment variable PYOPENCL_CTX='' to avoid being asked again.
[0. 0. 0. ... 0. 0. 0.]
0.0

得到结果没报错,看来是安装成功了.