当使用 n_jobs 参数并行化 scikit-learn 例程(如 GridSeachCV)时,有没有办法将并行进程设置为低于正常优先级?
我通常希望最大限度地利用并行化,同时仍然允许并行使用我的机器执行常规计算任务。我使用的是 Windows;打开任务管理器手动将 n_jobs=-1 的每个生成进程的优先级设置为低于正常水平,效果很好,但非常乏味。
将 n_jobs 设置为小于可用的 CPU 线程或内核并不是一个令人满意的解决方案,因为我的机器对常规任务的响应速度很慢,除非我保留至少两个物理 CPU 内核(例如,在 8 核 16 核上,n_jobs=6线程 CPU),这使得许多线程未得到充分利用,我希望当我不同时使用我的机器时使用所有线程。
我找到了这个答案关于使用 psutil.Process() 类降低子进程的进程优先级的问题。
以下代码大部分有效:
import psutil
# parallel processing for GridSearchCV.fit()
current_process = psutil.Process()
original_priority = current_process.nice()
current_process.nice(psutil.BELOW_NORMAL_PRIORITY_CLASS) # set parent priority
grid_search.fit(X, y)
current_process.nice(original_priority) # reset parent priority
这是运行上述代码的示例数据集和模型:
from sklearn.datasets import load_digits
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
# sample dataset
dataset = load_digits()
X, y = dataset.data, dataset.target
# sample model
rf_model = RandomForestClassifier(n_jobs=-1)
param_grid = {'max_depth': [x for x in range(5, 20)],
'min_samples_split': [x for x in range(2, 10)]}
grid_search = GridSearchCV(rf_model, param_grid, n_jobs=-1)
此代码通常允许 grid_search.fit() 以低于正常优先级成功生成其并行进程,但并非总是如此。有时,只有某些进程的优先级低于正常优先级,而大多数进程都是正常的,并且无论出于何种原因,我都无法始终如一地重现该行为。另外,我不确定将父进程设置为低于正常优先级(例如与 Jupyter Lab 会话交互或停止内核)会产生什么后果。
这是为 n_jobs 产生的 scikit-learn 并行进程设置较低优先级的正确方法吗?关于并行性的 scikit-learn 文档 表明 n_jobs 参数使用 joblib 作为其底层实现,但我在这组文档中没有看到任何有关进程优先级的内容。
我能做的最好的事情就是将 psutil 代码放入上下文管理器中:
import psutil
from contextlib import contextmanager
@contextmanager
def lower_process_priority():
current_process = psutil.Process()
original_priority = current_process.nice()
try:
current_process.nice(psutil.BELOW_NORMAL_PRIORITY_CLASS)
yield
finally:
current_process.nice(original_priority)
用途:
with lower_process_priority():
grid_search.fit(X, y)
这非常有效,可以让我在 scikit-learn 在后台运行时执行常规计算任务。有些应用程序的响应比其他应用程序更好(奇怪的是,Notepad++ 几乎无法使用),但它已经足够好了。
我发现的一个怪癖是,在 Firefox 中通过 Jupyter Lab 运行此代码时,Jupyter Lab 选项卡/进程本身通常被分配低优先级,这使得 Jupyer Lab 选项卡无响应。使用任务管理器手动将适当的 Firefox 进程设置为“正常”效果很好(在 Firefox 中调用 about:processes 并在括号中找到进程 ID)。