Przewidywanie za pomocą modelu ONNX rozwiązania AutoML na platformie .NET

Z tego artykułu dowiesz się, jak używać modelu automatycznego uczenia maszynowego (AutoML) Open Neural Network Exchange (ONNX) do przewidywania w aplikacji konsolowej .NET Core języka C# z ML.NET.

ML.NET to międzyplatformowa platforma uczenia maszynowego typu open source dla ekosystemu platformy .NET, która umożliwia trenowanie i korzystanie z niestandardowych modeli uczenia maszynowego przy użyciu podejścia opartego na kodzie w języku C# lub F#, a także za pomocą narzędzi z małą ilością kodu, takich jak Model Builder i interfejs wiersza polecenia ML.NET. Struktura jest również rozszerzalna i umożliwia korzystanie z innych popularnych platform uczenia maszynowego, takich jak TensorFlow i ONNX.

ONNX to format typu open source dla modeli sztucznej inteligencji. Platforma ONNX obsługuje współdziałanie między platformami. Oznacza to, że można wytrenować model w jednej z wielu popularnych struktur uczenia maszynowego, takich jak PyTorch, przekonwertować go na format ONNX i korzystać z modelu ONNX w innej strukturze, takiej jak ML.NET. Aby dowiedzieć się więcej, odwiedź witrynę internetową ONNX.

Wymagania wstępne

Tworzenie aplikacji konsolowej w języku C#

W tym przykładzie używasz interfejsu wiersza polecenia platformy .NET Core do kompilowania aplikacji, ale możesz wykonywać te same zadania przy użyciu programu Visual Studio. Dowiedz się więcej o interfejsie wiersza polecenia platformy .NET Core.

  1. Otwórz terminal i utwórz nową aplikację konsolową platformy .NET Core w języku C#. W tym przykładzie nazwa aplikacji to AutoMLONNXConsoleApp. Katalog jest tworzony przez tę samą nazwę z zawartością aplikacji.

    dotnet new console -o AutoMLONNXConsoleApp
    
  2. W terminalu przejdź do katalogu AutoMLONNXConsoleApp .

    cd AutoMLONNXConsoleApp
    

Dodawanie pakietów oprogramowania

  1. Zainstaluj pakiety NuGet Microsoft.ML, Microsoft.ML.OnnxRuntime i Microsoft.ML.OnnxTransformer przy użyciu interfejsu wiersza polecenia platformy .NET Core.

    dotnet add package Microsoft.ML
    dotnet add package Microsoft.ML.OnnxRuntime
    dotnet add package Microsoft.ML.OnnxTransformer
    

    Te pakiety zawierają zależności wymagane do używania modelu ONNX w aplikacji .NET. ML.NET udostępnia interfejs API, który używa środowiska uruchomieniowego ONNX do przewidywania.

  2. Otwórz plik Program.cs i dodaj następujące using instrukcje u góry, aby odwołać się do odpowiednich pakietów.

    using System.Linq;
    using Microsoft.ML;
    using Microsoft.ML.Data;
    using Microsoft.ML.Transforms.Onnx;
    

Dodawanie odwołania do modelu ONNX

Sposobem na uzyskanie dostępu do modelu ONNX przez aplikację konsolową jest dodanie go do katalogu wyjściowego kompilacji. Aby dowiedzieć się więcej o typowych elementach programu MSBuild, zobacz Przewodnik po programie MSBuild. Jeśli nie masz jeszcze modelu, postępuj zgodnie z tym notesem , aby utworzyć przykładowy model.

Dodawanie odwołania do pliku modelu ONNX w aplikacji

  1. Skopiuj model ONNX do katalogu głównego AutoMLONNXConsoleApp aplikacji.

  2. Otwórz plik AutoMLONNXConsoleApp.csproj i dodaj następującą zawartość w węźleProject.

    <ItemGroup>
        <None Include="automl-model.onnx">
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </None>
    </ItemGroup>
    

    W tym przypadku nazwa pliku modelu ONNX to automl-model.onnx.

  3. Otwórz plik Program.cs i dodaj następujący wiersz wewnątrz Program klasy.

    static string ONNX_MODEL_PATH = "automl-model.onnx";
    

Inicjowanie obiektu MLContext

Main Wewnątrz metody Program klasy utwórz nowe wystąpienie klasy MLContext.

MLContext mlContext = new MLContext();

Klasa MLContext jest punktem wyjścia dla wszystkich operacji ML.NET, a inicjowanie mlContext tworzy nowe środowisko ML.NET, które może być współużytkowane w całym cyklu życia modelu. Jest ona podobna koncepcyjnie do elementu DbContext w programie Entity Framework.

