gpt4 book ai didi

python - 是否值得将 IPython 与 scipy 的 eig 并行使用?

转载 作者:太空宇宙 更新时间:2023-11-03 11:06:33 28 4
gpt4 key购买 nike

我正在编写一个代码,它必须计算大量的特征值问题(典型的矩阵维数是几百)。我想知道是否可以通过使用 IPython.parallel 模块来加速这个过程。作为前 MATLAB 用户和 Python 新手,我一直在寻找类似于 MATLAB 的 parfor...

按照一些在线教程,我编写了一个简单的代码来检查它是否完全加快了计算速度,但我发现它并没有而且实际上经常减慢它的速度(视情况而定)。我想,我可能遗漏了其中的一点,也许 scipy.linalg.eig 的实现方式是使用所有可用的内核,并通过尝试并行化它来中断引擎管理。

这是“并行”代码:

import numpy as np
from scipy.linalg import eig
from IPython import parallel

#create the matrices
matrix_size = 300
matrices = {}

for i in range(100):
matrices[i] = np.random.rand(matrix_size, matrix_size)

rc = parallel.Client()
lview = rc.load_balanced_view()
results = {}

#compute the eigenvalues
for i in range(len(matrices)):
asyncresult = lview.apply(eig, matrices[i], right=False)
results[i] = asyncresult

for i, asyncresult in results.iteritems():
results[i] = asyncresult.get()

非并行变体:

#no parallel
for i in range(len(matrices)):
results[i] = eig(matrices[i], right=False)

两者的 CPU 时间差异非常细微。如果在特征值问题之上,并行化函数必须执行更多的矩阵运算,它将开始永远持续下去,即至少比非并行化变体长 5 倍。

特征值问题并不真正适合这种并行化,我说得对吗?还是我没有捕获要点?

非常感谢!

2013 年 7 月 29 日编辑;英国夏令时 12:20

根据 moarningsun 的建议,我尝试运行 eig,同时使用 mkl.set_num_threads 固定线程数。对于 500×500 矩阵,50 次重复的最少次数设置如下:

No of. threads    minimum time(timeit)    CPU usage(Task Manager) 
=================================================================
1 0.4513775764796151 12-13%
2 0.36869288559927327 25-27%
3 0.34014644287680085 38-41%
4 0.3380558903450037 49-53%
5 0.33508234276183657 49-53%
6 0.3379019065051807 49-53%
7 0.33858615048501406 49-53%
8 0.34488405094054997 49-53%
9 0.33380300334101776 49-53%
10 0.3288481198342197 49-53%
11 0.3512653110685733 49-53%

除了一个线程情况外,没有实质性差异(也许 50 个样本有点小......)。我仍然认为我没有捕获重点,可以做很多事情来提高性能,但不确定如何做。它们在启用超线程的 4 核机器上运行,提供 4 个虚拟内核。

感谢任何输入!

最佳答案

有趣的问题。因为我认为应该可以实现更好的缩放,所以我用一个小的“基准”来研究性能。通过此测试,我比较了单线程和多线程 eig(通过 MKL LAPACK/BLAS 例程交付的多线程)与 IPython 并行化 eig 的性能。为了查看它会带来什么不同,我改变了 View 类型、引擎数量和 MKL 线程以及在引擎上分配矩阵的方法。

以下是旧 AMD 双核系统的结果:

 m_size=300, n_mat=64, repeat=3
