見出し画像

VB.netからC#で書かれた回帰予測(AI・機械学習)の処理を呼び出す・その3

今回はVB.netからC#の回帰予測を利用する方法の最後となります。
VB.netで予測値が必要なデータを受け渡して、予測値を得て表示します。

訓練と検証で使うCSVファイルの指定、前回のコードで実現しています。
これが完成すれば、VB.netからC#で書かれた回帰予測のクラスライブラリーを実用的に使える基礎ができます。

C#側のコードを自分が作りたい仕組みに修正すれば、実用的な機械学習の処理として使えると思います。
何度も書きますが、お金が発生する仕事で必須の例外処理やロギング機能は省略しています。

VB.net側でC#のクラスを利用する方法と、C#側で関数間の値を受け渡す部分が今回の改造点です。
小さな変更でも、実用的な処理のための基本になります。

#学習 #勉強 #AI #機械学習 #プログラミング #Visual #CSharp #BASIC #ソースコード #Windows #自動判定
#数列 #予測 #次の値


VB.net側のソースコードです。

Imports System.Reflection
Imports System.Windows.Forms
Imports System.IO
Imports System.Text
Imports Microsoft.VisualBasic.FileIO
Imports System.Globalization


Public Class Form1


Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

'クラスライブラリーを使う宣言
Dim ClassLibraryObject As Object = New ClassLibrary1.Class1

'予測してほしいデータを準備する
Dim UnpredictedDataObj As Object = New ClassLibrary1.TaxiTrip
UnpredictedDataObj.VendorId = "VTS"
UnpredictedDataObj.RateCode = "1"
UnpredictedDataObj.PassengerCount = 1
UnpredictedDataObj.TripTime = 1140
UnpredictedDataObj.TripDistance = 3.75F
UnpredictedDataObj.PaymentType = "CRD"
UnpredictedDataObj.FareAmount = 0 ' 予測値を入れるため0指定.実際 / 観察 = 15.5

'予測値の領域を確保する
Dim PredictedValueObj As Object = New ClassLibrary1.TaxiTripFarePrediction

'csvファイルが保存されている位置を指定する
Dim DataForLearning As String = "C:\Users\dws57\source\repos\MlTest\ClassLibrary1\data\taxi-fare-train.csv"
Dim VerificationData As String = "C:\Users\dws57\source\repos\MlTest\ClassLibrary1\data\taxi-fare-test.csv"

'C#のクラスライブラリーで機械学習を行わせる
Dim BooleanReturn As Boolean = ClassLibraryObject.SampleMachineLearning(UnpredictedDataObj, DataForLearning, VerificationData, PredictedValueObj)

'値を表示させる
MsgBox(PredictedValueObj.FareAmount.ToString)

End Sub
End Class


C#側のソースコードです。

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(TaxiTrip UnpredictedData, string SynthesizedCsvFileForLearning,string SynthesizedCsvFileForEvaluation,ref TaxiTripFarePrediction PredictedValue)
{

//すべての ML.NET 操作は、MLContext クラスで始まります。
//mlContext を初期化することで、モデル作成ワークフローのオブジェクト間で共有できる新しい ML.NET 環境が作成されます。
//これは Entity Framework における DBContext と概念的には同じです。
//seed、ML.net環境で仕様する乱数の指定?
MLContext mlContext = new MLContext(seed: 0);

//トレーニング用のCSVファイルを指定し、予測計算式を取得する。
var model = Train(mlContext, SynthesizedCsvFileForLearning);

//評価用のCSVファイルを指定し、予測計算式の正確性を確認する
Evaluate(mlContext, model, SynthesizedCsvFileForEvaluation);


//予測計算式を使い、予測を行う。
TestSinglePrediction(mlContext, model, UnpredictedData,ref PredictedValue);

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, TaxiTrip UnpredictedData, ref TaxiTripFarePrediction PredictedValue)
{
//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つの予測を行います。
PredictedValue = predictionFunction.Predict(UnpredictedData);

//指定された旅行の予測運賃を表示します。
Console.WriteLine($"**********************************************************************");
Console.WriteLine($"Predicted fare: {PredictedValue.FareAmount:0.####}, actual fare: 15.5");
Console.WriteLine($"**********************************************************************");
}

}

}

この記事が気に入ったらサポートをしてみませんか?