Verteilen von Modellen für Windows ML

Windows ML lädt ein Modell aus einem lokalen Dateipfad, daher ist keine bestimmte Verteilungsmethode erforderlich. Ihre App liefert das Modell entweder als Teil ihres Pakets mit aus oder bezieht das Modell separat – entweder durch Herunterladen im Installationsprogramm oder durch die App, wenn es erstmals benötigt wird. In diesem Artikel werden die beiden Ansätze verglichen und die einzelnen Vorgehensweisen erläutert.

Auswählen eines Ansatzes

Fügen Sie das Modell Ihrem Paket hinzu Laden Sie das Modell separat herunter.
Ideal für Kleine Modelle oder Modelle, die sofort nach der Installation offline funktionieren müssen Große Modelle oder Modelle, die Sie separat von Ihrer App verteilen möchten
Erfahrung beim ersten Start Das Modell ist sofort verfügbar. Erfordert vor der ersten Verwendung einen Download, es sei denn, Sie laden ihn über Ihr Installationsprogramm herunter oder laden ihn im Hintergrund vorab herunter.
Auswirkungen der App-Größe Erhöht die Installationsgröße für alle Benutzer. Verwendet nur Speicher auf Geräten, auf denen sich ein Benutzer für das Feature entscheidet, das das Modell benötigt.
Offline-Support Immer offline verfügbar Nur offline verfügbar nach dem ersten erfolgreichen Download

Wenn Ihr Modell ein paar Megabytes ist und sich selten ändert, ist die Bündelung einfacher und bietet Benutzern sofort eine funktionierende App. Wenn Ihr Modell groß, häufig aktualisiert oder optional für einige Benutzer ist, laden Sie es stattdessen separat herunter.

Tip

Wenn Sie eine Bibliothek oder ein SDK veröffentlichen, von denen mehrere unabhängige Apps abhängen, und diese Apps sollten eine einzelne Kopie auf dem Datenträger des Modells freigeben, verwenden Sie die Windows ML-Modellkatalog-APIs, anstatt Ihre eigene Download- und Freigabelogik zu schreiben. Die meisten App-Entwickler, die nur ein Modell für ihre eigene App benötigen, sollten einen der beiden hier beschriebenen Ansätze verwenden.

Fügen Sie das Modell Ihrem Paket hinzu.

Fügen Sie die ONNX-Modelldatei zusammen mit allen Dateien hinzu, die davon abhängig sind, z. B. Tokenizer- oder Bezeichnungsdateien, als Inhalt in Ihrem App-Projekt. Windows ML lädt das Modell dann direkt aus dem Installationsort Ihrer App, ohne dass ein Netzwerkzugriff erforderlich ist.

Implementierungsschritte

  1. Fügen Sie die Modelldatei Ihrem Projekt hinzu, und legen Sie ihren Erstellungsvorgang auf Inhalt fest (oder auf die entsprechende Einstellung für Ihren Projekttyp), damit sie in das Ausgabeverzeichnis kopiert und in das App-Paket aufgenommen wird.
  2. Lösen Sie den Pfad des Modells relativ zum Installationsspeicherort Ihrer App zur Laufzeit auf. Schreiben Sie keinen absoluten Pfad fest, da der Installationsspeicherort je nach Benutzer- und Bereitstellungstyp variiert.
  3. Laden Sie das Modell von diesem Pfad mithilfe Ihrer Inferenz-APIs.
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.

Überlegungen

  • Paketgröße: Jede Installation trägt das vollständige Modell, das die Downloadgröße und die Datenträgernutzung für alle Benutzer erhöht, einschließlich derjenigen, die das Feature möglicherweise nie verwenden.
  • Keine Downloadfehlerbehandlung erforderlich: Da sich das Modell bereits auf dem Datenträger befindet, wenn die App gestartet wird, müssen Sie keine Wiederholungs-, Integritätsüberprüfungs- oder Offline-Fallbacklogik ausführen.
  • Optionale Pakete: Wenn Sie das Modell aus der Basisinstallation heraushalten möchten, aber dennoch keine Downloadlogik schreiben möchten, können Sie es in einem optionalen MSIX-Paket versenden, das Benutzer oder Ihre App bei Bedarf installiert. Dadurch bleibt das Basispaket klein und ein benutzerdefinierter Downloadpfad wird vermieden, allerdings auf Kosten der Abhängigkeit von der Paketbereitstellung anstelle eines einfachen Downloads.

