Wol*_*tan 105 c++ python benchmarking numpy blas
我想编写一个广泛使用BLAS和LAPACK线性代数功能的程序.由于性能是一个问题,我做了一些基准测试,并想知道,如果我采取的方法是合法的.
可以说,我有三位参赛者,他们希望用简单的矩阵矩阵乘法来测试他们的表现.参赛者是:
dot.我为不同的维度实现了矩阵 - 矩阵乘法i.i为5的增量和matricies运行5-500 m1和m2设置了这样的:
m1 = numpy.random.rand(i,i).astype(numpy.float32)
m2 = numpy.random.rand(i,i).astype(numpy.float32)
Run Code Online (Sandbox Code Playgroud)
使用的代码如下所示:
tNumpy = timeit.Timer("numpy.dot(m1, m2)", "import numpy; from __main__ import m1, m2")
rNumpy.append((i, tNumpy.repeat(20, 1)))
Run Code Online (Sandbox Code Playgroud)
有了这个功能
_blaslib = ctypes.cdll.LoadLibrary("libblas.so")
def Mul(m1, m2, i, r):
no_trans = c_char("n")
n = c_int(i)
one = c_float(1.0)
zero = c_float(0.0)
_blaslib.sgemm_(byref(no_trans), byref(no_trans), byref(n), byref(n), byref(n),
byref(one), m1.ctypes.data_as(ctypes.c_void_p), byref(n),
m2.ctypes.data_as(ctypes.c_void_p), byref(n), byref(zero),
r.ctypes.data_as(ctypes.c_void_p), byref(n))
Run Code Online (Sandbox Code Playgroud)
测试代码如下所示:
r = numpy.zeros((i,i), numpy.float32)
tBlas = timeit.Timer("Mul(m1, m2, i, r)", "import numpy; from __main__ import i, m1, m2, r, Mul")
rBlas.append((i, tBlas.repeat(20, 1)))
Run Code Online (Sandbox Code Playgroud)
现在c ++代码自然要长一点,所以我将信息减少到最小.
我加载函数
void* handle = dlopen("libblas.so", RTLD_LAZY);
void* Func = dlsym(handle, "sgemm_");
Run Code Online (Sandbox Code Playgroud)
我这样测量时间gettimeofday:
gettimeofday(&start, NULL);
f(&no_trans, &no_trans, &dim, &dim, &dim, &one, A, &dim, B, &dim, &zero, Return, &dim);
gettimeofday(&end, NULL);
dTimes[j] = CalcTime(start, end);
Run Code Online (Sandbox Code Playgroud)
这里j是运行20次的循环.我计算过去的时间
double CalcTime(timeval start, timeval end)
{
double factor = 1000000;
return (((double)end.tv_sec) * factor + ((double)end.tv_usec) - (((double)start.tv_sec) * factor + ((double)start.tv_usec))) / factor;
}
Run Code Online (Sandbox Code Playgroud)
结果如下图所示:

