görüntü sınıflandırma etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
görüntü sınıflandırma etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

27 Eylül 2025 Cumartesi

WebGPU ile Tarayıcıda Makine Öğrenmesi: ONNX Runtime Web ile GPU Hızlandırmalı Görüntü Sınıflandırma

Giriş

WebGPU, tarayıcıda modern grafik ve hesaplama iş yüklerini donanıma yakın performansla çalıştırmaya imkan tanıyor. Bu makalede, ONNX Runtime Web kullanarak WebGPU üzerinde GPU hızlandırmalı bir görüntü sınıflandırma örneğini adım adım kuracağız. Amaç, ek bir sunucuya gerek kalmadan, tamamen istemci tarafında çalışan ve gerçek zamanlıya yakın tepki veren bir makine öğrenmesi deneyimi elde etmek.

Neden WebGPU ve ONNX Runtime Web?

WebGL veya WASM ile kıyaslandığında WebGPU, paralel iş yüklerini daha verimli planlayarak tensör işlemlerini hızlandırır. ONNX Runtime Web ise aynı model dosyasını hem WebGPU hem WASM üzerinde çalıştırabilen esnek bir yürütme altyapısı sunar. Bu sayede destekli cihazlarda GPU, diğerlerinde otomatik olarak CPU kullanılabilir; uygulama tek kod tabanıyla geniş bir cihaz yelpazesini kapsar.

Ön Koşullar ve Ortam

- Chrome 121+ veya Edge 121+ gibi WebGPU destekli bir tarayıcı kullanın. Firefox’ta Nightly sürümünde dom.webgpu.enabled bayrağıyla çalışır. Safari’de ise güncel sürümler kısmi destek verir. Uygulamayı güvenli kökenden (https veya localhost) barındırın.

- Node.js 18+ ve npm gereklidir. Örnek, vanilla JS ve Vite ile hazırlanacaktır.

Proje Kurulumu

1) Yeni bir proje oluşturun: npm create vite@latest webgpu-ml -- --template vanilla

2) Klasöre girin ve bağımlılıkları ekleyin: cd webgpu-ml && npm i onnxruntime-web

3) Basit bir dizin yapısı oluşturun: /public/model/mobilenetv3.onnx ve etiketler için /public/model/labels.json. ONNX modelini ONNX Model Zoo’dan veya dönüştürdüğünüz bir MobileNetV3 modelinden alabilirsiniz.

Temel Kod: Oturum, Ön İşleme, Çıkarım

Aşağıdaki kod, WebGPU destekli bir tarayıcıda modeli başlatır, bir görüntüyü 224x224’e ölçekler, normalleştirir, tensöre çevirir ve çıkarım yapar. Destek yoksa WASM’e otomatik düşer.

import * as ort from 'onnxruntime-web';
// 1) Oturum oluşturma (GPU + CPU yedekli)
const session = await ort.InferenceSession.create('/model/mobilenetv3.onnx', {
  executionProviders: ['webgpu', 'wasm'],
  graphOptimizationLevel: 'all'
});

async function loadImageToTensor(imgEl) {
  const size = 224;
  const canvas = document.createElement('canvas');
  canvas.width = size; canvas.height = size;
  const ctx = canvas.getContext('2d');
  ctx.drawImage(imgEl, 0, 0, size, size);
  const { data } = ctx.getImageData(0, 0, size, size);
  const mean = [0.485, 0.456, 0.406];
  const std = [0.229, 0.224, 0.225];
  const chw = new Float32Array(1 * 3 * size * size);
  for (let i = 0; i < size * size; i++) {
    const r = data[i * 4] / 255, g = data[i * 4 + 1] / 255, b = data[i * 4 + 2] / 255;
    chw[i] = (r - mean[0]) / std[0];
    chw[i + size * size] = (g - mean[1]) / std[1];
    chw[i + 2 * size * size] = (b - mean[2]) / std[2];
  }
  return new ort.Tensor('float32', chw, [1, 3, size, size]);
}

