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

16 Ekim 2025 Perşembe

Rust ve WebAssembly ile Tarayıcıda Görüntü İşleme: Adım Adım Rehber

Giriş

WebAssembly (WASM), tarayıcıda neredeyse yerlisi kadar hızlı çalışan kodlar yazmayı mümkün kılıyor. Eğer piksel piksel görüntü işleme, gerçek zamanlı filtreler veya CPU yoğun işlemlerle uğraşıyorsanız, JavaScript tek başına her zaman yeterli olmayabilir. Bu rehberde, Rust + WebAssembly ikilisini kullanarak tarayıcıda basit bir görüntü işleme modülü oluşturmayı ve performansı artırmanın pratik yollarını adım adım anlatıyorum.

Neden Rust + WebAssembly?

Performans: Rust derlenmiş kodu WebAssembly’ye taşıdığınızda, piksel manipülasyonu gibi yoğun işlemlerde belirgin bir hız kazanırsınız. Özellikle büyük görsellerde JavaScript döngülerinin sınırlamalarını aştığınızı hissedeceksiniz.

Bellek güvenliği: Rust’ın sahiplik modeli ve derleyici kontrolleri, tipik bellek hatalarını en başında engeller. Tarayıcı gibi hassas bir ortamda bu oldukça kritiktir.

Taşınabilirlik: WASM çıktısı, modern tüm tarayıcılarda çalışır. Rust tarafında yazdığınız çekirdek algoritmaları, Node.js veya Wasmtime gibi ortamlarda da kullanabilirsiniz.

Gereken Araçlar ve Kurulum

Rust kurulumu için resmi yönlendiriciyi tercih edin: rustup. Ardından WASM hedefini ekleyin: rustup target add wasm32-unknown-unknown. Paketleme ve bağlayıcılar için wasm-pack aracını kurun: cargo install wasm-pack. Tarayıcı tarafında modülü kullanmak için npm veya yarn da işinizi kolaylaştırır.

Yeni bir kütüphane projesi oluşturun: cargo new goruntu-wasm --lib. Proje klasörüne geçin ve Cargo.toml dosyasına wasm-bindgen bağımlılığını ekleyin.

Proje İskeleti ve Yapılandırma

Cargo.toml içine aşağıdakine benzer satırlar ekleyin: [dependencies] wasm-bindgen = "0.2". Derleme hedefi için [lib] bölümüne crate-type = ["cdylib", "rlib"] yazmayı unutmayın. Bu, Rust kütüphanesinin WASM olarak bağlanabilmesini sağlar.

Kaynak dosyası src/lib.rs içinde, JavaScript ile köprü kurmak için wasm_bindgen makrolarını kullanacağız. Temel bir dışa aktarma şöyle görünür: use wasm_bindgen::prelude::*; #[wasm_bindgen] pub fn versiyon() -> String { "0.1.0".into() }. Bu, tarayıcıda modül yüklendiğinde çağrılabilir bir fonksiyon üretir.

Tarayıcı Entegrasyonu

Derlemek için wasm-pack build --target web komutunu çalıştırın. Bu, pkg klasöründe ES modül uyumlu bir çıktı üretir. Ön yüzde bir modül dosyasında şu şekilde içe aktarabilirsiniz: import init, { versiyon } from "./pkg/goruntu_wasm.js"; await init(); console.log(versiyon());. Basit bir HTML sayfasında <script type="module"> kullanarak bu modülü kolayca yükleyebilirsiniz.

Paket yöneticisi ile entegre çalışmak isterseniz wasm-pack çıktısını bir NPM paketi gibi tüketebilirsiniz. Bu sayede Vite, Webpack veya Parcel ile ağaç sarsma ve önbellekleme gibi optimizasyonlardan faydalanırsınız.

Basit Bir Gri Tonlama (Grayscale) Örneği

Tarayıcıdan aldığınız ImageData nesnesi, RGBA kanal sıralı bir Uint8ClampedArray içerir. Bu diziyi WASM tarafına aktarıp geri almak için iki pratik yol var: kopyalamak veya paylaşılan bir tampon üzerinden erişmek. Başlangıç için, güvenli ve net olduğu için kopyalama yaklaşımı işinizi görecektir.

