JavaScript etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
JavaScript etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

27 Ocak 2026 Salı

WebRTC ile Tarayıcıdan Tarayıcıya Dosya Aktarımı: Sinyal Sunucusu ve Güvenli P2P Akışı Kurulumu

WebRTC ile P2P dosya aktarımı neden hâlâ önemli?

Bulut depolama servisleri pratik ama her zaman ideal değil: büyük dosyalarda yükleme süresi, kota sınırları, bağlantı hızına bağlı gecikmeler ve kimi senaryolarda gizlilik endişeleri devreye giriyor. WebRTC (Web Real-Time Communication) ise tarayıcıların birbirleriyle doğrudan haberleşmesini sağlayarak, arada dosyayı tutan bir “depo” olmadan aktarımı mümkün kılıyor. Bu yazıda, ileri seviye ama uygulanabilir bir yaklaşımla, tarayıcıdan tarayıcıya güvenli P2P dosya transferi için gerekli bileşenleri ve kritik ayarları adım adım ele alacağım.

Mimarinin özeti: Sinyal mi, medya mı?

WebRTC, bağlantıyı “kendi kendine” başlatmaz. İki tarayıcının birbirini bulması ve bağlantı parametrelerini paylaşması için bir sinyal (signaling) kanalına ihtiyacı vardır. Bu kanal genellikle WebSocket ile kurulur. Sinyal sunucusu sadece şu verileri iletir: SDP teklif/yanıtları (offer/answer) ve ICE adayları. Dosyanın kendisi ise ideal durumda RTCDataChannel üzerinden P2P akar.

Özet akış: (1) İstemciler sinyal sunucusuna bağlanır. (2) Bir oda/kimlik üzerinden eşleşir. (3) SDP/ICE alışverişi yapılır. (4) NAT arkasından geçiş için STUN/TURN devreye girer. (5) DataChannel açılır ve dosya parçalı şekilde gönderilir.

Gereksinimler: STUN/TURN, HTTPS ve tarayıcı kısıtları

Modern tarayıcılarda WebRTC çoğu zaman “secure context” ister. Üretimde HTTPS kullanmanız önemlidir (localhost istisna). NAT/kurumsal ağ koşullarında yalnız STUN yetmeyebilir; bu nedenle bir TURN sunucusu kritik bir güvence katmanıdır. TURN, doğrudan bağlantı kurulamadığında trafiği relay eder; bu da maliyetli ama erişilebilirliği artıran bir çözümdür.

Pratik öneri: Geliştirme aşamasında STUN ile başlayın; sahaya çıkarken TURN ekleyin. En çok kullanılan açık kaynak TURN çözümü coturn’dür. Ayrıca aktarımın güvenliği WebRTC’de varsayılan olarak DTLS ile sağlanır; yani DataChannel üzerinde giden veri şifrelenir.

1) Basit bir sinyal sunucusu (Node.js + WebSocket)

Sinyal sunucusunun görevi “mesaj taşımak”tır, dosya aktarmak değil. Basit bir odalı yapı kurgulayabilirsiniz: istemci bir odaya katılır, diğer istemci gelince birbirlerinin mesajlarını iletir. Aşağıdaki yaklaşım üretim için değil, mantığı netleştirmek içindir: tek sunucu, oda eşleşmesi, mesaj yönlendirme.

İpucu: Mesajları tip alanıyla sınıflandırın: offer, answer, ice, join. Böylece istemci tarafı daha okunaklı olur ve hataları ayıklamak kolaylaşır.

2) İstemci tarafı: RTCPeerConnection ve RTCDataChannel

Tarayıcı tarafında iki temel nesne kullanılır: RTCPeerConnection ve RTCDataChannel. PeerConnection, ICE/STUN/TURN ile bağlantıyı kurar; DataChannel ise dosya parçalarını taşır. Buradaki kritik konu, dosyayı tek seferde göndermeye kalkmamak. Büyük bir Blob’u tek mesajla yollamak bellek patlamasına, tarayıcı takılmalarına veya kanal buffer’ının dolmasına yol açabilir.

Sağlıklı yöntem: Dosyayı chunk’lara bölün (örneğin 16 KB–256 KB arası), sırayla gönderin ve backpressure yönetin. WebRTC tarafında bunun için dataChannel.bufferedAmount değerini izleyip belirli eşiğin üstünde beklemek iyi bir pratiktir.

3) Chunk stratejisi, akış kontrolü ve bütünlük

Dosya transferinde üç konu genelde gözden kaçar: akış kontrolü, bütünlük ve yeniden birleştirme. Akış kontrolü için bufferedAmount eşiği belirleyin (ör. 8–16 MB). Bütünlük için en basit yaklaşım: dosya boyutu, parça sayısı, her parçanın indeks bilgisi ve isteğe bağlı hash (ör. SHA-256) gönderin. Yeniden birleştirmede alıcı tarafta parçaları sıraya koyup ArrayBuffer/Blob olarak birleştirin.

Ayrıca DataChannel için iki mod var: ordered (varsayılan) ve unordered. Dosya aktarımında genelde ordered işinizi kolaylaştırır. Paket kaybına dayanıklılık isterseniz, parçaları indeksleyip unordered kullanabilir, eksikleri yeniden isteyebilirsiniz; bu ileri seviye bir iyileştirmedir.

4) ICE yapılandırması: STUN ve TURN örneği

PeerConnection oluştururken ICE sunucularını tanımlarsınız. STUN, dış IP/port keşfine yardım eder; TURN ise relay görevi görür. Kurumsal ağlarda UDP engellenmiş olabilir; TURN’u TCP/TLS ile de sunmak gerekir. Üretimde en çok takılınan yer burasıdır: “Aynı Wi‑Fi’da çalışıyor, dış ağda çalışmıyor.” Sebebi genellikle TURN eksikliği veya yanlış kimlik bilgisidir.

Güvenlik notu: TURN kullanıcı adı/parola bilgilerini statik tutmak yerine zaman kısıtlı (time-limited) kimlik doğrulama kullanmak daha güvenlidir. coturn bu konuda esnektir.

5) Test, hata ayıklama ve performans ipuçları

Test aşamasında önce iki sekme arasında (aynı makine) deneyin; sonra aynı LAN, sonra farklı ağlar. Chrome’da chrome://webrtc-internals sayfası ICE adaylarını, bağlantı durumlarını ve kanal istatistiklerini incelemek için çok değerlidir. Bağlantı kurulamıyorsa genellikle sorun sinyal değil, ICE/TURN tarafındadır.

Performans için öneriler: Chunk boyutunu cihazlara göre ayarlayın, gereksiz kopyalamaları azaltın, alıcı tarafta parçaları birleştirirken bellek kullanımını izleyin. Çok büyük dosyalarda (ör. birkaç GB) tarayıcı sınırlarına yaklaşabilirsiniz; bu durumda indirme/streaming yaklaşımı ve dosya sistemi erişimi (File System Access API) gibi ek teknikler gündeme gelir.

Sonuç: Bulutsuz paylaşım için sağlam bir temel

WebRTC ile tarayıcıdan tarayıcıya dosya aktarımı, doğru kurgulandığında hem hızlı hem de şifreli bir deneyim sunar. Bu işin kalbi dosyayı taşımaktan çok, bağlantıyı güvenilir biçimde kurmaktır: sinyal sunucusu basit kalabilir, fakat ICE/STUN/TURN ayarları ve chunk tabanlı aktarım stratejisi projenin başarısını belirler. Buradaki yaklaşımı bir temel olarak alıp; oda yönetimi, kimlik doğrulama, yeniden deneme mekanizmaları ve transfer ilerleme göstergesi gibi parçalarla üretim seviyesine rahatça taşıyabilirsiniz.

6 Aralık 2025 Cumartesi

WebGPU ile Tarayıcıda Gerçek Zamanlı Makine Öğrenmesi: TensorFlow.js ile Adım Adım

WebGPU neden önemli?

Tarayıcıda makine öğrenmesi denildiğinde yıllardır WebGL ve WebAssembly (WASM) üzerinden çalışan çözümler öne çıkıyordu. Ancak bu yaklaşımlar, genel amaçlı hesaplama tarafında ciddi kısıtlar içeriyordu. WebGPU, modern grafik API’lerinin (Vulkan/Metal/Direct3D 12) üzerine inşa edilmiş, düşük gecikmeli ve yüksek verimli bir standarda dayanır. Bu sayede tensör işlemleri, matris çarpımları ve konvolüsyon gibi ML çekirdekleri doğrudan GPU üzerinde, daha az ara kopya ve daha iyi paralellik ile çalışır. Kısacası WebGPU, tarayıcıda gerçek zamanlı çıkarım (inference) yapmayı pratik hale getirir ve mobil dahil geniş bir cihaz yelpazesinde daha istikrarlı performans sağlar.

Tarayıcı desteği ve gereksinimler

WebGPU bugün Chrome 113+ ve Edge 113+ sürümlerinde varsayılan olarak kullanılabilir. Safari tarafında macOS ve iOS’in yeni sürümlerinde destek giderek olgunlaşıyor; Firefox içinse Nightly üzerinde bayrak ile etkinleştirme gerekebiliyor. Projenizi yayına almayı düşünüyorsanız, özellik tespiti (feature detection) yaparak WebGPU desteklenmiyorsa WASM veya WebGL’e otomatik düşüş sağlamanız kritik. Kullanıcı tarafında ekstra bir eklenti gerekmiyor; tek koşul güncel bir tarayıcı ve yeterli GPU/driver desteği.

TensorFlow.js ile WebGPU backend’i etkinleştirme

TensorFlow.js, WebGPU için resmi bir backend sunuyor. Uygulama başlangıcında WebGPU özelliğini tespit edip uygun backend’i seçmeniz en sağlıklı yaklaşım. Genel akış şudur: WebGPU destekleniyorsa TF.js’i webgpu backend ile başlatın, aksi durumda wasm veya webgl’e geri dönün. Başlangıçta bir “ısınma” (warm-up) adımı uygulamak da önemlidir; bir sahte giriş (dummy input) ile modeli bir kez çalıştırarak shader derlemelerinin tamamlanmasına izin verirsiniz. Bu sayede ilk gerçek tahmin sırasında yaşanabilecek ani gecikme önemli ölçüde azalır.

Model seçimi: boyut, hassasiyet ve gecikme dengesi

Gerçek zamanlı çıkarım hedefliyorsanız model seçimi kadar nicemleme (quantization) stratejisi de önemlidir. MobilNet tabanlı sınıflandırıcılar, BlazeFace veya MediaPipe tabanlı hafif yüz/eldeneyim modelleri ve COCO-SSD gibi optimize edilmiş nesne tespit ağları tarayıcı için uygundur. FP16 veya INT8 nicemleme ile model boyutu azalırken bellek kullanımınız düşer ve GPU bant genişliği tasarrufu sağlanır. Ancak nicemleme ile birlikte doğruluk payında ufak düşüşler olabilir; hedef senaryonuza göre tatlı noktayı bulmak için A/B testleri yapın.