Laden Sie das Modell separat herunter.

Anstatt das Modell zu bündeln, laden Sie es separat vom App-Paket auf das Gerät herunter und speichern es im lokalen App-Speicher. Dadurch bleibt Ihr Paket klein. Der Download muss nicht aus Ihrer laufenden App erfolgen – Sie können das Modell beim ersten Start aus Ihrer App herunterladen oder Ihr Installationsprogramm es während der Installation herunterladen lassen. Auf beide Weise sind Sie für das Herunterladen, Überprüfen, Speichern und Bereinigen der Datei verantwortlich.

Implementierungsschritte

  1. Hosten Sie die Modelldatei (und alle abhängigen Dateien) in einer HTTPS-URL zusammen mit ihrem SHA-256-Hash, damit Sie den Download überprüfen können.
  2. Entscheiden Sie, wann der Download erfolgt: in Ihrem Installationsprogramm oder aus Ihrer App, wenn das Modell zum ersten Mal benötigt wird. Bei beiden Ansätzen wird dieselbe Logik zum Herunterladen und Überprüfen verwendet.
  3. Überprüfen Sie, ob das Modell bereits im lokalen Speicher vorhanden ist, bevor Sie es erneut herunterladen.
  4. Speichern Sie die Datei in einem schreibbaren, app-lokalen Ordner, und überprüfen Sie den Hash vor der Verwendung.
  5. Melden Sie dem Benutzer den Downloadfortschritt und fangen Sie Netzwerkfehler ab, damit der Download erneut versucht oder ordnungsgemäß auf eine Alternative zurückgegriffen werden kann.
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);
}

Überlegungen

  • Integritätsüberprüfung: Überprüfen Sie nach dem Herunterladen immer einen SHA-256-Hash (oder ähnlich), bevor Sie das Modell verwenden oder es als zwischengespeichert behandeln. Andernfalls kann ein unvollständiger oder beschädigter Download während der Inferenz unbemerkt fehlschlagen.
  • Atomare Schreibvorgänge: Laden Sie die Datei in eine temporäre Datei herunter und benennen Sie sie erst dann an den Zielort um, wenn die Überprüfung erfolgreich war, sodass ein fehlgeschlagener oder unterbrochener Download niemals eine beschädigte Datei im erwarteten Pfad hinterlässt.
  • Wiederholen und Offlinebehandlung: Behandeln von Netzwerkfehlern explizit. Entscheiden Sie, ob Ihre App im Modus mit eingeschränkter Funktionalität ausgeführt werden kann, den Benutzer auffordern, den Vorgang erneut auszuführen oder das Feature zu blockieren, bis der Download erfolgreich war.
  • Speicherort: Verwenden Sie einen app-lokalen, schreibbaren Ordner, der über App-Updates hinweg überdauert, aber bereinigt wird, wenn die App deinstalliert wird.
  • Aufräumen: Wenn Sie das Modell durch eine neue Version ersetzen, löschen Sie die alte Datei, damit sich auf dem Gerät des Benutzers keine ungenutzten Dateien ansammeln.
  • Download während der Installation vs. beim ersten Start: Wenn Ihr Installationsprogramm die Ausführung einer benutzerdefinierten Aktion oder eines Skripts unterstützt, kann es das Modell während der Installation herunterladen, sodass es bereit ist, bevor der Benutzer die App zum ersten Mal startet. Dabei wird eine längere Installationszeit zugunsten einer besseren Erfahrung beim ersten Start in Kauf genommen, und es wird dieselbe Download- und Verifizierungslogik verwendet wie beim Herunterladen aus der laufenden App.

Freigeben eines heruntergeladenen Modells für alle Apps

Wenn Sie eine Bibliothek oder ein SDK erstellen, von denen mehrere unabhängige Apps abhängig sind, und sie möchten, dass diese Apps eine Kopie des Modells auf dem Datenträger freigeben, anstatt jedes eigene Herunterzuladen, verwenden Sie die Windows ML-Modellkatalog-APIs, anstatt Ihre eigene Downloadlogik zu schreiben. Weitere Informationen finden Sie unter "Erste Schritte mit den Modellkatalog-APIs".

Nächste Schritte