Rust tarafında bir fonksiyon düşünün: #[wasm_bindgen] pub fn grayscale(input: Vec<u8>) -> Vec<u8> { ... }. Algoritma basit: Her piksel için r, g, b değerlerinin ağırlıklı ortalamasını alın ve geri yazın. Yaygın bir yaklaşım: gray = 0.299*r + 0.587*g + 0.114*b. Rust’ta tamsayı işlemlerinde küçük bir yuvarlama eklemek renk doğruluğunu iyileştirir.

Ön yüzde, CanvasRenderingContext2D ile bir görüntüyü çizip getImageData ile pikselleri alın. Daha sonra const out = grayscale(new Uint8Array(imageData.data)); gibi bir çağrıyla sonuç dizisini alın ve putImageData ile tekrar tuvale yazın. Bu döngüde veriyi fazla kopyalamamak için işlemi toplu yapın; birden fazla filtre uygulayacaksanız tek bir WASM çağrısında zincirlemek daha etkilidir.

Performans İpuçları

SIMD desteği: Modern tarayıcılar WASM SIMD’i destekliyor. Rust’ta std::arch veya uygun crate’lerle vektörleştirme yaparak yaklaşık 2-4 kat hız artışı görebilirsiniz. Varsa RUSTFLAGS="-C target-feature=+simd128" deneyin.

Veri kopyalarını azaltın: Çok büyük görüntülerde her karede kopyalama pahalıdır. Orta vadede wasm-bindgen ile Uint8Array tamponunu paylaşmak veya WebAssembly.Memory üzerinden doğrudan yazmak daha iyi sonuç verir.

Web Workers: Ana iş parçacığını kilitlememek için görüntü işlemeyi bir Worker içine taşıyın. OffscreenCanvas kullanabiliyorsanız, çizim ve filtrelemeyi tamamen worker içine izole ederek UI akıcılığını korursunuz.

Ön ısıtma: Modülü sayfa yüklenir yüklenmez başlatıp küçük bir “ısındırma” çağrısı yapmak, JIT/optimizasyon basamaklarını kullanıcı etkileşimi öncesinde tamamlamaya yardımcı olur.

Hata Ayıklama ve Ölçüm

WASM kodunu debug modunda derlediğinizde boyut artar ve performans düşer; bu normaldir. Geliştirmede console.time/console.timeEnd ile uçtan uca süreleri ölçün, Performance.now() ile kare bazlı gecikmeyi takip edin. Rust tarafında log ve console_error_panic_hook kullanarak panik ve logları tarayıcı konsoluna yönlendirebilirsiniz.

Boyut optimizasyonu için üretim derlemesinde wasm-opt -O3 (Binaryen) deneyin. Ayrıca wasm-pack build --release kullanarak sembol isimlerini küçültür ve gereksiz debug bilgilerini atarsınız.

Sonuç

Rust ve WebAssembly, tarayıcıda görüntü işleme gibi CPU ağırlıklı görevlerde güvenli, hızlı ve öngörülebilir bir çalışma zemini sunuyor. Basit bir gri tonlama filtresiyle başladık; aynı yaklaşımı kenar algılama, bulanıklaştırma, renk düzeltme veya gerçek zamanlı kamera filtrelerine kolayca genişletebilirsiniz. Doğru veri aktarım stratejisi, SIMD ve Web Workers ile birleştiğinde, modern web uygulamalarında yerel uygulama hissi veren bir performans elde etmek mümkün. Bir kez kurduktan sonra, bu altyapıyı pek çok projede tekrar tekrar kullanabileceğinizi göreceksiniz.

7 Ekim 2025 Salı

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

Giriş

Tarayıcıda yapay zeka çalıştırmak, artık sadece demo projelerin konusu değil. WebAssembly (WASM) ve WebGPU sayesinde, masaüstü benzeri performansla gerçek zamanlı çıkarım almak mümkün. Bu rehberde, ONNX Runtime Web kullanarak bir modeli tarayıcıda çalıştırmayı, WebGPU ve WASM arasında nasıl seçim yapacağınızı ve performansla ilgili pratik ipuçlarını adım adım anlatıyorum.