Veri yolu ve gecikme: Kamera, Canvas ve sıfır kopya stratejileri

Gerçek zamanlı senaryolarda darboğaz genellikle GPU hesaplama gücünden ziyade veri aktarımıdır. Kamera akışını almak için getUserMedia kullanıyor, görüntüyü bir canvas’a çiziyor ve ardından tensöre dönüştürüyorsanız, gereksiz kopyalardan kaçınmalısınız. Modern tarayıcılarda OffscreenCanvas ve WebCodecs ile birlikte “zero-copy”a yakın akışlar kurulabiliyor; ancak API’ler platforma göre farklı olgunlukta. Her adımda gereksiz yeniden boyutlandırma ve renk uzayı dönüşümlerinden kaçınmak, çerçeve başına gecikmeyi düşürür. Ayrıca requestAnimationFrame ile çıkarımı ekran yenileme döngüsüne bağlamak yerine, sabit bir çıkarım frekansı belirleyip sonuçları görsel katmana asenkron taşımak çoğu zaman daha kararlı FPS verir.

Performans ipuçları

- Tek seferlik tensör tahsisleri yapın, tekrar kullanılan tensörleri yeniden yaratmak yerine cache’leyin. Bu yaklaşım hem GC baskısını hem de GPU bellek fragmentasyonunu azaltır.

- Batched çıkarım (ör. birden fazla çerçeveyi tek seferde işlemek) her zaman yararlı olmayabilir; gecikme duyarlı uygulamalarda mikro-batch yerine tekil çerçeve akışı daha iyi tepki süresi verir.

- Modeli hedef cihaza göre değiştirmek için koşullu yükleme yapın. Masaüstünde daha büyük bir model, mobilde hafif bir varyant seçmek kullanıcı deneyimini dengeler.

- WebGPU sürücülerindeki farklılıklardan etkilenmemek için düzenli olarak Chrome, Edge ve Safari üzerinde duman testleri (smoke test) koşturun.

Hata ayıklama ve ölçüm

Performansı yönetemediğiniz şeyi optimize edemezsiniz. Tarayıcının Performance paneli ile kare zaman çizelgesini (timeline) inceleyerek GPU tarafında beklenmedik duraklamaları tespit edin. TensorFlow.js, çıkarım sırasında bellek kullanımını ve kernel sürelerini profil etmeye yardımcı olacak yardımcı işlevler sunar; bu sayede hangi adımın darboğaz olduğunu netleştirirsiniz. Ayrıca FPS, gecikme (p95/p99) ve tahmin doğruluğunu aynı anda izleyebileceğiniz hafif bir telemetri katmanı kurmak, üretimde sorunları hızla yakalamanıza yardım eder.

Uyumluluk ve erişilebilirlik

Bazı kurumsal cihazlarda GPU erişimi kısıtlı olabilir veya kullanıcılar enerji tasarrufu modunda çalışıyor olabilir. Uygulamada “Gelişmiş hızlandırmayı aç/kapat” seçeneği sunarak WebGPU’yu kullanıcı tercihine bırakın. Erişilebilirlik açısından, çıkarım sonuçlarını yalnızca görsel olarak göstermek yerine metin çıktısı ve ARIA canlı bölgeleri üzerinden ekran okuyuculara iletmek, ML özelliklerini daha geniş kullanıcı kitlesine ulaştırır.

Güvenlik ve gizlilik

WebGPU, sitenin izni olmadan cihaz verilerine erişim sağlamaz; ancak yine de uzun süreli yoğun GPU kullanımı pil tüketimini artırabilir ve cihaz sıcaklığını yükseltebilir. Gerçek zamanlı uygulamalarda etkinlik algılama (ör. sekme arka plana geçince frekansı düşürme) ve otomatik duraklatma mekanizmaları ekleyin. Gizlilik açısından, modeli istemci tarafında çalıştırmak veriyi sunucuya göndermeden işleme imkânı sunduğu için hassas senaryolarda güçlü bir artıdır.

Sonuç

WebGPU, tarayıcıda makine öğrenmesini hobi projesi seviyesinden üretim kalitesine taşıyan bir dönüm noktası. TensorFlow.js ile birleştiğinde, kamera tabanlı gerçek zamanlı analitikten etkileşimli multimedya deneyimlerine kadar geniş bir yelpazede düşük gecikme ve yüksek kare hızına ulaşmak artık mümkün. Doğru model seçimi, dengeli nicemleme, dikkatli veri yolu tasarımı ve kapsamlı profil ile bugün dahi pek çok cihazda akıcı bir kullanıcı deneyimi sunabilirsiniz. WebGPU desteklenmeyen ortamlara zarifçe düşüş sağlamayı da unutmayın; böylece tüm kullanıcılar için çalışır bir çözüm elde edersiniz.

5 Aralık 2025 Cuma

WebGPU ile Tarayıcıda Makine Öğrenimi: ONNX Runtime Web ile Görsel Sınıflandırma (Adım Adım)

Giriş

WebGPU, modern tarayıcılarda GPU gücünden standart ve güvenli bir şekilde yararlanmayı sağlayan yeni bir web standardı. Bu yazıda, ONNX Runtime Web ve WebGPU kullanarak tarayıcı içinde tamamen istemci tarafında çalışan bir görsel sınıflandırma uygulamasını adım adım kuracağız. Sunucuya veri göndermeden, gizliliğe saygılı ve düşük gecikmeli bir makine öğrenimi deneyimi elde edeceğiz. Bu yaklaşım, SEO açısından da kıymetli; zira “tarayıcıda makine öğrenimi”, “WebGPU”, “ONNX Runtime Web”, “görsel sınıflandırma” gibi anahtar kelimelerle teknik kitlelere doğrudan hitap ediyor.

Ön Koşullar

- Güncel bir tarayıcı: Chrome 113+ sürümlerinde WebGPU masaüstünde varsayılan olarak açıktır. Safari’de ve Firefox’ta destek durumu değişebilir; deneysel bayraklar gerekebilir. Mobilde destek kısmi durumdadır.

- Node.js 18+ (geliştirme sunucusu ve paket yönetimi için)

- Temel HTML/JS bilgisi

Proje Kurulumu

1) Vite ile boş bir proje oluşturun:

npm create vite@latest webgpu-ml -- --template vanilla
cd webgpu-ml
npm install

2) ONNX Runtime Web paketini ekleyin:

npm i onnxruntime-web

3) Basit bir dosya yapısı hazırlayın: index.html, main.js ve bir models/ klasörü. Örnek olarak mobilenetv2.onnx gibi 224x224 giriş alan bir sınıflandırma modelini models/ altına yerleştirin. ONNX model arşivlerinden (örn. ResNet, MobileNet) hafif bir model tercih edin.

index.html İskeleti

Aşağıdaki minimal HTML, bir görsel yükleme alanı ve sonuçları göstermek için basit bir arayüz içerir.

<!doctype html>
<html lang="tr">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>WebGPU ile Görsel Sınıflandırma</title>
  </head>
  <body>
    <h1>WebGPU + ONNX Runtime Web</h1>
    <input type="file" id="file" accept="image/*" />
    <button id="predict">Sınıflandır</button>
    <div id="status">Hazır</div>
    <div id="result"></div>
    <canvas id="canvas" width="224" height="224" style="display:none"></canvas>
    <script type="module" src="/main.js"></script>
  </body>
</html>

WebGPU ve ONNX Runtime Web ile Çalıştırma

Aşağıdaki kodda, tarayıcıda WebGPU desteği kontrol edilir, ONNX modeli yüklenir, görsel 224x224 boyutuna ölçeklenir ve ImageNet ortalama/standart sapma değerleri ile normalize edilerek tensöre dönüştürülür. Ardından model çıkarımı yapılır ve en yüksek olasılıklı sınıf ekrana yazdırılır.

// main.js
import * as ort from 'onnxruntime-web/webgpu';

const statusEl = document.getElementById('status');
const resultEl = document.getElementById('result');
const fileInput = document.getElementById('file');
const predictBtn = document.getElementById('predict');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

let session;

// WebGPU desteğini kontrol edin
if (!('gpu' in navigator)) {
  statusEl.textContent = 'WebGPU desteklenmiyor. Varsayılan WASM ile deneyin.';
}

// Modeli başlat
async function initModel() {
  statusEl.textContent = 'Model yükleniyor...';
  // Fallback ile: önce WebGPU, olmazsa WASM
  session = await ort.InferenceSession.create('/models/mobilenetv2.onnx', {
    executionProviders: ['webgpu', 'wasm']
  });
  statusEl.textContent = 'Model yüklendi.';
}

function imageToTensor(img) {
  const size = 224;
  ctx.clearRect(0, 0, size, size);
  // Görseli 224x224'e çiz
  ctx.drawImage(img, 0, 0, size, size);
  const { data } = ctx.getImageData(0, 0, size, size);

  // NHWC(RGBA) -> NCHW, normalize [0,1], ImageNet mean/std
  const mean = [0.485, 0.456, 0.406];
  const std = [0.229, 0.224, 0.225];

  const input = new Float32Array(1 * 3 * size * size);
  let idx = 0;
  for (let y = 0; y < size; y++) {
    for (let x = 0; x < size; x++) {
      const i = (y * size + x) * 4;
      const r = data[i] / 255;
      const g = data[i + 1] / 255;
      const b = data[i + 2] / 255;
      // Kanal sırası: [R plane][G plane][B plane]
      input[0 * size * size + idx] = (r - mean[0]) / std[0];
      input[1 * size * size + idx] = (g - mean[1]) / std[1];
      input[2 * size * size + idx] = (b - mean[2]) / std[2];
      idx++;
    }
  }
  return new ort.Tensor('float32', input, [1, 3, size, size]);
}

function softmax(arr) {
  const max = Math.max(...arr);
  const exps = arr.map(v => Math.exp(v - max));
  const sum = exps.reduce((a, b) => a + b, 0);
  return exps.map(v => v / sum);
}

async function runInference(img) {
  if (!session) await initModel();

  statusEl.textContent = 'Çıkarım yapılıyor...';
  const tensor = imageToTensor(img);

  const inputName = session.inputNames[0];
  const output = await session.run({ [inputName]: tensor });

  const outputName = session.outputNames[0];
  const logits = Array.from(output[outputName].data);
  const probs = softmax(logits);

  // En yüksek olasılıklı sınıfı bul
  let bestIdx = 0;
  for (let i = 1; i < probs.length; i++) {
    if (probs[i] > probs[bestIdx]) bestIdx = i;
  }

  // Label dosyanız varsa fetch edip eşleyebilirsiniz (örn. imagenet-labels.txt)
  resultEl.textContent = `Tahmin sınıf index: ${bestIdx}, olasılık: ${(probs[bestIdx] * 100).toFixed(2)}%`;
  statusEl.textContent = 'Bitti';
}

// Görsel seç ve çıkarım başlat
predictBtn.addEventListener('click', async () => {
  const file = fileInput.files?.[0];
  if (!file) {
    alert('Lütfen bir görsel seçin.');
    return;
  }
  const img = new Image();
  img.onload = () => runInference(img);
  img.src = URL.createObjectURL(file);
});

