ScalaNLP/Breeze入門 2


ScalaNLP/Breezeの使い方の第2回です。

ScalaNLP/Breezeが何かとか、インストール方法などについては第1回をご覧下さい。

Breezeを用いた行列とベクトルの復習

簡単な例として、2行2列の例で説明しましょう。

オブジェクトの生成

breezeでは下記のような(密)ベクトル

\( \displaystyle x = \left( \begin{array}{c} 1 \\ 2 \end{array} \right) , \; y = \left( \begin{array}{c} 3 \\ 4 \end{array} \right) \)

と書く事が出来ます。

下記のような(密)行列

\( \displaystyle A = \left(\begin{array}{cc}
2 & 3 \\
1 & 2
\end{array}\right), \;
B = \left( \begin{array}{cc} 3 & 4 \\ 2 & 3 \end{array}\right)\)

を定義するには、行ベクトル(横ベクトル)を縦に並べて表現します。

加減算、積など

行列の加減算は通常の +, - といった演算子が使用出来ます。また行列の積も * で計算出来ます。

\( \displaystyle
x+y = \left( \begin{array}{c} 4 \\ 6 \end{array}\right), \;
A+B = \left( \begin{array}{cc} 5 & 7 \\ 3 & 5 \end{array}\right), \;
AB = \left( \begin{array}{cc} 12 & 17 \\ 7 & 10 \end{array}\right), \;
Ax = \left( \begin{array}{c} 8 \\ 5 \end{array}\right)
\)
は、

となります。

要素の取得、スライス

行列 \(A\) の要素を取り出したり、その部分(slice)を取り出す事も出来ます。行列 \(A\) をa で表すならば、\(A_{ij}\) は a(i,j) で表現されます。但し数学と違って添字が1-originではなく0-originであることに注意する必要があります。要素やスライスを取得する例は下記の様になります。(ここだけ判り易い様に3行3列の行列を使ってます)

各行や各列のsliceを作るには別の記法もあります。こちらの方が判り易いかもしれません。

mutable object

行列やベクトルは、メモリ使用量や効率を考えmutable objectとして作成されます。従って要素を変更可能です。またsliceは元のobjectを参照しているので下記の様にzの変更を通じてcが変更されます。また*=の様な自分自身を更新する演算子も多数用意されています。

逆行列

逆行列などを計算するにはDouble型の行列である必要があります。

\( \displaystyle A = \left(\begin{array}{cc}
2 & 3 \\
1 & 2
\end{array}\right), \;
B = \left(\begin{array}{cc}
3 & 4 \\
2 & 3
\end{array}\right),
\;x = \left(\begin{array}{c}
1 \\
2
\end{array}\right)
\)

を下記の様に定義します。

\(A\) の逆行列 \(A^{-1}\) はinv(a)で計算出来ますが、\(A^{-1}B, \; A^{-1}x\) と逆行列を用いて計算したいだけの場合は、a \ b, a \ x\ という演算子を用いて逆行列を計算しない事が推奨されています。

\( \displaystyle A^{-1} = \left(\begin{array}{cc}
2 & -3 \\
-1 & 2
\end{array}\right), \;
A^{-1}x = \left(\begin{array}{c}
-4 \\
3 \end{array}\right), \;
A^{-1}B = \left(\begin{array}{cc}
0 & -1 \\
1 & 2
\end{array}\right)
\)
は下記の様になります。

ScalaNLP/Breeze入門 1


はじめに

機械学習用途のOSSというと RWeka などのツールが有名かと思います。それらの分析用ツールはデータの分析を主目的としており、弊社のようにアプリケーションへの組み込み用途が主になる場合や、論文などを読んでツールに無いアルゴリズムを実装してみようと思った場合などは、多少使いにくい部分も有ります。(なお Weka は Java から呼び出し可能なライブラリとして提供されていますが。)

プログラミング言語から呼び出し易い数値計算のライブラリというと Python の SciPy, NumPy といった有名なライブラリ群があります。が、Scala を主たる開発言語としている弊社としては、出来れば JVM 上で動くライブラリを使いたいところです。

そういった目的の為のライブラリとしては Scala にも ScalaNLP/Breeze というライブラリがあります。ScalaNLP/Breeze は下位ライブラリとして netlib-java という数値計算ライブラリ経由で BLAS/LAPACK などの定評ある高速なネイティブ数値計算ライブラリを呼び出します。 (MacOSXの場合はMacにインストールされているApple版のBLAS/LAPACKが使用されます。Linux, Windows の場合は netlib-java の記述を参考として ATLAS などの導入が別途必要です)。

そこで ScalaNLP/Breeze の使い方の紹介を数回に渡って行おうと思います。

セットアップ

github上の README.md を参考にセットアップします。

ここでは scala 2.10 と sbt 0.12 が予め導入されている事を前提とします。

プロジェクトのディレクトリとして scalanlp-usage/ を作成し、その下にbuild.sbt ファイルを作成します。(ライブラリ取得先については多少無関係なものも含まれていますが、良く使うところなので。)

build.sbt 内容

上記のようなファイルを作成し、プロジェクトディレクトリ下で

$ sbt update

を実行し、[success] が表示されれば、ライブラリの導入完了です。

動作確認

動作確認をしてみましょう。下記は MacOSX 上で動作確認した場合です。

上記の様に、行列の掛け算は JNI 経由でネイティブなライブラリが呼び出されている事が判ります。

簡単な性能確認

どのくらいの規模の計算がどの程度の時間で計算出来るか、簡単に確かめてみましょう。その為に、ランダムな正方行列で定まる一次方程式を解く時間と、どの程度の大きさまで解けるのか、試してみます。

Main0.scala

引数で行列の大きさを適当に変えつつ試してみると、

と、計算時間はほぼ大きさの3乗に比例し、大きさ 1000×1000 の行列であれば 30msec 程度で解く事ができ、8000×8000 の行列であれば10秒以内には解けていることが判ります。これを試した条件は sbt起動オプションが -Xms1536m -Xmx1536m なので、ヒープサイズを多めにすればもう少し大きな問題も解けるでしょう。

次回からもう少し具体的に、ライブラリの使い方を解説します。