ML.NET
ML.NET は、Mirosoft が提供しているオープンソース機械学習フレームワークで
以下のページで紹介されています。
ML.NETガイド https://docs.microsoft.com/ja-jp/dotnet/machine-learning/)
チュートリアルがあったので実行したときのメモ
環境構築
環境構築には、quick-start
を見ながらすすめていきます。ざくっと説明すると。
.NET SDKのインストール
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
を実行。これで補完機能とか使いやすくなる。
データのダウンロード
チュートリアルでは、データは提供しているページのテキストをコピペしてね。と書かれています。
上のリンクを右ボタンで、「名前をつけてリンク先を保存」(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
:
というデータになっています。1行が一つのデータで、前の4つの浮動小数点が4つの特徴量について数値化したもので、次の文字列が花のアヤメ(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の1つ目のデータを float 型の SepalLength という変数で定義
変数名 | 意味 |
---|---|
SepalLength | がく片の長さ |
SepalWidth | がく片の幅 |
PetalLength | 花弁の長さ |
pPetalWidth | 花弁の幅 |
5番目の項目だけラベル名も追加で 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法として、scikit-learnの lightning.classification.SDCAにも実装されてますね
推論するデータラベルを数値に変換する対応を設定。先程のDictionarizer への入力する文字列と推論結果のIrisPredictionへの変換を意味するみたい(よくわかってない)。
pipeline.Add(new PredictedLabelColumnOriginalValueConverter() { PredictedLabelColumn = "PredictedLabel" });
ここで、ようやく学習データと推論値との関係を設定して学習をセットして開始。
var model = pipeline.Train<IrisData, IrisPrediction>();
この時点で学習が2つのスレッドを使ってあっという間に最適化されます。
最後に、本当に結果があっているかをチェックするため推論してみます。
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 ということですよね?