ML.NET のチュートリアルをやってみた


# ML.NET

ML.NET は、Mirosoft が提供しているオープンソース機械学習フレームワークで

以下のページで紹介されています。
[ML.NETガイド https://docs.microsoft.com/ja-jp/dotnet/machine-learning/)](https://docs.microsoft.com/ja-jp/dotnet/machine-learning/)

チュートリアルがあったので実行したときのメモ


## 環境構築

環境構築には、[quick-start](https://www.microsoft.com/net/learn/machine-learning-and-ai/get-started-with-ml-dotnet-tutorial)
を見ながらすすめていきます。ざくっと説明すると。

### .NET SDKのインストール

- [https://www.microsoft.com/net/download](https://www.microsoft.com/net/download)

Download .NET Core SDK をダウンロードすれば良いと思います。
ファイルは、 dotnet-sdk-2.1.XXX-win-x64.exe とかなので、
インストールします。

### アプリケーションのベースを作成

.NET Core にはコマンドラインツールの dotnet というビルド環境が提供されています。

```
dotnet new console -o myApp
cd myApp
```

dotnet new XXX で、雛形を作ってくれます。-o は、フォルダに出力。

### Visual Studio Code で実装環境を整備

myApp のフォルダで、Visual Studio Code(以下 Code)を立ち上げます。

右下にdialog が表示されているかもしれません。

```
Required assets to build and debug are missingfrom 'myApp'. Add them?
```

Codeからプログラムのデバックができるように環境についかしましょうか？ということなので、Yes と返事

### ML.NET パッケージをダウンロード

dotnet コマンドは、pip , npm のように必要なパッケージをネットからダウンロードして
使えるようにしてくれます。

```
dotnet add package Microsoft.ML --version 0.3.0
```

Codeの統合ターミナルで上のコマンドを入力すると nuget というネットからダウンロードするプログラムが複数の依存パッケージをダウンロードします。
終わると、右下にダイアログが

```
There are unresolved dependencies from 'myApp.csproj'. Please execute the restore command to continue. [Restore]
```

dotnet でパッケージなどをインストールすると、それらの依存関係をリストアという仕組みで整えてくれるので、ここでは restore ボダンもしくは

```
dotnet restore
```

を実行。これで補完機能とか使いやすくなる。

### データのダウンロード

チュートリアルでは、データは提供しているページのテキストをコピペしてね。と書かれています。

- [https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data](https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data)

上のリンクを右ボタンで、「名前をつけてリンク先を保存」（chromeの場合)で、myAppのフォルダに

```
iris-data.txt
```
というファイル名で保存しておきます。中身は、CSV形式のテキストで

```
5.1,3.5,1.4,0.2,Iris-setosa
4.9,3.0,1.4,0.2,Iris-setosa
4.7,3.2,1.3,0.2,Iris-setosa
4.6,3.1,1.5,0.2,Iris-setosa
    :
```
というデータになっています。１行が一つのデータで、前の４つの浮動小数点が４つの特徴量について数値化したもので、次の文字列が花のアヤメ(Iris)の種類を示しています。

ここでの課題は、この数値を受け取ってアヤメの名前を推定することを機械学習しましょうというものです。

### プログラムを実装

dotnet create で作成したコンソール向けのアプリケーションの雛形には、*Program.cs*というファイルが作られています。

チュートリアルで示されているプログラムで Program.cs を上書きしてします。

- https://www.microsoft.com/net/learn/machine-learning-and-ai/get-started-with-ml-dotnet-tutorial#code

### プログラムの実行

dotnetコマンドには、

- dotnet build   プログラムのビルド
- dotnet run     プログラムの実行

ここでは、コピペした場合には文法エラーなど無いので、*dotnet run* でコンパイル＆実行されます。

```
dotnet run
```
を統合ターミナルでコンパイル＆実行をすると、以下の出力が表示されました

```
Using 2 threads to train.
Automatically choosing a check frequency of 2.
Auto-tuning parameters: maxIterations = 9998.
Auto-tuning parameters: L2 = 2.667734E-05.
Auto-tuning parameters: L1Threshold (L1/L2) = 0.
Using best model from iteration 806.
Not training a calibrator because it is not needed.
Predicted flower type is: Iris-virginica
```

まずは、動作確認ができたところまで、何かよくわからないが iris-data.txt から分類問題を学習したという結果が表示されています。

### プログラムの分析

プログラムが何をしたのかちょっと見ます。

- 依存パッケージ

```
using Microsoft.ML;
using Microsoft.ML.Data;
using Microsoft.ML.Runtime.Api;
using Microsoft.ML.Trainers;
using Microsoft.ML.Transforms;
using System;
```

Microsoft.ML.XXX が、先程 dotnet add package で追加したパッケージ。

- データの定義

使用するデータを IrisData としてクラス定義してます。

```
        public class IrisData
        {
            [Column("0")]
            public float SepalLength;

            [Column("1")]
            public float SepalWidth;

            [Column("2")]
            public float PetalLength;

            [Column("3")]
            public float PetalWidth;

            [Column("4")]
            [ColumnName("Label")]
            public string Label;
        }
```

Column("0") は、CSVの１つ目のデータを float 型の SepalLength という変数で定義

|変数名|意味|
|-----|----|
|SepalLength| がく片の長さ|
|SepalWidth| がく片の幅|
|PetalLength| 花弁の長さ|
|pPetalWidth| 花弁の幅|

５番目の項目だけラベル名も追加で ColumnName("Label")

- 推論する項目

推論する項目もクラス定義し、ColumnNameで定義

```
        public class IrisPrediction
        {
            [ColumnName("PredictedLabel")]
            public string PredictedLabels;
        }
```

- 学習

ここからMain関数での処理です。まずは、学習させるためにデータと変数を結びつけるパイプラインを作成

```
    var pipeline = new LearningPipeline();
```

読み込むデータをセットします。CSVのファイル名を TextLoader のフィルターで処理するようにセット。データファイル形式は、先程定義した IrisData にデータをマッピングする。データの切り分け(separator)は、カンマ。

```
    string dataPath = "iris-data.txt";
    pipeline.Add(new TextLoader(dataPath).CreateFrom<IrisData>(separator: ','));
```

データ処理を数値計算のみにするため、入力した項目のラベルを辞書として文字列と数値を作成する。Dictionarizer という辞書化オブジェクで辞書の名前は Label。

```
    pipeline.Add(new Dictionarizer("Label"));
```

取り扱うデータをベクトルにするため、各項に名前をつける ColumnConcatenator でパイプラインに追加

```
    pipeline.Add(new ColumnConcatenator("Features", "SepalLength", "SepalWidth", "PetalLength", "PetalWidth"));
```

次に学習するためのアルゴリズムを追加。

```
    pipeline.Add(new StochasticDualCoordinateAscentClassifier());
```

[SDCA法](http://www.jmlr.org/papers/volume14/shalev-shwartz13a/shalev-shwartz13a.pdf)として、scikit-learnの [lightning.classification.SDCA](http://contrib.scikit-learn.org/lightning/generated/lightning.classification.SDCAClassifier.html)にも実装されてますね


推論するデータラベルを数値に変換する対応を設定。先程のDictionarizer への入力する文字列と推論結果のIrisPredictionへの変換を意味するみたい（よくわかってない）。

```
    pipeline.Add(new PredictedLabelColumnOriginalValueConverter() {     PredictedLabelColumn = "PredictedLabel" });
```

ここで、ようやく学習データと推論値との関係を設定して学習をセットして開始。

```
    var model = pipeline.Train<IrisData, IrisPrediction>();
```

この時点で学習が２つのスレッドを使ってあっという間に最適化されます。
最後に、本当に結果があっているかをチェックするため推論してみます。
IrisData のクラスに、パラメータをセットして model.Predict で結果を得ます。

```
    var prediction = model.Predict(new IrisData()
    {
        SepalLength = 3.3f,
        SepalWidth = 1.6f,
        PetalLength = 0.2f,
        PetalWidth = 5.1f,
    });
```

model.Predict の戻り値は、IrisPrediction となっているので、その結果を文字列として表示します。

```
    Console.WriteLine($"Predicted flower type is: {prediction.PredictedLabels}");
```

## まとめ

個人的な感想

- パイプラインというデータ処理の流れに、処理をadd していくスタイルなので流れが良くわかる。
- Python の numpy のように行列データにくらべて、データをクラスで定義するので内容はわかりやすいが、他のデータなどを行う場合など使い回しするときにためらう。
- Python だったら、このような問題を解く方法は山のようにあるのに対して、.NET での選択肢は少ないなぁと思った
- 普段はpython で jupyter-notebook で試行錯誤しながらデータ処理しているので、このようなプログラミングタイプは内容をしっかりわかっていないと書けない
- 簡単な識別問題は ML.NETで　Deep Learningをしたい場合には　CNTK　ということですよね?