loading

Resources

29Jan 2019

使用原生數學函式庫加速 Spark 機器學習應用程式

作者:Zuling Kang

原文:Using Native Math Libraries to Accelerate Spark Machine Learning Applications

 

Spark ML 是許多重要的機器習演算法最常使用的架構之一,例如推薦系統適用的交替最小二乘(Alternating Least Squares, ALS) 演算法、主成份分析(Principal Component Analysis) 演算法以及隨機森林(Random Forest) 演算法。不過,由於經常發生設定錯誤的問題,使得Spark ML 的潛力沒有太多機會全力發揮。讓Spark ML 使用原生數學函式庫是獲取那份潛力的方法之一。

 

本文討論讓Spark ML 使用原生函式庫如何能加速模型訓練速度。它也討論為什麼Spark ML 能從原生函式庫獲益、如何啟用CDH Spark 的原生函式庫,以及比較Spark ML 使用不同的原生函式庫時的效能。

Spark ML 的原生數學函式庫

Spark MLlib 使用 Breeze線性代數套件,其倚賴 netlib-java進行最佳化的數值處理。netlib-java是低階 BLASLAPACKARPACK函式庫的包裝函式。不過,因為執行時間專用二進位檔的授權問題,Cloudera 版本的Spark 以及Apache Spark 社群版本的預設設定均未包含 netlib-java原生代理伺服器。所以,若您未進行手動設定,netlib-java僅使用 F2J函式庫,這是轉譯自Fortran77 參考原始碼的Java 型數學函式庫。

要確認您使用的是Spark ML 或Java 型F2J 的原生數學函式庫,請使用Spark shell 來載入和輸出 netlib-java的實作函式庫。比如,下列命令回傳BLAS 函式庫的資訊且在這一行 com.github.fommil.netlib.F2jBLAS說明它正在使用F2J,那一行在下方以粗體顯示:

scala> import com.github.fommil.netlib.BLAS

import com.github.fommil.netlib.BLAS

 

scala> println(BLAS.getInstance().getClass().getName())

18/12/10 01:07:06 WARN netlib.BLAS: Failed to load implementation from: com.github.fommil.netlib.NativeSystemBLAS

18/12/10 01:07:06 WARN netlib.BLAS: Failed to load implementation from: com.github.fommil.netlib.NativeRefBLAS

com.github.fommil.netlib.F2jBLAS

 

 

在Spark ML 採用原生函式庫

Anand Iyer 和Vikram Saletore 在他們的工程部落格文章中指出,原生的數學函式庫如OpenBLAS 和Intel 數學核心函式庫(MKL) 會加速Spark ML 的訓練效能。不過,不同的模型有不同的加速幅度。

對於推薦系統(交替最小二乘(ALS) 演算法) 所使用的矩陣分解模型,OpenBLAS 和Intel MKL 皆能達到比F2J 實作更快4.3 倍的模型訓練速度。其他的比如Latent Dirichlet Allocation (LDA)、主成份分析(PCA) 以及奇異值分解(SVD) 演算法,使用Intel MKL 可達到56% 至72% 的改善幅度,而使用OpenBLAS 則有10% 至50% 的改進。

 

然而,該部落格文章也說明,有一些演算法,例如隨機森林(Random Forest) 和梯度提升樹(Gradient Boosted Tree) 在啟用OpenBLAS 或MKL 之後速度並未加速。其中原因,主要是因為這些樹狀結構型演算法的訓練集並不是向量。這表示說原生函式庫,無論OpenBLAS 或MKL,對於可以把訓練集當作向量來運作而且作為整體進行運算的演算法,適應效果更好。使用矩陣運作來操作訓練集的演算法,使用數學加速法會有更顯著的效果。

 

如何啟用原生函式庫

下列小節說明如何為Spark ML 啟用 libgfortran和MKL。範例中使用RHEL 7.4 上的CDH 5.15 來產生效能比較結果。CDH 6.x 提供相同的功能。

啟用libgfortran 原生函式庫

