Bayes Server を.NETから利用する

BayesServerには.NETやJavaのライブラリが存在し、API経由でほぼすべての機能が使えます。
学習、推論まで可能なのですが、残念ながらネットワークビューをSDKで利用することは無理なようです。（開発元に問い合わせ済み）
BayesServerのクライアント（BayesServerは実際”サーバー”ではありませんが）で、作成したネットワークは、GUI上で推論などが可能なのですが、推論や予測をターゲットを絞ってやる際や、アプリケーションに組み込みたい場合はAPIを利用するのがよいです。

# Bayes Server .NET Library を利用する

Bayes ServerをインストールしたPCであれば、すでに.NETのライブラリがインストールされています。

デフォルトであれば、以下のようなフォルダにあります。

> C:\Program Files\Bayes Server\Bayes Server 7.20\API\NET 4.0\BayesServer.dll

Visual Studioの参照追加から、以下のようになっていればOKです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/146939/1a50b17c-0b0f-398f-8884-39d56db43d91.png)

.NET Frameworkベースのアプリケーションを作成します。最新のVisual Studio 2017では、Windows クラシックデスクトップというらしいですね。

```C#
using BayesServer;
using BayesServer.Inference;
using BayesServer.Inference.RelevanceTree;
```

UWPなどではダメでした。GUIなしなんだから、Portable版期待。

# Bayes Serverの準備

[code center](https://www.bayesserver.com/code/)などからサンプルが手に入ります。
大体の事は網羅されていますが、少しマニアックになるとやり方わかりません。

読み込みは以下のように、簡単です。desktopアプリで作ったネットワークを読み込んでくれます。

```C#
var network = new Network();
network.Load(fileName); 
```

そして、推論用のクラスを生成しておきます。オプション、出力は空で良いようです。

```C#
var factory = new RelevanceTreeInferenceFactory();
inference = factory.CreateInferenceEngine(network);
queryOptions = factory.CreateQueryOptions();
queryOutput = factory.CreateQueryOutput();
```

# すぐ推論

学習済みのモデルを使うので、いきなり推論してみましょう。

まず、証拠となる入力データを設定します。
Evidenceというものが推論オブジェクトのメンバにあるので、そこに、当該のノードの変数の状態（Nodes[].Variables[].States[] のような構造）を設定しましょう。
実験ではbooleanしかないノードを使っていたので、States[1]をセットします。対象外のノードはState[0]にするとより良い結果を得られる可能性はあります。

```C#
        private void selectEvidences()
        {
            // reset query
            inference.Evidence.Clear();
            foreach (var n in network.Nodes)
            {
                var targetVar = n.Variables[0];
                State state;
                if (SelectedItems.Contains(n.Name))
                {
                    state = targetVar.States[1];
                }
                else
                {
                    state = targetVar.States[0];
                }
                inference.Evidence.SetState(state);
            }
        }
```

XAMLのコードビハインドのSelectedItemsというプロパティに設定された変数名がTrueになっている場合を想定しています。
これで、任意の変数セットがTrueになった場合の推論ができます。Evidenceは毎回Clearしないとどんどん増殖しますよ（笑）

次に推論を実行します。
QueryDistributionsというプロパティに、結果を収集したいVariableを設定します。ノードではなくVariableを設定しなければなりません。ここでは全ノードの全変数をクエリーしています。
クエリーする前には事前確率が設定されています。

```C#
        private void updateInference()
        {
            inference.QueryDistributions.Clear();
            foreach (var n in network.Nodes)
            {
                foreach (var v in n.Variables)
                {
                    inference.QueryDistributions.Add(new BayesServer.Table(v) );
                }
            }
            inference.Query(queryOptions, queryOutput); 
        }
```

# 結果を読む

inferenceオブジェクトの先ほど設定したQueryDistributionsに、値が入っているので、取りに行きます。
まずは確率値。Distributionの下のTable[1]に真になる確率が入っているので、降順にして取り出します。

```C#
            var tabs = from tab in inference.QueryDistributions
                           orderby tab.Distribution.Table[1] descending
                           select tab;
```

結果はQueryDistributionというクラスのコレクションが得られます。
これから、値を取り出して、Values（モデルを想定）に入れるには以下：

```C#
　　　　　　Values.Clear();
           Values.AddRange(tabs.Select(x => x.Distribution.Table[1])
```

ラベルのリストを取り出すには以下：

```C#
            Labels.Clear();
            var labels = tabs.Select(x => x.ToString());
            foreach (var lab in labels) Labels.Add(lab);
```

ValuesはAddRangeがあるコレクションですが、Labelsは普通のコレクションでした。。。
（チャートコントロールを使ったのでこんなことに）

# まとめ

BayesServerは、APIが整理されており、GUIの使い方を分かっていれば、APIドキュメントだけでもどうにか、アプリ開発できそうです。少し凝ったところも、GUIのメニューに書かれた文言を頼りにAPIを探っていきましょう。