GPU用于为矩阵运算进行加速开始在工业界和研究人员中获得了广泛关注。尤其是近来推出的各种深度学习框架,如mxnet、TensorFlow等,GPU加速更是不可或缺,成了提升运算速度的法宝。
然而,作为在Python中占据基础地位的numpy却始终没能提供这一功能,我们无法灵活地使用GPU为numpy的矩阵运算进行加速。不过,近来,作为mxnet的开发者,dmlc在mxnet的基础上,进一步开发了minpy,其为矩阵运算提供了GPU加速,而且可以做到与numpy近乎完美兼容;甚至有时,不需改动一行代码,只需在程序的开头将import numpy as npimport numpy as np改为import minpy.numpy as npimport minpy.numpy as np即可实现GPU加速,可谓十分省事儿方便。
1. 安装minpy
首先需要注意的是,以下内容是基于Ubuntu进行描述的,如果是其他操作系统,可能需要作相应的修改。
其次,因为要用GPU加速运算,自然要确保你的计算机上有NVIDIA的GPU,而且安装好GPU的诸如CUDA和cudnn驱动。
minpy是基于mxnet进行运算的,所以它离不开mxnet。安装minpy之前,需要先安装mxnet。现在的深度学习框架,再也不像早期的caffe那样毫无人性了,安装都十分方便快捷。具体来说,只需首先执行如下命令进行编译:
sudo apt-get update
sudo apt-get install -y build-essential git libatlas-base-dev libopencv-dev
git clone --recursive -b engine https://github.com/apache/incubator-mxnet
cd mxnet;
cp make/config.mk .
echo "USE_CUDA=1" >>config.mk
echo "USE_CUDA_PATH=/usr/local/cuda" >>config.mk
echo "USE_CUDNN=1" >>config.mk
make -j$(nproc)
sudo apt-get update
sudo apt-get install -y build-essential git libatlas-base-dev libopencv-dev
git clone --recursive -b engine https://github.com/apache/incubator-mxnet
cd mxnet;
cp make/config.mk .
echo "USE_CUDA=1" >>config.mk
echo "USE_CUDA_PATH=/usr/local/cuda" >>config.mk
echo "USE_CUDNN=1" >>config.mk
make -j$(nproc)
sudo apt-get update
sudo apt-get install -y build-essential git libatlas-base-dev libopencv-dev
git clone --recursive -b engine https://github.com/apache/incubator-mxnet
cd mxnet;
cp make/config.mk .
echo "USE_CUDA=1" >>config.mk
echo "USE_CUDA_PATH=/usr/local/cuda" >>config.mk
echo "USE_CUDNN=1" >>config.mk
make -j$(nproc)
编译完mxnet之后,可以直接设置一下路径(假设mxnet在home目录~下):export PYTHONPATH=~/mxnet/python:$PYTHONPATHexport PYTHONPATH=~/mxnet/python:$PYTHONPATH,即可使用。
当然,也可以在编译完之后,cd到mxnet目录的python目录下,运行sudo python setup.py installsudo python setup.py install将mxnet安装到系统目录下,这跟使用pip安装其他包的方式一样,安装完,即可以直接使用了。
安装完mxnet之后,再安装minpy则是极其简单的事情了,只需sudo pip install minpysudo pip install minpy即可。
2. 使用minpy
相比安装时的简单方便来说,使用minpy可能更为简单。无非如前所述,在程序的最开头将import numpy as npimport numpy as np替换为import minpy.numpy as npimport minpy.numpy as np。
下面以一个例子来说明一下。
使用numpy:
import numpy as np
import numpy.random as random
import time
x= random.rand(1024, 1024)
y= random.rand(1024, 1024)
st = time.time()
for i in xrange(10):
z= np.dot(x, y)
print('time: {:.3f}.'.format(time.time()-st))
import numpy as np
import numpy.random as random
import time
x= random.rand(1024, 1024)
y= random.rand(1024, 1024)
st = time.time()
for i in xrange(10):
z= np.dot(x, y)
print('time: {:.3f}.'.format(time.time()-st))
import numpy as np
import numpy.random as random
import time
x= random.rand(1024, 1024)
y= random.rand(1024, 1024)
st = time.time()
for i in xrange(10):
z= np.dot(x, y)
print('time: {:.3f}.'.format(time.time()-st))
使用minpy:
import minpy.numpy as np
import minpy.numpy.random as random
import time
x= random.rand(1024, 1024)
y= random.rand(1024, 1024)
st = time.time()
for i in xrange(10):
z= np.dot(x, y)
z.asnumpy()
print('time: {:.3f}.'.format(time.time()-st))
import minpy.numpy as np
import minpy.numpy.random as random
import time
x= random.rand(1024, 1024)
y= random.rand(1024, 1024)
st = time.time()
for i in xrange(10):
z= np.dot(x, y)
z.asnumpy()
print('time: {:.3f}.'.format(time.time()-st))
import minpy.numpy as np
import minpy.numpy.random as random
import time
x= random.rand(1024, 1024)
y= random.rand(1024, 1024)
st = time.time()
for i in xrange(10):
z= np.dot(x, y)
z.asnumpy()
print('time: {:.3f}.'.format(time.time()-st))
两个例子在我的计算机(GPU为Titan X)的运行时间对比:
直接使用numpy,即CPU进行运算,时间为:0.350s左右;
使用minpy,即GPU进行加速,时间为:0.040s左右。
从上对比可以看到使用minpy时,GPU对矩阵运算的加速效果。
3. 不足之处和注意事项
虽然使用minpy.numpy取代numpy可以灵活地在有GPU时实现加速,无GPU时正常使用CPU进行计算,但它也有自己的不足之处,具体来说,包括以下几点:
1. 不支持inplace操作
比如对minpy的ndarray a:a.transpose()会报错;但可以使用a = a.transpose()来实现。
另,如a[1, 2] = 12这样的操作虽然可以运行,但作为深度学习的autograd对这种操作将不能正常运行。
2. 使用numpy或minpy要保持连续性
即最好不要同时在一个程序的一部分使用numpy,另一部分又使用minpy,这可能会导致你得到预期之外的结果。
3. minpy支持的功能仍然有限
因为numpy的庞杂,minpy暂时还不能支持numpy的所有子模块。