Definiowanie schematu danych modelu

Model oczekuje danych wejściowych i wyjściowych w określonym formacie. ML.NET umożliwia zdefiniowanie formatu danych za pomocą klas. Czasami możesz już wiedzieć, jak wygląda ten format. W przypadkach, gdy nie znasz formatu danych, możesz użyć narzędzi, takich jak Netron, aby sprawdzić model ONNX.

Model używany w tym przykładzie używa danych z zestawu danych TLC Taxi Trip w Nowym Jorku. Poniżej przedstawiono przykładowe dane:

vendor_id rate_code passenger_count trip_time_in_secs trip_distance payment_type fare_amount
VTS 1 1 1140 3.75 CRD 15,5
VTS 1 1 480 2.72 CRD 10,0
VTS 1 1 1680 7,8 CSH 26,5

Sprawdzanie modelu ONNX (opcjonalnie)

Użyj narzędzia, takiego jak Netron, aby sprawdzić dane wejściowe i wyjściowe modelu.

  1. Otwórz narzędzie Netron.

  2. Na górnym pasku menu wybierz pozycję Plik > Otwórz i użyj przeglądarki plików, aby wybrać model.

  3. Zostanie otwarty model. Na przykład struktura modelu automl-model.onnx wygląda następująco:

    Netron AutoML ONNX Model

  4. Wybierz ostatni węzeł w dolnej części grafu (variable_out1 w tym przypadku), aby wyświetlić metadane modelu. Dane wejściowe i wyjściowe na pasku bocznym pokazują oczekiwane dane wejściowe, dane wyjściowe i typy danych modelu. Te informacje służą do definiowania schematu danych wejściowych i wyjściowych modelu.

Definiowanie schematu wejściowego modelu

Utwórz nową klasę o nazwie OnnxInput z następującymi właściwościami w pliku Program.cs .

public class OnnxInput
{
    [ColumnName("vendor_id")]
    public string VendorId { get; set; }

    [ColumnName("rate_code"),OnnxMapType(typeof(Int64),typeof(Single))]
    public Int64 RateCode { get; set; }

    [ColumnName("passenger_count"), OnnxMapType(typeof(Int64), typeof(Single))]
    public Int64 PassengerCount { get; set; }

    [ColumnName("trip_time_in_secs"), OnnxMapType(typeof(Int64), typeof(Single))]
    public Int64 TripTimeInSecs { get; set; }

    [ColumnName("trip_distance")]
    public float TripDistance { get; set; }

    [ColumnName("payment_type")]
    public string PaymentType { get; set; }
}

Każda z właściwości jest mapowania na kolumnę w zestawie danych. Właściwości są dodatkowo oznaczone atrybutami.

Atrybut ColumnName umożliwia określenie, jak ML.NET odwoływać się do kolumny podczas działania na danych. Na przykład, chociaż TripDistance właściwość jest zgodna ze standardowymi konwencjami nazewnictwa platformy .NET, model zna tylko kolumnę lub funkcję znaną jako trip_distance. Aby rozwiązać tę rozbieżność nazewnictwa, ColumnName atrybut mapuje TripDistance właściwość na kolumnę lub funkcję według nazwy trip_distance.

W przypadku wartości liczbowych ML.NET działa tylko na Single typach wartości. Jednak oryginalny typ danych niektórych kolumn to liczby całkowite. Atrybut OnnxMapType mapuje typy między ONNX i ML.NET.

Aby dowiedzieć się więcej na temat atrybutów danych, zobacz przewodnik ML.NET ładowania danych.

Definiowanie schematu wyjściowego modelu

Po przetworzeniu danych generuje dane wyjściowe określonego formatu. Zdefiniuj schemat danych wyjściowych. Utwórz nową klasę o nazwie OnnxOutput z następującymi właściwościami w pliku Program.cs .

public class OnnxOutput
{
    [ColumnName("variable_out1")]
    public float[] PredictedFare { get; set; }
}

Podobnie jak OnnxInput, użyj atrybutu ColumnName , aby zamapować variable_out1 dane wyjściowe na bardziej opisową nazwę PredictedFare.

Definiowanie potoku przewidywania