完整的基准测试可以在这里下载.(JF塞巴斯蒂安使该链接成为可能^^)
Ümi*_*mit 72
我在新的HPC上重新运行基准测试.硬件和软件堆栈都改变了原始答案中的设置.
我将结果放在谷歌电子表格中(也包含原始答案的结果).
我们的HPC有两个不同的节点,一个是Intel Sandy Bridge CPU,另一个是新的Ivy Bridge CPU:
桑迪(MKL,OpenBLAS,ATLAS):
常春藤(MKL,OpenBLAS,ATLAS):
软件堆栈适用于两个节点sam.代替GotoBLAS2,OpenBLAS被使用并且也有一个多线程的ATLAS它被设置为8个线程(硬编码)BLAS.
基准代码与以下相同.然而,对于新机器,我还运行了基质尺寸5000和8000的基准测试.
下表包括原始答案的基准测试结果(更名为:MKL - > Nehalem MKL,Netlib Blas - > Nehalem Netlib BLAS等)
![矩阵乘法(尺寸= [1000,2000,3000,5000,8000])](https://i.stack.imgur.com/ZU7u4.png)
单线程性能:

多线程性能(8个线程):

线程与矩阵大小(Ivy Bridge MKL):


单线程性能:

多线程(8线程)性能:

新的基准测试结果与原始答案中的结果类似.OpenBLAS和MKL在同一级别上执行,但特征值测试除外.在单线程模式下,特征值测试在OpenBLAS上的表现相当不错.在多线程模式下,性能更差.
的"矩阵大小VS线程图表"也表明,虽然MKL以及OpenBLAS通常与核/线程的数量很好地扩展,这取决于基质的大小.对于小型矩阵,添加更多内核不会极大地提高性能.
从Sandy Bridge到Ivy Bridge的性能提升约为30%,这可能是由于更高的时钟频率(+ 0.8 Ghz)和/或更好的架构.
前段时间我不得不优化一些使用numpy和BLAS用python编写的线性代数计算/算法,所以我对不同的numpy/BLAS配置进行了基准测试.
特别是我测试过:
我确实运行了两个不同的基准测试:
这是我的结果:
Linux(MKL,ATLAS,No-MKL,GotoBlas2):
Mac Book Pro(加速框架):
Mac服务器(加速框架):
代码:
import numpy as np
a = np.random.random_sample((size,size))
b = np.random.random_sample((size,size))
%timeit np.dot(a,b)
Run Code Online (Sandbox Code Playgroud)
结果:
System | size = 1000 | size = 2000 | size = 3000 |
netlib BLAS | 1350 ms | 10900 ms | 39200 ms |
ATLAS (1 CPU) | 314 ms | 2560 ms | 8700 ms |
MKL (1 CPUs) | 268 ms | 2110 ms | 7120 ms |
MKL (2 CPUs) | - | - | 3660 ms |
MKL (8 CPUs) | 39 ms | 319 ms | 1000 ms |
GotoBlas2 (1 CPU) | 266 ms | 2100 ms | 7280 ms |
GotoBlas2 (2 CPUs)| 139 ms | 1009 ms | 3690 ms |
GotoBlas2 (8 CPUs)| 54 ms | 389 ms | 1250 ms |
Mac OS X (1 CPU) | 143 ms | 1060 ms | 3605 ms |
Mac Server (1 CPU)| 92 ms | 714 ms | 2130 ms |

代码:
有关基准套件的其他信息,请参见此处.
结果:
System | eigenvalues | svd | det | inv | dot |
netlib BLAS | 1688 ms | 13102 ms | 438 ms | 2155 ms | 3522 ms |
ATLAS (1 CPU) | 1210 ms | 5897 ms | 170 ms | 560 ms | 893 ms |
MKL (1 CPUs) | 691 ms | 4475 ms | 141 ms | 450 ms | 736 ms |
MKL (2 CPUs) | 552 ms | 2718 ms | 96 ms | 267 ms | 423 ms |
MKL (8 CPUs) | 525 ms | 1679 ms | 60 ms | 137 ms | 197 ms |
GotoBlas2 (1 CPU) | 2124 ms | 4636 ms | 147 ms | 456 ms | 743 ms |
GotoBlas2 (2 CPUs)| 1560 ms | 3278 ms | 116 ms | 295 ms | 460 ms |
GotoBlas2 (8 CPUs)| 741 ms | 2914 ms | 82 ms | 262 ms | 192 ms |
Mac OS X (1 CPU) | 948 ms | 4339 ms | 151 ms | 318 ms | 566 ms |
Mac Server (1 CPU)| 1033 ms | 3645 ms | 99 ms | 232 ms | 342 ms |

安装MKL包括安装完整的英特尔编译器套件,这非常简单.然而,由于一些错误/问题配置和编译与MKL支持numpy是一个麻烦.
GotoBlas2是一个小包,可以很容易地编译为共享库.但是,由于存在错误,您必须在构建共享库后重新创建共享库,以便将其与numpy一起使用.
除了这个建筑之外,它还有多个目标平台因某些原因无效.所以我不得不为每个平台创建一个.so文件,我希望有一个优化的libgoto2.so文件.
如果从Ubuntu的存储库安装numpy,它将自动安装和配置numpy以使用ATLAS.从源代码安装ATLAS可能需要一些时间,需要一些额外的步骤(fortran等).
如果您在具有Fink或Mac端口的Mac OS X计算机上安装numpy,它将配置numpy以使用ATLAS或Apple的Accelerate Framework.您可以通过在numpy.core._dotblas文件上运行ldd 或调用numpy.show_config()来进行检查.
MKL表现最好,其次是GotoBlas2.
在特征值测试中,GotoBlas2的表现出乎意料地差于预期.不知道为什么会这样.
Apple的Accelerate Framework在单线程模式下表现非常好(与其他BLAS实现相比).
GotoBlas2和MKL都可以很好地扩展线程数.因此,如果你必须处理在多个线程上运行它的大矩阵将有很大帮助.
在任何情况下都不要使用默认的netlib blas实现,因为对于任何严肃的计算工作来说它太慢了.
在我们的集群上,我还安装了AMD的ACML,其性能类似于MKL和GotoBlas2.我没有任何强硬的数字.
我个人会建议使用GotoBlas2,因为它更容易安装,而且是免费的.
如果你想在C++/C中编码也可以查看Eigen3,它在某些情况下应该胜过MKL/GotoBlas2,并且也很容易使用.
pv.*_*pv. 20
这是另一个基准测试(在Linux上,只需键入make):http://dl.dropbox.com/u/5453551/blas_call_benchmark.zip
http://dl.dropbox.com/u/5453551/blas_call_benchmark.png
我不认为Numpy,Ctypes和Fortran之间的大矩阵的不同方法之间存在任何差异.(Fortran而不是C++ ---如果这很重要,你的基准测试可能会被打破.)
你也许您的基准测试还有其他错误,例如,比较不同的BLAS库,或不同的BLAS设置,如线程数,或实时和CPU时间之间?CalcTime在C++中的函数似乎有一个符号错误.... + ((double)start.tv_usec))应该是... - ((double)start.tv_usec)).
编辑:未能计算CalcTime函数中的大括号- 没关系.
作为指导:如果您做基准测试,请始终在所有地方发布所有代码.评论基准测试,特别是在出现意外情况时,如果没有完整的代码,通常就没有效率.
要找出与哪个BLAS Numpy相关联,请执行以下操作:
$ python
Python 2.7.2+ (default, Aug 16 2011, 07:24:41)
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy.core._dotblas
>>> numpy.core._dotblas.__file__
'/usr/lib/pymodules/python2.7/numpy/core/_dotblas.so'
>>>
$ ldd /usr/lib/pymodules/python2.7/numpy/core/_dotblas.so
linux-vdso.so.1 => (0x00007fff5ebff000)
libblas.so.3gf => /usr/lib/libblas.so.3gf (0x00007fbe618b3000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fbe61514000)
更新:如果你不能导入numpy.core._dotblas,你的Numpy正在使用它的BLAS内部后备副本,这个副本速度较慢,并不打算用于性能计算!来自@Woltan的回复表明,这是他/她在Numpy vs. Ctypes + BLAS中看到的差异的解释.
要解决这个问题,您需要ATLAS或MKL ---请查看以下说明:http://scipy.org/Installing_SciPy/Linux 大多数Linux发行版都附带ATLAS,因此最好的选择是安装他们的libatlas-dev软件包(名称可能会有所不同) .
鉴于您在分析中表现出的严谨性,我对迄今为止的结果感到惊讶.我把它作为一个"答案",但这只是因为评论太长了并且提供了一种可能性(尽管我希望你已经考虑过了).
我认为numpy/python方法不会为合理复杂性的矩阵增加太多开销,因为随着复杂性的增加,python参与的比例应该很小.我对图表右侧的结果更感兴趣,但显示的数量级差异会令人不安.
我想知道你是否正在使用numpy可以利用的最佳算法.从linux的编译指南:
"构建FFTW(3.1.2):SciPy版本> = 0.7且Numpy> = 1.2:由于许可证,配置和维护问题,在SciPy> = 0.7和NumPy> = 1.2的版本中删除了对FFTW的支持. fftpack的内置版本.如果需要分析,有几种方法可以利用FFTW的速度.降级到包含支持的Numpy/Scipy版本.安装或创建自己的FFTW包装.请参阅http: //developer.berlios.de/projects/pyfftw/作为一个未得到认可的例子."
你用mkl编译numpy了吗?(http://software.intel.com/en-us/articles/intel-mkl/).如果你在linux上运行,那么用mkl编译numpy的指令就在这里:http://www.scipy.org/Installing_SciPy/Linux#head-7ce43956a69ec51c6f2cedd894a4715d5bfff974(尽管是url).关键部分是:
[mkl]
library_dirs = /opt/intel/composer_xe_2011_sp1.6.233/mkl/lib/intel64
include_dirs = /opt/intel/composer_xe_2011_sp1.6.233/mkl/include
mkl_libs = mkl_intel_lp64,mkl_intel_thread,mkl_core
Run Code Online (Sandbox Code Playgroud)
如果您使用的是Windows,你可以在获得与MKL已编译的二进制,(也获得pyfftw,和许多其他相关算法):http://www.lfd.uci.edu/~gohlke/pythonlibs/,用感谢加州大学欧文分校荧光动力学实验室的Christoph Gohlke.
在任何一种情况下,都有许多许可问题需要注意,但英特尔页面解释了这些问题.再说一遍,我想你已经考虑过了,但是如果你满足了许可要求(在linux上很容易做到),相对于使用简单的自动构建而言,这甚至可以加速numpy部分,甚至没有FFTW.我有兴趣关注这个帖子,看看别人怎么想.无论如何,优秀的严谨和优秀的问题.谢谢你发布它.
| 归档时间: |
|
| 查看次数: |
36305 次 |
| 最近记录: |