重要:下列指示可供CDH 5.x 中的Spark 1.6x 以及CDH 6.x 中的Spark 2.x 使用。在那些版本中,GPLEXTRAS 自動把使用原生函式庫所需要的JAR 檔案的classpath 新增到 /etc/spark/conf/classpath.txt。接著 spark-env.sh在boostrap 期間載入額外的Java 函式庫。不過若是CDH 5.x 中的Spark 2.x,則GPLEXTRAS 無法這麼做。若您要使用Spark 2.x,您必須升級至CDH 6.x,它便能為Spark 2.x 進行這個設定。

  • 在每一個CDH 節點上啟用 libgfortran4.8 函式庫。例如,在RHEL 中,在每一個節點上執行下列指令:yum -y install libgfortran
  •  在Cloudera Manager 中安裝GPLEXTRAS parcel,然後啟動它:
    1. 要安裝GPLEXTRAS parcel,請參閱Cloudera Manager 說明文件的「Installing the GPL Extras Parcel」。
    2. 要啟動套件,請參閱啟動parcel
    3. 在啟動GPLEXTRAS parcel 之後,在Cloudera Manager 中,瀏覽至主機> Parcels 來確認已經啟動GPLEXTRAS:

GPLEXTRAS parcel 當作是 libgfortran的包裝函式。

  • 按照Cloudera Manager 的指引,重新啟動適當的CDH 服務。
  • 重新啟動一旦完成,便使用下列命令,利用 Spark shell 來確認已經載入原生函式庫:

scala> import com.github.fommil.netlib.BLAS

import com.github.fommil.netlib.BLAS

 

scala> println(BLAS.getInstance().getClass().getName())

18/12/23 06:29:45 WARN netlib.BLAS: Failed to load implementation from: com.github.fommil.netlib.NativeSystemBLAS

18/12/23 06:29:45 INFO jni.JniLoader: successfully loaded /tmp/jniloader6112322712373818029netlib-native_ref-linux-x86_64.so
com.github.fommil.netlib.NativeRefBLAS

您可能不瞭解為什麼仍然出現一則關於 NativeSystemBLAS 無法載入的警告訊息。請別擔心。之所以出現警告,是因為我們僅設定 Spark 使用的原生函式庫,而不是供全系統使用。您可以忽略這個警告,不必擔心。
 

啟用Intel MKL 原生函式庫

  • Intel 在網站上以Cloudera Manager parcel 的形式提供MKL 原生函式庫。您可以新增它作為Cloudera Manager 的遠端parcel 儲存庫。然後您可以下載該函式庫並啟動它:
  1. 在Cloudera Manager 中,瀏覽至主機> Parcel。
  2. 選擇設定。
  3. 在遠端parcel 儲存庫URL 小節中,按一下加號並新增下列URL:http://parcels.repos.intel.com/mkl/latest
  4. 按一下儲存變更,然後您會回到列出可用parcel 的頁面。
  5. 為 mklparcel 按一下下載:
  6. 按一下分發,當它分發到叢集上主機完成之後,按一下啟動。
  • MKL parcel 僅含有Linux 共用的函式庫檔案(.so檔案),為了讓JVM 可以存取,必須建立一個JNI 包裝函式。要建立包裝函式,請使用下列MKL 包裝函式parcel。使用步驟1 說明的相同程序把下列連結新增到Cloudera Manager parcel 設定頁面,下載該parcel,把它分發到各個主機,然後啟動它:https://raw.githubusercontent.com/Intel-bigdata/mkl-wrappers-parcel-repo/master/
  • 按照Cloudera Manager 的指引重新啟動對應的CDH 服務,必要時重新部署用戶端設定。
  • 在Cloudera Manager 中,把下列設定資訊新增到for spark-conf/spark-defaults.conf 的Spark Client Advanced Configuration Snippet (Safety Valve) 中:spark.driver.extraJavaOptions=-Dcom.github.fommil.netlib.BLAS=com.intel.mkl.MKLBLAS -Dcom.github.fommil.netlib.LAPACK=com.intel.mkl.MKLLAPACK