Neden Tarayıcıda Yapay Zeka?

Tarayıcı üzerinde çıkarımın üç büyük avantajı var: gizlilik (veri cihazdan çıkmıyor), kurulum kolaylığı (ekstra bağımlılık yok) ve dağıtım hızı (sadece bir web sayfası). Örneğin bir görüntü sınıflandırma modeli, web uygulamanızda kullanıcı fotoğrafını anında analiz edebilir ve bu sırada veriyi sunucuya göndermenize gerek kalmaz. Üstelik WebGPU desteği olan tarayıcılarda GPU hızlandırma ile mobil cihazlarda bile akıcı performans elde edebilirsiniz.

Gereksinimler

- Güncel bir tarayıcı (Chrome 113+, Edge 113+, Safari 17+). WebGPU desteği yoksa WASM sağlayıcısı otomatik devreye girer.
- Basit bir HTTP sunucu (ör. npx serve veya python -m http.server). Güvenlik nedeniyle dosyaları doğrudan dosya sistemi üzerinden açmak yerine bir sunucu gerekli.
- Bir ONNX modeli (ör. MobilNet v2 sınıflandırma modeli). Dilerseniz kendi modelinizi torch.onnx.export ile dışa aktarabilirsiniz.

Proje Kurulumu

1) Klasör oluşturun: mkdir ort-web-demo && cd ort-web-demo
2) Model dosyasını model.onnx olarak kök dizine koyun.
3) Aşağıdaki basit HTML dosyasını index.html olarak kaydedin (CDN üzerinden ONNX Runtime Web yüklenecek):

<!doctype html>
<html lang="tr">
<head>
  <meta charset="utf-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1"/>
  <title>ONNX Runtime Web Demo</title>
</head>
<body>
  <h3>Tarayıcıda Yapay Zeka (WebGPU / WASM)</h3>
  <input type="file" id="file" accept="image/*"/>
  <div id="log">Hazır...</div>
  <script src="https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.min.js"></script>
  <script>
  (async () => {
    // WebGPU uygunsa önce onu, değilse WASM'ı dene
    const providers = (navigator.gpu) ? ['webgpu', 'wasm'] : ['wasm'];
    ort.env.wasm.simd = true; // SIMD hızlandırma
    ort.env.wasm.numThreads = Math.min(4, navigator.hardwareConcurrency || 2);

    const session = await ort.InferenceSession.create('model.onnx', { executionProviders: providers });
    document.getElementById('log').innerText = 'Model yüklendi. Sağlayıcı: ' + session.executionProvider;

    const fileInput = document.getElementById('file');
    fileInput.onchange = async () => {
      const file = fileInput.files[0];
      if (!file) return;
      const img = new Image();
      img.src = URL.createObjectURL(file);
      await img.decode();

      // Basit ön işleme: 224x224'e ölçekle, [0,1] normalizasyonu
      const canvas = document.createElement('canvas');
      canvas.width = 224; canvas.height = 224;
      const ctx = canvas.getContext('2d');
      ctx.drawImage(img, 0, 0, 224, 224);
      const { data } = ctx.getImageData(0, 0, 224, 224);
      const input = new Float32Array(1 * 3 * 224 * 224);
      for (let i = 0; i < 224 * 224; i++) {
        const r = data[i * 4] / 255;
        const g = data[i * 4 + 1] / 255;
        const b = data[i * 4 + 2] / 255;
        input[i] = r; input[i + 224 * 224] = g; input[i + 2 * 224 * 224] = b;
      }

      const tensor = new ort.Tensor('float32', input, [1, 3, 224, 224]);
      const feeds = {}; feeds[session.inputNames[0]] = tensor;
      const t0 = performance.now();
      const results = await session.run(feeds);
      const t1 = performance.now();
      const output = results[session.outputNames[0]].data;
      const maxIndex = output.indexOf(Math.max(...output));
      document.getElementById('log').innerText = `Sınıf: ${maxIndex}, Süre: ${(t1 - t0).toFixed(1)}ms`;
    };
  })();
  </script>
</body>
</html>

Uygulamayı Çalıştırma