// Sayfa yüklenince modeli hazırlayın (isteğe bağlı)
initModel().catch(err => {
  console.error(err);
  statusEl.textContent = 'Model yüklenirken hata oluştu.';
});

Performans İpuçları

- WebGPU genellikle WASM/WASM SIMD’e göre daha yüksek paralellik ve throughput sunar. Ancak küçük modellerde fark az olabilir. Model boyutu ve katman türleri sonucu etkiler.

- Modeli mümkün olduğunca küçük seçin (MobileNet, EfficientNet-Lite gibi). Büyük modeller hem ağdan indirmede hem de bellek kullanımında sorun çıkarabilir.

- İlk çıkarım (warm-up) genellikle daha yavaştır. Gerçek kullanıcı deneyimi için ikinci/üçüncü çıkarımı da ölçün.

- Vite yerine üretime alırken kodu küçültün ve model dosyasını CDN veya HTTP/2 ile hızlı sunun. Cache-Control başlıklarını doğru ayarlayın.

Sorun Giderme

- “WebGPU desteklenmiyor”: Tarayıcınızı güncelleyin veya chrome://flags içinde WebGPU ile ilgili bayrakları kontrol edin. Kurumsal politikalar GPU erişimini kısıtlayabilir.

- “Model giriş/çıkış adı uyuşmuyor” hatası: session.inputNames ve session.outputNames üzerinden gerçek isimleri alın, manuel isim yazmayın.

- Görselin renkleri veya sonuçlar beklenenden farklıysa, normalize adımlarını (mean/std) ve kanal sırasını (NCHW vs NHWC) model dokümantasyonuna göre doğrulayın.

- Bazı platformlarda WebGPU var ama belirli doku formatları kısıtlı olabilir. Fallback olarak WASM sağlayıcısını eklediğinizden emin olun.

Sonuç

WebGPU ve ONNX Runtime Web ile tarayıcıda makine öğrenimi artık gerçek bir seçenek. İstemci tarafında görsel sınıflandırma gibi görevlerde gizlilik, düşük gecikme ve çevrimdışı çalışma avantajları sunar. Bu rehberle temel bir iskelet kurdunuz; bundan sonra model çeşitliliğini artırabilir, etiket dosyaları ile daha anlaşılır sonuçlar gösterebilir, hatta Web Workers kullanarak arayüzü bloklamadan çoklu çıkarım senaryolarını deneyebilirsiniz. Kısacası, WebGPU sayesinde modern web uygulamaları, yapay zeka kabiliyetlerini kullanıcıya en yakın yerde, doğrudan tarayıcıda sunabiliyor.

4 Aralık 2025 Perşembe

WebGPU ile Tarayıcıda Yapay Zeka Çalıştırma: ONNX Runtime Web ve Transformers.js ile Adım Adım Rehber

Tarayıcıda yapay zeka modelleri çalıştırmak, son iki yılda WebGPU’nun olgunlaşmasıyla pratik hale geldi. WebGL ve saf WebAssembly çözümleri artık yerini daha modern, düşük seviye ve yüksek performanslı WebGPU’ya bırakıyor. Bu rehber, WebGPU destekli ONNX Runtime Web ve Transformers.js kullanarak istemci tarafında model çalıştırmayı adım adım anlatır; kurulum, performans ipuçları, geriye uyumluluk ve sorun giderme başlıklarını içerir.

WebGPU neden önemli?

WebGPU, GPU’ya daha doğrudan erişim sağlar, bellek kopyalamayı azaltır ve paralel işlemleri daha verimli yürütür. Görüntü sınıflandırma, metin gömme (embedding), duygu analizi, hatta küçük dil modelleri gibi görevlerde CPU’ya kıyasla ciddi hızlanma sağlayabilirsiniz. Üstelik tüm bunlar, veriyi sunucuya göndermeden, gizliliği koruyarak gerçekleşir.

Önkoşullar ve tarayıcı desteği

Güncel Chrome/Edge (121+), Safari 17+ (veya Technology Preview) ve Firefox Nightly, değişen derecelerde WebGPU desteği sunar. Chrome’da sorun yaşarsanız chrome://flags altında “Unsafe WebGPU” seçeneğini kontrol edin. Kurumsal cihazlarda kısıtlamalar olabilir. Destek yoksa ONNX Runtime Web’in WASM sağlayıcısına otomatik geçiş yapabilirsiniz.

Proje kurulumu (Vite + NPM)

Hızlı başlamak için Vite ile bir ön yüz projesi kurabilir ve hem düşük seviyeli API (onnxruntime-web) hem de yüksek seviyeli bir sarmalayıcı (Transformers.js) ekleyebilirsiniz. Aşağıdaki komutlar, örnek bir React projesi içindir; framework bağımlı değilsiniz, vanilla JS ile de kullanabilirsiniz.

# Proje oluşturma
npm create vite@latest webgpu-ai -- --template react
cd webgpu-ai

# Bağımlılıklar
npm i onnxruntime-web @xenova/transformers

# Geliştirme sunucusu
npm run dev

ONNX Runtime Web ile WebGPU’da model çalıştırma

ONNX Runtime Web (ORT Web), aynı API ile birden fazla yürütme sağlayıcısını (WebGPU, WebGL, WASM) destekler. Aşağıda WebGPU var ise onu, yoksa WASM’i kullanacak minimal bir örnek yer alıyor. Burada mobilenet gibi hafif bir görüntü sınıflandırma modeli varsayılmıştır.

import * as ort from 'onnxruntime-web';

async function loadSession() {
  const hasWebGPU = typeof navigator !== 'undefined' && !!navigator.gpu;

  const session = await ort.InferenceSession.create('/models/mobilenetv2.onnx', {
    executionProviders: hasWebGPU ? ['webgpu'] : ['wasm'],
    graphOptimizationLevel: 'all'
  });

  return session;
}

async function run(session, inputTensor) {
  const [inputName] = session.inputNames;
  const [outputName] = session.outputNames;
  const feeds = { [inputName]: inputTensor };

  const results = await session.run(feeds);
  const output = results[outputName]; // ort.Tensor
  return output;
}

// Basit ön işleme (örnek): 224x224, [1,3,224,224], normalize edilmiş Float32Array
// Gerçek uygulamada resmi canvas ile yeniden boyutlandırıp kanalları CHW formatına çevirin.

Modelin giriş/çıkış adları modellere göre değişir; yukarıdaki gibi session.inputNames ve session.outputNames kullanmak en güvenli yoldur. Performans için FP16’ye dönüştürülmüş modeller ve 224x224 gibi küçük giriş boyutları tercih edin. Ayrıca tek seferde birden fazla örnek (batch) işletecekseniz tarayıcı GPU belleği sınırlamalarını aklınızda tutun.

Transformers.js ile “yüksek seviyeli” kullanım

@xenova/transformers, tarayıcıda hazır NLP ve bazı görsel modelleri kolayca çalıştırmanızı sağlar. Arkada ONNX Runtime Web ve uygun olduğunda WebGPU kullanır. Aşağıdaki örnek duygu analizi içindir:

import { pipeline } from '@xenova/transformers';

async function runSentiment() {
  const hasWebGPU = typeof navigator !== 'undefined' && !!navigator.gpu;
  const device = hasWebGPU ? 'webgpu' : 'cpu'; // 'cpu' = WASM

  const pipe = await pipeline(
    'text-classification',
    'Xenova/distilbert-base-uncased-finetuned-sst-2-english',
    { device }
  );

  const out = await pipe('Bu film şaşırtıcı derecede iyiydi!');
  console.log(out);
}

Transformers.js, ilk çalıştırmada modeli indirip tarayıcı önbelleğine alır. Üretim ortamında model dosyalarını kendi CDN’inizden sunmak ve sürümleri sabitlemek iyi bir pratiktir. Bazı modeller büyük olduğundan, başlangıç gecikmesini azaltmak için “tiny” veya “base” sürümleri tercih edin.

Performans ipuçları

1) Doğru veri türü: FP16 modeller WebGPU’da bellek ve bant genişliği avantajı sağlar. Mümkünse ağırlıkları FP16’ya dönüştürün. 2) Boyutlandırma: Görsel görevlerde 160–224 piksel aralığı mobil cihazlar için iyi bir dengedir. 3) Ön bellekleme: Uygulama açılışında session’ı yükleyip sıcak tutmak (warm-up) soğuk başlangıç gecikmesini azaltır. 4) I/O bağlama: ORT Web’de (sürümünüze bağlı) tensörleri GPU belleğinde tutmak için IOBindings seçeneklerini inceleyin. 5) Paralellik: WASM’a düşerseniz SIMD ve çok iş parçacığı hız kazandırır; bunun için COOP/COEP başlıklarıyla cross-origin isolation etkin olmalı.

Geriye uyumluluk ve düşüş (fallback) stratejisi

Her cihaz WebGPU desteklemeyebilir. Bu yüzden navigator.gpu kontrolüyle otomatik geçiş uygulayın: WebGPU → WASM. Kullanıcıya “hızlandırma kapalı” gibi basit bir durum göstergesi sunmak, deneyimi şeffaf kılar. Mobilde pil ve termal kısıtlar için bir “düşük güç modu” eklemek de değerlidir.

Güvenlik ve gizlilik

İstemci tarafı çıkarım (inference), verinin cihazdan çıkmamasını sağlar. Ancak model dosyaları herkese açık sunuluyorsa, telif ve lisans koşullarını gözden geçirin. Ayrıca büyük modeller cihaz belleğini hızla tüketebilir; kademeli yükleme (lazy load) ve dinamik boşaltma (dispose) uygulayın.

Sorun giderme

WebGPU görünmüyor: Kurumsal politikalar veya eski tarayıcı sürümü olabilir; flags ve sürüm kontrolü yapın. GPU belleği yetersiz: Giriş çözünürlüğünü ve batch boyutunu düşürün, FP16 kullanın. Yavaş ilk çalıştırma: Modeli önden ısıtın ve CDN’de sıkıştırma (gzip/br) + cache headers kullanın. WASM fallback çok yavaş: cross-origin isolation ile WASM SIMD/threads’i etkinleştirin ve daha hafif bir model seçin.

Sonuç

WebGPU, tarayıcıda yapay zekayı gerçek zamanlıya yaklaştırıyor. ONNX Runtime Web ile ince ayarlı, Transformers.js ile hızlı ve pratik bir deneyim kurabilirsiniz. Doğru model boyutu, FP16, akıllı ön/son işlem ve sağlam fallback stratejisiyle hem masaüstü hem mobilde akıcı bir kullanıcı deneyimi sunmak mümkün.

24 Kasım 2025 Pazartesi

WebGPU ile Tarayıcıda Küçük Dil Modeli (LLM) Çalıştırma: Transformers.js ile Adım Adım Rehber

