VB.netからC#で書かれた回帰予測(AI・機械学習)の処理を呼び出す・その1
このコード、以下のWebアドレスに掲載されているものを基本にしています。
https://docs.microsoft.com/ja-jp/dotnet/machine-learning/
印刷して文章を噛み砕きながら、学びたい場合もPDFファイルがあるので参考になります。
https://docs.microsoft.com/ja-jp/dotnet/opbuildpdf/machine-learning/toc.pdf?branch=live
Pythonでは苦戦した回帰予測のソースコード、ML.netでは、CSVファイルも含めて動作するサンプルソースが公開されています。
とても学びやすいと思いますし、こういう環境が初心者には必要だと改めて感じています。
とりあえず、私が学びやすいようにC#のクラスライブラリー化したソースコードを記載します。
PDFの解説と自分で考えたコメントも追加していますので、コメント間違っていたらごめんなさい。
NuGetでMicrosoft.MLとMicrosoft.ML.FastTreeが必要です。
それぞれ、インストールしてください。
#Visual #CSharp #BASIC #使える #ソースコード #Windows #自動判定
#数列 #予測 #次の値
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.ML;
using Microsoft.ML.Data;
namespace ClassLibrary1
{
//TaxiTrip は入力データ クラスであり、各データ セット列の定義が含まれています。
//LoadColumn 属性を使用して、データ セット内のソース列のインデックスを指定します。
public class TaxiTrip
{
[LoadColumn(0)]
public string VendorId;
[LoadColumn(1)]
public string RateCode;
[LoadColumn(2)]
public float PassengerCount;
[LoadColumn(3)]
public float TripTime;
[LoadColumn(4)]
public float TripDistance;
[LoadColumn(5)]
public string PaymentType;
[LoadColumn(6)]
public float FareAmount;
}
//TaxiTripFarePrediction クラスは予測結果を表します。
//このクラスには、Score ColumnName 属性が適用された 1 つの浮動小数点型フィールド FareAmount が含まれています。
//回帰タスクの場合、Score 列には、予測ラベル値が含まれます。
public class TaxiTripFarePrediction
{
[ColumnName("Score")]
public float FareAmount;
}
//VB.netから呼び出されるクラスライブラリーのクラス
public class Class1
{
//モデルのトレーニングに使用するデータ セットがあるファイルへのパス。
static readonly string _trainDataPath = Path.Combine(Environment.CurrentDirectory, "Data", "taxi-fare-train.csv");
//モデルの評価に使用するデータ セットがあるファイルへのパス。
static readonly string _testDataPath = Path.Combine(Environment.CurrentDirectory, "Data", "taxi-fare-test.csv");
//トレーニング済みモデルが格納されるファイルへのパス。
static readonly string _modelPath = Path.Combine(Environment.CurrentDirectory, "Data", "Model.zip");
//VB.netから呼び出される関数
public Boolean SampleMachineLearning()
{
//すべての ML.NET 操作は、MLContext クラスで始まります。
//mlContext を初期化することで、モデル作成ワークフローのオブジェクト間で共有できる新しい ML.NET 環境が作成されます。
//これは Entity Framework における DBContext と概念的には同じです。
//seed、ML.net環境で仕様する乱数の指定?
MLContext mlContext = new MLContext(seed: 0);
//トレーニング用のCSVファイルを指定し、予測計算式を取得する。
var model = Train(mlContext, _testDataPath);
//評価用のCSVファイルを指定し、予測計算式の正確性を確認する
Evaluate(mlContext, model, _testDataPath);
//予測計算式を使い、予測を行う。
TestSinglePrediction(mlContext, model);
return true;
}
//Train メソッドは、モデルをトレーニングします。
//次の処理を実行します。
//・データを読み込みます。
//・データを抽出して変換します。
//・モデルをトレーニングします。
//・モデル(予測計算式)を返します。
public static ITransformer Train(MLContext mlContext, string dataPath)
{
//データを読み込んで変換する
//ML.NET では、数値またはテキストの表形式データを記述する柔軟で効率的な方法として、IDataView クラスを使います。
//IDataView は、テキスト ファイルを読み込むか、またはリアルタイムで読み込むことができます
//(たとえば、SQL データベースまたはログ ファイル)。
//入力データのクラス TaxiTrip
//トレーニング用CSV dataPath
//CSVにヘッダがあるか true=ある false=なし
//CSVの区切文字 ,
IDataView dataView = mlContext.Data.LoadFromTextFile<TaxiTrip>(dataPath, hasHeader: true, separatorChar: ',');
//注意:Appendで始まる行も含めて、C#では;までが1行として処理されます
//予測に使わないtrip_time_in_secsが処理されていない事が重要です
//タクシー運賃を予測したいので、FareAmount 列を、予測する Label に指定します。
//CopyColumnsEstimator 変換クラスを使って FareAmount をコピーします。
var pipeline = mlContext.Transforms.CopyColumns(outputColumnName: "Label", inputColumnName: "FareAmount")
//モデルをトレーニングするアルゴリズムには、数値が必要であるため、
//カテゴリ データ (VendorId、RateCode、PaymentType) の値を文字列から
//(VendorIdEncoded、RateCodeEncoded、PaymentTypeEncoded)へ数値に変換する必要があります。
//それを行うには、異なる数値キーの値を各列内の異なる値に割り当てる OneHotEncodingTransformer 変換クラスを使用します。
.Append(mlContext.Transforms.Categorical.OneHotEncoding(outputColumnName: "VendorIdEncoded", inputColumnName: "VendorId"))
.Append(mlContext.Transforms.Categorical.OneHotEncoding(outputColumnName: "RateCodeEncoded", inputColumnName: "RateCode"))
.Append(mlContext.Transforms.Categorical.OneHotEncoding(outputColumnName: "PaymentTypeEncoded", inputColumnName: "PaymentType"))
//mlContext.Transforms.Concatenate 変換クラスを使用して、すべての特徴列を Features 列に結合します。
//既定では、学習アルゴリズムは Features 列の特徴のみを処理します。
.Append(mlContext.Transforms.Concatenate("Features", "VendorIdEncoded", "RateCodeEncoded", "PassengerCount", "TripDistance", "PaymentTypeEncoded"))
//学習アルゴリズムでFastTreeを選択する
//この問題の中心となるのは、ニューヨーク市のタクシー運賃の予測です。
//一見すると、単に乗車距離に依存すると思われるかもしれません。
//しかし、ニューヨークのタクシー会社は追加の乗客数や現金でなくクレジット カードによる支払いなど、その他の要因によって請求額を変えます。
//データ セット内の他の要因に基づき、実際の値である価格値を予測します。
//それを行うには、回帰機械学習タスクを選択します。
//データ変換定義に FastTreeRegressionTrainer 機械学習タスクを追加します。
//ここまで1行で処理が行われます。
.Append(mlContext.Regression.Trainers.FastTree());
//モデルをトレーニングする
//Fit() メソッドでは、データセットを変換して、トレーニングを適用することにより、モデルがトレーニングされます。
var model = pipeline.Fit(dataView);
//トレーニング済みモデルを返します。
return model;
}
//モデルを評価する
//品質保証と検証のためのテスト データを使って、モデルのパフォーマンスを評価します。
//Evaluate メソッドは次の処理を実行します。
//・テスト データ セットを読み込む。
//・回帰エバリュエーターを作成する。
//・モデルを評価し、メトリック(結果)を作成する。
//・メトリック(結果)を表示する。
private static void Evaluate(MLContext mlContext, ITransformer model, string dataPath)
{
//LoadFromTextFile() メソッドを使って、テスト データセットを読み込みます。
//このデータセットを品質チェックとして使って、モデルを評価します。
IDataView dataView = mlContext.Data.LoadFromTextFile<TaxiTrip>(dataPath, hasHeader: true, separatorChar: ',');
//Test データを変換します。
//Transform() メソッドによって、テスト データセットの入力行に対する予測が行われます。
//RegressionContext.Evaluate メソッドは、指定されたデータセットを使用して PredictionModel の品質メトリックを計算します。
//これによって返される RegressionMetrics オブジェクトには、回帰エバリュエーターによって計算されるメトリック全体が含まれます。
var predictions = model.Transform(dataView);
//これらを表示してモデルの品質を判定するには、最初にメトリックを取得する必要があります。
var metrics = mlContext.Regression.Evaluate(predictions, "Label", "Score");
//予測セットができたら、Evaluate() メソッドがモデルを評価します。
//これは予測された値をテスト データセット内の実際の Labels と比較して、モデルのパフォーマンスのメトリックを返します。
Console.WriteLine();
Console.WriteLine($"*************************************************");
Console.WriteLine($"* Model quality metrics evaluation ");
Console.WriteLine($"*------------------------------------------------");
//RSquared は回帰モデルのもう 1 つの評価メトリックです。
//RSquared は 0 から 1 までの値を取ります。
//値が 1 に近づくほど、優れたモデルになります。
//次のコードを Evaluate メソッドに追加して、RSquared 値を表示します。
Console.WriteLine($"* RSquared Score: {metrics.RSquared:0.##}");
//RMS は回帰モデルの評価メトリックの 1 つです。
//RMS が低いほど、優れたモデルになります。
//Evaluate メソッドに次のコードを追加することで、RMS 値を表示します。
Console.WriteLine($"* Root Mean Squared Error: {metrics.RootMeanSquaredError:#.##}");
}
//モデルを使用して予測を行う
//TestSinglePrediction メソッドは次の処理を実行します。
//・テスト データの 1 つのコメントを作成します。
//・テスト データに基づいて運賃合計を予測します。
//・テスト データと予測をレポート用に結合する。
//・予測された結果を表示する。
private static void TestSinglePrediction(MLContext mlContext, ITransformer model)
{
//PredictionEngine を使って運賃を予測します。
//PredictionEngine は、データの 1 つのインスタンスに対して予測を実行できる便利な API です。
//PredictionEngine はスレッド セーフではありません。
//シングル スレッド環境またはプロトタイプ環境で使用できます。
//運用環境でパフォーマンスとスレッド セーフを向上させるには、PredictionEnginePool サービスを使用します。
//これにより、アプリケーション全体で使用するできる PredictionEngine オブジェクトの ObjectPool が作成されます。
//ASP.NET Core Web API で PredictionEnginePool を使用する方法については、こちらのガイドを参照してください。
//https://docs.microsoft.com/ja-jp/dotnet/machine-learning/how-to-guides/serve-model-web-api-ml-net
//PredictionEnginePool サービスの拡張機能は、現在プレビュー段階です。
//学習用クラスと予測用クラスを指定し、予測用計算式を受け渡します
var predictionFunction = mlContext.Model.CreatePredictionEngine<TaxiTrip, TaxiTripFarePrediction>(model);
//予測値を計算させるための課題を作成します。
//TaxiTrip のインスタンスを作成して、TestSinglePrediction() メソッドでコストのトレーニング済みモデルの予測をテストするために、
//旅行データを作成します。
var taxiTripSample = new TaxiTrip()
{
VendorId = "VTS",
RateCode = "1",
PassengerCount = 1,
TripTime = 1140,
TripDistance = 3.75f,
PaymentType = "CRD",
FareAmount = 0 // 予測値を入れるため0指定. 実際/観察 = 15.5
};
//タクシー乗車データを1個与えて、運賃を予測させます。
//Predict() 関数では、データ1個で1つの予測を行います。
var prediction = predictionFunction.Predict(taxiTripSample);
//指定された旅行の予測運賃を表示します。
Console.WriteLine($"**********************************************************************");
Console.WriteLine($"Predicted fare: {prediction.FareAmount:0.####}, actual fare: 15.5");
Console.WriteLine($"**********************************************************************");
}
}
}