为啥 scikit-learn 中的 GridSearchCV 会产生这么多线程
Posted
技术标签:
【中文标题】为啥 scikit-learn 中的 GridSearchCV 会产生这么多线程【英文标题】:Why GridSearchCV in scikit-learn spawn so many threads为什么 scikit-learn 中的 GridSearchCV 会产生这么多线程 【发布时间】:2018-03-03 05:35:09 【问题描述】:这是我当前运行的 GridSearch 的 pstree
输出,我很想知道正在发生什么进程,还有一些我无法解释的东西。
├─bash─┬─perl───20*[bash───python─┬─5*[python───31*[python]]]
│ │ └─11*[python]]
│ └─tee
└─bash───pstree
我删除了不相关的内容。花括号表示线程。
perl 的出现是因为我使用parallel -j 20
来启动我的python 作业。如您所见,20*
确实显示有 20 个进程。
每个 python 进程之前的 bash
进程是由于使用 source activate venv
激活 Anaconda 虚拟环境所致。
在每个 python 进程中,还会产生另外 5 个 python 进程 (5*
)。这是因为我将n_jobs=5
指定为GridSearchCV
。
我的理解到此结束。
问题:谁能解释为什么在网格搜索的同时还有另外 11 个 Python 线程 (11*[python]
),并且在 5 个网格搜索作业中的每一个中都产生了 31 个 Python 线程 (31*[python]
) ?
更新:添加调用GridSearchCV
的代码
Cs = 10 ** np.arange(-2, 2, 0.1)
skf = StratifiedKFold(n_splits=10, shuffle=True, random_state=0)
clf = LogisticRegression()
gs = GridSearchCV(
clf,
param_grid='C': Cs, 'penalty': ['l1'],
'tol': [1e-10], 'solver': ['liblinear'],
cv=skf,
scoring='neg_log_loss',
n_jobs=5,
verbose=1,
refit=True)
gs.fit(Xs, ys)
更新(2017-09-27):
我总结了一个test code 的要点,如果您有兴趣,可以轻松复制。
我在 Mac Pro 和多台 linux 机器上测试了相同的代码,并重现了 @igrinis 的结果,但仅在 Mac Pro 上。在 linux 机器上,我得到的数字与以前不同,但始终如一。因此产生的线程数可能取决于向 GridSearchCV 提供的特定数据。
python─┬─5*[python───31*[python]]
└─3*[python]
注意,homebrew/linuxbrew 在 Mac Pro 和 linux 机器上安装的 pstree 是不同的。在这里,我发布了我使用的确切版本:
苹果机:
pstree $Revision: 2.39 $ by Fred Hucht (C) 1993-2015
EMail: fred AT thp.uni-due.de
Linux:
pstree (PSmisc) 22.20
Copyright (C) 1993-2009 Werner Almesberger and Craig Small
Mac 版本似乎没有显示线程的选项,我认为这可能是结果中看不到它们的原因。我还没有找到一种在 Mac Pro 上轻松检查线程的方法。如果您碰巧知道方法,请发表评论。
更新 (2017-10-12)
在另一组实验中,我确认设置环境变量OMP_NUM_THREADS
会产生影响。
在export OMP_NUM_THREADS=1
之前,如上所述产生了许多(在本例中为 63 个)用途不明的线程:
bash───python─┬─23*[python───63*[python]]
└─3*[python]
这里没有使用 linux parallel
。 n_jobs=23
.
export OMP_NUM_THREADS=1
之后,没有产生线程,但是 3 个 Python 进程仍然存在,我仍然不知道它们的用途。
bash───python─┬─23*[python]
└─3*[python]
我最初遇到OMP_NUM_THREADS
,因为它在我的一些 GridSearchCV 作业中导致错误,错误消息是这样的
OMP: Error #34: System unable to allocate necessary resources for OMP thread:
OMP: System error #11: Resource temporarily unavailable
OMP: Hint: Try decreasing the value of OMP_NUM_THREADS.
【问题讨论】:
你能用 GridSearchCV 的确切参数值显示函数调用吗? @MohammedKashif,请看我添加的代码 ActivityMonitor 显示 Mac 上的线程数。 1 个进程有 4 个线程,其他 5 个只有 1 个。 设置export OMP_NUM_THREADS=1
,这可能会起作用
【参考方案1】:
来自sklearn.GridSearchCV
文档:
n_jobs : int, 默认=1 并行运行的作业数。
pre_dispatch : int 或 string,可选 控制在并行执行期间分派的作业数。当调度的作业多于 CPU 可以处理的作业时,减少此数字有助于避免内存消耗的爆炸式增长。这个参数可以是: 无,在这种情况下,所有作业都会立即创建和生成。将此用于轻量级和快速运行的作业,以避免由于按需生成作业而导致的延迟 一个 int,给出产生的总作业的确切数量 一个字符串,将表达式作为 n_jobs 的函数,如“2*n_jobs”
如果我正确理解文档,GridSearchCV
会生成一堆线程作为网格点的数量,并且只会同时运行 n_jobs
。我相信第 31 号是您的 40 个可能值的某种上限。尝试使用pre_dispatch
参数的值。
我认为另外 11 个线程与 GridSearchCV
本身无关,因为它显示在同一级别。我认为这是其他命令的剩余部分。
顺便说一句,我在 Mac 上没有观察到这种行为(只看到GridSearchCV
产生了 5 个进程,正如人们所期望的那样),因此它可能来自不兼容的库。尝试手动更新sklearn
和numpy
。
这是我的pstree
输出(为保护隐私而删除了部分路径):
└─┬= 00396 *** -fish
└─┬= 21743 *** python /Users/***/scratch_5.py
├─── 21775 *** python /Users/***/scratch_5.py
├─── 21776 *** python /Users/***/scratch_5.py
├─── 21777 *** python /Users/***/scratch_5.py
├─── 21778 *** python /Users/***/scratch_5.py
└─── 21779 *** python /Users/***/scratch_5.py
回答第二条评论:
这实际上是您的代码。刚刚生成了可分离的一维二分类问题:
N = 50000
Xs = np.concatenate( (np.random.random(N) , 3+np.random.random(N)) ).reshape(-1, 1)
ys = np.concatenate( (np.zeros(N), np.ones(N)) )
100k 样本足以让 CPU 忙碌大约一分钟。
【讨论】:
您能否展示一下您的pstree
输出是什么样的?
能否请您也出示您的代码?我会尝试重现你的实验
我在 Mac OS 上重现了您的结果,但我在多台 Linux 机器上测试的完全相同的代码仍然产生了许多线程。我已经在 gist 上发布了我的整个测试代码,请查看更新。
能否请您在 linux 机器上进行实验,看看效果如何?
嗨@igrinis,你认为你已经找到原因了吗?我倾向于给你赏金,但不确定你的结果是否符合答案。以上是关于为啥 scikit-learn 中的 GridSearchCV 会产生这么多线程的主要内容,如果未能解决你的问题,请参考以下文章
为啥带有铰链损失的 SGDClassifier 比 scikit-learn 中的 SVC 实现更快
scikit-learn 和 scipy 库之间的确定系数不同。为啥?
scikit-learn ExtraTreesClassifier - 为啥泡菜文件这么大? (几 GB)
为啥 scikit-learn 对不同的回归器要求不同的数据形状?