Tarayıcıda çalışan yapay zeka artık bir merak değil, gerçek bir ürün gerekliliği. WebGPU sayesinde GPU hızlandırmalı çıkarım, kullanıcı verisini sunucuya göndermeden, düşük gecikmeyle mümkün hale geldi. Bu rehberde, Transformers.js kullanarak tarayıcı içinde küçük bir dil modelini (LLM) nasıl çalıştırabileceğinizi adım adım anlatıyorum. Kurulumdan performans ayarlamalarına, gerçek dünyada dağıtıma kadar pratik bir yol haritası bulacaksınız.

Neden tarayıcıda LLM? Gizlilik (veri cihazdan çıkmıyor), offline senaryolar, anında yanıt, ölçeklenebilirlik (sunucu maliyetini uç cihazlara dağıtma) ve daha iyi kullanıcı deneyimi. Ayrıca WebGPU, CPU tabanlı WASM’a kıyasla büyük hız artışları sunuyor.

Gereksinimler ve hazırlık

- Güncel bir Chrome/Edge sürümü (WebGPU varsayılan olarak açık). Safari’de güncel sürümlerde kısmi destek mevcut, Firefox’ta ise Nightly/ayrık yapılandırmalar gerekebilir.
- HTTPS üzerinden sunum (yerelde http://localhost kabul edilir).
- GPU destekli bir cihaz (entegre grafikler de iş görür, ancak ayrık GPU belirgin fark yaratır).

Proje iskeleti: Hızlı başlamak için bir ön yüz iskeleti oluşturun. Örneğin Vite kullanıyorsanız: npm create vite@latest webgpu-llm, ardından proje klasörüne geçip npm install ile bağımlılıkları kurun. Ardından @xenova/transformers paketini ekleyin: npm i @xenova/transformers.

Model seçimi ve indirme stratejisi

Tarayıcıda çalıştırılacak modelin boyutu kritik. 0.1B–1B parametre aralığındaki, Transformers.js uyumlu ve WebGPU desteği eklenmiş dönüştürülmüş (ONNX tabanlı) modelleri tercih edin. Hugging Face üzerinde “Transformers.js”, “onnx” ve “text-generation” etiketlerine bakın. Küçük ama iyi ayarlanmış instruction modelleri, sohbet ve kısa metin üretiminde tatmin edici sonuç verir.

İpucu: İlk açılışta model dosyaları indirileceği için yükleme süresini yönetmek gerekir. Uygulamada bir önbellek stratejisi kullanın (Service Worker ile Cache Storage) ve kullanıcıya ilerleme çubuğu gösterin. Dosyaları parça parça (chunk) indirmek ve CDN üzerinden sunmak açılışı hızlandırır.

Transformers.js ile temel akış

- Yükleme: import ile pipeline fonksiyonunu içeri alın.
- Boru hattı: const generator = await pipeline('text-generation', MODEL_ADI, { device: 'webgpu' }). Burada device olarak webgpu vererek GPU hızlandırmayı etkinleştirirsiniz. Uygun olmayan tarayıcılarda otomatik olarak WASM’a düşebilir.
- Çıkarım: await generator('Merhaba, bugün neler öğrenelim?', { max_new_tokens: 64, temperature: 0.7, top_p: 0.9 }). Parametrelerle çıktı kalitesi ve hız arasında denge kurun.

Akıcı deneyim için akış (stream) modu: Token bazlı akış kullanıcıya “yazıyor” hissi verir. UI tarafında bir akış tamponu tutup yeni token geldikçe metni güncelleyin. İlk yanıtın ortaya çıkma süresi (TTFT) kullanıcı memnuniyeti için kilit metriklerden biridir.

Web Worker ile ana iş parçacığını özgür bırakın

GPU çağrıları ve token üretimi zaman zaman ana iş parçacığını meşgul edebilir. Bir Web Worker oluşturup modeli Worker içinde açın. UI’dan gelen prompt’ları postMessage ile Workera gönderin, tokenları da mesaj olarak geri alın. Bu sayede animasyonlar ve girişler takılmaz.

Not: Çok iş parçacıklı WASM’a düşülen senaryolarda SharedArrayBuffer gerekebilir. Bunun için sunucuda Cross-Origin-Opener-Policy: same-origin ve Cross-Origin-Embedder-Policy: require-corp başlıklarını ayarlayarak cross-origin isolation sağlayın.

Performans ve optimizasyon ipuçları

- Model boyutu ve quantization: INT8 veya 4-bit nicemleme bellek kullanımını ve yükleme süresini düşürür. Küçük modellerde kalite düşüşü sınırlıdır, özellikle kısa yanıtlar için.
- max_new_tokens ve repetition_penalty: Gereksiz uzun cevapların önüne geçer, hız kazandırır.
- Top-p/top-k/temperature: Çeşitlilik ve deterministiklik dengesini kurun. Üretimde genellikle temperature 0.6–0.9, top_p 0.8–0.95 iyi başlama noktalarıdır.
- Önbellek (KV cache): Destekleyen modellerde tekrar token üretiminde hesaplama azaltılır.
- Model varlıklarını yakına alın: Bölgesel CDN veya edge cache ile soğuk başlatmayı kısaltın.
- Lazy ve background preload: Uygulama açılır açılmaz arka planda model dosyalarını ısıtın; kullanıcı prompt yazana kadar yükleme tamamlanmış olur.

Donanım ve tarayıcı farklılıkları: iGPU’larda bellek bant genişliği sınırlıdır; daha küçük model + agresif quantization seçin. Mobil tarayıcılarda enerji tüketimi ve termal kısıtlar nedeniyle kısa oturumları hedefleyin. Masaüstü dGPU’larda ise 1B sınıfı modellere kadar makul akış hızları elde edilebilir.

Hata ayıklama ve yayına hazırlık

- WebGPU yok: Özellik algılama yapın ve kullanıcıya “Hızlandırma devre dışı, CPU modunda çalışıyor” mesajı gösterin.
- Büyük dosya indirme hataları: İndirme yönetimi, yeniden deneme ve parça doğrulaması (checksum) ekleyin.
- Hafıza tavanları: Tarayıcı sekmesinin bellek sınırını aşmayın; model boyutunu ve eşzamanlı çıkarımı sınırlayın.
- Gizlilik: Tüm çıkarım yerelde; telemetri topluyorsanız kullanıcıdan açık onay alın.
- UI/UX: Net yükleme durumu, iptal düğmesi, “Yeniden dene” ve token sayacı gerçek kullanıcı deneyimini iyileştirir.

Gerçek dünyada, bir “akıllı arama” veya “özetleyici” aracı yapmak istiyorsanız RAG (Retrieval Augmented Generation) ile tarayıcı içi gömlemeler (embeddings) üretip, küçük bir vektör dizini (ör. IndexedDB üzerinde) tutabilirsiniz. Arama sonucunu prompt’a enjekte ederek küçük bir modeli, büyük bir modelin doğruluğuna yaklaştırmak mümkün olur.

Özetle: WebGPU + Transformers.js, tarayıcıda LLM çalıştırmayı pratik ve üretime uygun hale getiriyor. Doğru model seçimi, iyi bir önbellekleme stratejisi ve Worker tabanlı mimari ile ilk yanıt süresini düşürür, akıcı bir sohbet deneyimi sunarsınız. Küçük başlayın, kullanıcı geri bildirimlerini toplayın ve gerektiğinde model boyutunu artırın. Bugün tarayıcıda çalışan bir yapay zeka prototipi çıkarmak, artık saatler meselesi.

23 Kasım 2025 Pazar

Tarayıcıda WebGPU ile Yerel LLM Çalıştırma: WebLLM Kurulum Rehberi ve Performans İpuçları

Giriş

Tarayıcıda WebGPU desteğinin olgunlaşması, büyük dil modellerini (LLM) tamamen istemci tarafında çalıştırmayı pratik hale getirdi. Bu rehberde, WebLLM kullanarak Chrome/Edge gibi modern tarayıcılarda internet bağlantısı olmadan çalışan, gizliliğe duyarlı ve hızlı bir sohbet asistanını adım adım kuracağız. Amaç, hem geliştirici deneyimini sade tutmak hem de performans, gizlilik ve SEO açısından en iyi uygulamaları özetlemek.

Ön Gereksinimler

- Güncel bir tarayıcı: Chrome 113+ veya Edge 113+ önerilir. Firefox’ta WebGPU Nightly ile etkinleştirilebilir; macOS’te Safari 17+ destek sunar.

- Güncel ekran kartı sürücüleri: Windows’ta D3D12, Linux’ta Vulkan, macOS’te Metal backend ile WebGPU çalışır. Eski sürücüler “uygun GPU adaptörü bulunamadı” hatasına yol açabilir.

- Node.js 18+ (Vite veya benzeri bir bundler kullanacağız). Alternatif olarak CDN ile basit bir HTML sayfası da kullanılabilir.

Neden WebLLM?

WebLLM, MLC ekosisteminin tarayıcıya optimize edilmiş LLM çalışma zamanı. Avantajları:

- Gizlilik: Veriler cihazı terk etmez. Kurumsal ve kişisel gizlilik gerektiren iş akışları için idealdir.

- Kurulum Kolaylığı: Sunucu yok; CDN veya statik hosting ile dağıtım yapılabilir.

- Performans: 4-bit gibi quantization seçenekleriyle orta segment GPU’larda dahi akıcı deneyim sağlanır.

Hızlı Başlangıç: Vite + WebLLM

Aşağıdaki adımlar React örneğiyle gösterilmiştir; vanilla veya başka framework’ler de benzer şekilde ilerler.

1) Proje oluşturma:

npm create vite@latest webllm-demo -- --template react-ts
cd webllm-demo
npm install

2) Paketleri ekleme:

npm i @mlc-ai/web-llm

3) Basit bir sohbet bileşeni oluşturma (src/App.tsx):

import { useEffect, useState } from "react";
import { CreateMLCEngine, InitProgressReport } from "@mlc-ai/web-llm";

export default function App() {
  const [engine, setEngine] = useState<any>(null);
  const [loading, setLoading] = useState("Model hazırlanıyor...");
  const [input, setInput] = useState("");
  const [messages, setMessages] = useState([{ role: "system", content: "Yardımcı asistan." }]);

  useEffect(() => {
    const init = async () => {
      const model = "Llama-3-8B-Instruct-q4f32_1-MLC"; // Donanımınıza göre daha küçük bir model seçebilirsiniz.
      const eng = await CreateMLCEngine(model, {
        initProgressCallback: (p: InitProgressReport) => {
          setLoading(`${Math.round(p.progress * 100)}% - ${p.text}`);
        },
      });
      setEngine(eng);
      setLoading("");
    };
    init();
  }, []);

  const send = async () => {
    if (!engine || !input.trim()) return;
    const next = [...messages, { role: "user", content: input }];
    setMessages(next);
    setInput("");
    const out = await engine.chat.completions.create({
      messages: next,
      temperature: 0.7,
      max_tokens: 256,
    });
    const reply = out.choices[0].message.content;
    setMessages([...next, { role: "assistant", content: reply }]);
  };

  return (
    <div style={{ padding: 16 }}>
      <h3>WebGPU + WebLLM Yerel Sohbet</h3>
      {loading && <p>{loading}</p>}
      {!loading && (
        <>
          <div style={{ whiteSpace: "pre-wrap", marginBottom: 12 }}>
            {messages.map((m, i) => (
              <div key={i}><b>{m.role}:</b> {m.content}</div>
            ))}
          </div>
          <input
            value={input}
            onChange={(e) => setInput(e.target.value)}
            placeholder="Bir soru yazın..."
            style={{ width: "70%" }}
          />
          <button onClick={send} style={{ marginLeft: 8 }}>Gönder</button>
        </>
      )}
    </div>
  );
}