async function classify(imgEl) {
  const input = await loadImageToTensor(imgEl);
  const feeds = { [session.inputNames[0]]: input };
  const outputMap = await session.run(feeds);
  const logits = outputMap[session.outputNames[0]].data;
  // Softmax ve top-k
  const exps = logits.map(x => Math.exp(x - Math.max(...logits)));
  const sum = exps.reduce((a, b) => a + b, 0);
  const probs = exps.map(e => e / sum);
  const topK = [...probs].map((p, i) => ({ i, p })).sort((a, b) => b.p - a.p).slice(0, 5);
  const labels = await fetch('/model/labels.json').then(r => r.json());
  return topK.map(({ i, p }) => ({ label: labels[i], prob: p }));
}

Performans İpuçları

- FP16 kullanımı: Bazı modelleri yarım hassasiyetle (Float16) çalıştırmak bellek ve bant genişliği kullanımını düşürerek hız kazandırır. Modeliniz FP16’ya dönüştürülmüşse WebGPU’da belirgin fark görebilirsiniz.

- Girdi boyutu: 224x224 yerine 192x192 gibi daha küçük boyutlar deneyerek gecikmeyi azaltın. Bu değişim doğruluk kaybı ile hız kazanımı arasında bir denge gerektirir.

- Ortak önbellek: Modeli uygulama yaşam döngüsü boyunca bir kez yükleyip aynı oturumu tekrar kullanın. Tekrarlı session.create maliyetlidir.

- Grafik optimizasyon seviyesi: graphOptimizationLevel: 'all' çoğu senaryoda iyi sonuç verir. Bazı modellerde extended veya basic de test edilmeli.

- Çalışma zamanında veri kopyalarını azaltın: Canvas’tan aldığınız ImageData yerine WebCodecs API ile VideoFrame kullanmak (destekliyse) dönüşümleri hızlandırabilir.

Uyumluluk ve Geriye Dönük Çalışma

WebGPU her cihazda aynı düzeyde mevcut olmayabilir. executionProviders: ['webgpu', 'wasm'] sıralaması sayesinde GPU destekli tarayıcılarda hızlanır, diğerlerinde WASM’e düşer. Bu yaklaşım üretim ortamında kesintisiz deneyim sağlar. Ayrıca HTTPS ve güvenli bağlam zorunluluğuna dikkat edin; yerel geliştirmede localhost istisnadır.

Hata Ayıklama

- Model giriş/çıkış adları: session.inputNames ve session.outputNames ile doğrulayın; ONNX ihracında katman adları değişmiş olabilir.

- Bellek taşmaları: Büyük modeller mobil cihazlarda bellek sınırlarına takılabilir. Modeli quantize ederek (INT8/UINT8) veya daha hafif mimarilere geçerek çözebilirsiniz.

- WebGPU hataları: Tarayıcı konsolunda validation error mesajlarını kontrol edin. Sürücü veya adaptör sınırlamaları için navigator.gpu.requestAdapter() ile dönen limitleri inceleyin.

Gerçek Hayat Senaryoları

- Ürün arama: Kullanıcı yüklediği fotoğrafla eşleşen kategoriye gerçek zamanlı yönlendirme.

- İçerik güvenliği: Tarayıcıda ön filtreleme yaparak sunucu maliyetini ve gecikmeyi azaltma.

- Eğitim: Etkileşimli ML demoları ve ders materyalleri, laboratuvar kurulumları olmadan, yalnızca bir URL ile erişilebilir.

Sonuç

WebGPU ve ONNX Runtime Web birlikteliği, tarayıcıda makine öğrenmesi için yeni bir performans eşiği oluşturuyor. Doğru model seçimi, hafif ön/son işleme ve dikkatli optimizasyonlarla, mobil dahi pek çok cihazda tatmin edici hızlara ulaşmak mümkün. Bu temel iskeleti kullanarak; nesne tespiti, metinden görüntü üretimi veya konuşma tanıma gibi daha karmaşık senaryolara ilerleyebilirsiniz. Üstelik tümü, kullanıcı verisini cihazdan çıkarmadan, gizlilik dostu bir şekilde.

