Dystrybuowanie modeli dla Windows ML

Windows ML ładuje model ze ścieżki pliku lokalnego, więc nie wymaga żadnej określonej metody dystrybucji. Aplikacja albo dołącza model jako część swojego pakietu, albo pobiera go osobno — za pomocą instalatora lub przez aplikację przy pierwszej potrzebie. W tym artykule porównane są dwa podejścia i opisano implementację każdego z nich.

Wybieranie podejścia

Uwzględnij model w pakiecie Pobieranie modelu oddzielnie
Najlepsze dla Małe modele lub modele, które muszą działać w trybie offline natychmiast po zainstalowaniu Duże modele lub modele, które mają być dystrybuowane oddzielnie od aplikacji
Pierwsze uruchomienie Model jest dostępny natychmiast Wymaga pobrania przed pierwszym użyciem, o ile nie zostanie pobrane w instalatorze lub wstępnie pobrane w tle
Wpływ na rozmiar aplikacji Zwiększa rozmiar instalacji dla każdego użytkownika Korzysta z pamięci tylko na urządzeniach, na których użytkownik włączy funkcję, dla której potrzebny jest model
Pomoc techniczna w trybie offline Zawsze dostępne w trybie offline Dostępne tylko w trybie offline po pierwszym pomyślnym pobraniu

Jeśli model ma kilka megabajtów i rzadko się zmienia, prościej jest dołączyć go do aplikacji, dzięki czemu użytkownicy od razu otrzymują działającą aplikację. Jeśli model jest duży, często aktualizowany lub opcjonalny dla niektórych użytkowników, pobierz go oddzielnie.

Wskazówka

Jeśli publikujesz bibliotekę lub zestaw SDK, od której zależy wiele niezależnych aplikacji, a te aplikacje powinny udostępniać pojedynczą kopię modelu na dysku, użyj interfejsów API katalogu modeli Windows ML zamiast pisać własną logikę pobierania i udostępniania. Większość deweloperów aplikacji, którzy potrzebują tylko modelu dla własnej aplikacji, powinna używać jednego z dwóch metod opisanych tutaj.

Uwzględnij model w pakiecie

Dodaj plik modelu ONNX wraz ze wszystkimi plikami, których wymaga, takimi jak plik tokenizatora lub pliki z etykietami, jako zawartość projektu aplikacji. Windows ML następnie ładuje model bezpośrednio z lokalizacji instalacji aplikacji, bez wymaganego dostępu do sieci.

Kroki implementacji

  1. Dodaj plik modelu do projektu i ustaw jego akcję kompilacji na Zawartość (lub odpowiednik typu projektu), aby został skopiowany do danych wyjściowych i uwzględniony w pakiecie aplikacji.
  2. Określ ścieżkę modelu względem lokalizacji instalacji Twojej aplikacji w czasie wykonywania. Nie należy pisać stałej ścieżki bezwzględnej, ponieważ lokalizacja instalacji różni się w zależności od typu użytkownika i wdrożenia.
  3. Załaduj model z tej ścieżki przy użyciu interfejsów API wnioskowania.
using System;
using System.IO;

// Resolve the model path relative to the app's install location.
string modelPath = Path.Combine(AppContext.BaseDirectory, "Assets", "Models", "model.onnx");

if (!File.Exists(modelPath))
{
    throw new FileNotFoundException("The bundled model is missing from the app package.", modelPath);
}

// Load modelPath with your inference APIs.

Kwestie wymagające rozważenia

  • Rozmiar pakietu: każda instalacja zawiera pełny model, który zwiększa rozmiar pobierania i użycie dysku dla wszystkich użytkowników, w tym tych, którzy nigdy nie mogą korzystać z tej funkcji.
  • Nie trzeba obsługiwać błędów pobierania: ponieważ model jest już na dysku w chwili uruchomienia aplikacji, nie potrzebujesz mechanizmów ponownych prób, sprawdzania integralności ani mechanizmów awaryjnych dla trybu offline.
  • Opcjonalne pakiety: jeśli chcesz zachować model poza instalacją podstawową, ale nadal unikać pisania logiki pobierania, możesz wysłać go w opcjonalnym pakiecie MSIX instalowanym przez użytkowników lub aplikację na żądanie. Pozwala to utrzymać niewielki rozmiar pakietu podstawowego, unikając własnej ścieżki pobierania, kosztem konieczności polegania na wdrażaniu pakietów zamiast zwykłego pobrania.

Pobieranie modelu oddzielnie

Zamiast dołączać model do pakietu aplikacji, pobierz go na urządzenie oddzielnie od pakietu aplikacji i zapisz go w lokalnej pamięci aplikacji. Dzięki temu pakiet jest mały. Pobieranie nie musi odbywać się w działającej aplikacji — możesz pobrać model przy pierwszym uruchomieniu aplikacji albo zlecić jego pobranie instalatorowi w ramach instalacji. Tak czy inaczej, odpowiadasz za pobieranie, weryfikowanie, przechowywanie i czyszczenie pliku.