4) Geliştirme sunucusunu çalıştırma:

npm run dev

İlk başlatmada model dosyaları indirileceği için yükleme biraz sürebilir. Tarayıcı konsolunda ilerleme yüzdesi ve ayrıntıları görürsünüz.

Model Seçimi ve Bellek

Model adı genelde “-MLC” soneki ve quantization içeren bir desen izler: örn. q4f32_1 gibi. 4-bit seçenekler performans/bellek dengesini iyi kurar. 7–8B parametreli Llama 3 veya Phi türevleri, modern entegre GPU’larda dahi çalışabilir. Yüksek VRAM’e sahipseniz daha büyük varyantlar deneyebilirsiniz.

Performans İpuçları

- WebGPU f16: Çoğu cihazda varsayılan olarak etkinleşir; mümkünse f16 yolunu kullanan modelleri tercih edin.

- Maksimum token: Yanıt başına max_tokens değerini gereksiz büyütmeyin; daha kısa yanıtlar daha hızlı üretilecektir.

- İlk yükleme önbelleği: Statik sunucuda HTTP cache ve Service Worker kullanarak model dosyalarını yerel önbelleğe alın; tekrar ziyaretlerde soğuk başlangıç azalır.

- İçerik güvenliği: Üretim ortamında COOP/COEP başlıkları ve sıkı CSP ile hem performans hem de güvenlikte tutarlılık sağlayın.

Güvenlik ve Gizlilik

Tarayıcıda çalışan bir LLM, sohbet içeriklerini dış servislere göndermediği için hassas verilerle çalışırken büyük avantaj sağlar. Yine de kullanıcı verilerini kalıcı olarak saklamadan önce açık rıza isteyin ve localStorage/IndexedDB kullanımını minimal tutun.

Karşılaşılan Yaygın Hatalar

- “No suitable GPU adapter”: Tarayıcınızı ve GPU sürücülerinizi güncelleyin. Linux’ta Vulkan, Windows’ta D3D12 desteğinin aktif olduğundan emin olun.

- Yavaş ilk yükleme: Modeli daha küçük bir varyantla değiştirin (ör. 4-bit), CDN/önbellek ayarlarınızı kontrol edin.

- Tarayıcı desteği: Kurumsal kısıtlı cihazlarda WebGPU devre dışı olabilir; BT politikalarını gözden geçirin veya alternatif tarayıcı deneyin.

SEO İçin Küçük Dokunuşlar

Başlık, meta açıklama ve alt başlıklarda “WebGPU”, “tarayıcıda LLM”, “WebLLM” gibi anahtar kelimeleri doğal akışta kullanın. İlk paragrafta hedef terimleri geçirip, alt başlıklarda soru bazlı ifadeler (ör. “Nasıl kurulur?”, “Hangi modeller hızlı?”) eklemek arama sonuçlarında tıklanma oranını artırır.

Sonuç

WebGPU, tarayıcıyı salt bir istemci olmaktan çıkarıp güçlü bir yerel AI yürütme katmanına dönüştürüyor. WebLLM ile dakikalar içinde çalışan bir sohbet asistanı kurabilir, kurumsal ortamlarda gizlilik avantajı sağlayabilir ve kullanıcılarınıza düşük gecikmeli deneyimler sunabilirsiniz. Küçük bir modelle başlayıp donanımınıza göre ölçeklenin; doğru quantization ve önbellekleme stratejileriyle fark edilir bir performans elde edeceksiniz.

22 Kasım 2025 Cumartesi

WebAuthn ve Passkey ile Parolasız Kimlik Doğrulama: Adım Adım Uygulama Rehberi

WebAuthn ve Passkey Nedir? Neden Önemli?

Parolalar güvenliğin en zayıf halkası olmaya devam ediyor: sızıntılar, kimlik avı, parola tekrar kullanımı ve sosyal mühendislik riski her zamankinden yüksek. WebAuthn (W3C) ve FIDO2 standardı, kullanıcıların cihazlarını (telefon, güvenlik anahtarı, bilgisayar) bir Passkey olarak kullanmasını sağlayarak parolasız, kimlik avına dayanıklı ve kullanıcı dostu bir kimlik doğrulama sunar. Bu yazıda, modern bir web uygulamasında WebAuthn ve Passkey ile parolasız kimlik doğrulamayı adım adım nasıl kuracağınızı anlatıyorum.

Mimari ve Akışın Özeti

WebAuthn iki temel akışa dayanır: kayıt (registration) ve giriş (authentication). Kayıt sırasında sunucu bir “challenge” üretir, tarayıcı ve cihaz bu challenge’ı cihaza özgü özel anahtarla imzalar ve sunucu bu kaydı güvenli şekilde saklar. Girişte yine challenge üretilir ve kullanıcı cihazıyla imza atar; sunucu saklanan genel anahtar ile imzayı doğrular. Bu süreçte kullanıcı deneyimi Touch ID/Face ID, Windows Hello veya bir güvenlik anahtarı dokunuşu kadar basittir.

Önkoşullar ve Dikkat Edilecekler

- HTTPS zorunludur (localhost hariç).
- RP ID (Relying Party ID) genellikle alan adınızdır (ör. example.com).
- Passkey senkronizasyonu için kullanıcılar Apple/Google/Microsoft hesabına giriş yapmış olabilir; güvenlik anahtarı (roaming authenticator) ile de çalışır.
- Tarayıcı desteği modern tarayıcılarda çok iyi; mobilde de yaygın.

Sunucu Tarafı: Challenge Üretimi ve Doğrulama

Sunucuda iki uç nokta gerekir: kayıt için “options” ve “verify”, giriş için “options” ve “verify”. Node.js dünyasında @simplewebauthn/server popüler ve güvendiğim bir çözümdür. Aşağıda yalın bir örnek görebilirsiniz.

// npm i @simplewebauthn/server express cors
import express from 'express';
import cors from 'cors';
import {
  generateRegistrationOptions,
  verifyRegistrationResponse,
  generateAuthenticationOptions,
  verifyAuthenticationResponse,
} from '@simplewebauthn/server';

const app = express();
app.use(cors());
app.use(express.json());

const rpID = 'example.com';
const rpName = 'Örnek Uygulama';
const db = { users: new Map() }; // { userId: { id, username, credentials: [] } }

app.post('/webauthn/register/options', (req, res) => {
  const { userId, username } = req.body;
  const user = db.users.get(userId) || { id: userId, username, credentials: [] };
  const opts = generateRegistrationOptions({
    rpID,
    rpName,
    userID: user.id,
    userName: user.username,
    attestationType: 'none',
    excludeCredentials: user.credentials.map(c => ({ id: c.credentialID, type: 'public-key' })),
    authenticatorSelection: { residentKey: 'required', userVerification: 'required' },
  });
  user.currentChallenge = opts.challenge;
  db.users.set(userId, user);
  res.json(opts);
});

app.post('/webauthn/register/verify', async (req, res) => {
  const { userId, attResp } = req.body;
  const user = db.users.get(userId);
  const verification = await verifyRegistrationResponse({
    response: attResp,
    expectedChallenge: user.currentChallenge,
    expectedRPID: rpID,
    expectedOrigin: 'https://example.com',
  });
  if (verification.verified) {
    const { credentialPublicKey, credentialID, counter } = verification.registrationInfo;
    user.credentials.push({ credentialID, credentialPublicKey, counter });
    db.users.set(userId, user);
  }
  res.json({ ok: verification.verified });
});

app.post('/webauthn/auth/options', (req, res) => {
  const { userId } = req.body;
  const user = db.users.get(userId);
  const opts = generateAuthenticationOptions({
    rpID,
    userVerification: 'required',
    allowCredentials: user.credentials.map(c => ({ id: c.credentialID, type: 'public-key' })),
  });
  user.currentChallenge = opts.challenge;
  db.users.set(userId, user);
  res.json(opts);
});

app.post('/webauthn/auth/verify', async (req, res) => {
  const { userId, authResp } = req.body;
  const user = db.users.get(userId);
  const verification = await verifyAuthenticationResponse({
    response: authResp,
    expectedChallenge: user.currentChallenge,
    expectedRPID: rpID,
    expectedOrigin: 'https://example.com',
    authenticator: user.credentials.find(c => c.credentialID.equals(Buffer.from(authResp.rawId, 'base64url'))),
  });
  res.json({ ok: verification.verified });
});

app.listen(3000);

Ön Uç: Tarayıcıda Kayıt ve Giriş

Tarayıcı API’si navigator.credentials üzerinden çalışır. Dönüş tipleri ArrayBuffer içerdiğinden Base64URL dönüşümleri gerekir. Basitlik için @github/webauthn-json veya @simplewebauthn/browser kullanabilirsiniz.

// npm i @simplewebauthn/browser
import {
  create as webauthnCreate,
  get as webauthnGet,
} from '@simplewebauthn/browser';

async function registerPasskey(userId, username) {
  const opts = await fetch('/webauthn/register/options', {
    method: 'POST', headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({ userId, username }),
  }).then(r => r.json());

  const attResp = await webauthnCreate({ publicKey: opts });
  const verify = await fetch('/webauthn/register/verify', {
    method: 'POST', headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({ userId, attResp }),
  }).then(r => r.json());

  return verify.ok;
}

async function loginWithPasskey(userId) {
  const opts = await fetch('/webauthn/auth/options', {
    method: 'POST', headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({ userId }),
  }).then(r => r.json());

  const authResp = await webauthnGet({ publicKey: opts });
  const verify = await fetch('/webauthn/auth/verify', {
    method: 'POST', headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({ userId, authResp }),
  }).then(r => r.json());

  return verify.ok;
}

Güvenlik ve UX İpuçları

- Kullanıcı doğrulamasını “required” tutun; cihaz biyometri veya PIN ister.
- Passkey’i birincil giriş yöntemi yapın, parolayı opsiyonel geri dönüş kanalı olarak değerlendirin.
- Aynı kullanıcı için birden fazla autentikatör kaydına izin verin (telefon, laptop, güvenlik anahtarı).
- Cihaz değiştirmede QR ile “cihazlar arası” passkey oturumu deneyimini etkinleştirin (Chrome/Safari destekler).
- Kaydı tamamlamadan önce challenge ve RP ID eşleşmelerini mutlaka doğrulayın.

