Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Windows ML carica un modello da un percorso di file locale, quindi non richiede alcun metodo di distribuzione specifico. La tua app o include il modello nel proprio pacchetto, oppure lo ottiene separatamente, scaricandolo tramite il programma di installazione o tramite l'app stessa la prima volta che serve. Questo articolo confronta i due approcci e illustra l'implementazione di ogni approccio.
Scegliere un approccio
| Includere il modello nel pacchetto | Scaricare il modello separatamente | |
|---|---|---|
| Ideale per | Modelli di piccole dimensioni o modelli che devono funzionare offline immediatamente dopo l'installazione | Modelli di grandi dimensioni o modelli da distribuire separatamente dall'app |
| Esperienza al primo avvio | Il modello è disponibile immediatamente | Richiede un download prima del primo utilizzo, a meno che il download non venga effettuato tramite il programma di installazione o precaricato in background |
| Impatto sulle dimensioni dell'app | Aumenta lo spazio di installazione per ogni utente | Usa l'archiviazione solo nei dispositivi in cui un utente acconsente esplicitamente alla funzionalità che richiede il modello |
| Supporto offline | Sempre disponibile offline | Disponibile solo offline dopo il primo download riuscito |
Se il modello è di pochi megabyte e raramente cambia, la creazione di bundle è più semplice e offre agli utenti un'app funzionante immediatamente. Se il modello è di grandi dimensioni, viene aggiornato frequentemente o è facoltativo per alcuni utenti, conviene scaricarlo separatamente.
Tip
Se si pubblica una libreria o un SDK da cui dipendono più app indipendenti e tali app devono condividere una singola copia su disco del modello, usare le API del catalogo di modelli di ML Windows anziché scrivere la logica di download e condivisione personalizzata. La maggior parte degli sviluppatori di app che necessitano solo di un modello per la propria app deve usare uno dei due approcci descritti qui.
Includere il modello nel pacchetto
Aggiungere il file del modello ONNX, insieme ai file da cui dipende, ad esempio tokenizer o file di etichetta, come contenuto nel progetto dell'app. Windows ML carica quindi il modello direttamente dal percorso di installazione dell'app, senza che sia necessario l'accesso alla rete.
Passaggi di implementazione
- Aggiungere il file del modello al progetto e impostarne l'azione di compilazione su Contenuto (o l'equivalente per il tipo di progetto) in modo che venga copiato nell'output e incluso nel pacchetto dell'app.
- Determina il percorso del modello in base al percorso di installazione dell'app in fase di esecuzione. Non codificare un percorso assoluto, perché il percorso di installazione varia in base all'utente e al tipo di distribuzione.
- Caricare il modello da tale percorso usando le API di inferenza.
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.
Considerations
- Dimensioni del pacchetto: ogni installazione include il modello completo, che aumenta le dimensioni del download e l'utilizzo del disco per tutti gli utenti, inclusi quelli che potrebbero non usare mai la funzionalità.
- Nessuna gestione degli errori di download necessaria: poiché il modello è già su disco all'avvio dell'app, non è necessario riprovare, controllare l'integrità o la logica di fallback offline.
- Pacchetti facoltativi: se si vuole mantenere il modello fuori dall'installazione di base, ma si evita comunque di scrivere la logica di download, è possibile spedirla in un pacchetto MSIX facoltativo che gli utenti o l'app installa su richiesta. In questo modo il pacchetto di base viene ridotto evitando un percorso di download personalizzato, a costo di affidarsi alla distribuzione dei pacchetti anziché a un semplice download.
Scaricare il modello separatamente
Invece di creare un bundle del modello, scaricarlo nel dispositivo separatamente dal pacchetto dell'app e archiviarlo nello spazio di archiviazione locale dell'app. Questo mantiene il pacchetto di dimensioni ridotte. Il download non deve necessariamente avvenire dalla tua app in esecuzione: puoi scaricare il modello dalla tua app al primo avvio, oppure fare in modo che il tuo programma di installazione lo scarichi come parte della procedura di installazione. In entrambi i casi, l'utente è responsabile del download, della verifica, dell'archiviazione e della pulizia del file.
Passaggi di implementazione
- Ospitare il file del modello (ed eventuali file dipendenti) in un URL HTTPS, insieme al relativo hash SHA-256, in modo da poter verificare il download.
- Decidere quando avviene il download: nel programma di installazione o dalla tua app la prima volta che ha bisogno del modello. Entrambi gli approcci usano la stessa logica di download e verifica.
- Verificare se il modello esiste già nella risorsa di archiviazione locale prima di scaricarlo di nuovo.
- Salvare il file in una cartella scrivibile, app-local e verificarne l'hash prima dell'uso.
- Segnalare lo stato di avanzamento del download all'utente e gestire gli errori di rete in modo che il download possa riprovare o eseguire il fallback normalmente.
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);
}
Considerations
- Verifica dell'integrità: verificare sempre un hash SHA-256 (o simile) dopo il download, prima di usare il modello o considerarlo come memorizzato nella cache. In caso contrario, un download parziale o danneggiato può fallire silenziosamente in fase di inferenza.
- Scritture atomiche: scarica in un file temporaneo e rinominalo con il nome definitivo solo dopo il buon esito della verifica, in modo che un download non riuscito o interrotto non lasci mai un file corrotto nel percorso previsto.
- Ripetizione di tentativi e gestione offline: gestire gli errori di rete in modo esplicito. Decidere se l'app può essere eseguita in modalità con funzionalità ridotte, chiedere all'utente di riprovare o bloccare la funzionalità fino a quando il download non riesce.
- Percorso di archiviazione: usare una cartella scrivibile locale dell'app che sopravvive tra gli aggiornamenti dell'app, ma viene pulita se l'app viene disinstallata.
- Pulizia: se si sostituisce il modello con una nuova versione, eliminare il file precedente in modo da non accumulare file inutilizzati nel dispositivo dell'utente.
- Download nel programma di installazione e prima esecuzione: se il programma di installazione supporta l'esecuzione di un'azione o uno script personalizzato, può scaricare il modello come parte dell'installazione in modo che sia pronto prima che l'utente avvii l'app per la prima volta. Questo comporta un tempo di installazione più lungo in cambio di una migliore esperienza al primo avvio e usa la stessa logica di download e verifica dei download dall'app in esecuzione.
Condividere un modello scaricato tra app
Se si sta creando una libreria o un SDK da cui dipendono più app indipendenti e si vuole che tali app condividano una copia su disco del modello invece di ogni download, usare le API del catalogo modelli di ML Windows anziché scrivere la logica di download personalizzata. Per altre info, vedi Introduzione alle API del catalogo di modelli.