8.3. 并行, 資源管理和配置?
8.3.1. 并行計算
一些scikit-learn的評估器與實用程序可以通過多核CPU進行并行計算,這要歸功于下面的組件:
通過 joblib 庫. 可以通過 n_jobs
參數控制程序的進程或線程數量.通過OpenMP, 使用 C 或者 Cython 代碼.
此外,如果numpy安裝了特定的數字庫(如MKL、OpenBLAS或BLIS),scikit learn內部使用的一些numpy例程也可以并行化。
我們將在下面的小節中描述這三個場景。
8.3.1.1. 基于Joblib的并行計算
當底層實現使用joblib時,可以通過n_jobs
參數來控制并行生成的worker(線程或進程)的數量。
注意 在估計器中并行化發生的位置(和方式)目前文獻記錄不多。請幫助我們改進我們的文檔并解決 issue 14228!
Joblib能夠同時支持多處理和多線程。joblib選擇生成線程還是進程取決于它使用的后端。Scikit learn通常依賴于loky
后端,這是joblib的默認后端。Loky是一個多處理后端。
在進行多進程計算時,為了避免在每個進程中復制內存(對于大數據集來說這是不合理的),joblib將創建一個memmap當數據大于1MB時,所有進程都可以共享。
在某些特定情況下(當并行運行的代碼釋放GIL時),scikit learn將向joblib
指示多線程后端是更可取的。
作為用戶,您可以通過使用上下文管理器來控制joblib將使用的后端(無論scikit learn推薦什么):
from joblib import parallel_backend
with parallel_backend('threading', n_jobs=2):
# Your scikit-learn code here
有關更多詳細信息,請參閱joblib’s docs。
實際上,并行性運算是否有助于改進運行時取決于許多因素。實驗通常是一個好主意,而不是假設增加并行計算的數量總是一件好事。在某些情況下,并行運行某些估計器或函數的多個副本會對性能造成極大的損害(請參閱下面的超額訂閱)。
8.3.1.2. 基于OpenMP的并行運算
OpenMP使用Cython或C編寫的代碼實現并行化,完全依賴多線程。默認情況下(除非joblib試圖避免超額使用)將使用盡可能多的線程。
您可以通過OMP-NUM-threads
環境變量控制使用的線程的確切數量:
OMP_NUM_THREADS=4 python my_script.py
8.3.1.3. 基于特定數字庫的numpy并行化例程
Scikit learn在很大程度上依賴于NumPy和SciPy,后者在內部調用在MKL、OpenBLAS或BLIS等庫中實現的多線程線性代數例程。
OpenBLAS、MKL或BLIS庫使用的線程數可以通過MKL_NUM_threads
、OpenBLAS_NUM_threads
和BLIS_NUM_threads
環境變量設置。
請注意,scikit learn無法直接控制這些實現。Scikit-learn完全依賴于Numpy和Scipy
注意 在撰寫本文時(2019年),NumPy和SciPy軟件包在pypi.org網站(通過pip安裝)。conda forge通道上安裝的conda包與OpenBLAS鏈接,而從anaconda.org 默認通道上安裝的conda包與MKL鏈接。
8.3.1.4. 過度消耗: 生成太多線程
通常建議避免使用比計算機上CPU數量多得多的進程或線程。當程序同時運行太多線程時,會發生過度消耗。
假設你有一臺有8個CPU的機器。考慮一種情況,在histgradientboostingcrifier(與OpenMP并行)上運行GridSearchCV
(與joblib并行)和n_jobs=8
。HistGradientBoostingClassifier
的每個實例將產生8個線程(因為您有8個CPU)。總共有8*8=64
個線程,這會導致物理CPU資源的超額訂閱和調度開銷。
使用嵌套在joblib調用中的MKL,OpenBLAS或BLIS的并行化例程,可以以完全相同的方式產生超額訂閱。
從joblib>=0.14
開始,當使用oky
后端(這是默認值)時,joblib將告訴其子進程,以限制它們可以使用的線程數,從而避免超額訂閱。在實踐中,joblib使用的啟發式方法是通過相應的環境變量告訴進程使用max_threads=n_cpu//n_jobs
。回到上面的例子,由于GridSearchCV的joblib后端是loky,因此每個進程只能使用1個線程而不是8個線程,從而減少了訂閱過多的問題。
注意:
手動設置其中一個環境變量(
OMP NUM_THREADS
、MKL NUM_THREADS
、OPENBLAS NUM_THREADS
或BLIS NUM_THREADS
)將優先于joblib嘗試執行的操作。線程總數將為n_jobs*_NUM_threads
。請注意,設置此限制還將影響主進程中的計算,該進程只使用NUM
線程。Joblib公開一個上下文管理器,以便更好地控制其工作線程的數量(請參閱下面鏈接的Joblib文檔)。Joblib當前無法避免多線程上下文中的超額訂閱。它只能使用“loky”后端(它生成進程)。
您將在joblib文檔中找到有關joblib緩解超額訂閱的其他詳細信息。
8.3.2. 配置開關
8.3.2.1. python 運行時
sklearn.set_config
參數控制下列行為:
assume_finite(假設有限)
用于跳過驗證,這可以加快計算速度,但如果數據包含NaN,則可能導致分段錯誤。
working_memory(工作內存)
一些算法使用的臨時數組的最佳大小。
8.3.2.2. 環境變量
在導入scikit-learn之前應該先設置這些變量。
SKLEARN_SITE_JOBLIB
當此環境變量設置為非零值時,scikit-learn使用站點joblib而不是其供應商版本。因此,必須安裝joblib才能運行scikit-learn。請注意,使用網站joblib需要您自擔風險:scikit-learn和joblib的版本必須兼容。當前,支持joblib 0.11+。此外,joblib.Memory的轉儲可能不兼容,您可能會丟失一些緩存并必須重新下載一些數據集。
*從版本0.21開始不推薦使用:*從版本0.21開始,此參數無效,已刪除供應商的joblib,并且始終使用站點joblib。
SKLEARN_ASSUME_FINITE
為
assume_finite
參數 設置默認值sklearn.set_config
.SKLEARN_WORKING_MEMORY
為
working_memory
參數 設置默認值sklearn.set_config
.SKLEARN_SEED
為了運行可重復性,在運行測試時設置全局隨機數生成器的種子。
SKLEARN_SKIP_NETWORK_TESTS
當此環境變量設置為非零值時,將跳過需要網絡訪問的測試。