此設定資訊指示Spark 應用程式載入MKL 包裝函式並使用MKL 作為Spark ML 的預設原生函式庫。重要:

  • 藉由設定 MKL_VERBOSE=1,MKL 記錄有哪些運算函式被呼叫、哪些參數被傳遞到函式,以及花費多少時間執行函式。這些資訊對於實作可能甚有幫助,但是它耗用叢集中HDFS 的大量空間。在下個小節討論的實驗性案例中,每個工作的日誌記錄可能會佔用數百GB 的空間。

  • 在驗證所使用的原生函式庫時如果傳回 UnsatisfiedLinkError訊息,如下所示,把 /opt/cloudera/parcels/mkl/linux/mkl/lib/intel64目錄新增到每個叢集節點的 LD_LIBRARY_PATH環境變數中。Native code library failed to load.

java.lang.UnsatisfiedLinkError: /opt/cloudera/parcels/mkl_wrapper_parcel-1.0/lib/native/mkl_wrapper.so: libmkl_rt.so: cannot open shared object file: No such file or directory

  • 再次開啟Spark shell 來驗證原生函式庫,而且您應該會看到下列輸出:scala> import com.github.fommil.netlib.BLAS

import com.github.fommil.netlib.BLAS

scala> println(BLAS.getInstance().getClass().getName())

com.intel.mkl.MKLBLAS

 

效能比較

在本小節,我們使用ALS 演算法來比較使用不同的數學函式庫(包括F2J、libgfortran和Intel 的MKL) 當基礎的訓練速度。

我們所使用的硬體是Amazon EC2 的 r4.largeVM 實例,每個實例含有2 個CPU 核心以及15.25 GB 的記憶體。此外,我們使用CentOS 7.5 及CDH 5.15.2 搭配Cloudera Distribution of Spark 2.3 Release 4。訓練程式碼取自O’Reilly 出版(2017) 由Sandy Ryza 等人著作的Advanced Analytics with Spark (第二版) 中ALS 章節的核心部分。訓練資料集是由Audioscrobbler 發佈,要下載請至:

https://storage.googleapis.com/aas-data-sets/profiledata_06-May-2005.tar.gz

     

通常ALS 模型的級別會設定為比預設的10 大上許多的數值,所以我們在這裡使用數值200,確保結果與現實世界的例子更接近。以下是為ALS 模型設定參數值所需要的程式碼:

val model = new ALS().

     setSeed(Random.nextLong()).

     setImplicitPrefs(true).

     setRank(200).

     setRegParam(0.01).

     setAlpha(1.0).

     setMaxIter(20).

     setUserCol("user").

     setItemCol("artist").

     setRatingCol("count").

     setPredictionCol("prediction")

     

下列表格和圖形顯示Spark ML 使用不同的原生函式庫的訓練時間。數值以分鐘為單位。我們發現 libgfortran和Intel 的MKL 的確改善了訓練速度,而MKL 的效能表現似乎更加出色。從這些實驗結果來看,libgfortran改善了18% 至68%,而MKL 的改進則從92% 至213%。

Worker/Executor 的數量

F2J

libgfortran

Intel MKL

3 個worker ( 9 個executor)

426

360

222

9 個worker (26 個executor)

282

168

90

鳴謝

感謝Cloudera 的Alex Bleakley 和Ian Buss 提供有用的建議及審閱本文!

作者簡介

Zuling Kang 是Cloudera, Inc., 的資深解決方案架構設計師,具有電腦科學博士學位。在加入Cloudera 之前,他曾在中國移動通信集團浙江有限公司擔任巨量資料系統的架構設計師。目前他已發表了9 篇學術/技術論文,其中7 篇獲得科技期刊引用文獻資料庫(SCI)/Ei Compendex 資料庫(前身是Engineering Index)列入索引。其中一篇論文〈Performance-Aware Cloud Resource Allocation via Fitness-Enabled Auction〉發表在《IEEE Transactions on Parallel and Distributed Systems》。Zuling 目前在研究與工程設計方面的興趣包括巨量資料平台的架構、巨量資料處理技術以及機器學習。

Back to list.
Prev
資料科學越來越重視 DevOps
資料科學越來越重視 DevOps
Next
Cloudera DataFlow (CDF) 簡介
Cloudera DataFlow (CDF) 簡介