Kök dizinde küçük bir sunucu başlatın. Node.js varsa: npx serve . veya Python ile: python -m http.server 8080. Ardından tarayıcıdan http://localhost:8080 adresine gidin. Bir görsel seçtiğinizde model çıkarımı yapacak ve süreyi ms cinsinden gösterecektir. WebGPU mevcutsa sağlayıcı olarak webgpu, değilse wasm kullanılır.

Performans İpuçları

- SIMD ve çok iş parçacığı: Kodda ort.env.wasm.simd = true ve numThreads ayarları etkin. Tarayıcı buna izin veriyorsa WASM performansı ciddi artar.
- WebGPU avantajı: Büyük modellerde GPU hızlandırma dramatik fark yaratır. Ancak WebGPU, HTTPS ve güvenli bağlam gerektirir. Üretimde daima HTTPS kullanın.
- Model optimizasyonu: ONNX modeli fuse ve constant folding ile optimize edin. INT8 quantization (ör. onnxruntime-tools veya optimum) tarayıcıda boyutu küçültür ve hız kazandırır.
- Lazy yükleme: Modeli sayfa yüklendiğinde değil, kullanıcı etkileşimi başladığında indirin. İlk TTI süresini iyileştirir.
- Önbellek: Model dosyasını IndexedDB veya Cache Storage ile saklayın. İlk açılıştan sonra bekleme neredeyse sıfırlanır.

Hata Ayıklama ve Uyumluluk

- Giriş/çıkış adları: Bazı modellerde giriş ismi input değil, farklı olabilir. session.inputNames ve session.outputNames ile dinamik alın.
- Bellek limitleri: Büyük modeller mobilde bellek sınırına takılabilir. Daha küçük veya quantized sürüme geçin.
- CORS: Modeli farklı bir domain’den çağırıyorsanız CORS başlıklarını doğru ayarlayın (Access-Control-Allow-Origin).
- Tarayıcı farkları: Safari’de GPU bellek kotaları daha katı olabilir; WASM yedek planınızın iyi çalıştığından emin olun.

Güvenlik ve Gizlilik

Tarayıcıda çıkarımın en güçlü yanı, verinin cihazda kalmasıdır. Yine de kullanıcı içeriğini asla arka plana otomatik yüklemeyin ve gerekli olmadıkça loglamayın. Model dosyalarınızı bütünlüğü doğrulanmış bir CDN’den servis edin ve içerik güvenlik politikanızda (Content-Security-Policy) sadece ihtiyaç duyulan kaynaklara izin verin.

Sonuç

ONNX Runtime Web ile WebGPU/WASM arasında otomatik geçiş yaparak, modern tarayıcılarda güçlü bir yapay zeka deneyimi sunmak mümkün. Yukarıdaki basit örnek; görüntü sınıflandırma, metin analizi veya poz tahmini gibi pek çok senaryonun temelini oluşturur. Üretime geçerken model optimizasyonu, önbellekleme ve güvenlik adımlarını uyguladığınızda, native’e yakın bir hız ve akıcılık elde edebilirsiniz.

22 Ağustos 2025 Cuma

Rust ile WebAssembly (WASM) Kullanarak Yüksek Performanslı Web Uygulamaları Geliştirme

Giriş

Web uygulamalarında CPU yoğunluklu işlemleri tarayıcıya taşımak gerektiğinde WebAssembly (WASM) önemli bir seçenek sunar. Rust ise bellek güvenliği, performans ve derleyici garantileriyle WASM için sık tercih edilen dillerden biridir. Bu yazıda, Rust ile WASM geliştirirken dikkat edilmesi gereken temel adımları, optimizasyonları ve üretime hazırlık süreçlerini sade ve uygulamalı şekilde ele alacağım.

Hazırlık ve araçlar Öncelikle sisteminizde Rust kurulu olmalı. rustup üzerinden güncel toolchain'i kurduktan sonra hedef olarak wasm32-unknown-unknown eklenir: rustup target add wasm32-unknown-unknown. Ardından proje paketlemeyi kolaylaştıran wasm-pack veya doğrudan wasm-bindgen tercih edilebilir. İyi bir optimizasyon için Binaryen'in wasm-opt aracını da kurmanızı öneririm.

