python joblib_Python之并行--基于joblib

本文介绍了Python中使用joblib进行并行计算的方法,通过实例展示了Parallel和delayed的用法,包括单参数、多参数并行,以及CPU分配和选择并行的时机。并讨论了并行计算可能带来的额外开销和效率问题。
摘要由CSDN通过智能技术生成

Python的并行远不如Matlab好用。比如Matlab里面并行就直接把for改成parfor就行(当然还要注意迭代时下标的格式),而Python查 一查并行,各种乱七八糟的方法一大堆,而且最不爽的一点就是只能对函数进行并行。

当然,这点困难也肯定不能就难倒我们,该克服也得克服,毕竟从本质上讲,也就只是实现的方式换一换而已。

大名鼎鼎的sklearn里面集成了很方便的并行计算,这在之前的机器学习教程里面也有^1

仔细查看其代码发现就是用joblib实现的,并且用法还挺巧。

from joblib import Parallel, delayed

parallel = Parallel(n_jobs=self.n_jobs, verbose=self.verbose,

pre_dispatch=self.pre_dispatch)

out = parallel(delayed(_fit_and_score)(clone(base_estimator),

X, y,

train=train, test=test,

parameters=parameters,

**fit_and_score_kwargs)

for parameters, (train, test)

in product(candidate_params,

cv.split(X, y, groups)))

这段代码的意思非常简单,即是用n_jobs个CPU来计算_fit_and_score函数,其中参数为clone(base_estimator), X, y,train=train, test=test,parameters=parameters,**fit_and_score_kwargs,而这里只有parameters,(train,test)作为被枚举的变量,其它参数始终保持不变。至于里为何要用clone函数是因为如果直接将base_estimator传入的话,这个模型在外部也将会被改变。具体原因可以参看其它文档。

这里就简单回顾下joblib的用法:

使用之前可以在自己的环境里先安装好这个库:

pip install joblib

1、简单示例

首先joblib里面最常用到的一个类和一个方法分别是Parallel和delayed。Parallel主要用于初始化并行计算时需要用到的参数,而delayed则主要用来指定需要被并行的参数。比如官方给出的以下示例:

from math import sqrt

from joblib import Parallel, delayed

Parallel(n_jobs=2)(delayed(sqrt)(i ** 2) for i in range(10))

[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]

这段代码其实已经基本看出方法的主要使用模式了。

解释一下:Parallel(n_jobs=2): 指定两个CPU(默认是分配给不同的CPU)

后面的delayed(sqrt)表示要用的函数是sqrt,这里这种用法就非常类似C++里面的委托(delegate)。

(i ** 2) for i in range(10): 这里注意(i**2)的括号和delayed(sqrt)是紧挨着的。这一小段表示要传递给delayed中指定的函数的参数是i^2。

那么结合这么一小段程序,其实已经能大致理解它的使用方法了。这里最开始可能主要不习惯的是要用到了Python里面的内部函数机制。

当然,作为 ~~调包侠~~ 工程师的我们,先不管这么多,用起来再说。比如写点简单的hello world

c = 'hello world'

Parallel(n_jobs=2)(delayed(print)(i) for i in c)

Out: [None, None, None, None, None, None, None, None, None, None, None]

这里就出现问题了,因为直接用print函数并没有返回值。所以这种实现方式是不正确的。要解决这个问题可以用另外一种方式来实现,比如:

def test_print(c):

for i in c:

print(i)

return c

Parallel(n_jobs=2)(delayed(test_print)(i) for i in test_print(c))

h

e

l

l

o

w

o

r

l

d

Out[8]: ['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']

这里注意,真正实现了print功能的是后面的函数test_print(c)。

2、多参数并行

由于Python提供了很好的多参数同时并行机制,可以用product、zip等方法将多个集合放在一起,那么就可以实现多参数的并行。比如:

import numpy as np

def test_mvar(a,b):

return a + b

Parallel(n_jobs=5)(delayed(test_mvar)(i,j) for i,j in zip(np.random.rand(10),np.random.rand(10)))

[0.8787518714894541,

1.3086203058912202,

1.3478235487198926,

1.1963547010071447,

1.2705711575828578,

0.5354314753331146,

1.0794490655604165,

0.6707125925684075,

0.8861808920187632,

1.1512627654053902]

当然注意到开头的代码,函数中可以只并行一部分参数,这里我们也可以如此,比如:

Parallel(n_jobs=5)(delayed(test_mvar)(i,1) for i,j in zip(np.random.rand(10),np.random.rand(10)))

[1.2137475752125968,

1.4543891439818082,

1.952684349026534,

1.3565884407873496,

1.5411521108342199,

1.0820532116263255,

1.8668685545516257,

1.397012511283467,

1.1645324713909715,

1.899119157699394]

下面这段代码就只计算数字1和一系列随机数的和。

那么到这里可以简单再分析一下用法:delayed函数指定了被运行的主函数test_mvar,而其后的参数则是由元组形式给出(i,1),后面需要进行for循环的参数只要保持和前面元组中相同的变量名即可。另外,需要注意的是变量的顺序必须和被运行的主函数保持一致。

3、并行时CPU是怎么分配的

这个问题相对比较麻烦。在joblib中默认是采用loky实现并行,这种方式最为简单直接,它会自然地将任务分配到多个CPU上去运行,同时更加稳定。当然除此之外还有其它的一些方式,比如多进程。这些方法之间的区别在我们大多数时候是相对比较细微的(追求极致并行的除外),我们只需要对它有个简单直接的了解即可。

再看一个例子:

from joblib import Parallel, delayed

import numpy as np

def test_non(a):

return a

c = range(20)

Parallel(n_jobs=2,backend='multiprocessing')(delayed(test_non)(i) for i in c)

注意,这里什么也没有发生。我们把并行方式改成了多进程,出现的结果就是一直卡着。这里主要就是分配机制的问题。所以一般而言,直接采用默认方式就好。

4、何时选用并行

这个问题其实是最关键的。并行其实也不一定一直会很快。因为并行的处理流程实际上是这样的:

这里拆分、合并和CPU之间的通信都是会产生时间消耗的。那么很容易想到,如果本身的任务很小,其实消耗的时间反而会更多。另外,往往实际的并行不能达到几个CPU就有几倍速度也正是这个原因。比如:直接循环

st = time.time()

for i in range(20):

i

et = time.time()

print(et-st)

0.0双核

st = time.time()

Parallel(n_jobs=2)(delayed(test_non)(i) for i in c)

et = time.time()

print(et-st)

0.010970830917358398四核

st = time.time()

Parallel(n_jobs=-1)(delayed(test_non)(i) for i in c)

et = time.time()

print(et-st)

0.23437237739562988

可以很清楚地看到,这时核心数越多,反而时间越慢。

因此在使用并行时,也要严格根据自己的需求来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值