Bayes Net Toolbox for Octave


bnt
以前、Wekaのベイジアンネットワークを触ってみました。あれから色々なツールを探してみたところ、CUIながら様々な機能が実装されているBayes Net Toolbox for Matlab(以下bnt)というものを知りました。名前の通りMatlab上で動くものですが、Matlab互換をうたうGnu Octaveでも動かせるかも知れない(*)ということなので、ちょっと触ってみようと思っています。

(*)https://code.google.com/p/bnt/wiki/WhyMatlab より引用:

Many people ask me why I did not use Octave, an open-source Matlab clone. The reason is that, when I first wrote BNT, Octave did not support multi-dimensional arrays,cell arrays, objects, etc. However, currently (Jan 2010) it does support those thins, so it should be possible to run most of BNT in Octave.

試した環境は以下の通りです。bntにはテストプログラム test_BNT が同梱されているようなのでこちらを一通り実行することを目標とします。

  • Ubuntu 12.04
  • Octave 3.6.2
  • bnt 1.0.7

インストール

UbuntuへのOctaveのインストールは、こちらを参考にしました。http://blogs.bu.edu/mhirsch/2012/08/octave-3-6-on-ubuntu-12-04/
bntを利用するには、上記サイトからzipファイルをダウンロードし、適当な場所に解凍すればOKです。以下のように /home/nishio/project というディレクトリの下に解凍したものとします。

% pwd
/home/nishio
% wget http://bnt.googlecode.com/files/FullBNT-1.0.7.zip
% mkdir project
% unzip FullBNT-1.0.7.zip -d project/FullBNT-1.0.7
% octave

octave を起動したら、プログラムのルートディレクトリに移動し、関数へのパスを通せば使えるようになるみたいです。

octave:1> cd project/FullBNT-1.0.7/bnt
octave:2> addpath(genpathKPM(pwd))

いくつか警告が出ますが、無視してテストを実行してみます。

octave:3> test_BNT

すると以下のエラーで止まってしまいます。

error: tabular_CPD: A(I): index out of bounds; value 1 out of bound 0
error: called from:
error:   /home/nishio/project/FullBNT-1.0.7/bnt/BNT/CPDs/@tabular_CPD/tabular_CPD.m at line 74, column 1
error:   /home/nishio/project/FullBNT-1.0.7/bnt/BNT/examples/static/Models/mk_incinerator_bnet.m at line 44, column 18
error:   /home/nishio/project/FullBNT-1.0.7/bnt/BNT/examples/static/cg2.m at line 4, column 7
error:   /home/nishio/project/FullBNT-1.0.7/bnt/BNT/test_BNT.m at line 6, column 1

これはOctaveとMatlabの差異によるもののようです。

OctaveとMatlabの差異について

Differences between Octave and MATLABの日本語訳(pdf) という文書を見たところ、エラーの原因は論理演算子のショートサーキット判定にまつわるモノだと考えられます。(原文には何故か含まれていませんが)
上記エラーは、以下の行で発生しています。配列が空で無いことを確認してから配列要素にアクセスするコードですが、octaveの&は演算子の前後が両方評価されるためエラーとなります。演算子の前を評価しただけで結果が明らかな場合は演算子の後を評価しない(ショートサーキット)ようにするには、&& を使えば良いらしいです。修正し、test_BNTを再実行するとエラーが出なくなります。

/home/nishio/project/FullBNT-1.0.7/bnt/BNT/CPDs/@tabular_CPD/tabular_CPD.m:74:if ~isempty(args) & ~isstr(args{1})

このパターンのエラーが何回か出てくるので、都度修正していきます。(途中で原因不明のエラーが出ることがありますが、octaveを再起動すると直りました)以下が修正箇所となります。

