Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu kılavuzda, Windows Uygulama SDK'sı ML API'leri için JS bağlamalarını kullanarak Electron'dan ONNX model çıkarımının nasıl çalıştırıldığı (yürütme sağlayıcısı bulma ExecutionProviderCatalog ve aracılığıyla model indirmeModelCatalog) onnxruntime-node ile birlikte çıkarım için nasıl çalıştırıldığı gösterilmektedir; C# eklentisi gerekmez. Çıkarım bir Elektron yardımcı programı işleminde çalıştırılır, böylece ana işlemi engellemez.
Prerequisites
Bu kılavuza başlamadan önce şunları yaptığınızdan emin olun:
Node için ONNX Runtime'ı yükleyin:
npm install onnxruntime-node@1.24.3
Important
Windows Uygulaması Runtime, kendi onnxruntime.dll bileşenini alt işlemlere önceden yükler. Sürüm, onnxruntime-node Windows Uygulama SDK'sı sürümünüzle birlikte gelen ORT ABI ile eşleşmelidir. Windows Uygulama SDK'sı 2.x için kullanınonnxruntime-node@1.24.x.
1. Adım: WinML bağlamalarını onaylama
Windows Uygulama SDK'sı’nın Microsoft.WindowsAppSDK.ML için geçişli bağımlılığı vardır; bu nedenle WinML API’leri zaten oluşturulan bağlamalarınızda yer alır. Şunu doğrulayın:
@microsoft/dynwinrt-codegen≥0.1.0-preview.8gerektirir — eski projeler için alternatifler için Electron ile çalışmaya başlama konusuna bakın.
node -e "console.log(Object.keys(require('#winapp/bindings')).filter(k => k.startsWith('ExecutionProvider')))"
ifadesini görmeniz [ 'ExecutionProvider', 'ExecutionProviderCatalog', 'ExecutionProviderReadyState' ]gerekir.
2. Adım: Modeli Model Kataloğu aracılığıyla indirme (ana işlem)
Modeli yerel olarak indirmek ve önbelleğe almak için JS bağlamalarından kullanın ModelCatalog . Katalog, kullanılabilir modelleri ve bunların indirme URL'lerini açıklayan bir JSON bildirimini (uzaktan veya yerel olarak barındırılan) okur. İlk indirmeden sonra, sonraki çalıştırmalar önbelleğe alınmış kopyayı kullanır:
Oluştur src/winml-model.js:
const { ModelCatalog, ModelCatalogSource, Uri } = require('#winapp/bindings');
const fs = require('node:fs');
const path = require('node:path');
// Remote catalog JSON hosted in the WindowsAppSDK-Samples repo
const MODEL_CATALOG_URL =
'https://raw.githubusercontent.com/microsoft/WindowsAppSDK-Samples/main/Samples/WindowsML/Resources/SqueezeNetModelCatalog.json';
async function downloadModel(modelId, onProgress) {
const uri = Uri.createUri(MODEL_CATALOG_URL);
const source = await ModelCatalogSource.createFromUriAsync(uri);
const catalog = ModelCatalog.createInstance([source]);
const model = await catalog.findModelAsync(modelId);
const op = model.getInstanceAsync();
if (onProgress) {
op.progress((value) => {
try { onProgress(value); } catch {}
});
}
const result = await op;
const instance = result.getInstance();
if (!instance) return undefined;
const paths = instance.modelPaths;
// modelPaths returns directories containing model files
for (let i = 0; i < paths.size; i++) {
const dir = paths.getAt(i);
if (fs.existsSync(dir) && fs.statSync(dir).isDirectory()) {
const onnx = fs.readdirSync(dir).find((f) => f.endsWith('.onnx'));
if (onnx) {
instance.close();
return path.join(dir, onnx);
}
} else if (dir.endsWith('.onnx')) {
instance.close();
return dir;
}
}
instance.close();
return undefined;
}
module.exports = { downloadModel };
3. Adım: Yürütme sağlayıcılarını bulma ve sağlama (ana işlem)
Kullanılabilir sağlayıcıları (CPU, DirectML, QNN/NPU) listelemek için ExecutionProviderCatalog, gerekirse çalışma zamanlarını indirmek içinse ensureReadyAsync kullanın:
Oluştur src/winml-ep.js:
const { ExecutionProviderCatalog, ExecutionProviderReadyState, ExecutionProviderReadyResultState } = require('#winapp/bindings');
function listProviders() {
const catalog = ExecutionProviderCatalog.getDefault();
return catalog.findAllProviders().map((p) => ({
name: p.name,
readyState: p.readyState,
libraryPath: p.libraryPath,
}));
}
async function ensureProviderReady(providerName, onProgress) {
const catalog = ExecutionProviderCatalog.getDefault();
const providers = catalog.findAllProviders();
const provider = providers.find((p) => p.name === providerName);
if (!provider) {
throw new Error(`Execution provider not found: ${providerName}`);
}
if (provider.readyState === ExecutionProviderReadyState.Ready) {
return { name: provider.name, readyState: 'Ready', libraryPath: provider.libraryPath };
}
const op = provider.ensureReadyAsync();
if (onProgress) {
op.progress((value) => {
try { onProgress(value); } catch {}
});
}
const result = await op;
let readyState;
if (result.status === ExecutionProviderReadyResultState.Success) readyState = 'Ready';
else if (result.status === ExecutionProviderReadyResultState.Failure) readyState = 'Failed';
else readyState = 'InProgress';
return {
name: provider.name,
readyState,
diagnosticText: result.diagnosticText,
libraryPath: provider.libraryPath,
};
}
module.exports = { listProviders, ensureProviderReady };
4. Adım: Bir yardımcı program işleminde çıkarım çalıştırma
ONNX Runtime oturumu oluşturma ve çıkarım işlemleri bloklayıcıdır — ana sürecin yanıt vermeye devam etmesini sağlamak için bunları bir Electron yardımcı işleminde çalıştırın.
4.1. Çalışanı oluşturma
Oluştur src/winml-worker.js (bu dosya bir yardımcı program işleminde çalışır):
const { roInitialize } = require('@microsoft/dynwinrt');
// When dynwinrt and onnxruntime-node share the same process, ORT's native
// init can leave the COM apartment uninitialized. Explicitly init MTA first.
roInitialize(1);
const ort = require('onnxruntime-node');
async function runModel(modelPath, inputData, inputShape, ep) {
const providers = ep === 'dml'
? [{ name: 'dml', deviceId: 0 }, 'cpu']
: ['cpu'];
const session = await ort.InferenceSession.create(modelPath, {
executionProviders: providers,
graphOptimizationLevel: 'all',
});
const inputName = session.inputNames[0];
const input = new ort.Tensor('float32', inputData, inputShape);
const outputs = await session.run({ [inputName]: input });
return Array.from(outputs[session.outputNames[0]].data);
}
process.parentPort.on('message', async (e) => {
const { id, method, args } = e.data;
try {
if (method === 'classify') {
const [modelPath, inputData, inputShape, ep] = args;
const result = await runModel(modelPath, new Float32Array(inputData), inputShape, ep);
process.parentPort.postMessage({ id, ok: true, result });
}
} catch (err) {
process.parentPort.postMessage({ id, ok: false, error: err.message });
}
});
4.2. Çalışana ana bilgisayardan başlatma ve çağırma
Lütfen aşağıdakileri src/index.js'a ekleyin:
const { utilityProcess } = require('electron');
const path = require('node:path');
const { listProviders, ensureProviderReady } = require('./winml-ep.js');
const { downloadModel } = require('./winml-model.js');
let worker = null;
let workerReady = null;
const pending = new Map();
let nextId = 1;
function startWinmlWorker() {
worker = utilityProcess.fork(path.join(__dirname, 'winml-worker.js'), [], {
stdio: 'pipe',
serviceName: 'winml-worker',
});
worker.on('message', (msg) => {
const entry = pending.get(msg.id);
if (!entry) return;
pending.delete(msg.id);
if (msg.ok) entry.resolve(msg.result);
else entry.reject(new Error(msg.error));
});
workerReady = new Promise((resolve) => worker.once('spawn', resolve));
}
async function classify(modelPath, inputData, inputShape, ep) {
if (!worker) startWinmlWorker();
await workerReady;
return new Promise((resolve, reject) => {
const id = nextId++;
pending.set(id, { resolve, reject });
worker.postMessage({ id, method: 'classify', args: [modelPath, Array.from(inputData), inputShape, ep] });
});
}
4.3. Bunu kullanın
İşlevinizin createWindow olduğundan asyncemin olun ve şunları ekleyin:
const createWindow = async () => {
// ... existing window creation code ...
// List and ensure all execution providers are ready
const providers = listProviders();
console.log('Available providers:', providers);
for (const ep of providers) {
console.log(`Ensuring ${ep.name} is ready...`);
const result = await ensureProviderReady(ep.name, (progress) => {
const pct = progress <= 1 ? Math.round(progress * 100) : Math.round(progress);
process.stdout.write(`\r ${ep.name}: ${pct}%`);
});
process.stdout.write('\n');
console.log(` ${ep.name}: ${result.readyState}`);
}
// Download model via Model Catalog (cached after first run)
console.log('Downloading model...');
const modelPath = await downloadModel('squeezenet', (progress) => {
if (progress >= 0 && progress <= 100) {
process.stdout.write(`\rDownloading model: ${Math.round(progress)}%`);
}
});
process.stdout.write('\n');
console.log('Model path:', modelPath);
// Run inference in utility process (replace with real preprocessed data)
const inputData = new Float32Array(1 * 3 * 224 * 224);
const output = await classify(modelPath, inputData, [1, 3, 224, 224], 'dml');
console.log('Model output (top 5 values):', output.slice(0, 5));
};
5. Adım: Çalıştırma
npx winapp node add-electron-debug-identity
npm start
Konsolda kullanılabilir yürütme sağlayıcılarını ve model çıkışını görmeniz gerekir.
Tip
JS bağlamaları (StorageFile, BitmapDecoder, BitmapTransform) aracılığıyla görüntü kod çözme ile eksiksiz bir görüntü sınıflandırma işlem hattı için bkz. Elektron Galerisi WinML örneği.
Sonraki Adımlar
Tebrikler! JavaScript'ten WinML yürütme sağlayıcıları ve ONNX Çalışma Zamanı çalıştırıyorsunuz; C# eklentisi gerekmez. 🎉
Artık şunu yapmaya hazırsınız:
- Uygulamanızı Dağıtım için Paketle — gönderebileceğiniz bir MSIX oluşturun.
Veya diğer kılavuzları keşfedin:
- JavaScript'ten Bildirim Gösterme — JS bağlantıları aracılığıyla Windows Uygulama SDK'sı bildirimleri.
- JavaScript'ten Windows API'lerini çağır — JS bağlamalarını kullanarak bir dosya seçin.
- JavaScript'ten Phi Silica'yı çağırın; Windows Uygulama SDK'sı yapay zeka ile metin özetleyin.
- WinML Eklentisi oluşturma — yerel C# eklentisi.
- Başlarken Genel Bakış — ana kılavuza dönün.
Windows developer