如何让scikit-learn RandomizedSearchCV嵌套并行充分利用全部核心?
我正在使用RandomizedSearchCV优化并评估多个机器学习模型,尝试通过joblib的Parallel()运行优化流程,但在16核的HPC上运行代码时,仅能用到其中2个核心,其余核心处于闲置状态。
相关代码片段
jobs = 16 x = Parallel(n_jobs=jobs, backend='multiprocessing', verbose=3)(delayed(fit)(m, X_train, y_train, n_iter= 3, cv = 3, return_train_score= True, scoring='r2', refit='r2', n_jobs=4, verbose = 3) for m in models)
补充说明
测试2个模型时,Parallel()仅占用2个核心,其余14个核心使用率为0.0%。fit()函数内的迭代/折叠操作似乎以线程形式在这2个核心上运行。
核心疑问
是否存在方法实现嵌套并行执行,以充分利用全部16个核心?
要实现嵌套并行并充分利用HPC的全部核心,需要调整并行层级的资源分配逻辑,避免并行资源浪费,以下是具体方案:
1. 合理分配内外层并行的核心数
当前代码外层Parallel(n_jobs=16)但仅传入2个模型,因此外层最多启动2个进程;每个进程内的RandomizedSearchCV设置n_jobs=4,总核心占用最多为2*4=8,远低于16核的上限。
正确的做法是根据模型数量和总核心数,按比例分配内外层的n_jobs:
- 总核心数固定为16,模型数量为2时,设置外层
n_jobs=2(每个模型对应一个外层进程),内层RandomizedSearchCV的n_jobs=8(每个进程分配8个核心),总核心占用刚好为2*8=16。 - 若模型数量变化,可按
内层核心数=总核心数//模型数量的逻辑动态计算。
修改后的核心代码:
total_cores = 16 num_models = len(models) inner_jobs = total_cores // num_models x = Parallel(n_jobs=num_models, verbose=3)( delayed(fit)( m, X_train, y_train, n_iter=3, cv=3, return_train_score=True, scoring='r2', refit='r2', n_jobs=inner_jobs, verbose=3 ) for m in models )
2. 使用对嵌套并行更友好的后端
默认的multiprocessing后端在嵌套并行场景下存在限制,建议使用joblib默认的loky后端,它对嵌套并行的支持更稳定,无需额外配置,直接去掉backend参数即可:
x = Parallel(n_jobs=num_models, verbose=3)( delayed(fit)( m, X_train, y_train, n_iter=3, cv=3, return_train_score=True, scoring='r2', refit='r2', n_jobs=inner_jobs, verbose=3 ) for m in models )
3. 强制内层并行使用进程模式
部分sklearn模型内部默认使用线程并行,会受GIL锁限制导致核心无法充分利用。可在fit函数内强制内层并行使用进程模式:
def fit(mod,X ,y , **kwargs): with parallel_backend('loky'): grid_search = RandomizedSearchCV(mod['estimator'], mod['param'], **kwargs) grid_search.fit(X, y) return grid_search, mod['model']
4. 验证核心使用情况
修改后可通过HPC的监控工具(如htop)观察核心使用率,确认是否所有16个核心都被充分利用。若仍有闲置,可微调内外层n_jobs数值(比如总核心数无法被模型数整除时,给其中一个模型多分配1个核心)。
内容的提问来源于stack exchange,提问作者Christine

