LoginSignup
28
26

More than 5 years have passed since last update.

Spark MLlib でネイティブライブラリを使う

Last updated at Posted at 2015-05-01

Spark と MLlib

Sparkはオープンソースの分散処理フレームワークです。
Hadoopと比較した場合、インメモリで処理を行うため繰り返しの計算に強く、特に機械学習にメリットがあります。
Sparkは標準でMLlibという機械学習ライブラリを用意していて、キラーアプリといえる存在になっています。
MLlibにはBLASのような著名なアルゴリズムが用意されています。

MLlib と Netlib

MLlibのアルゴリズムには、Javaで実装されたjblasが使用されています。
しかし、MLlibのパフォーマンスを高めるために、内部のアルゴリズムをネイティブの実装であるNetlibと差し替えたいと考えるのは自然なことでしょう。
Sparkはそのための手段を用意しています。

netlib-javaのビルド

SparkはJavaVM上で動作しますので、JNI経由でNetlibを呼び出すことになります。
JNIのラッパーはnetlib-javaと呼ばれています。
SparkでNetlibを使うためには、まず、netlib-javaをビルドする必要があります。
GitHubのREADMEにビルド手順が書かれていないので、非常に分かりにくい上に、pom.xmlに誤りがあったりとヘコみますが、ここを参考にしてビルドしましょう。
なお、blas-devel、lapack-devel、atlas-devel、libgfortranを事前にインストールしておきます。

$ git clone https://github.com/fommil/netlib-java.git
$ cd netlib-java
$ git checkout -b 1.1.2 refs/tags/1.1.2
$ sed -i "s/1.2-SNAPSHOT/1.1.2/g" `grep -l 1.2-SNAPSHOT pom.xml perf/pom.xml legacy/pom.xml`          # pom.xmlを修正する
$ sed -i "s/1.1.1/1.1.2/g" `grep -l 1.1.1 generator/pom.xml core/pom.xml all/pom.xml`                 # pom.xmlを修正する
$ sed -i "s/1.2-SNAPSHOT/1.1/g" `grep -rl --include='pom.xml' 1.2-SNAPSHOT native_ref native_system`  # pom.xmlを修正する
$ mvn package                                               # エラーは無視する
$ cd native_system
$ mvn package                                               # エラーは無視する
$ cd xbuilds/linux-x86_64
$ mvn package
$ cd ../../../native_ref
$ mvn package                                               # エラーは無視する
$ cd xbuilds/linux-x86_64
$ mvn package

ビルドしてできたsoファイルをインストールします。
残念ながら、ファイル名が lib*.so 形式になっていないので、ldconfigが使えません。(ファイル名をリネームしてもよいですが)

$ cd netlib-java
# cp native_system/xbuilds/linux-x86_64/target/netlib-native_system-linux-x86_64.so /usr/lib64
# cp native_ref/xbuilds/linux-x86_64/target/netlib-native_ref-linux-x86_64.so /usr/lib64

Netlibを有効にしてSparkをビルドする

netlib-javaをインストールしただけではSparkから利用できません。
Netlibを使うようにSparkをビルドする必要があります。
-Pオプションにnetlib-lgplを追加するだけなので簡単です。
LGPLとなっていますが、Netlibのライセンス不明が正しいようです。
今回はYARN対応と合わせてビルドします。

$ git clone https://github.com/apache/spark.git
$ cd spark
$ git checkout -b v1.3.1 refs/tags/v1.3.1
$ ./make-distribution.sh --tgz -Phadoop-2.4 -Pyarn -Pnetlib-lgpl -DskipTests

ビルドしたSparkをインストールします。
お好みの方法でどうぞ。
Sparkの設定については省略します。

# cp spark-1.3.1-bin-2.4.0.tgz /usr/local/
# cd /usr/local
# tar xvf spark-1.3.1-bin-2.4.0.tgz
# chown -R spark:hadoop spark-1.3.1-bin-2.4.0
# ln -s spark-1.3.1-bin-2.4.0 spark

ビルドしたspark-assemblyをHDFSに配置します。
HDFSに配置しなくても自動でアップロードしてくれますが、毎回アップロードするのは無駄ですからね。

$ cd spark
$ hdfs dfs -put lib/spark-assembly-1.3.1-hadoop2.4.0.jar /user/spark/share/lib/spark-assembly.jar
$ hdfs dfs -chown spark /user/spark/share/lib/spark-assembly.jar

動作確認

SparkShell を起動して確認します。
ネイティブライブラリを使用するか否かは以下の順番で試行されます。
また、com.github.fommil.netlib.BLASプロパティで強制的に指定することもできます。

  1. NativeSystemBLAS
  2. NativeRefBLAS
  3. F2jBLAS

NativeSystemBLAS と NativeRefBLAS の違いは不明です...。
詳しい方がいたら教えてください。

$ spark-shell --master yarn
$ spark-shell --master yarn --driver-java-options -Dcom.github.fommil.netlib.BLAS=com.github.fommil.netlib.F2jBLAS    # F2jBLASを強制的に使用する場合
:
Spark context available as sc.
scala> import com.github.fommil.netlib.BLAS
import com.github.fommil.netlib.BLAS
:
scala> println(BLAS.getInstance().getClass().getName())
15/05/01 14:22:12 INFO JniLoader: successfully loaded /usr/lib64/netlib-native_system-linux-x86_64.so
com.github.fommil.netlib.NativeSystemBLAS

NativeSystemBLAS が表示されれば成功です。

ベンチマーク

簡単ですが、ベンチマークとしてDenseMatrix(1000,1000)の掛け算を実行してみました。
疑似分散環境なので参考程度ですが。

NativeSystemBLAS NativeRefBLAS F2jBLAS
1回目 399 830 1105
2回目 362 834 1091
3回目 337 814 1452

(単位:ms)

F2jBLAS に比べて NativeSystemBLAS は 3.3倍高速 という結果になりました。

28
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
26