de[v|b]log

ShellScript, Coffee, iOS/OSX Dev
Origin: Himajinworks.
About.

あいさつ

さて、世間はクリスマスイブなわけですが私にはそんなの関係ないわけです。みなさまいかがお過ごしでしょうか。 そんな私が贈る今日の記事ですが、今年はタイトルにもあるとおりに寝起きを共にする仲となった GNU Octave に関連した話にしたいと思います。

ということで、この記事は Aizu Advent Calendar 2015 24日目の記事です。 前の人は mic_psm 、今年のAizu Advent Calendarを締めるのは大御所 Mopp_jp です。皆様よろしくお願いいたします。

GNU Octaveの紹介

まず今回の主役でもある、 GNU Octave の紹介です。

GNU Octaveは数値計算を目的としたインタプリタ言語(+環境)であり、線形・非線形問題や他の数値実験に利用することができるツールであり、また、ツール内ではデータの可視化等も行うことができます。プログラムとしては Matlab に類似したシンタックスを利用して記述することができ、ソフトウェア自体はGPLの下で配布されています。 ( 本サイト の意訳)

めでたく2015年5月29日にバージョン4.0.0が公開されました。

octave

MATLAB使えばいいじゃん

まずこのツッコミが来ます。8割方これです。 ということでまずはここでなぜ私がGNU Octaveを使うか、何に使っているのかを紹介したいと思います。

なぜGNU Octaveを使うのか

  • MATLAB代替のオープンソースソフトウェア(OSS)として扱える
  • シンタックス/関数群が他のMATLABクローンよりもMATLABに近い

上記の2つです。基本的にはOSSとして扱えるのが大きいと思っています。

MATLAB代替のオープンソースソフトウェア(OSS)として扱える

現在MathWorks社はMATLABに対して学生ライセンスを用意しており、学生である私は普通に購入するよりも安価で手に入れることが可能です。 しかしそこにも色々あるわけで、特に拡張機能を利用したい場合にはアドオンの購入(各3,000円程度)が必要となります。 個人的には、やっていることの規模が狭いのであればアドオンを2-3個程度購入すれば済みそうなのでMATLABを買うと思うんですが、残念なことにやりたいことというのは日々増えていくわけで、関連したツールがちょくちょく欲しくなるということでMATLABから離れています。

シンタックス/関数群が他のMATLABクローンよりもMATLABに近い

検索してみるとわかると思うのですが、MATLAB用のコードとしてブログに例を上げている方が結構いらっしゃって、かつMATLAB系のQ&Aには多くの情報があります。それに対しての共通点が多いというのはひとつの強みだと思ってます。 実際に作業をしている際は MATLABのドキュメントOctaveのドキュメント を行き来して作業してます。

あと研究関係でどうしてもMATLABのコードの対応をしなければならないタイミングがあるんですが、シンタックス/関数がほぼ同じというのはこういうところでも役立つなと思います。

何に使っているのか

研究

まずは大学での日々の研究で。 研究しているとやっぱり計算用サーバーとか用意して計算したりうんぬんというのがあって、パッケージマネージャでひょいひょいインストールできるのがまず嬉しいなと思います。

1
sudo apt-get install octave

これだけである程度使えるような環境が入るのはありがたい。 これでAnsibleでもなんでも使えるようになって便利ですね。

もちろんセットアップしたあとは作業するわけですが、ここから先はMATLABと何ら変わりのないところなので省略。

日常作業

日常の作業でもたまに使ったりということがあります。とは言っても単純な計算だったりとか、簡単な画像処理だったりとか、グラフのプロットだったりですが。 ただ、これがインストールされているだけでどうにかなるというのは割と強いんじゃないかなと思いますね。

よくないところ

ここまでの話を見ているとMATLABがよくないんじゃないかと見えてくると思うのですが、そういうことではありません。もちろん商用ソフトウェアであるということだけあって強い点が多々あります。 例えばですが、Octaveを使っていると Missing function が結構現れます。特に難しめの関数については頻繁に現れます。 それから実は負の数に対する AND、OR、XORとかが使えません。 https://www.gnu.org/software/octave/doc/interpreter/Bit-Manipulations.html

ただOctaveはOSSの一種であるため、自分たちが動けば解決しないことはないためこれ以上は言及しないものとします。

よって、Octaveは気合次第ではMATLAB相当の機能を手に入れられるものである。程度に考えるのが妥当かと思います。

ここまでのまとめ

