Xamarin.iOS の Core ML 2

Core ML は、iOS、macOS、tvOS、watchOS で利用できる機械学習テクノロジです。 これにより、アプリは機械学習モデルに基づいて予測を行うことができます。

iOS 12 では、Core ML にはバッチ処理 API が含まれています。 この API は、Core ML をより効率的にし、連続した予測を行うためにモデルが使用されるシナリオでパフォーマンスの向上をもたらします。

サンプル データを作成する

ViewController では、以下のように、サンプル アプリの ViewDidLoad メソッドが LoadMLModel を呼び出し、これによって含まれている Core ML モデルが読み込まれます。

void LoadMLModel()
{
    var assetPath = NSBundle.MainBundle.GetUrlForResource("CoreMLModel/MarsHabitatPricer", "mlmodelc");
    model = MLModel.Create(assetPath, out NSError mlErr);
}

次に、サンプル アプリは、連続する Core ML の予測の入力として使用する 100,000 個の MarsHabitatPricerInput オブジェクトを作成します。 以下のように、生成された各サンプルでは、ソーラー パネルの数、温室の数、牧草地の数にランダムな値が設定されています。

async void CreateInputs(int num)
{
    // ...
    Random r = new Random();
    await Task.Run(() =>
    {
        for (int i = 0; i < num; i++)
        {
            double solarPanels = r.NextDouble() * MaxSolarPanels;
            double greenHouses = r.NextDouble() * MaxGreenHouses;
            double acres = r.NextDouble() * MaxAcres;
            inputs[i] = new MarsHabitatPricerInput(solarPanels, greenHouses, acres);
        }
    });
    // ...
}

アプリの 3 つのボタンのいずれかをタップすると、次の 2 つの予測シーケンスが実行されます。1 つは for ループを使用するもので、もう 1 つは iOS 12 で導入された新しいバッチ GetPredictions メソッドを使用するものです。

async void RunTest(int num)
{
    // ...
    await FetchNonBatchResults(num);
    // ...
    await FetchBatchResults(num);
    // ...
}

for ループ

テストの for ループ バージョンは、指定された数の入力を単純に反復処理し、それぞれに対して GetPrediction を呼び出し結果を破棄します。 以下のように、このメソッドは自身が予測に要する時間を計測します。

async Task FetchNonBatchResults(int num)
{
    Stopwatch stopWatch = Stopwatch.StartNew();
    await Task.Run(() =>
    {
        for (int i = 0; i < num; i++)
        {
            IMLFeatureProvider output = model.GetPrediction(inputs[i], out NSError error);
        }
    });
    stopWatch.Stop();
    nonBatchMilliseconds = stopWatch.ElapsedMilliseconds;
}

GetPredictions (新しいバッチ API)

テストのバッチ バージョンは、入力配列から MLArrayBatchProvider オブジェクトを作成し (これは GetPredictions メソッドに必要な入力パラメーターであるためです)、予測計算が CPU に制限されることを防ぐ MLPredictionOptions オブジェクトを作成し、GetPredictions API を使用して予測をフェッチします。ここでも結果は破棄されます。

async Task FetchBatchResults(int num)
{
    var batch = new MLArrayBatchProvider(inputs.Take(num).ToArray());
    var options = new MLPredictionOptions()
    {
        UsesCpuOnly = false
    };

    Stopwatch stopWatch = Stopwatch.StartNew();
    await Task.Run(() =>
    {
        model.GetPredictions(batch, options, out NSError error);
    });
    stopWatch.Stop();
    batchMilliseconds = stopWatch.ElapsedMilliseconds;
}

結果

シミュレーターとデバイスのどちらでも、GetPredictions はループベースの Core ML 予測よりも早く終了します。