+------------------------------------+----------------------+
| settings | speedup factor |
+--------+------+------+-------------+-----------+----------+
| func | neng | nmkl | view type | vs single | vs multi |
+--------+------+------+-------------+-----------+----------+
| ip_map | 2 | 1 | direct_view | 1.67 | 1.62 |
| ip_map | 2 | 1 | loadb_view | 1.60 | 1.55 |
| ip_map | 2 | 2 | direct_view | 1.59 | 1.54 |
| ip_map | 2 | 2 | loadb_view | 0.94 | 0.91 |
| ip_map | 4 | 1 | direct_view | 1.69 | 1.64 |
| ip_map | 4 | 1 | loadb_view | 1.61 | 1.57 |
| ip_map | 4 | 2 | direct_view | 1.15 | 1.12 |
| ip_map | 4 | 2 | loadb_view | 0.88 | 0.85 |
| parfor | 2 | 1 | direct_view | 0.81 | 0.79 |
| parfor | 2 | 1 | loadb_view | 1.61 | 1.56 |
| parfor | 2 | 2 | direct_view | 0.71 | 0.69 |
| parfor | 2 | 2 | loadb_view | 0.94 | 0.92 |
| parfor | 4 | 1 | direct_view | 0.41 | 0.40 |
| parfor | 4 | 1 | loadb_view | 1.62 | 1.58 |
| parfor | 4 | 2 | direct_view | 0.34 | 0.33 |
| parfor | 4 | 2 | loadb_view | 0.90 | 0.88 |
+--------+------+------+-------------+-----------+----------+

如您所见,性能增益随使用的不同设置而变化很大,最多是常规多线程 eig 的 1.64 倍。在这些结果中,除非在引擎上禁用 MKL 线程(使用 view.apply_sync(mkl.set_num_threads, 1)),否则您使用的 parfor 函数执行不佳。

改变矩阵大小也会产生显着差异。在禁用了 4 个引擎和 MKL 线程的 direct_view 上使用 ip_map 与常规多线程 eig 相比:

 n_mat=32, repeat=3
+--------+----------+
| m_size | vs multi |
+--------+----------+
| 50 | 0.78 |
| 100 | 1.44 |
| 150 | 1.71 |
| 200 | 1.75 |
| 300 | 1.68 |
| 400 | 1.60 |
| 500 | 1.57 |
+--------+----------+

显然,对于相对较小的矩阵,性能会有所下降,对于中等大小,加速比最大,而对于较大的矩阵,加速比会再次下降。在我看来,您可以获得 1.75 的性能提升,这将使使用 IPython.parallel 变得值得。

我早些时候也在一台英特尔双核笔记本电脑上做了一些测试,但我得到了一些有趣的结果,显然笔记本电脑过热了。但在该系统上,加速比通常要低一些,最大值约为 1.5-1.6。

现在我认为你的问题的答案应该是:视情况而定。性能增益取决于硬件、BLAS/LAPACK 库、问题大小和 IPython.parallel 的部署方式,以及我可能不知道的其他因素。最后但并非最不重要的一点是,它是否值得还取决于认为值得多少性能提升。

我使用的代码:

from __future__ import print_function
from numpy.random import rand
from IPython.parallel import Client
from mkl import set_num_threads
from timeit import default_timer as clock
from scipy.linalg import eig
from functools import partial
from itertools import product

eig = partial(eig, right=False) # desired keyword arg as standard

class Bench(object):
def __init__(self, m_size, n_mat, repeat=3):
self.n_mat = n_mat
self.matrix = rand(n_mat, m_size, m_size)
self.repeat = repeat
self.rc = Client()

def map(self):
results = map(eig, self.matrix)

def ip_map(self):
results = self.view.map_sync(eig, self.matrix)

def parfor(self):
results = {}
for i in range(self.n_mat):
results[i] = self.view.apply_async(eig, self.matrix[i,:,:])
for i in range(self.n_mat):
results[i] = results[i].get()

def timer(self, func):
t = clock()
func()
return clock() - t

def run(self, func, n_engines, n_mkl, view_method):
self.view = view_method(range(n_engines))
self.view.apply_sync(set_num_threads, n_mkl)
set_num_threads(n_mkl)
return min(self.timer(func) for _ in range(self.repeat))

def run_all(self):
funcs = self.ip_map, self.parfor
n_engines = 2, 4
n_mkls = 1, 2
views = self.rc.direct_view, self.rc.load_balanced_view
times = []
for n_mkl in n_mkls:
args = self.map, 0, n_mkl, views[0]
times.append(self.run(*args))
for args in product(funcs, n_engines, n_mkls, views):
times.append(self.run(*args))
return times

不知道启动 4 个 IPython 并行引擎是否重要,我在命令行输入:

ipcluster start -n 4

希望这有帮助:)

关于python - 是否值得将 IPython 与 scipy 的 eig 并行使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17829759/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com