14 Eylül 2025 Pazar

WebGPU ile Tarayıcıda Yapay Zeka: ONNX Runtime Web ile Hızlı Görüntü Sınıflandırma Rehberi

Giriş

Tarayıcıda yapay zeka çalıştırmak artık bir deney olmaktan çıktı; WebGPU ve ONNX Runtime Web gibi teknolojiler sayesinde ciddi performans elde etmek mümkün. Bu rehberde, WebGPU hızlandırmasıyla bir ONNX görüntü sınıflandırma modelini tamamen tarayıcı içinde, ek bir sunucu tarafı altyapı olmadan nasıl koşturabileceğinizi adım adım anlatıyorum. Hedefimiz düşük gecikme, daha iyi gizlilik (veri cihazı terk etmez) ve çevrimdışı çalışma imkânı.

Neden WebGPU?

WebGPU, WebGL’in ötesine geçen, modern GPU mimarilerinden doğrudan faydalanmayı kolaylaştıran bir tarayıcı API’sidir. Hesaplama (compute) kabiliyetleri, daha düşük sürücü ek yükü ve daha öngörülebilir performans sunar. ONNX Runtime Web de bu yeteneklerden yararlanarak modeli GPU üzerinde çalıştırabilir; GPU desteklenmiyorsa otomatik olarak WASM (CPU) yoluna düşer.

Önkoşullar ve Ortam

• Tarayıcı: Chrome/Edge 113+ sürümlerinde WebGPU varsayılan olarak açıktır. Safari’de kısmi, Firefox’ta Nightly ve bayrak ile destek var. En güncel Chrome önerilir.
• Temel JS/HTML bilgisi ve statik bir sunucu (ör. npx serve veya Vite).
• Model dosyası: ONNX Model Zoo’dan MobileNetV2-7 küçük ve hızlı bir başlangıçtır. Alternatif olarak SqueezeNet veya EfficientNet-Lite tercih edilebilir.

Proje İskeleti

Basit bir index.html dosyasıyla başlayın. Aşağıdaki minimal iskelet, bir dosya girişi, bir tuş ve sonucu göstermek için alan içerir:

<!doctype html>
<html lang="tr">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>WASM + WebGPU Sınıflandırma</title>
</head>
<body>
  <input id="file" type="file" accept="image/*">
  <button id="run">Çalıştır</button>
  <canvas id="canvas" width="224" height="224"></canvas>
  <div id="out"></div>
  <script type="module" src="./app.js"></script>
</body>
</html>

ONNX Runtime Web’i Entegre Etme

CDN üzerinden ORT’yi kullanabilirsiniz. app.js dosyasında ORT’yi içe alın ve WebGPU’yu tercih eden bir oturum oluşturun. WASM fallback’i yedekte kalsın:

import * as ort from "https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.min.js";

// WASM dosyalarının yolu (CDN veya yerel) - doğru ayarlayın
ort.env.wasm.wasmPaths = "https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/";
// Daha yüksek performans için çoklu iş parçacığı (COOP/COEP gerektirebilir)
// ort.env.wasm.numThreads = navigator.hardwareConcurrency || 4;

const preferGPU = !!navigator.gpu;
const session = await ort.InferenceSession.create("./models/mobilenetv2-7.onnx", {
  executionProviders: preferGPU ? ["webgpu", "wasm"] : ["wasm"],
  graphOptimizationLevel: "all"
});

Ön İşleme: Görseli Tensore Dönüştürme

MobileNet türü modeller genelde 224x224 giriş, RGB kanal sırası ve kanal başta (NCHW) düzeni bekler. Pixel değerlerini 0-1 aralığına getirip normalize etmek gerekir. Örnek bir dönüştürme:

async function imageToTensor(file) {
  const img = new Image();
  img.src = URL.createObjectURL(file);
  await img.decode();
  const canvas = document.getElementById("canvas");
  const ctx = canvas.getContext("2d");
  ctx.drawImage(img, 0, 0, 224, 224);
  const { data } = ctx.getImageData(0, 0, 224, 224);
  const chw = new Float32Array(1 * 3 * 224 * 224);
  const mean = [0.485, 0.456, 0.406];
  const std = [0.229, 0.224, 0.225];
  let p = 0;
  for (let y = 0; y < 224; y++) {
    for (let x = 0; x < 224; x++) {
      const i = (y * 224 + x) * 4;
      const r = data[i] / 255;
      const g = data[i + 1] / 255;
      const b = data[i + 2] / 255;
      // NCHW: önce tüm R, sonra G, sonra B kanalı
      chw[0 * 224 * 224 + p] = (r - mean[0]) / std[0];
      chw[1 * 224 * 224 + p] = (g - mean[1]) / std[1];
      chw[2 * 224 * 224 + p] = (b - mean[2]) / std[2];
      p++;
    }
  }
  return new ort.Tensor("float32", chw, [1, 3, 224, 224]);
}

Çalıştırma ve Sonuçları Yorumlama

Girdi tensörünü oluşturduktan sonra oturumu çalıştırın. Çoğu sınıflandırma modelinde çıktı tek bir tensördür; en büyük olasılığı seçip etikete dönüştürürsünüz. ImageNet etiketlerini küçük bir JSON dosyası olarak projeye ekleyebilirsiniz:

import labels from "./labels-imagenet.json" assert { type: "json" };

document.getElementById("run").addEventListener("click", async () => {
  const file = document.getElementById("file").files[0];
  if (!file) return;
  const input = await imageToTensor(file);
  const feeds = { input: input }; // Modelin gerçek girdi ismini kontrol edin
  const out = await session.run(feeds);
  const outputName = session.outputNames[0];
  const data = out[outputName].data;
  let idx = 0, max = -Infinity;
  for (let i = 0; i < data.length; i++) { if (data[i] > max) { max = data[i]; idx = i; } }
  document.getElementById("out").textContent = labels[idx] + " (" + max.toFixed(3) + ")";
});

Performans İpuçları

• İlk yüklemede bir “ısındırma” (warm-up) çağrısı yapın; modelin derlenmesi ve GPU kaynaklarının hazırlanması süre alabilir.
• WebGPU aktifleştirilmişse IOBinding ile giriş/çıkışları GPU üzerinde tutmak ek hız kazandırır (ileri kullanım).
• Modellerin quantized (INT8) sürümlerini tercih ederek dosya boyutunu ve gecikmeyi azaltın.
• Model dosyasını Brotli/Gzip ile sıkıştırıp uygun cache header’ları ayarlayın; tarayıcı önbelleğini ve Service Worker ile Cache Storage’ı kullanın.
• Görüntü ön işlemesini OffscreenCanvas veya Web Worker içinde yaparak ana iş parçacığını serbest bırakın.

Güvenlik ve Uyumluluk Notları

WASM tarafında çoklu iş parçacığı ve SharedArrayBuffer kullanmak istiyorsanız COOP/COEP başlıklarını etkinleştirmeniz gerekir. Bu mümkün değilse tek iş parçacığı da gayet iş görür; WebGPU varsa GPU hızlandırması zaten ciddi bir fark yaratır. Tarayıcı uyumluluğunda problem yaşıyorsanız, geçici olarak executionProviders: ["wasm"] ile çalışmaya devam edebilirsiniz.

Sonuç

Bu rehberle, yalnızca statik dosyalardan oluşan basit bir web projesinde ONNX Runtime Web ve WebGPU kullanarak gerçek zamanlıya yakın görüntü sınıflandırma kurdunuz. Avantajları açık: düşük gecikme, veri gizliliği ve dağıtım kolaylığı. Bir sonraki adım olarak kamera akışı (getUserMedia) ile canlı sınıflandırma, farklı model mimarileri (ResNet, EfficientNet, ViT), otomatik etiketleme veya yerleşik önbellekle çevrimdışı kullanım gibi özellikleri ekleyebilirsiniz. WebGPU ekosistemi hızla olgunlaşıyor; bugün attığınız adımlar, yarının tarayıcı tabanlı yapay zeka uygulamalarının temelini oluşturacak.

3.