Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Ce guide vous montre comment créer un module complémentaire natif C# qui utilise Windows Machine Learning (WinML) dans votre application Electron. WinML vous permet d’exécuter des modèles machine learning (format ONNX) localement sur les appareils Windows pour des tâches telles que la classification d’images, la détection d’objets, etc.
Prerequisites
Avant de commencer ce guide, vérifiez que vous avez :
- Fin de la configuration de l’environnement de développement
- Windows 11 ou Windows 10 (version 1809 ou ultérieure)
Note
WinML s’exécute sur n’importe quel appareil Windows 10 (1809+) ou Windows 11. Pour des performances optimales, les périphériques équipés de GPU ou d'unités de traitement neuronal sont recommandés, mais l'API fonctionne également sur processeur.
Important
Le module complémentaire WinML nécessite la experimental SDK d'application Windows. Si vous avez sélectionné « Kits de développement logiciel (SDK) stables » pendant winapp init le guide d’installation, vous devez mettre à jour votre version du Kit de développement logiciel (SDK). Modifiez winapp.yaml et remplacez la version Microsoft.WindowsAppSDK par 2.0.0-experimental3, puis exécutez npx winapp restore pour mettre à jour.
Étape 1 : Créer un complément natif C#
Nous allons créer un module complémentaire natif qui utilisera des API WinML. Nous allons utiliser un modèle C# qui tire parti de node-api-dotnet pour ponter JavaScript et C#.
npx winapp node create-addon --template cs --name winMlAddon
Cela crée un winMlAddon/ dossier avec :
-
addon.cs- Votre code C# qui appelle les API WinML -
winMlAddon.csproj- fichier Project avec des références au Kit de développement logiciel (SDK) Windows et SDK d'application Windows -
README.md- Documentation sur l’utilisation du module complémentaire
La commande ajoute également un build-winMlAddon script à votre package.json pour générer le module complémentaire et un clean-winMlAddon script pour le nettoyage des artefacts de build :
{
"scripts": {
"build-winMlAddon": "dotnet publish ./winMlAddon/winMlAddon.csproj -c Release",
"clean-winMlAddon": "dotnet clean ./winMlAddon/winMlAddon.csproj"
}
}
Le modèle inclut automatiquement des références aux deux kits SDK, ce qui vous permet de commencer immédiatement à appeler Windows API !
Vérifions que tout est configuré correctement en créant le module complémentaire :
# Build the C# addon
npm run build-winMlAddon
Note
Vous pouvez également créer un module complémentaire C++ à l’aide npx winapp node create-addon (sans l’indicateur --template ). Les compléments C++ utilisent node-addon-api et fournissent un accès direct aux API Windows avec des performances maximales. Pour plus d’options, consultez le guide du module complémentaire de notification C++ pour obtenir une procédure pas à pas ou la documentation complète de la commande .
Étape 2 : Télécharger le modèle SqueezeNet et obtenir un exemple de code
Nous allons utiliser l’exemple Classifier l’image à partir de la galerie de développement AI comme référence. Cet exemple utilise le modèle SqueezeNet 1.1 pour la classification d’images.
2.1. Télécharger le modèle
- Installer la galerie AI Dev
- Accédez à l’exemple Classifier l’image
- Téléchargez le modèle SqueezeNet 1.1 (il prend en charge l’UC, le GPU et le NPU)
- Cliquez sur Ouvrir le dossier contenant pour localiser le
.onnxfichier
- Copiez le fichier
squeezenet1.1.onnxdans un dossiermodels/à la racine de votre projet.
Note
Le modèle peut également être téléchargé directement à partir du dépôt ONNX Model Zoo GitHub
Étape 3 : Ajouter des packages NuGet requis
Avant d’ajouter le code WinML, nous devons ajouter des packages NuGet supplémentaires requis pour le traitement des images, le runtime ONNX et la prise en charge de GenAI.
3.1. Mettre à jour Directory.packages.props
Ajoutez les versions de package suivantes au Directory.packages.props fichier à la racine de votre projet (doivent avoir été créées lors de la création du module complémentaire) :
<Project>
<PropertyGroup>
<!-- Enable central package versioning -->
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Microsoft.JavaScript.NodeApi" Version="0.9.17" />
<PackageVersion Include="Microsoft.JavaScript.NodeApi.Generator" Version="0.9.17" />
<!-- Add these packages for WinML -->
+ <PackageVersion Include="Microsoft.ML.OnnxRuntime.Extensions" Version="0.14.0" />
+ <PackageVersion Include="System.Drawing.Common" Version="9.0.9" />
+ <PackageVersion Include="Microsoft.Extensions.AI" Version="9.9.1" />
+ <PackageVersion Include="Microsoft.ML.OnnxRuntimeGenAI.Managed" Version="0.10.1" />
+ <PackageVersion Include="Microsoft.ML.OnnxRuntimeGenAI.WinML" Version="0.10.1" />
<!-- These versions may be updated automatically during restore to match yaml -->
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="2.0.0-experimental3" />
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.7175" />
</ItemGroup>
</Project>
3.2. Mettre à jour winMlAddon.csproj
Ouvrez winMlAddon/winMlAddon.csproj et ajoutez les références de package au <ItemGroup>:
<ItemGroup>
<PackageReference Include="Microsoft.JavaScript.NodeApi" />
<PackageReference Include="Microsoft.JavaScript.NodeApi.Generator" />
<!-- Add these packages for WinML -->
+ <PackageReference Include="Microsoft.ML.OnnxRuntime.Extensions" />
+ <PackageReference Include="System.Drawing.Common" />
+ <PackageReference Include="Microsoft.Extensions.AI" />
+ <PackageReference Include="Microsoft.ML.OnnxRuntimeGenAI.Managed" />
+ <PackageReference Include="Microsoft.ML.OnnxRuntimeGenAI.WinML" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" />
<PackageReference Include="Microsoft.WindowsAppSDK" />
</ItemGroup>
Ce que font ces packages :
- Microsoft.ML.OnnxRuntime.Extensions - Fournit des opérateurs et utilitaires supplémentaires pour le runtime ONNX
- System.Drawing.Common - Active le chargement et la manipulation d’images pour le prétraitement
- Microsoft.Extensions.AI - Abstractions IA pour .NET
- Microsoft.ML.OnnxRuntimeGenAI.Managed - Liaisons managées pour ONNX Runtime GenAI
- Microsoft.ML.OnnxRuntimeGenAI.WinML - Intégration WinML pour ONNX Runtime GenAI
Étape 4 : Ajouter l’exemple de code
La galerie AI Dev présente l’implémentation complète de la classification d’images avec SqueezeNet :
Nous avons adapté ce code pour Electron et vous trouverez l’implémentation complète dans l’exemple electron-winml. Le winMlAddon/ dossier contient le code modifié à partir de la galerie AI Dev.
Copiez l’intégralité winMlAddon/ du dossier de samples/electron-winml/winMlAddon/ à la racine de votre projet, en remplaçant celui créé à l’étape 1. L’exemple inclut plusieurs fichiers au-delà addon.cs (classes d’assistance dans Utils/, un client de conversation, etc.) requis pour que le module complémentaire génère et s’exécute.
Important
Vous devez copier l’intégralité du dossier, pas seulement addon.cs. Le module complémentaire dépend des fichiers auxiliaires dans le Utils/ sous-dossier (Prediction.cs, ImageNet.cs, BitmapFunctions.cs, etc.).
Détails de l’implémentation clé
Mettons en évidence les parties importantes de l’implémentation et les principales différences du code de la galerie de développement IA :
1. Condition requise du chemin racine du projet
Contrairement au code AI Dev Gallery, notre module complémentaire Electron requiert que le code JavaScript transmette le chemin racine du projet. Cela est nécessaire, car :
- Le module complémentaire doit localiser le fichier de modèle ONNX dans le
models/dossier - Les dépendances natives (DLL) doivent être chargées à partir de répertoires spécifiques
[JSExport]
public static async Task<Addon> CreateAsync(string projectRoot)
{
if (!Path.Exists(projectRoot))
{
throw new Exception("Project root is invalid.");
}
var addon = new Addon(projectRoot);
addon.PreloadNativeDependencies();
string modelPath = Path.Join(projectRoot, "models", @"squeezenet1.1-7.onnx");
await addon.InitModel(modelPath, ExecutionProviderDevicePolicy.DEFAULT, null, false, null);
return addon;
}
Cela sélectionne automatiquement le meilleur fournisseur d’exécution (PROCESSEUR, GPU ou NPU) en fonction des fonctionnalités de l’appareil.
2. Préchargement des dépendances natives
Le module complémentaire inclut une PreloadNativeDependencies() méthode pour charger les DLL requises. Cette approche fonctionne à la fois pour les scénarios de développement et de production sans avoir à copier des DLL à la racine du projet :
private void PreloadNativeDependencies()
{
// Loads required DLLs from the winMlAddon build output
// This ensures dependencies are available regardless of the execution context
}
Cela est appelé lors de l’initialisation avant le chargement du modèle, ce qui garantit que toutes les bibliothèques natives sont disponibles.
3. Configuration de Electron Forge pour l’empaquetage
Pour vous assurer que le module complémentaire fonctionne correctement dans les builds de production, vous devez configurer votre packageur sur :
- Décompresser les fichiers natifs - DLL, modèles ONNX et fichiers .node doivent être accessibles en dehors de l’archive ASAR
- Exclure les fichiers inutiles - Conserver la taille du package petite en excluant les artefacts de build et les fichiers temporaires
Pour Electron Forge, mettez à jour votre forge.config.js:
// From samples/electron-winml/forge.config.js
module.exports = {
packagerConfig: {
asar: {
// Unpack native files so they can be accessed by the addon
unpack: "**/*.{dll,exe,node,onnx}"
},
ignore: [
// Exclude .winapp folder (SDK packages and headers)
/^\/.winapp\//,
// Exclude MSIX packages
"\\.msix$",
// Exclude winMlAddon source files, but keep the dist folder
/^\/winMlAddon\/(?!dist).+/
]
},
// ... rest of your config
};
Utilité :
asar.unpack- Extrait les DLL, les exécutables, les fichiers binaires .node et les modèles ONNX dansapp.asar.unpacked/- Cela les rend accessibles au moment de l’exécution via des chemins de système de fichiers
- Le code JavaScript ajuste automatiquement les chemins d’accès (voir la
app.asar→app.asar.unpackedremplacement ci-dessus)
ignore- Exclut du package final :-
.winapp/- Packages et en-têtes du Kit de développement logiciel (SDK) (non nécessaires lors de l’exécution) -
.msixfichiers - Sorties empaquetées -
winMlAddon/fichiers sources - Conserve uniquement le dossier avec desdist/fichiers binaires compilés
-
Note
Si vous utilisez un autre outil d’empaquetage (electron-builder, etc.), vous devez configurer des paramètres similaires pour décompresser les dépendances natives et exclure les fichiers de développement. Consultez la documentation de votre emballeur pour connaître les options de décompression ASAR.
4. Classification des images
La ClassifyImage méthode traite une image et retourne des prédictions :
[JSExport]
public async Task<Prediction[]> ClassifyImage(string imagePath)
{
// Loads the image, preprocesses it, and runs inference
// Returns top predictions with labels and confidence scores
}
L'implémentation complète gère :
- Chargement et prétraitement d’images (redimensionnement, normalisation)
- Exécution de l’inférence du modèle
- Résultats de traitement postérieur pour obtenir les prédictions optimales avec des étiquettes et des scores de confiance.
Note
Le code source complet inclut le prétraitement d’images, la création de capteurs et l’analyse des résultats. Vérifiez l’exemple d’implémentation pour obtenir tous les détails.
Présentation du code
Le module complémentaire fournit les principales fonctions suivantes :
- CreateAsync : initialise le module complémentaire et charge le modèle SqueezeNet
- ClassifyImage - Prend un chemin d'image et fournit des prédictions de classification
WinML sélectionne automatiquement le meilleur appareil d’exécution (PROCESSEUR, GPU ou NPU) en fonction de la disponibilité.
Étape 5 : Générer le module complémentaire C#
Maintenant, générez le module complémentaire :
npm run build-winMlAddon
Cela compile votre code C# à l’aide d’AOT natif (compilation anticipée), qui :
- Crée un
.nodefichier binaire (format de complément natif) - Supprime le code inutilisé pour une taille d’offre groupée plus petite
- Ne nécessite aucun runtime .NET sur les machines cibles
- Fournit la performance native
Le module complémentaire compilé sera dans winMlAddon/dist/winMlAddon.node.
Étape 6 : Tester le module complémentaire
Nous allons maintenant tester le module complémentaire en l’appelant à partir du processus principal. Ouvrez src/main.js et procédez comme suit :
6.1. Charger le module complémentaire
Ajoutez les instructions require en haut :
const winMlAddon = require('../winMlAddon/dist/winMlAddon.node');
6.2. Créer une fonction de test
Ajoutez cette fonction pour tester la classification d’images :
const testWinML = async () => {
console.log('Testing WinML addon...');
try {
let projectRoot = path.join(__dirname, '..');
// Adjust path for packaged apps
if (projectRoot.includes('app.asar')) {
projectRoot = projectRoot.replace('app.asar', 'app.asar.unpacked');
}
const addon = await winMlAddon.Addon.createAsync(projectRoot);
console.log('Model loaded successfully!');
// Classify a sample image
const imagePath = path.join(projectRoot, 'test-images', 'sample.jpg');
const predictions = await addon.classifyImage(imagePath);
console.log('Top predictions:');
predictions.slice(0, 5).forEach((pred, i) => {
console.log(`${i + 1}. ${pred.label}: ${(pred.confidence * 100).toFixed(2)}%`);
});
} catch (error) {
console.error('Error testing WinML:', error.message);
}
};
Points clés :
- L’ajustement du chemin (
app.asar→app.asar.unpacked) garantit que le code fonctionne à la fois dans les applications de développement et empaquetées - Cela accède aux fichiers natifs décompressés configurés dans
forge.config.js
6.3. Appeler la fonction de test
Ajoutez cette ligne à la fin de la createWindow() fonction :
testWinML();
6.4. Préparer des images de test
Pour tester la classification d’images :
- Créer un
test-images/dossier à la racine de votre projet - Ajouter une image de test nommée
sample.jpg(le code attend ce nom de fichier exact) - Le modèle SqueezeNet reconnaît 1 000 classes ImageNet différentes (animaux, objets, scènes, etc.)
Lorsque vous exécutez l’application, vous verrez les résultats de classification dans la console !
Tip
Pour une implémentation complète avec des gestionnaires IPC, des dialogues de sélection de fichiers et une interface utilisateur, consultez l’exemple electron-winml.
Étape 7 : Mettre à jour l’identité de débogage
Pour vous assurer que le SDK d'application Windows est chargé et disponible pour l’utilisation, nous devons configurer l’identité de débogage, ce qui garantit que l’infrastructure est chargée chaque fois que notre application s’exécute. De même, chaque fois que vous modifiez Package.appxmanifest ou modifiez des ressources référencées dans le manifeste (comme les icônes d’application), vous devez mettre à jour l’identité de débogage de votre application. Run:
npx winapp node add-electron-debug-identity
Cette commande :
- Lit
Package.appxmanifestafin d'obtenir les détails et les fonctionnalités de l'application -
electron.exeest enregistré dans votrenode_modulesavec une identité temporaire - Vous permet de tester les API nécessitant une identité sans la nécessité d'un empaquetage MSIX complet
Note
Cette commande fait déjà partie du postinstall script que nous avons ajouté dans le guide d’installation. Elle s’exécute donc automatiquement après npm install. Toutefois, vous devez l’exécuter manuellement chaque fois que vous :
- Modifier
Package.appxmanifest(modifier les fonctionnalités, l’identité ou les propriétés) - Mettre à jour les ressources de l’application (icônes, logos, etc.)
Exécutez maintenant votre application :
npm start
Vérifiez la sortie de la console . Vous devez voir les résultats des tests WinML !
⚠️ Problème connu : Blocage de l’application ou fenêtre vide (cliquez pour développer)
Il existe un bogue Windows connu avec le conditionnement sparse d'applications Electron qui provoque un plantage de l'application au démarrage ou empêche le rendu du contenu web. Le problème a été résolu dans Windows mais n’a pas encore été propagé à tous les appareils.
Consultez la configuration de l’environnement de développement pour la solution de contournement.
Prochaines étapes
Félicitations! Vous avez créé un module complémentaire natif qui peut exécuter des modèles Machine Learning avec WinML ! 🎉
Vous êtes maintenant prêt à :
- Empaqueter votre application pour la distribution - Créer un package MSIX que vous pouvez distribuer
Ou explorez d’autres guides :
- Création d’un module complémentaire Phi Silicon - Découvrez comment utiliser l’API IA Phi Silicon
- Vue d’ensemble de la prise en main - Revenir au guide principal
Personnalisation de votre modèle
Pour intégrer entièrement votre modèle ONNX, vous devez :
- Comprendre les entrées de votre modèle : images, tenseurs, séquences, etc.
- Créer des liaisons d’entrée appropriées - Convertir vos données au format attendu par WinML
- Traiter les sorties - Analyser et interpréter les prédictions du modèle
- Gérer correctement les erreurs : le chargement et l’inférence du modèle peuvent échouer
Ressources additionnelles
- Documentation WinML - Documentation officielle WinML
- Documentation de l’interface CLI winapp - Informations de référence sur l’interface CLI complète
- Exemple d’application Electron - Exemple de travail complet
- Ai Dev Gallery - Exemple de galerie de toutes les API IA
- Exemples SDK d'application Windows - Collection d’exemples de SDK d'application Windows
- node-api-dotnet - Bibliothèque d’interopérabilité JavaScript C# ↔
Résolution des problèmes
La génération échoue avec NU1010 : les éléments PackageReference ne définissent pas de packageVersion correspondante
Vérifiez que tous les packages référencés dans winMlAddon.csproj ont des entrées correspondantes dans Directory.packages.props. Consultez l’étape 3 pour obtenir la liste complète des packages requis.
« non une application Win32 valide » lors du chargement du module complémentaire
Cela signifie que le module complémentaire a été conçu pour une architecture différente de celle de votre runtime Node.js/Electron. Vérifiez votre architecture de Node.js :
node -e "console.log(process.arch)"
Régénérez ensuite le module complémentaire avec la cible correspondante :
# For x64 Node.js:
dotnet publish ./winMlAddon/winMlAddon.csproj -c Release -r win-x64
# For ARM64 Node.js:
dotnet publish ./winMlAddon/winMlAddon.csproj -c Release -r win-arm64
Si vous avez récemment modifié votre installation de Node.js, réinstallez node_modules également pour obtenir le binaire Electron correspondant :
rm -rf node_modules package-lock.json
npm install
Obtenir de l’aide
- Vous avez trouvé un bogue ?Signalez un problème
- Questions sur WinML ? Consultez la documentation WinML
Bon apprentissage automatique! 🤖
Windows developer