Hata Ayıklama: Sık Karşılaşılan Sorunlar

- origin ve rpID eşleşmiyor: HTTPS alan adınız ile RP ID aynı olmalı (subdomain farklarına dikkat).
- Base64URL dönüşümleri eksik: webauthn-json veya simplewebauthn/browser kullanın.
- localhost testi: http://localhost için istisna var, ancak 127.0.0.1 farklı kabul edilebilir; tutarlı kullanın.
- allowCredentials boş: Kullanıcının kayıtlı credential listesini girişte doğru döndürdüğünüzden emin olun.

Sonuç

WebAuthn ve Passkey ile parolasız kimlik doğrulama artık niş bir teknoloji değil; büyük tarayıcılar ve platformlarca olgun şekilde destekleniyor. Doğru kütüphanelerle kurulum süreci şaşırtıcı derecede kısa, güvenlik kazanımı ise çok büyük. Ürününüzde parolaları azaltmak ve kimlik avına dayanıklı, modern bir deneyim sunmak istiyorsanız, bugün küçük bir POC ile başlayın ve kullanıcı tabanınıza kademeli olarak yayınlayın.

14 Kasım 2025 Cuma

WebGPU ile Tarayıcıda Yapay Zeka: Transformers.js Kullanarak Yerel Metin Sınıflandırıcı Kurulumu

Özet

Tarayıcıda çalışan yapay zeka uygulamaları, veriyi cihazdan çıkarmadan işlemek ve sunucu maliyetlerini azaltmak için güçlü bir çözüm haline geldi. WebGPU sayesinde artık yalnızca WebAssembly (WASM) ile sınırlı değiliz; modern ekran kartlarının gücünü doğrudan JavaScript ile kullanabiliyoruz. Bu rehberde, Transformers.js kütüphanesi ile tek sayfalık bir uygulama geliştirerek WebGPU üzerinde yerel metin sınıflandırma (pozitif/negatif duygu analizi) kuracağız. Kod, hiçbir sunucu tarafı model barındırma olmadan çalışacak ve tarayıcı, modeli indirip IndexedDB üzerinde önbellekleyecek.

Neden WebGPU?

WebGPU, grafik ve hesaplama iş yüklerinde tarayıcıya modern bir düşük seviye API sunar. WASM ile CPU üzerinde çalışan modeller, bazen yeterli performansı yakalayamazken, WebGPU destekli ONNX Runtime Web ve Transformers.js kombinasyonu, önemli ölçüde hız kazandırır. Sonuç: daha düşük gecikme, daha akıcı kullanıcı deneyimi ve ölçeklenmesi kolay bir mimari.

Önkoşullar

- Güncel bir Chromium tabanlı tarayıcı (Chrome/Edge 113+). Çoğu sistemde WebGPU varsayılan olarak açıktır. Eğer kapalıysa chrome://flags üzerinden “Enable WebGPU” etkinleştirilebilir.

- Modern bir GPU ve güncel sürücüler önerilir. GPU yoksa, uygulama otomatik olarak WASM’e düşer (daha yavaş olabilir).

- Basit bir yerel sunucu. Örnek olarak python -m http.server 8000 veya npx serve . kullanabilirsiniz.

Proje Yapısı ve Temel Sayfa

Bir klasör oluşturun: webgpu-ai-demo/. İçine index.html adında bir dosya ekleyin ve aşağıdaki iskeleti yerleştirin. COOP/COEP başlıkları, çok iş parçacıklı WASM için önerilir; yerel geliştirmede meta etiketleriyle eşdeğeri sağlanabilir. Üretimde ise HTTP yanıt başlıklarını sunucuda ayarlayın.

Aşağıdaki kodu tek bir HTML dosyasında kullanabilirsiniz:

<!doctype html>
<html lang="tr">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>WebGPU ile Metin Sınıflandırma</title>
  <meta http-equiv="Cross-Origin-Opener-Policy" content="same-origin">
  <meta http-equiv="Cross-Origin-Embedder-Policy" content="require-corp">
  <style>body{font-family:system-ui, Arial, sans-serif;max-width:800px;margin:40px auto;padding:0 16px}</style>
</head>
<body>
  <h1>WebGPU ile Tarayıcıda Duygu Analizi</h1>
  <textarea id="input" rows="6" style="width:100%" placeholder="Değerlendirilecek metni yazın..."></textarea>
  <br><br>
  <button id="analyze">Analiz Et</button>
  <pre id="log" style="background:#f6f8fa;padding:12px;white-space:pre-wrap">Hazırlanıyor...</pre>
  <script type="module">
    import { pipeline, env } from 'https://cdn.jsdelivr.net/npm/@xenova/transformers/dist/transformers.min.js';
    // WebGPU varsa kullan, yoksa WASM'e düş.
    const preferGPU = 'gpu' in navigator;  // navigator.gpu modern tarayıcılarda mevcuttur.
    const device = preferGPU ? 'webgpu' : 'wasm';
    // WASM fallback için iş parçacığı sayısı (COOP/COEP ile etkin çoklu iş parçacığı).
    env.backends.onnx.wasm.numThreads = Math.max(1, Math.min(4, (navigator.hardwareConcurrency||4)-1));
    const logEl = document.getElementById('log');
    const btn = document.getElementById('analyze');
    const input = document.getElementById('input');

    log('Model indiriliyor ve hazırlanıyor...');
    const classifier = await pipeline('text-classification', 'Xenova/distilbert-base-uncased-finetuned-sst-2-english', {
      device, quantized: true,
      progress_callback: x => log('İndiriliyor: ' + Math.round((x.progress||0)*100) + '%')
    });
    log('Hazır. Bir metin yazıp "Analiz Et"e basın.');

    btn.addEventListener('click', async () => {
      btn.disabled = true;
      const text = input.value.trim();
      if (!text) { log('Lütfen bir metin girin.'); btn.disabled = false; return; }
      log('Analiz ediliyor...');
      const output = await classifier(text, { topk: 2 });
      log(JSON.stringify(output, null, 2));
      btn.disabled = false;
    });

    function log(msg){ logEl.textContent = msg; }
  </script>
</body>
</html>

Çalıştırma

Proje klasörüne geçip basit bir sunucu açın. Örneğin Python kullanıyorsanız: python -m http.server 8000. Ardından tarayıcıdan http://localhost:8000 adresine gidin. İlk çalıştırmada model ağırlıkları indirileceği için bir miktar bekleme olabilir. Bu dosyalar IndexedDB üzerinde önbelleklenecek; bir sonraki açılışta çok daha hızlı başlayacaktır.

Performans İpuçları

- WebGPU: Kodda device: 'webgpu' geçiliyorsa GPU kullanılacaktır. Tarayıcınız ve ekran kartınız destekliyorsa belirgin hız kazanırsınız.

- Kuantizasyon: quantized: true seçeneğiyle 8-bit ağırlıklar kullanılır; indirme boyutu ve bellek tüketimi düşer, hız genellikle artar.

- Isınma (warm-up): Uygulama açıldığında boş bir metinle hızlı bir “ısınma” çağrısı yapmak, ilk gerçek isteğin gecikmesini azaltır.

- Çok iş parçacığı: WASM’e düşmeniz halinde COOP/COEP etkinse env.backends.onnx.wasm.numThreads ile çekirdek sayınıza göre değer belirleyin.

- Küçük modeller: Tarayıcı için küçük/orta boy modeller tercih edin. Daha büyük LLM’ler (ör. 7B) tarayıcıda pratik olmayabilir; sunucuya veya yerel native uygulamalara yönelin.

Hata Giderme

- “navigator.gpu tanımsız” uyarısı alıyorsanız tarayıcınızı güncelleyin veya WebGPU’yu flags üzerinden etkinleştirin. Bazı kurumsal politikalar WebGPU’yu devre dışı bırakabilir.

- “CORS/COEP/COOP” ile ilgili hatalarda sayfayı mutlaka bir HTTP sunucusundan servis edin. Üretimde, meta etiket yerine gerçek yanıt başlıklarını (COOP/COEP) sunucuda ayarlayın.

- Model indirme yavaşsa farklı bir ağa geçmeyi deneyin. İlk indirme bir kez yapılır; sonraki açılışlarda IndexedDB önbelleği devreye girer.

- Sonuçlar beklediğiniz gibi değilse Türkçe metinler için uygun bir modele geçebilirsiniz; Transformers.js ile Türkçe duygu analizi veya çok dilli modelleri deneyin.

Kısa Değerlendirme

Bu yaklaşım, uçtan uca gizlilik (metin cihazdan çıkmaz), anında ölçeklenebilirlik (sunucu GPU’su gerekmez) ve düşük gecikme gibi avantajlar sunuyor. Chrome ve Edge üzerinde WebGPU ile duyduğum hız artışı belirgin oldu; Safari ve Firefox tarafında ise deneysel destekler hızla olgunlaşıyor. Projenizde basit bir duygu analiziyle başlayıp, soru-cevap ya da özetleme gibi diğer görevler için hafif modellerle devam edebilirsiniz.

Sonuç

WebGPU ve Transformers.js, tarayıcıda çalışan modern yapay zeka uygulamalarını herkes için erişilebilir kılıyor. Bu yazıdaki örneği temel alarak kendi metin moderasyonu, kullanıcı geri bildirimi analizi veya içerik sınıflandırma araçlarınızı birkaç yüz satırlık kodla hayata geçirebilirsiniz. Performansı artırmak için kuantizasyon, uygun model seçimi ve önbellekleme stratejilerinden yararlanmayı unutmayın.

12 Kasım 2025 Çarşamba

Tarayıcıda WebGPU ile Makine Öğrenmesi: ONNX Runtime Web ve TensorFlow.js Rehberi

WebGPU, tarayıcıda donanım hızlandırmalı hesaplamayı modern grafik API’lerine (Metal, Direct3D 12, Vulkan) yakın bir modelle sunarak WebGL’in ötesine geçen yeni standart. Bu sayede makine öğrenmesi (ML) çıkarımını doğrudan kullanıcının cihazında, ek sunucu maliyeti olmadan ve gizliliği koruyarak çalıştırmak mümkün oluyor. Bu yazıda, WebGPU ile tarayıcıda ML modelini çalıştırmak için iki pratik yaklaşımı adım adım göstereceğim: ONNX Runtime Web ve TensorFlow.js. İkisini de basit örneklerle kurup, performans ipuçları ve sık karşılaşılan sorunlarla birlikte ele alacağız.

WebGPU hazır mı? Uyum ve kontrol

Güncel Chrome/Edge sürümlerinde WebGPU varsayılan olarak etkin. Safari’de kademeli destek ilerliyor; Firefox cephesinde Nightly kanalıyla deneysel destek mevcut. Hızlı bir kontrol için konsolda if (navigator.gpu) { console.log("WebGPU hazir"); } çalıştırabilirsiniz. Üretimde en sağlıklı deneyimi almak için HTTPS üzerinde barındırma yapın; bazı gelişmiş optimizasyonlar ve çoklu iş parçacığı (WASM tarafı) için COOP/COEP başlıklarını ayarlamak da gerekebilir.