Potok w ML.NET jest zazwyczaj serią przekształceń łańcuchowych, które działają na danych wejściowych w celu wygenerowania danych wyjściowych. Aby dowiedzieć się więcej na temat przekształceń danych, zobacz przewodnik ML.NET przekształcania danych.

  1. Tworzenie nowej metody o nazwie GetPredictionPipeline wewnątrz Program klasy

    static ITransformer GetPredictionPipeline(MLContext mlContext)
    {
    
    }
    
  2. Zdefiniuj nazwę kolumn wejściowych i wyjściowych. Dodaj następujący kod wewnątrz GetPredictionPipeline metody .

    var inputColumns = new string []
    {
        "vendor_id", "rate_code", "passenger_count", "trip_time_in_secs", "trip_distance", "payment_type"
    };
    
    var outputColumns = new string [] { "variable_out1" };
    
  3. Zdefiniuj potok. Element zawiera IEstimator strategię operacji, danych wejściowych i wyjściowych schematów potoku.

    var onnxPredictionPipeline =
        mlContext
            .Transforms
            .ApplyOnnxModel(
                outputColumnNames: outputColumns,
                inputColumnNames: inputColumns,
                ONNX_MODEL_PATH);
    

    W takim przypadku ApplyOnnxModel jest to jedyna transformacja w potoku, która przyjmuje nazwy kolumn wejściowych i wyjściowych, a także ścieżkę do pliku modelu ONNX.

  4. Element IEstimator definiuje tylko zestaw operacji, które mają być stosowane do danych. To, co działa na danych, jest nazywane ITransformer. Fit Użyj metody , aby utworzyć element na podstawie elementu onnxPredictionPipeline.

    var emptyDv = mlContext.Data.LoadFromEnumerable(new OnnxInput[] {});
    
    return onnxPredictionPipeline.Fit(emptyDv);
    

    Metoda Fit oczekuje IDataView jako danych wejściowych do wykonania operacji. Element IDataView to sposób reprezentowania danych w ML.NET przy użyciu formatu tabelarycznego. Ponieważ w tym przypadku potok jest używany tylko do przewidywania, możesz podać puste IDataView , aby nadać ITransformer niezbędne informacje o schemacie wejściowym i wyjściowym. Następnie dopasowany ITransformer element zostanie zwrócony do dalszego użycia w aplikacji.

    Napiwek

    W tym przykładzie potok jest definiowany i używany w tej samej aplikacji. Zaleca się jednak używanie oddzielnych aplikacji do definiowania potoku i używania go do przewidywania. W ML.NET potoki można serializować i zapisywać w celu dalszego użycia w innych aplikacjach użytkownika końcowego platformy .NET. ML.NET obsługuje różne cele wdrażania, takie jak aplikacje klasyczne, usługi internetowe, aplikacje zestawu WebAssembly* i wiele innych. Aby dowiedzieć się więcej na temat zapisywania potoków, zobacz przewodnik ML.NET zapisywania i ładowania wytrenowanych modeli.

    *Zestaw WebAssembly jest obsługiwany tylko w programie .NET Core 5 lub nowszym

  5. Wewnątrz metody wywołaj Main metodę GetPredictionPipeline z wymaganymi parametrami.

    var onnxPredictionPipeline = GetPredictionPipeline(mlContext);
    

Korzystanie z modelu do przewidywania

Teraz, gdy masz potok, nadszedł czas, aby użyć go do przewidywania. ML.NET udostępnia wygodny interfejs API do przewidywania w pojedynczym wystąpieniu danych o nazwie PredictionEngine.

  1. Main Wewnątrz metody utwórz element PredictionEngine przy użyciu CreatePredictionEngine metody .

    var onnxPredictionEngine = mlContext.Model.CreatePredictionEngine<OnnxInput, OnnxOutput>(onnxPredictionPipeline);
    
  2. Utwórz dane wejściowe danych testowych.

    var testInput = new OnnxInput
    {
        VendorId = "CMT",
        RateCode = 1,
        PassengerCount = 1,
        TripTimeInSecs = 1271,
        TripDistance = 3.8f,
        PaymentType = "CRD"
    };
    
  3. Użyj elementu , predictionEngine aby tworzyć przewidywania na podstawie nowych testInput danych przy użyciu Predict metody .

    var prediction = onnxPredictionEngine.Predict(testInput);
    
  4. Wygeneruj wynik przewidywania w konsoli programu .

    Console.WriteLine($"Predicted Fare: {prediction.PredictedFare.First()}");
    
  5. Użyj interfejsu wiersza polecenia platformy .NET Core, aby uruchomić aplikację.

    dotnet run
    

    Wynik powinien wyglądać podobnie do następujących danych wyjściowych:

    Predicted Fare: 15.621523
    

Aby dowiedzieć się więcej na temat tworzenia przewidywań w ML.NET, zobacz przewodnik dotyczący tworzenia przewidywań przy użyciu modelu.

Następne kroki