「うう、MATLAB使いたいよぅ・・・ でも財布が氷河期だよぅ・・・(´・ω・`)」 「プログラムならある程度書けるけど、できれば行列計算とか諸々はMATLAB互換のシンタックスが使いたいよぅ・・・(´・ω・`)」 「できればいろんな環境に入れて使いたいよぅ・・・(´・ω・`)」

こんな人にはおすすめです。

最近やった工夫

最後に最近やった工夫として一点、計算の高速化に関連した話をしたいと思います。

OpenBLASの導入

Octaveでは BLAS として内部で ATLAS 等を用いて行列演算の最適化をしているわけですが、まずこれを OpenBLAS に切り替えます。こうすることでまず行列演算の並列化が有効になります。(もしかしたらOctaveインストール時点での自分のやり方が悪いだけで、もともと並列処理ができるようになってるのかもしれませんが・・・) これに関しては ubuntu 14.04でBLASを使う - kashiの日記 を参考にしてUbuntu環境で行いました。

NVBLASの導入

ここで次に CUDA を導入します。ここでは特にGPGPUに触れることはしませんのであしからず。

上記でのOpenBLASでかなり以前よりも速くなったのですが、若干の物足りなさを感じたのと、CUDAが使える環境であったという点からCUDAを利用するために NVBLAS を導入しました。NVBLAS自体は本家ページにもあるとおり、GPUあくせられぃてっどなBLAS実装です。

これなのですが特に難しいことはなく、CUDAをインストールして実行時に適用するだけという感じです。 残念ながら私はUbuntu (Server)環境で作業を行っているもので、GUIなんてリッチなものがない環境でやっているのでXをぶっ倒してからやるという流れはありません。GUIがある環境でやる方はぜひXにCQCでもかましてから作業をしてください。(参考リンクを参照するといいと思います)

まずCUDAのインストールと環境設定(パスを通す)などに関しては UbuntuにCUDAを入れようとしたらハマった - Qiita を参考にしてください。尚、X11とかが一緒に忍び込もうとするので嫌な人は sudo dpkg -i cuda-repo-ubuntu*.debsudo apt-get update を行ったあとのインストールのタイミングで適切なパッケージ群を選択することをおすすめします。

さて、ここまできたら次にOctaveでNVBLASを利用するという段階ですが、全然むずかしくはありません。まず参考ページを示します。 Drop-in Acceleration of GNU Octave | Parallel Forall | Parallel Forall ここで書かれていることで重要なことは以下。

  • nvblas.conf をOctaveを起動するディレクトリにおいておくこと
  • LD_PRELOAD=libnvblas.so をOctaveを起動する際に付加すること

この2つ。

まず nvblas.conf は、参考ページにあるとおり以下のようにすれば大概の場合十分です。ただし、OpenBLAS以外を利用している場合はCPUで処理する際に適用するBLASライブラリ (CPU BLAS fallback Library)を NVBLAS_CPU_BLAS_LIB libopenblas.so の部分を適切に変更することで設定する必要があります。

1
2
3
4
5
NVBLAS_CPU_BLAS_LIB libopenblas.so
NVBLAS_LOGFILE nvblas.log

NVBLAS_GPU_LIST 0 1
NVBLAS_AUTOPIN_MEM_ENABLED

次に起動時に関しては以下のようにするとよい。

1
LD_PRELOAD=libnvblas.so octave <filename>

上記での </code> 自体はoptionalであり、特に必須ということではない。スクリプトを渡して動作させる場合はここにファイルパスを渡す。

これだけでCUDA環境を利用できるようになる。非常に簡単。

最後にOpenBLASを導入しCPUで処理した場合と、OpenBLAS + NVBLASを適用しCPU+GPUで処理した場合の簡単な比較を示す。 今回の比較に関しては以下の環境・問題で行われました。尚、問題の選択はちょうど実装したという関係で選んだだけです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function Y  =  geninv(G)
    % Transpose if m < n
    [m, n]    = size(G);
    transpose = false;

    if m < n
        transpose = true;

        A = G * G';
        n = m;
    else
        A = G' * G;
    end

    % Cholesky factorization of A
    L = chol(A, 'lower');

    % Computation of the generalized inverse of G
    M = inv(L' * L);
    if transpose
        Y = G' * L * M * M * L';
    else
        Y = L * M * M * L' * G';
    end
end

実行用のコードは以下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
source('./geninv.m');

scale = 100;

for k = 1 : 30;
    rand('seed', 1024);

    m = k * scale;

    results = [];
    for i = 1 : 10;
        a = rand(m, m - 1);

        tic;
        g_i = geninv(a);
        t = toc;

        results = [results, t];
    end

    v_mean = mean(results);
    v_std  = std(results);

    printf("%d, %d, %.10f, %.10f\n", m, m - 1, v_mean, v_std);
end
1
2
3
4
5
6
7
#! /usr/bin/env zsh

# CPU
octave -q ./test.m > result_cpu.csv

# GPU
LD_PRELOAD=libnvblas.so octave -q ./test.m > result_gpu.csv

上記は単純化するためにコレスキー分解の部分をcholに置き換えたくらいで、あとはオリジナルの論文のコードのノリとほぼ同じ感じです。

comparison

今回最大で 3000 × 2999 までしか計測してないのでそこまで大きな差が見えてこないと思いますが、最大サイズの時点でCPU/CPU+GPU間で2秒程度開いてきているのが解ると思います。こんな感じで簡単な工夫次第では高速化が可能です。上記の結果は10回平均になってます。

結果は こちら

さいごに

ということでこんな感じでGNU Octaveをぐいぐいっといじりながら使うと楽しいよという話でした。 今年の年末はCUDAを使えるようにしたOctaveを使ってGPUを唸らせて暖をとりながら生活したいと思います。

さて、この記事がAizu Advent Calendar 2015 24日目の記事だったということは25日、明日が最後となります。ということで、あとは 大御所 Mopp_jp 、任せました。 また同時に今年もAdvent Calendarを企画してくれた yutopp に感謝です。

そういえばそろそろ ALT#0x06 企画しないとな…