/home/nishio/project/FullBNT-1.0.7/bnt/BNT/CPDs/@tabular_CPD/tabular_CPD.m:74:if ~isempty(args) && ~isstr(args{1})
/home/nishio/project/FullBNT-1.0.7/bnt/BNT/CPDs/@softmax_CPD/softmax_CPD.m:94:if nargin >= 3 && isstr(varargin{1}) % might have passed in 'discrete'
/home/nishio/project/FullBNT-1.0.7/bnt/BNT/CPDs/@softmax_CPD/softmax_CPD.m:134:    if nargs >= 1 && ~isempty(args{1}), CPD = set_fields(CPD, 'weights', args{1}); end
/home/nishio/project/FullBNT-1.0.7/bnt/BNT/CPDs/@softmax_CPD/softmax_CPD.m:135:    if nargs >= 2 && ~isempty(args{2}), CPD = set_fields(CPD, 'offset', args{2});  end
/home/nishio/project/FullBNT-1.0.7/bnt/BNT/CPDs/@softmax_CPD/softmax_CPD.m:136:    if nargs >= 3 && ~isempty(args{3}), CPD = set_clamped(CPD, args{3});           end
/home/nishio/project/FullBNT-1.0.7/bnt/BNT/CPDs/@softmax_CPD/softmax_CPD.m:137:    if nargs >= 4 && ~isempty(args{4}), CPD.max_iter    = args{4}; end
/home/nishio/project/FullBNT-1.0.7/bnt/BNT/CPDs/@softmax_CPD/softmax_CPD.m:138:    if nargs >= 5 && ~isempty(args{5}), CPD.verbose     = args{5}; end
/home/nishio/project/FullBNT-1.0.7/bnt/BNT/CPDs/@softmax_CPD/softmax_CPD.m:139:    if nargs >= 6 && ~isempty(args{6}), CPD.wthresh     = args{6}; end
/home/nishio/project/FullBNT-1.0.7/bnt/BNT/CPDs/@softmax_CPD/softmax_CPD.m:140:    if nargs >= 7 && ~isempty(args{7}), CPD.llthresh   = args{7}; end
/home/nishio/project/FullBNT-1.0.7/bnt/BNT/CPDs/@softmax_CPD/softmax_CPD.m:141:    if nargs >= 8 && ~isempty(args{8}), CPD.approx_hess = args{8}; end
/home/nishio/project/FullBNT-1.0.7/bnt/netlab3.3/gmmem.m:92:      if (n > 1 && abs(e - eold) < options(3))
/home/nishio/project/FullBNT-1.0.7/bnt/BNT/inference/static/@pearl_inf_engine/private/parallel_protocol.m:46:    if (iter == 1) || ~approxeq_bel(bel{n}, old_bel{n}, engine.tol, engine.msg_type)
/home/nishio/project/FullBNT-1.0.7/bnt/BNT/general/sample_dbn.m:57:    if ~isempty(stop_test) || isempty(seq{i,t})
/home/nishio/project/FullBNT-1.0.7/bnt/BNT/examples/dynamic/HHMM/Square/is_F2_true_D3.m:10:if (iscell(vals) && vals{F2}==2) | (~iscell(vals) && vals(F2)==2)
/home/nishio/project/FullBNT-1.0.7/bnt/BNT/examples/dynamic/HHMM/pretty_print_hhmm_parse.m:56:    if (d > 1) && (mpe(Fnodes(d-1),t) == 2)

また、テストデータの読み込みが失敗するというエラーが出ます。データファイルにパスが通っていないのが原因なようです。

error: load: unable to find file /examples/static/Misc/mixexp_data.txt
error: called from:
error:   /home/nishio/project/FullBNT-1.0.7/bnt/BNT/examples/static/mixexp2.m at line 53, column 1
error:   /home/nishio/project/FullBNT-1.0.7/bnt/BNT/test_BNT.m at line 19, column 1

簡単な対処として、絶対パスに変えてしまいます。

/home/nishio/project/FullBNT-1.0.7/bnt/BNT/examples/static/mixexp2.m:53:load('/home/nishio/project/FullBNT-1.0.7/bnt/BNT/examples/static/Misc/mixexp_data.txt', '-ascii');

もう一つ、/home/nishio/project/FullBNT-1.0.7/bnt/BNTtools/strsplit.m という関数が、Octave組み込みの関数を上書きしており、引数の順番が異なっているという問題がありました。これに関連して、num2str という関数が動作しなくなったり(どういう理屈か分かりませんが、空文字が返るようになってしまう)もするので、リネームするか削除してしまいます。

まとめ

以上のように対処した結果、とりあえずテストコードが最後まで走るようになりました。各テストコードもツールの中身もまだ全然分かっていませんが、これからぼちぼち調べていこうと思います。
今回は以上です。


This entry was posted in ベイジアンネットワーク. Bookmark the permalink.