ONNX Runtime Web ile WebGPU: Dönüştür, yükle, çalıştır

ONNX formatı; PyTorch, TensorFlow, scikit-learn ve daha fazlasından dönüştürülebilen evrensel bir model temsili sunar. Tarayıcıda ONNX modellerini çalıştırmak için onnxruntime-web paketinin WebGPU varyantını kullanacağız.

Kurulum (npm):
npm i onnxruntime-web

Basit örnek (WebGPU yüklü sürümle import):
import * as ort from 'onnxruntime-web/webgpu';

// 1) Oturumu aç
const session = await ort.InferenceSession.create('/models/model.onnx');

// 2) Girdi hazırlama (ör. 1x3x224x224 float32 tensör)
const data = new Float32Array(1 * 3 * 224 * 224);
// ... preprocess ile veriyi doldurun
const feeds = {
  'input': new ort.Tensor('float32', data, [1, 3, 224, 224])
};

// 3) Çıkarım
const results = await session.run(feeds);
const output = results['output'] || Object.values(results)[0];
console.log('Çıkış boyutu:', output.dims);

Önemli nokta: webgpu varyantını import ettiğinizde yürütücü bu backend’i tercih eder. WebGPU destekli değilse otomatik olarak WASM’e düşebilir; ancak tutarlı performans için destekli tarayıcı hedefleyin. Büyük modelleri CDN üzerinden getirirken HTTP/2 veya HTTP/3 tercih edin; tek büyük dosya yerine parçalara bölünmüş ağırlıklar ilk etkileşimi hızlandırabilir.

TensorFlow.js + WebGPU: Hızlı başlangıç

TensorFlow ekosisteminde çalışıyorsanız veya TFJS’nin zengin yüksek seviyeli API’lerinden faydalanmak istiyorsanız WebGPU backend’i iyi bir seçenek. Aşağıdaki adımlarla bir GraphModel’i WebGPU üzerinde çalıştırabiliriz.

Kurulum (npm):
npm i @tensorflow/tfjs @tensorflow/tfjs-backend-webgpu

Örnek kullanım:
import * as tf from '@tensorflow/tfjs';
import '@tensorflow/tfjs-backend-webgpu';

await tf.setBackend('webgpu');
await tf.ready();

// Modeli yükle (GraphModel tercih)
const model = await tf.loadGraphModel('/models/model.json');

// Girdi oluştur (NHWC: [1, 224, 224, 3])
const input = tf.randomNormal([1, 224, 224, 3]);
const warmup = model.predict(input);
await warmup.data(); // sıcak başlatma
warmup.dispose();

const output = model.predict(input);
const result = await output.data();
console.log('İlk 5 skor:', Array.from(result).slice(0, 5));
input.dispose();
output.dispose();

TFJS tarafında model.predict zincirindeki tensörleri zamanında dispose() etmek ve tahmin öncesi bir warmup çağrısı yapmak kare sürelerini belirgin biçimde iyileştirir. Özellikle görüntü tabanlı modellerde tf.image.resizeBilinear gibi GPU dostu operasyonları kullanmak CPU-GPU senkronizasyonunu azaltır.

Performans ipuçları: FP16, quantization ve bellek

- FP16 desteği: Cihazınız destekliyse (çoğu modern GPU’da var), FP16 ile bant genişliği ve bellek kullanımını düşürürsünüz. ONNX tarafında dönüştürme sırasında, TFJS tarafında ise uygun model varyantını tercih edin.
- INT8 quantization: Görsel sınıflandırma ve bazı NLP modellerinde int8 kuantizasyon ciddi hız ve boyut kazancı sağlar. Kalibrasyon verisiyle kuantize edilmiş ONNX modelleri WebGPU’da iyi sonuç verir.
- Graf optimizasyonu: ONNX için optimize edilmiş grafik ve sabit katman birleştirme (fusion) seçenekleri; TFJS için GraphModel tercih edin ve gereksiz düğümleri taşımayın.
- Veri aktarımını minimize edin: GPU’dan CPU’ya data() çağrılarını sadece gerekli olduğunda yapın. Akış içinde tensörleri GPU’da tutmak darboğazları azaltır.
- Pipeline hazırlığı: Tek seferlik session ve model nesnelerini uygulama ömrü boyunca yeniden kullanın; her tahminde yeniden oluşturmayın.

Hata ayıklama ve yaygın sorunlar

- navigator.gpu undefined: Tarayıcı desteklemiyor ya da ortam güvenli değil. Güncel sürüm kullanın ve sayfayı HTTPS üzerinde servis edin.
- CORS/COEP/COOP: Büyük modelleri farklı bir origin’den çekiyorsanız CORS başlıkları ve gerekiyorsa COOP/COEP ayarları doğru olmalı. Aksi halde iş parçacığı/optimizasyon kısıtları veya yükleme hataları görebilirsiniz.
- Çıktı isimleri: ONNX modellerinde çıktı adları farklı olabilir. Object.keys(results) ile kontrol edip doğru düğümü okuyun.
- Bellek sızıntısı: TFJS ve ORT’ta tek kullanımlık tensörleri mutlaka dispose() edin. Uzun oturumlarda aksi halde GPU belleği dolar.
- Mobil cihazlar: Termal kısıtlar nedeniyle uzun süreli çıkarımda hız düşebilir. Toplu işler için aralıklı işlem veya daha küçük/kuantize model seçin.

Hangi yolu seçmeli?

- ONNX Runtime Web: Farklı çerçevelerden gelen modelleri tek formatta toplamak, üretim odaklı sabitlenmiş bir çalışma zamanı kullanmak ve WebGPU/WASM arasında esnek geçiş yapmak istediğiniz projeler için ideal.
- TensorFlow.js: TF ekosistemine aşinalığınız varsa, tarayıcıya özel yüksek seviyeli API’lerle hızlı prototipleme ve zengin yardımcı fonksiyonlar arıyorsanız tercih edin.

Sonuç olarak WebGPU, tarayıcı tarafı makine öğrenmesinde yeni bir sayfa açıyor. Doğru model boyutu, kuantizasyon stratejisi ve bellek yönetimiyle, gerçek zamanlı veya etkileşimli deneyimleri tamamen istemci tarafında, gizliliğe saygılı ve düşük gecikmeli şekilde sunmak artık mümkün. Hem ONNX Runtime Web hem de TensorFlow.js, geliştirici deneyimini olgunlaştıracak seviyede; projenizin kökenine ve ekosistem tercihlerinize göre seçim yapıp hızla üretime geçebilirsiniz.

4 Kasım 2025 Salı

WebGPU ile Tarayıcıda Gerçek Zamanlı Nesne Tespiti: ONNX Runtime Web ile Adım Adım

Giriş

Tarayıcıda yapay zekâ çalıştırmak, yerel gizlilik, düşük gecikme ve kurulum gerektirmeyen dağıtım gibi avantajlar sunuyor. WebGPU’nun olgunlaşması ve ONNX Runtime Web’in hızla gelişmesi sayesinde, bugün artık masaüstü veya sunucuya gerek duymadan tarayıcı içinde gerçek zamanlı nesne tespiti mümkün. Bu yazıda, WebGPU ve ONNX Runtime Web kullanarak YOLO tabanlı hafif bir modelle, sıfırdan çalışan bir demo kurulumunun nasıl yapılacağını, performans ipuçlarını ve dikkat edilmesi gereken noktaları adım adım anlatıyorum.

Gereksinimler ve Hazırlık

Öncelikle güncel bir tarayıcıya ihtiyacınız var. WebGPU için Chrome/Edge 121+ tavsiye edilir; bazı cihazlarda WebGPU devre dışı olabilir, bu durumda ONNX Runtime Web otomatik olarak WASM (WebAssembly) yürütücüsüne düşebilir. Uygulamanızı HTTPS üzerinden ve mümkünse yerel geliştirmede localhost ile çalıştırın. Kamera erişimi için getUserMedia iznine de ihtiyaç olacak.

Proje Kurulumu

Hızlı başlamak için Vite kullanacağız. Terminalde aşağıdaki adımları izleyin:
1) npm create vite@latest webgpu-onnx-demo -- --template vanilla
2) cd webgpu-onnx-demo
3) npm install onnxruntime-web
4) npm install ve ardından npm run dev ile geliştirme sunucusunu başlatın.

Model Seçimi ve Dosya Yapısı

Tarayıcı için hafif bir model seçmek kritik. YOLO ailesinden yolov8n veya benzeri küçük bir ONNX modeli başlangıç için ideal. Model dosyasını projenizde public/models/yolov8n.onnx gibi bir yola koyun. Eğer int8/FP16 gibi quantized sürüm elinizde varsa performans kazanabilirsiniz; WebGPU bu tür ağlarda ciddi hız kazandırır.

ONNX Runtime Web ile Oturum Oluşturma

Tarayıcıda model çalıştırmak için onnxruntime-web kütüphanesi tek noktadan çözüm sunar. Basit bir başlatma şeması şöyle olabilir: import * as ort from 'onnxruntime-web' ardından const session = await ort.InferenceSession.create('/models/yolov8n.onnx', { executionProviders: ['webgpu', 'wasm'] }). Bu yapı, WebGPU destekliyse GPU’yu, değilse WASM’ı kullanır. Uygulama açılışında bir kez oturum oluşturup bellekte tutmak başlangıç gecikmesini azaltır.

Görüntü Kaynağı ve Ön İşleme

Kameradan akış almak için navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } }) kullanın. Video karesini bir canvas üzerine çizip modelin beklediği çözünürlüğe (örneğin 640x640) yeniden boyutlandırın. Piksel verisini canvas.getContext('2d').getImageData(...) ile alın, RGB sırasına getirip 0-1 aralığına normalize edin ve tensörü NCHW formatında Float32Array olarak oluşturun. ONNX’a beslemek için new ort.Tensor('float32', data, [1, 3, 640, 640]) şeklinde bir tensör üretin.

Çıktı Sonrası İşleme (Post-Processing)

YOLO benzeri modellerin çıktısı genellikle kutular, sınıf olasılıkları ve skorlar içerir. Sigmoid/Softmax dönüşümlerini uyguladıktan sonra bir Non-Maximum Suppression (NMS) adımı gerekir. NMS için IoU eşiğini (ör. 0.45) ve skor eşiğini (ör. 0.25) kendiniz belirleyin. Tarayıcı performansı için döngüleri optimize edin, mümkünse tek tip diziler (Float32Array) ve önceden ayrılmış tamponlar kullanın.

Çalıştırma Döngüsü ve Çizim

Her karede sırasıyla: videodan canvas’a çizim → ön işleme → session.run(feeds) → post-processing → kutuları ve etiketleri ikinci bir overlay canvas’ına çizim. Çizim için requestAnimationFrame kullanarak akıcı bir döngü yakalayın. WebGPU yürütücüsü açıkken orta sınıf bir dizüstünde 30 FPS ve üzeri değerlere ulaşmak mümkün; WASM yolunda ise 8-15 FPS aralığı gerçekçi bir beklentidir.