Kroki implementacji

  1. Hostuj plik modelu (i wszystkie pliki zależne) pod adresem URL protokołu HTTPS wraz z skrótem SHA-256, aby można było zweryfikować pobieranie.
  2. Zdecyduj, kiedy ma się odbywać pobieranie: w instalatorze czy z poziomu aplikacji, gdy model będzie po raz pierwszy potrzebny. W obu metodach jest używana ta sama logika pobierania i weryfikowania.
  3. Przed ponownym pobraniem modelu sprawdź, czy model już istnieje w magazynie lokalnym.
  4. Zapisz plik w zapisywalnym folderze app-local i sprawdź jego skrót przed użyciem.
  5. Zgłoś postęp pobierania użytkownikowi i obsłuż błędy sieci, dzięki czemu pobieranie może ponawiać próbę lub bezpiecznie wrócić.
using System;
using System.IO;
using System.Net.Http;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;

public static async Task<string> GetModelPathAsync(
    Uri modelUri,
    string expectedSha256,
    IProgress<double>? progress = null,
    CancellationToken cancellationToken = default)
{
    string modelsFolder = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
        "Contoso", "Models");
    Directory.CreateDirectory(modelsFolder);

    string modelPath = Path.Combine(modelsFolder, Path.GetFileName(modelUri.LocalPath));

    // Reuse the file if it's already downloaded and passes integrity verification.
    if (File.Exists(modelPath) && await VerifyHashAsync(modelPath, expectedSha256, cancellationToken))
    {
        return modelPath;
    }

    string tempPath = modelPath + ".download";

    using (var httpClient = new HttpClient())
    using (var response = await httpClient.GetAsync(
        modelUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken))
    {
        response.EnsureSuccessStatusCode();

        long? totalBytes = response.Content.Headers.ContentLength;
        long bytesRead = 0;

        using var contentStream = await response.Content.ReadAsStreamAsync(cancellationToken);
        using var fileStream = File.Create(tempPath);

        var buffer = new byte[81920];
        int read;
        while ((read = await contentStream.ReadAsync(buffer, cancellationToken)) > 0)
        {
            await fileStream.WriteAsync(buffer.AsMemory(0, read), cancellationToken);
            bytesRead += read;

            if (totalBytes.HasValue)
            {
                progress?.Report((double)bytesRead / totalBytes.Value);
            }
        }
    }

    if (!await VerifyHashAsync(tempPath, expectedSha256, cancellationToken))
    {
        File.Delete(tempPath);
        throw new InvalidOperationException("Downloaded model failed integrity verification.");
    }

    File.Move(tempPath, modelPath, overwrite: true);
    return modelPath;
}

private static async Task<bool> VerifyHashAsync(
    string filePath, string expectedSha256, CancellationToken cancellationToken)
{
    using var sha256 = SHA256.Create();
    using var fileStream = File.OpenRead(filePath);
    byte[] hash = await sha256.ComputeHashAsync(fileStream, cancellationToken);
    string actualSha256 = Convert.ToHexString(hash);
    return string.Equals(actualSha256, expectedSha256, StringComparison.OrdinalIgnoreCase);
}

Kwestie wymagające rozważenia

  • Weryfikacja integralności: zawsze sprawdzaj skrót SHA-256 (lub podobny) po pobraniu, przed użyciem modelu lub traktuj go jako buforowany. W przeciwnym razie częściowe lub uszkodzone pobieranie może dyskretnie zakończyć się niepowodzeniem w czasie wnioskowania.
  • Zapis atomowy: Pobierz plik do pliku tymczasowego i przemianuj go na docelową nazwę dopiero po pomyślnym zakończeniu weryfikacji, dzięki czemu nieudane lub przerwane pobieranie nigdy nie pozostawi uszkodzonego pliku pod oczekiwaną ścieżką.
  • Ponawianie i obsługa trybu offline: Jawnie obsługuj błędy sieciowe. Zdecyduj, czy aplikacja może działać w trybie ograniczonej funkcjonalności, monitować użytkownika o ponowienie próby lub zablokować tę funkcję do momentu pomyślnego pobrania.
  • Miejsce przechowywania: Użyj zapisywalnego folderu lokalnego dla aplikacji, który pozostanie po aktualizacjach aplikacji, ale zostanie usunięty po jej odinstalowaniu.
  • Oczyszczanie: jeśli zastąpisz model nową wersją, usuń stary plik, aby nie gromadzić nieużywanych plików na urządzeniu użytkownika.
  • Pobieranie podczas instalacji czy przy pierwszym uruchomieniu: Jeśli instalator obsługuje uruchamianie niestandardowej akcji lub skryptu, może pobrać model w ramach procesu instalacji, aby był gotowy przed pierwszym uruchomieniem aplikacji przez użytkownika. Odbywa się to kosztem dłuższego czasu instalacji, ale zapewnia lepsze wrażenia przy pierwszym uruchomieniu i wykorzystuje tę samą logikę pobierania i weryfikacji, co pobieranie z uruchomionej aplikacji.

Udostępnij pobrany model między aplikacjami

Jeśli tworzysz bibliotekę lub zestaw SDK, od którego zależy wiele niezależnych aplikacji i chcesz, aby te aplikacje udostępniały jedną kopię modelu na dysku zamiast pobierać własne, użyj interfejsów API katalogu modeli uczenia maszynowego Windows zamiast pisać własną logikę pobierania. Aby uzyskać więcej informacji, zobacz Pierwsze kroki z interfejsami API Katalogu modeli.

Następne kroki