Basit bir başlangıç örneği

Yeni bir kütüphane projesi oluşturup JavaScript ile çağırılabilir fonksiyonler yazalım. Cargo projesi oluşturduktan sonra Cargo.toml'a wasm-bindgen ekleyin ve Rust kodunda şu örneği kullanın:

use wasm_bindgen::prelude::*; #[wasm_bindgen] pub fn heavy_compute(n: u32) -> u64 { (0..n as u64).map(|x| x * x).sum() }

Derleme aşaması için iki yaygın yol var: wasm-pack build --target web --release ile paketleyip doğrudan bir modül olarak kullanmak veya cargo build --target wasm32-unknown-unknown --release sonrası wasm-bindgen CLI ile çıktıyı hazırlamak. wasm-pack yeni başlayanlar için entegrasyon kolaylığı sağlar.

Performans ipuçları

WASM ve Rust kombinasyonunda performansı etkileyen başlıca noktalar şunlardır: bellek tahsisi, JavaScript ile sınır-maliyetli geçişler, veri kopyalama ve algoritma seçimi. Fonksiyonlar arasında sık sık büyük veri yapıları geçiriyorsanız, işinizi Rust içinde bitirip tek bir sonuç döndürmeye çalışın. JS-Rust dönüşümlerinde serializasyon maliyetini azaltmak için serde-wasm-bindgen kullanabilirsiniz.

Ayrıca, release derlemelerinde --release kullanmak ve mümkünse wasm-opt -Oz ile sıkıştırma yapmak önemlidir. Örnek: wasm-opt pkg/your_crate_bg.wasm -Oz -o pkg/your_crate_bg.wasm. Bunun yanında wasm-strip ile gereksiz sembolleri kaldırabilirsiniz.

Tarayıcı özellikleri: SIMD ve threads

WASM SIMD ve threads (Web Workers + SharedArrayBuffer) performansı ciddi oranda artırabilir, ancak tarayıcı desteği ve güvenlik başlıkları gerektirir. Threads kullanmak için sunucunuzda COOP/COEP başlıklarını ayarlayarak cross-origin isolation sağlamalısınız. SIMD ise belirli tarayıcı sürümlerinde etkin olur; derleme sırasında RUSTFLAGS="-C target-feature=+simd128" gibi bayraklar kullanılabilir ve hedef desteğine dikkat edilmelidir.

Hata ayıklama ve geliştirici deneyimi

WASM çıktıları doğrudan okunması zor olabilir. Rust tarafında panik mesajlarını tarayıcı konsoluna almak için console_error_panic_hook kullanın: console_error_panic_hook::set_once(). Kaynak haritaları (source maps) ile Rust kaynaklarına dönebilmek için ilgili araçları etkinleştirin. Ayrıca wasm-bindgen çıktılarındaki JS wrapper'ları incelenebilir; onlar JS tarafında yapılması gereken hafif köprüleri gösterir.

Dağıtım ve boyut azaltma

Üretim ortamında paket boyutu ve yükleme süresi önemlidir. Aşağıdaki adımlar genelde iyi sonuç verir: release derleme, wasm-opt -Oz, gzip ya da brotli sıkıştırma, ve JS paketleyicide tree-shaking. Eğer proje büyükse, kritik olmayan kodu WebAssembly yerine JS veya dinamik modüller olarak ayırmak da yararlı olabilir.

Frameworkler ve örnekler

Tek başına WASM kullanmak kadar Yew veya Seed gibi Rust tabanlı çerçevelerle SPA geliştirmek de mümkün. Bu çerçeveler geliştirme deneyimini hızlandırır ancak çıktı büyüklüğünü etkileyebilir; dolayısıyla ön testler yapın ve yalnızca ihtiyaç duyulan parçaları kullanın.

Sonuç Rust + WebAssembly modern web uygulamalarında performansı artırmak için güçlü bir kombinasyon sunar. Ancak başarı için derleme ve optimizasyonda dikkatli olmak, JS-etkileşim maliyetlerini minimize etmek ve tarayıcı özellikleri ile kısıtlamalarını bilmek gerekir. Küçük bir modül ile başlayın, profilleyin ve adım adım üretim güvenliğine geçin.