Performans İpuçları

1) Web Worker + OffscreenCanvas: Ön işleme ve NMS’i bir Worker içine alarak ana iş parçacığını boşaltabilirsiniz. OffscreenCanvas ile çizimleri de iş parçacığı dışında yapmak mümkün.
2) Isınma (Warm-up): Uygulama açılışında bir yapay girişle bir kez session.run çağırarak ilk kare gecikmesini düşürün.
3) Boyut ve Oran: Giriş çözünürlüğünü cihaz gücüne göre 320, 480, 640 şeklinde seçin. Düşük çözünürlük daha yüksek FPS demektir.
4) Kuantizasyon: FP16 veya INT8 modellerle hem bant genişliği hem de hesap yükünü azaltırsınız. WebGPU ile özellikle FP16 iyi sonuç verir.
5) Bellek Yönetimi: Her karede yeni dizi oluşturmak yerine tamponları yeniden kullanın; gereksiz GC duraklamalarını önleyin.

WebGPU Özel Notlar

Bazı cihazlarda navigator.gpu görünse bile adaptör kısıtları performansı etkileyebilir. adapter = await navigator.gpu.requestAdapter() ve device = await adapter.requestDevice() çağrılarında hata yakalama koyun. Uzun süren işlemlerde device.lost olayını dinleyip yeniden kurulum yapın. Ayrıca, farklı GPU sürücülerinde küçük nüanslar olabilir; kritik bölümlerde tarayıcı konsolunu takip edin.

WASM Yürütücüsü İçin Ek Ayarlar

WebGPU devre dışıysa ONNX Runtime Web’in WASM yürütücüsü devreye girer. graphOptimizationLevel: 'all' gibi seçeneklerle optimizasyonu artırın. Bazı SIMD hızlandırmaları için COOP/COEP başlıkları gereklidir; üretimde sunucu yapılandırmanızı Cross-Origin-Opener-Policy: same-origin ve Cross-Origin-Embedder-Policy: require-corp ile güncellemeyi düşünün. Bu sayede WASM SIMD ve bazı paralel özellikler etkin hale gelir.

Hata Ayıklama ve Ölçüm

FPS’i ölçmek için basit bir sayaç yazın ya da PerformanceObserver kullanın. ONNX katman sürelerini anlamak için giriş/çıkış zamanlarını konsola basmak yeterli olur. Çıktılar boşsa ilk bakacağınız yer ön işleme adımıdır: kanal sırası (NCHW/NHWC), normalize edilmemiş değerler veya çözünürlük uyuşmazlığı genellikle sorumludur.

WebGL mi, WebGPU mu?

WebGL tabanlı çözümler hâlâ iş görse de, makine öğrenmesi iş yüklerinde WebGPU ile daha tutarlı ve modern bir performans elde ediliyor. ONNX Runtime Web’in WebGPU yürütücüsü, operator kapsamını genişlettikçe fark daha da açılıyor. Kısacası, uzun vadede WebGPU tercih etmek mantıklı.

Sonuç

Bu rehberle, WebGPU ve ONNX Runtime Web kullanarak tarayıcıda gerçek zamanlı nesne tespiti uygulamasını uçtan uca kurmanın temel adımlarını gördük. Doğru model, dikkatli ön/post-işleme ve küçük optimizasyonlarla akıcı bir deneyim elde edebilirsiniz. Üstelik tümü istemci tarafında çalıştığı için gizlilik ve dağıtım kolaylığı cabası. Bir sonraki adım olarak, izleme (tracking), bölütleme (segmentation) veya metin çıkarımı (OCR) gibi ek yetenekleri aynı altyapı üzerinde denemeyi düşünebilirsiniz.

2 Kasım 2025 Pazar

Tarayıcıda Yerel Yapay Zeka: WebGPU ve ONNX Runtime Web ile Görsel Sınıflandırma Nasıl Çalıştırılır?

Özet ve Neden Önemli?

Tarayıcıda çalışan yapay zeka, gizlilik, gecikme ve kullanıcı deneyimi açısından oyunun kurallarını değiştiriyor. WebGPU ile birlikte ONNX Runtime Web kullanarak bir görsel sınıflandırma modelini tamamen istemcide, yani kullanıcının cihazında çalıştırabilirsiniz. Böylece veriler sunucuya gönderilmez, ağ gecikmesi azalır ve uygulama çevrimdışı senaryolarda dahi işlevini sürdürür. Bu yazıda, sıfırdan bir ön yüz projesine WebGPU destekli ONNX Runtime Web ekleyerek, bir görüntüyü sınıflandırma adımlarını sade ama teknik açıdan tatmin edici bir şekilde ele alacağız.

Gereksinimler ve Mimari

WebGPU, modern tarayıcılarda donanım hızlandırmalı hesaplamaya erişmek için tasarlanmış, Vulkan/Metal/DX12 benzeri bir grafik ve hesap arayüzüdür. Chrome ve Edge’de kararlı; Safari’de Technology Preview; Firefox’ta ise genellikle bayrakla etkinleştirilmektedir. ONNX Runtime Web (kısaca ort), ONNX formatındaki modelleri tarayıcıda WASM, WebGL veya WebGPU üzerinde çalıştırır. Mimari şu şekilde işler: model dosyası (örn. mobilenetv3.onnx), tarayıcıya indirilir; preprocess aşamasıyla görüntü tensöre dönüştürülür; WebGPU yürütücüsü ile ileri besleme yapılır; sonuçlar postprocess ile insan tarafından anlaşılır etiketlere çevrilir.

Kurulum ve Dosya Yapısı

Basit bir yapı için bir HTML dosyası (index.html), bir JavaScript dosyası (app.js) ve model/etiket dosyalarınız (models/mobilenetv3.onnx, labels.txt) yeterlidir. Paket yöneticisi kullanacaksanız onnxruntime-web paketini ekleyebilir veya CDN üzerinden import edebilirsiniz. Yerel geliştirme için npm create vite@latest ile hafif bir iskelet kurup, npm i onnxruntime-web komutuyla kütüphaneyi dahil edebilirsiniz. Veya basit bir HTML sayfasında <script type="module"> ile ESM import yapabilirsiniz.

WebGPU’nun Etkinliği ve Geri Dönüş Planı

Önce tarayıcının WebGPU desteğini kontrol edin: if ('gpu' in navigator). ONNX Runtime Web oturumunu başlatırken yürütücüleri öncelik sırasına koyabilirsiniz: executionProviders: ['webgpu', 'webgl', 'wasm']. Böylece WebGPU yoksa WebGL, o da yoksa WASM’a otomatik düşülür. Bu yaklaşım, geniş bir cihaz/tarayıcı yelpazesini hedeflemenizi sağlar.

Modeli Yükleme ve Oturum Oluşturma

Bir InferenceSession başlatırken, graphOptimizationLevel ve preferredOutputLocation gibi seçeneklerle performansı iyileştirebilirsiniz. Örnek bir akış şu şekildedir: modeli fetch ile indirip await ort.InferenceSession.create çağırarak oturumu hazırlayın; etiket dosyasını (labels.txt) satır satır belleğe alın; giriş tensörünü uygun boyuta (ör. 224x224), kanal sırasına ve normalizasyona getirip Float32Array içine yerleştirin; ardından session.run(feeds) ile çıktı alın.

Ön İşleme: Doğru Tensör, Doğru Sonuç

Ön işleme aşaması, modelden iyi sonuç almak için kritiktir. Tipik olarak aşağıdaki adımları uygularsınız: resmi canvas üzerinde 224x224’e yeniden boyutlandırma; RGB kanallarını çıkarma; piksel değerlerini 0–1 aralığına ölçekleme; modelin beklediği ortalama ve standart sapma ile normalizasyon; kanal sırasını HWC’den CHW’ye çevirme. Son olarak tensörü new ort.Tensor('float32', data, [1, 3, 224, 224]) şeklinde oluşturursunuz.

Çıktının İşlenmesi ve Etiketleme

Modelden alınan ham skorları (logit) softmax ile olasılığa çevirmek, ardından en yüksek değere sahip sınıfı ve olasılığını bulmak temel adımdır. Etiket dosyanızla eşleyip kullanıcıya en olası ilk üç sonucu gösterebilirsiniz. Basit bir kullanıcı arayüzü için bir dosya yükleme alanı ve sonuç listesini güncelleyen kısa bir fonksiyon yeterlidir.

Performans İpuçları

1) WebGPU seçimi: Cihaz destekliyse WebGPU belirgin hız sağlar. 2) Kantizasyon: INT8 veya FP16 kantize modeller daha küçük ve hızlıdır; doğruluk/performans dengesini ölçün. 3) Toplu işleme: Birden fazla görseli ardışık yerine mini-batch olarak çalıştırmak throughput’u artırabilir. 4) WASM ayarları: Geri dönüş halinde ort.env.wasm.numThreads gibi ayarlarla CPU tarafını hızlandırın. 5) IO binding: Gelişmiş senaryolarda giriş/çıkışları GPU belleğinde bağlamak kopyalama maliyetini düşürür. 6) Önyükleme: İlk yüklemede modeli önbelleğe almak (Service Worker, HTTP caching) deneyimi iyileştirir.

Uyumluluk ve Sorun Giderme

Eğer “WebGPU desteklenmiyor” uyarısı alırsanız tarayıcınızı güncelleyin veya geçici olarak WebGL/WASM geri dönüş yolu kullanın. CORS hataları için model ve etiket dosyalarınızı aynı origin’den servis edin veya uygun başlıkları ayarlayın. Bozuk sonuçlar genelde ön işleme hatalarından kaynaklanır: kanal sırası (CHW vs HWC), normalizasyon değerleri ve giriş boyutunu iki kez kontrol edin. Performans düşükse geliştirici araçlarında GPU işlem kullanımını izleyin; entegre GPU’larda FP16/INT8 kazancı değişebilir.

Gizlilik ve Güvenlik

Yerel çıkarım, görsellerin cihazdan çıkmaması sayesinde gizliliği güçlendirir. Yine de kullanıcı izni olmadan dosya okuma, kalıcı depolama veya kamera erişimi gibi API’ler kullanılmamalıdır. Büyük modeller için indirme boyutunu küçültmek (sıkıştırma, kantizasyon) hem veri kullanımı hem de ilk yükleme süresini azaltır.

Sonuç

WebGPU ve ONNX Runtime Web ile tarayıcıda görsel sınıflandırma, artık bir prototipten öteye geçmiş durumda. Doğru model, sağlam ön işleme ve akıllı geri dönüş stratejileriyle, yüksek performanslı ve gizliliğe saygılı deneyimler oluşturabilirsiniz. Küçük bir demoyla başlayın; ardından etkileşimli görsel arama, canlı kamera üzerinde etiketleme veya tamamen çevrimdışı çalışan PWA gibi senaryolara genişleyin. Gelecek, kullanıcıların cihazında—ve siz bugün bunun temelini atabilirsiniz.