写在前面
本文主要是针对 theano 的多 GPU 使用问题,做一个记录与总结。 在此之前我没有接触过关于 Theano 框架的内容,也是因为某些原因需要研究一下 theano 框架是否可以使用 GPU,如果可以,如何配置使用多 GPU。下面的内容写的很详细,甚至有点冗长,为了详细说明,贴了很多中间的步骤图,可以说很详细了,无非也是记录自己在一个之前没有任何接触的情况下,遇到了哪些问题,包括遇到这些问题我是如何处理和解决的。还好最后问题都一一解决了,不然也不会有这篇文章了 ???? ,刚开始接触和配置的前一个小时内,只配置好了Theano 单 GPU,当时查多 GPU 问题,没有什么答案,我甚至也给这个框架下了定义,它只能指定一块 GPU 训练,但是一步一步去查找,最后柳暗花明了。有些问题还是不能轻易放弃!可能不是没有方法,只是我们了解的还不够,希望给看到这篇文章的朋友提供一些经验。重要的不是内容,而是解决问题的思路和方法。
内容概括
因为文章很长,写的又很详细,看完需要一定的耐心和时间,这里先给出一个内容概括:
本文是在 Ubuntu 16.04 + CUDA9.0 + CUDNN 7 + Anaconda 3(python 3.6) 下进行的,配置了 Platoon 和 Synkhronos 两个数据并行库来使用多 GPU:
-
Synkhronos只支持 Python3,并且不支持 Windows 平台,有提供官方学习文档,但是需要额外的一些精力去学习如何使用 -
Platoon并未看见有什么限制,而且被 theano 官方文档所推荐,并且theano 官方文档给出了一些使用例程
就安装过程中的测试样例来看, Platoon 的学习成本更低一些(即可以更快上手使用),Synkhronos 需要一定时间摸索它的使用方法,所以推荐安装 Platoon.
正文
Theano 框架在2017年9月29日,Yoshua Bengio 教授宣布将不再更新。稍微使用过现在比较流行的框架,例如: Pytorch, Keras, Tensorflow 等,在框架环境安装完成以后都可以通过在训练时直接设置一些语句实现多 GPU 的使用,只要环境配置好无需额外安装其他东西,但是对于一些相对来说老牌的框架步骤就会复杂一些,例如本文的主角 Theano ,以及Caffe, Caffe 需要在配置前安装 NCCL,然后在编译Caffe 的时候选择 USE_NCCL 选项,才可以在后面的使用中使用多GPU来训练,theano 也需要做一些准备工作。
下面的配置和安装均是在: Ubuntu 16.04 + CUDA9.0 + CUDNN 7 + Anaconda 3(python 3.6) 下进行的。
1. 安装 Theano
这里不多提,官方文档也给出了安装方法:
这里直接:
conda install theano pygpu
默默根据步骤下载完即可。
下载完,有的会在 python 环境里直接 import theano ,有的会在程序运行时,报出含有下面关键词的错误:
Can not use cuDNN on context None: cannot compile with cuDNN. xxxxxx
包括另一个错误:
ERROR (theano.gpuarray): Could not initialize pygpu, support disabled
所以我们还应该完成一些配置工作,首先新建一个 .theanorc 配置文件:
sudo gedit ~/.theanorc
在其中输入:
这里根据自己的 cuda 版本替换一下对应的位置就可以了
到这里我们的 theano 环境基本搭建完成!
2. Theano 的多 GPU 使用问题
下面主要说明一下,查找 theano 如何使用多 GPU 相关资料的过程,以及一些第三方库配置过程中可能出现的问题。
前面提到的官方文档,其实给出了一些答案。
.
可以看到,device=cuda 我们在 .theanorc 文件中已经配置好了,在使用中通过添加 THEANO_FLAGS='device=cuda{0,1,...}' 便可以指定某一块GPU,习惯了 Caffe 里面 -gpu=0,1,2,3,以及Pytorch里面 CUDA_VISIBLE_DEVICES='0,1,2,3' 设置多GPU 使用的同学一定跃跃欲试,THEANO_FLAGS='device=cuda{0,1,2,3}'就可以同样使用多 GPU 了? No,No,No, 注意这里 {0,1,…} 的意思是在这些数字里面选一个,cuda0,cuda1,cuda2 分别代表不同的GPU,如果想上面那种写法,这里我有4块 GPU, THEANO_FLAGS='device=cuda{0,1,2,3}' 会报错说不认识 '{0' 这个字符的。 然后我转身就去寻求网络上的帮助了,百度里基本都只是在安装及配置 theano 使用单GPU 时的一些问题及回答,该做的都做了,单 GPU 已经可以跑通官方文档给的小例程了,多GPU 无论怎么改还是不行。
那怎么办呢?
Step1: 我点进 Github 里 theano 项目的 issues 输入关键词: multi GPU ,然后搜索。
在问题的第一页,目光就锁定在了上面框出的两个问题。
题目为: MultiGPU: ValueError: Could not infer context from inputs #6655 的问题,点进去一看,问题其实没人解决,里面给了个链接, google 的,没翻墙打不开。
最终的解决思路来自于:已经被关闭的问题 theano-0.10.0beta2 even simple funcs crash in multi-GPU setup after recompile #6422,也就是第二个红框。
点开看完问题描述,下面有一个人的回复很关键:
.
从上面的回答可以看出,theano 框架不能直接支持多 GPU 训练,但是我们可以借助一些基于 theano 的第三方的库来实现,我们继续点开上面的链接可以看到:
.
最上面就是介绍了一些在 Theano 上拓展的,使用多 GPU 的并行库,正是我想要的!
Synkhronos 库
这里以第一个 Synkhronos 为例,我们点击进去直接就会跳转到 Synkhronos 的 github 项目,最下面 ReadME 介绍了官方文档。
.
继续点击这个文档链接,可以看到是一个很全面的手册:
.
直接选择左侧的 1. Installation。 根据文档内容,要安装这个库依次输入以下内容:
git clone https://github.com/astooke/Synkhronos
cd Synkhronos
pip install . // 注意 install 的后面有一个小点
然后需要安装这个库的一些依赖项:
conda posix_ipc
conda pyzmq
至此 Synkhronos 库就安装好了。
.
从官方文档可以看出,目前只支持 Python3 以及非 Windows 版本。
首先在使用 Synkhronos 给出的测试小程序时会报错如下错误:
.
好消息是,从上面的内容可以看出,可以使用多 GPU 了,但是下面这个问题刚开始还是有点抓不着头脑的,乍一看,是我自己少东西了吧,百度了这个错误,根本没有相关结果,查看了 Synkhronos 项目的 issues(只有 2 个问题),也没有人问,找了一圈也没找到我少的这个东西该怎么办。 我们就来看一下这个函数的定义吧:
.
这个函数不是很复杂,可以看到上面红框位置是我们程序报错的地方,仔细一读该函数的定义,主要是绿框部分的内容,大概意思是:这个函数会自动将 Theano 中的 functions 的数据压缩成一个 pkl 文件,然后再读取它。
原来这个东西是自己生成的,那我们就刨根问底,去报错的路径下看一看,到底有什么:
.
可以对比上面报错的信息,这个路径下连名字为pkl的文件加都没有,肯定找不到对应的.pkl文件,只要在这里手动新建一个名字为 pkl 的文件夹就可以了。 再次运行程序,这个错误就解决了。 四个 GPU 就可以使用了。
再追根问底以下,上面的绿色区域最后一句写了,可以在 synkhronos/util.py 中修改对应的 pkl 路径, 下面我们找到这个文件,打开一看,果然有这个子文件夹是因为这里面红框区域设定了,我们不新建文件,直接在这里做改动,将 'pkl/' 改成 '/' 也可以。
.
反过来,最根本的还是在安装的第一步 git clone 以后,在项目的 synkhronos/utils.py 中直接修改,然后再运行 pip install . 应该就不会有以上 pkl 路径的错误了。
Platoon 库
其实在 theano 的官方文档里,也给出了答案,但是刚开始真的没看到!!! Using the GPU 的下面就是 Using multiple GPUs
.
我们点进去,可以看到官方文档说,为了数据并行化,你最好使用 platoon, 我们再来看一下刚才那张罗列 theano 第三方库的图:
.
第 3 个就是 Platoon,噢,原来还是要安装第三方库,那么我们就也看一下吧。 安装步骤类似于 Synkhronos,点击名字直接跳到 platoon 的 Github 项目。
git clone https://github.com/mila-udem/platoon
pip install -e /path/to/platoon/folder
安装完以后就可以了,我们再回到 theano 的官方文档,里面给了我们测试的命令和小例程,我们新建一个名为 theano_demo.py 的文件,内容为 :
import numpy
import theano
v01 = theano.shared(numpy.random.random((1024, 1024)).astype('float32'),
target='dev0')
v02 = theano.shared(numpy.random.random((1024, 1024)).astype('float32'),
target='dev0')
v11 = theano.shared(numpy.random.random((1024, 1024)).astype('float32'),
target='dev1')
v12 = theano.shared(numpy.random.random((1024, 1024)).astype('float32'),
target='dev1')
f = theano.function([], [theano.tensor.dot(v01, v02),
theano.tensor.dot(v11, v12)])
print(f())
然后在命令行里输入:
THEANO_FLAGS=“contexts=dev0->cuda0;dev1->cuda1” python theano_demo.py
输出为:
可以看到我指定了 2 个 GPU ,使用了 2 个 GPU。至此两个 theano 的多 GPU 库都配置完成了。