Machine Learning

LiteRT.js: ML di Browser Tanpa Server Mahal

M
MUGHU
35 menit baca
LiteRT.js: ML di Browser Tanpa Server Mahal
Daftar isi

Kalau Teman-Teman lagi cari cara menjalankan model machine learning di browser tanpa server mahal, latency tinggi, dan data yang bolak-balik ke cloud, LiteRT.js layak jadi opsi utama. Runtime WebAI dari Google ini bikin inference model .tflite jalan lokal di browser, dengan akselerasi WebGPU, WebAssembly (XNNPack), dan WebNN untuk NPU. Ringkasnya: privasi lebih aman, biaya server turun, dan performa mendekati native—asal model dan pipeline-nya disiapkan dengan benar.

LiteRT.js adalah JavaScript binding dari LiteRT (sebelumnya TensorFlow Lite) yang menargetkan aplikasi web production. Ia menjalankan model LiteRT (.tflite) langsung di browser untuk tugas seperti image segmentation, klasifikasi teks, pose estimation, object detection, dan sejenisnya.

MUGHU pertama kali nyobain LiteRT.js pas lagi bantu tim product di Jakarta yang pengin deteksi dokumen KTP di browser, tanpa upload foto mentah ke server. Saat itu pipeline TensorFlow.js terasa “cukup”, tapi di laptop menengah dan HP Android entry-level lag-nya kerasa. Setelah pindah inference ke LiteRT.js (sambil pre/post-processing tetap di TF.js), latency turun signifikan dan UX-nya jauh lebih enak. Tulisan ini merangkum apa yang MUGHU pelajari: dari masalah yang sering muncul, cara setup, konversi model, integrasi, perbandingan opsi, studi kasus, sampai error yang sering bikin pusing.

Kenapa AI di browser sering terasa berat (dan kenapa itu penting)

Banyak tim product di Indonesia—baik startup di BSD, fintech di Jakarta Selatan, maupun software house di Bandung—ingin pengin “AI di web” tapi stuck di tiga rasa sakit yang sama.

Problem yang sering muncul di production web AI

  • Latency bolak-balik ke server: setiap frame webcam atau upload gambar harus nunggu jaringan. Di koneksi 4G yang fluktuatif, UX langsung rusak.
  • Biaya GPU server: traffic naik = bill naik. Demo bagus di staging, mahal di production.
  • Privasi & compliance: data KTP, wajah, rekaman suara, atau dokumen legal nggak selalu boleh keluar device.
  • Pipeline konversi yang rapuh: jalur PyTorch → ONNX → TensorFlow → TensorFlow.js sering pecah di tengah jalan.
  • Performa WebGL yang “melempem” untuk model vision real-time, terutama di resolusi lebih tinggi.

Kenapa ini penting buat bisnis, bukan cuma “keren secara teknis”

Kalau inference bisa jalan di device user:

  • ROI lebih jelas: potong cost inference server untuk traffic tinggi.
  • Efisiensi operasional: model yang sama (.tflite) bisa dipakai web + mobile edge.
  • Kepercayaan user: data sensitif diproses lokal dulu (redaksi PII, blur, dsb.) sebelum upload.
  • Produk offline-first: cocok untuk field app, inspeksi, retail, atau area dengan sinyal jelek.

Solusi yang MUGHU rekomendasikan di sini bukan “buang semua stack lama”, tapi ganti engine inference dengan LiteRT.js, sambil pre/post-processing yang sudah nyaman di TensorFlow.js tetap dipakai kalau perlu.

Apa itu LiteRT.js, dan bedanya dengan “sekadar library ML di web”

LiteRT adalah kerangka kerja on-device AI Google yang berkembang dari fondasi TensorFlow Lite. Fokusnya: runtime cepat, multi-platform, dan support framework training yang luas (PyTorch, JAX, TensorFlow). Di sisi web, LiteRT.js membawa runtime native yang dioptimasi itu ke browser lewat Wasm + backend hardware modern.

Fitur inti yang bikin LiteRT.js relevan

  1. Inference terakselerasi di browser

    • CPU: XNNPack lewat WebAssembly
    • GPU: WebGPU (ML Drift di ekosistem LiteRT)
    • NPU / hardware khusus: WebNN (masih experimental di banyak browser)
  2. Kompatibilitas multi-framework

    • Model dari PyTorch, JAX, atau TensorFlow bisa diarahkan ke format .tflite yang sama.
  3. Integrasi dengan pipeline TensorFlow.js

    • Tensor TF.js bisa dipakai sebagai boundary input/output lewat paket interop, jadi nggak harus rewrite seluruh pre/post-processing.

Kalau dianalogikan: TensorFlow.js itu “toolbox lengkap di JavaScript”, sementara LiteRT.js lebih ke “mesin inference production” yang sama stack-nya dengan edge Android/iOS, tapi dibuka ke web.

Dokumentasi resmi Google untuk web ada di LiteRT for Web. Paket utamanya di npm: @litertjs/core.

Getting Started: prasyarat sebelum coding

Sebelum npm install, pastikan fondasinya beres. Ini langkah yang sering disepelekan, padahal 70% error “aneh” datang dari sini.

Prasyarat teknis

  • Node.js LTS (disarankan 18+ atau 20+)
  • Familiar dasar JavaScript/TypeScript dan module ESM
  • Browser modern:
    • WebGPU: Chrome/Edge 113+, Safari 17.4+, Firefox 121+ (partial)
    • WebNN: experimental di Chromium, butuh flag
  • Model dalam format .tflite (atau siap dikonversi)
  • Server static yang bisa serve file Wasm (jangan di-block CORS / MIME salah)

Prasyarat “product sense” (sering dilupakan)

  • Tahu input shape model (NCHW vs NHWC)
  • Tahu dtype yang didukung I/O: float32 dan int32
  • Punya rencana cleanup memory (tensor di LiteRT.js perlu di-delete() manual)
  • Punya target device nyata untuk benchmark (bukan cuma MacBook M-series)

Istilah penting biar ngobrolnya nyambung

Istilah Arti sederhana Kenapa penting
Inference Menjalankan model untuk prediksi Ini “hot path” yang user rasakan
.tflite Format model LiteRT/TFLite Satu file, portabel lintas platform
WebGPU API GPU modern di browser Throughput tinggi untuk vision/audio
Wasm + XNNPack CPU cepat di browser Fallback andal kalau GPU/NPU nggak available
WebNN API ke NPU / ML OS-level Latency & power efficiency (masih experimental)
Accelerator Backend eksekusi (webgpu / wasm / webnn) Salah pilih = lambat atau error op
Pre/post-processing Normalisasi gambar, top-k, dsb. Sering lebih ribet dari model.run itu sendiri

Review jujur: kelebihan, kekurangan, dan buat siapa

MUGHU suka framework yang jujur soal trade-off. Jadi sebelum tutorial panjang, ini potret seimbangnya.

Overview singkat

LiteRT.js cocok kalau Teman-Teman ingin:

  • deploy model .tflite yang sama ke web
  • performa lebih serius dari kernel JS murni
  • jalur konversi PyTorch yang lebih lurus
  • opsi GPU/NPU ke depan tanpa ganti format model

Key features yang kerasa di kerjaan harian

  • loadLiteRt() untuk inisialisasi runtime Wasm
  • loadAndCompile() untuk load model + pilih accelerator
  • Tensor + model.run() untuk inference
  • Interop TF.js via @litertjs/tfjs-interop (runWithTfjsTensors)
  • Model tester (@litertjs/model-tester) untuk cek op support & benchmark kasar

Use case dunia nyata

  • KYC / OCR dokumen di browser (fintech & legal)
  • Virtual background / segmentation di video call
  • Offline vision untuk inspeksi lapangan
  • Image upscaling, depth estimation, object detection (YOLO lewat jalur LiteRT)
  • Vector search ringan di client (contoh ekosistem EmbeddingGemma di materi Google)

Kelebihan

  • Performa hardware-aware (WebGPU + XNNPack)
  • Format model unified dengan edge native
  • Interop bagus dengan pipeline TF.js existing
  • Multi-framework conversion path, termasuk PyTorch langsung ke LiteRT
  • Fallback op ke CPU kalau GPU/WebNN belum cover

Kekurangan / batasan (ini penting buat trust)

  • Ukuran model terbatas di lingkungan Wasm; model kebesaran bisa Aborted() / gagal alokasi memori
  • I/O tensor utamanya float32/int32
  • WebNN masih experimental (flag browser, OS dependency)
  • Memory management manual—lupa delete() = bocor pelan-pelan di SPA long-running
  • Kadang perlu transpose / reorder / rename input setelah konversi
  • Coverage operator di GPU/WebNN belum se-lebar CPU

Cocok untuk

  • Tim yang sudah (atau mau) pakai .tflite lintas platform
  • Product privacy-sensitive
  • Real-time vision/audio di web yang butuh GPU path
  • Tim yang capek jalur konversi ONNX berlapis

Sebaiknya dihindari dulu kalau

  • Model GenAI sangat besar dan belum di-quantize / belum dipecah arsitekturnya
  • Tim butuh “zero config” tanpa urus Wasm hosting
  • Browser target masih didominasi environment tanpa WebGPU dan device CPU-nya lemah
  • Belum ada kapasitas debug shape/layout tensor

Verdict MUGHU: untuk production WebAI berbasis model edge klasik sampai mid-size, LiteRT.js terasa seperti upgrade strategis dari “demo TF.js” ke “runtime yang bisa diandalkan”. Bukan sihir—tetap perlu disiplin model packaging—tapi arahnya jelas dan stack-nya kredibel.

LiteRT.js vs opsi lain: perbandingan biar nggak salah pilih

Teman-Teman biasanya bandingkan tiga kutub: TensorFlow.js, ONNX Runtime Web, dan LiteRT.js. Ini ringkasan praktis (bukan marketing slide).

Kriteria LiteRT.js TensorFlow.js ONNX Runtime Web
Format model utama .tflite (LiteRT) Layers / Graph model TFJS .onnx
Jalur dari PyTorch Lebih langsung ke LiteRT Sering multi-hop (ONNX/TF) ONNX export
Akselerasi web WebGPU, Wasm/XNNPack, WebNN WebGL/WebGPU/CPU (bergantung backend) WebGPU/Wasm (bergantung build)
Integrasi TF.js existing Kuat (tfjs-interop) Native Perlu jembatan sendiri
Unifikasi dengan Android/iOS edge Sangat kuat (satu keluarga LiteRT) Terbatas Bergantung stack mobile terpisah
Maturity tooling web Baru tapi production-oriented Sangat matang di ekosistem JS Matang di banyak industri
Operasional model lintas platform Unggul untuk tim multi-client Bagus untuk full-JS team Bagus jika ONNX sudah standar perusahaan
Learning curve Sedang (Wasm, accelerator, tensor lifecycle) Rendah–sedang Sedang

Best-for scenarios

  • Pilih LiteRT.js kalau: mau satu format .tflite untuk web + mobile edge, butuh WebGPU serius, dan model berasal dari PyTorch/TF/JAX.
  • Pilih TensorFlow.js kalau: seluruh pipeline (termasuk training experiments ringan di JS) ingin tetap di dunia TFJS, dan model graph-nya sudah stabil di TFJS.
  • Pilih ONNX Runtime Web kalau: standar perusahaan sudah ONNX end-to-end (training/serving multi-language).

Rekomendasi per use case

Use case Rekomendasi MUGHU Alasan singkat
KYC document AI di browser LiteRT.js Privasi + model edge reusable
Prototype cepat klasifikasi gambar TF.js atau LiteRT.js TF.js cepat start; LiteRT.js kalau target production edge
Real-time segmentation 30fps LiteRT.js (WebGPU) Hot path inference lebih “native”
Perusahaan locked ke ONNX ONNX Runtime Web Kurangi friksi standar internal
Satu model untuk Android + Web LiteRT.js Format & runtime sekeluarga

Studi kasus: dari lag di demo client jadi pipeline yang bisa di-demo ulang

Background

Sebuah tim product (hybrid web + field ops) ingin fitur klasifikasi kondisi objek dari kamera browser. Target user-nya campur: kantor di kota besar dan petugas lapangan di area suburban. Mereka sudah punya model PyTorch yang “bagus di notebook”, plus UI web React.

Challenge / Problem

  1. Round-trip ke server bikin prediksi terasa lambat saat sinyal turun.
  2. Jalur konversi ke TF.js memakan waktu debug berhari-hari.
  3. Di beberapa device, WebGL path tidak stabil untuk target latency.
  4. Legal minta opsi “proses lokal dulu” untuk sebagian data visual.

Approach

  • Kunci model ke format .tflite sebagai single source artifact.
  • Pakai LiteRT.js untuk inference.
  • Pertahankan pre/post-processing di TensorFlow.js (resize, normalisasi, top-k).
  • Target utama accelerator: webgpu, fallback wasm.
  • Tambahkan model tester + fake input test sebelum wiring UI.

Implementation (ringkas)

  1. Convert ResNet-style classifier ke .tflite via alur LiteRT Torch.
  2. Host wasm/ dan model di CDN internal.
  3. Init loadLiteRtloadAndCompile(..., {accelerator: 'webgpu'}).
  4. Samakan WebGPU device antara TF.js dan LiteRT.js.
  5. runWithTfjsTensors di hot path kamera (throttle frame).
  6. Instrumentasi: p50/p95 latency, memory, error op fallback.

Results (metrik yang masuk akal di lapangan)

Angka pasti bergantung device, tapi pola yang MUGHU lihat berulang:

  • Latency inference di device kelas menengah: turun ke kisaran yang “terasa instan” untuk single-frame classification (sering belasan–puluhan ms di GPU path, vs terasa lebih berat di path lama).
  • Server GPU cost untuk fitur itu turun drastis karena hanya menerima hasil/metadata, bukan full inference tiap frame.
  • Drop-off demo berkurang: sales engineer bisa demo offline di coffee shop tanpa takut Wi-Fi hotel.
  • Trade-off: waktu engineering pindah ke model packaging + shape debugging (bukan ke scaling GPU server).

Key learnings

  • Salah layout (NCHW vs NHWC) bikin model “jalan” tapi akurasi kacau—ini lebih berbahaya daripada hard crash.
  • WebGPU menang di throughput, tapi ops tidak support harus siap fallback.
  • Cleanup tensor bukan kosmetik; di tab yang nyala seharian, itu nyawa.
  • Quantization bantu size, tapi I/O tetap perlu disiplin float32/int32 sesuai constraint runtime.

Step 1: Siapkan project dan instal paket LiteRT.js

Kenapa ini penting: tanpa fondasi paket + static assets Wasm yang benar, semua kode inference di atasnya akan gagal dengan error yang kelihatan “acak”.

Inisialisasi project

BASH
mkdir litertjs-demo
cd litertjs-demo
npm init -y
npm install @litertjs/core

Kalau mau interop TF.js:

BASH
npm install @litertjs/tfjs-interop @tensorflow/tfjs @tensorflow/tfjs-backend-webgpu

Untuk ngetes model cepat:

BASH
npm install -D @litertjs/model-tester

Serve folder Wasm

File Wasm ada di:

node_modules/@litertjs/core/wasm/

Opsi praktis:

  • copy folder wasm/ ke public/wasm/ (Vite/Next static)
  • atau load dari CDN jsDelivr saat dev

Kenapa ini krusial: browser harus bisa fetch .wasm dan helper JS-nya. Salah path = runtime tidak pernah siap.

Expected output: package.json berisi dependency @litertjs/core, dan folder Wasm bisa diakses lewat URL HTTP (bukan cuma path disk).

Step 2: Load runtime LiteRT.js (Wasm) dengan benar

Kenapa ini penting: loadLiteRt memilih build runtime yang sesuai (termasuk varian JSPI untuk WebNN). Ini “mesin”-nya; model belum masuk sama sekali.

JS
import { loadLiteRt } from '@litertjs/core';

// Dev cepat via CDN
await loadLiteRt('https://cdn.jsdelivr.net/npm/@litertjs/core/wasm/');

// Production: host sendiri (lebih predictable)
await loadLiteRt('/wasm/');

Untuk WebNN (experimental):

JS
await loadLiteRt('/wasm/', { jspi: true });

Checklist Step 2

  • Network tab menampilkan fetch Wasm sukses (bukan 404)
  • Tidak ada MIME type aneh dari server
  • Dipanggil sekali saat bootstrap app (bukan tiap inference)

Expected output: promise loadLiteRt resolve tanpa throw; siap lanjut compile model.

Step 3: Konversi model PyTorch ke .tflite (jalur yang lebih waras)

Kenapa ini penting: keunggulan strategis LiteRT.js di banyak tim adalah keluar dari labirin konversi multi-hop. PyTorch → LiteRT jauh lebih masuk akal untuk maintenance.

Contoh alur konversi (Python):

PYTHON
import torch
import torchvision
import litert_torch  # sesuai paket/docs yang kamu pakai di environment konversi

# contoh model
resnet18 = torchvision.models.resnet18(
    weights=torchvision.models. ResNet18_Weights. IMAGENET1K_V1
)
resnet18.eval()

sample_inputs = (torch.randn(1, 3, 224, 224),)

edge_model = litert_torch.convert(resnet18, sample_inputs)
edge_model.export("resnet18_web.tflite")

Catatan pengalaman MUGHU:

  • Model harus exportable (searah dengan persyaratan torch.export / TorchDynamo-friendly).
  • Hindari cabang Python yang bergantung nilai runtime tensor.
  • Dynamic shape (termasuk batch dinamis) sering jadi sumber sakit kepala—mulai dari shape fixed dulu.
  • Kalau model sudah “ONNX-exportable” atau “TensorRT-friendly”, biasanya lebih dekat ke jalur sukses, tapi tetap cek op & layout.

Expected output: file resnet18_web.tflite yang bisa di-load di web dan di tool inspeksi model.

Step 4: Load & compile model di browser

Kenapa ini penting: compile step menentukan backend, fallback behavior, dan kesiapan graph untuk jalan di device user.

JS
import { loadLiteRt, loadAndCompile, Tensor } from '@litertjs/core';

await loadLiteRt('/wasm/');

const model = await loadAndCompile('/models/resnet18_web.tflite', {
  accelerator: 'webgpu', // 'webgpu' | 'wasm' | 'webnn'
});

Pilih accelerator dengan kepala dingin

  • webgpu: default modern untuk speed di device ber-GPU
  • wasm: paling “aman” untuk coverage op & fallback
  • webnn: untuk NPU/OS acceleration—siap-siap experimental flags

Load dari memory juga bisa (kalau Teman-Teman fetch sendiri):

JS
const buffer = new Uint8Array(await (await fetch('/models/resnet18_web.tflite')).arrayBuffer());
const model = await loadAndCompile(buffer, { accelerator: 'webgpu' });

Expected output: objek model siap run, dan getInputDetails() / getOutputDetails() bisa dipanggil.

Step 5: Siapkan input tensor (di sinilah banyak orang salah)

Kenapa ini penting: model bisa “berjalan” tapi hasilnya sampah kalau layout/dtype/shape salah. Ini error bisu yang paling mahal.

JS
// contoh NCHW: [batch, channel, height, width]
const image = new Float32Array(1 * 3 * 224 * 224);
// TODO: isi pixel yang sudah dinormalisasi

const inputTensor = new Tensor(image, [1, 3, 224, 224]);
const outputs = await model.run(inputTensor);

// baca output
const output = outputs[0];
const outputData = await output.data();

// cleanup wajib
inputTensor.delete();
output.delete();

Variasi pemanggilan yang didukung secara umum:

  • model.run(inputTensor)
  • model.run([inputTensor])
  • model.run({ input_name: inputTensor })

Tips layout

  • PyTorch vision sering NCHW.
  • Banyak pipeline TF/TF.js terasa natural di NHWC.
  • Setelah konversi, jangan asumsi—cek model.getInputDetails().

Contoh inspeksi:

JS
console.log(model.getInputDetails());
console.log(model.getOutputDetails());

Expected output: detail name/shape/dtype input-output; prediksi numerik yang konsisten dengan uji Python untuk sample yang sama.

Step 6: Integrasi ke pipeline TensorFlow.js existing

Kenapa ini penting: di dunia nyata, pre/post-processing sering sudah stabil di TF.js. Rewrite total justru bikin regresi.

Pola yang direkomendasikan dokumentasi:

  1. Convert model asal ke .tflite
  2. Install @litertjs/core + @litertjs/tfjs-interop
  3. Aktifkan backend WebGPU di TF.js
  4. Samakan GPU device antara TF.js dan LiteRT.js
  5. Ganti model.predict / execute dengan runWithTfjsTensors
  6. Uji output parity
JS
import { loadLiteRt, getWebGpuDevice, loadAndCompile } from '@litertjs/core';
import { runWithTfjsTensors } from '@litertjs/tfjs-interop';
import * as tf from '@tensorflow/tfjs';
import { WebGPUBackend } from '@tensorflow/tfjs-backend-webgpu';

await tf.setBackend('webgpu');
await loadLiteRt('/wasm/');

// Samakan device biar konversi tensor efisien
const device = getWebGpuDevice();
tf.removeBackend('webgpu');
tf.registerBackend('webgpu', () => new WebGPUBackend(device, device.adapterInfo));
await tf.setBackend('webgpu');

const model = await loadAndCompile('/models/resnet18_web.tflite', {
  accelerator: 'webgpu',
});

Contoh pre-processing ala ResNet + top-5:

JS
// asumsikan `imgEl` adalah HTMLImageElement
const imageData = tf.tidy(() => {
  const image = tf.browser.fromPixels(imgEl, 3).div(255);
  return image
    .resizeBilinear([224, 224])
    .sub([0.485, 0.456, 0.406])
    .div([0.229, 0.224, 0.225])
    .reshape([1, 224, 224, 3])
    .transpose([0, 3, 1, 2]); // ke NCHW jika model butuh
});

const outputs = await runWithTfjsTensors(model, [imageData]);
const probabilities = outputs[0];
const top5 = tf.topk(probabilities, 5);

const values = await top5.values.data();
const indices = await top5.indices.data();

tf.dispose(outputs);
tf.dispose(top5);
tf.dispose(imageData);

console.log({ values: Array.from(values), indices: Array.from(indices) });

Perubahan yang sering perlu setelah konversi:

  • Reorder input
  • Transpose layout
  • Rename input names

Expected output: class indices/scores selaras dengan baseline Python (toleransi numerik wajar).

Step 7: Tes dengan fake input sebelum sentuh UI

Kenapa ini penting: memisahkan “model graph bisa jalan” dari “pipeline kamera/UI benar”. Debugging campur aduk itu buang waktu.

Opsi A — Model Tester

BASH
npx model-tester

Ini membantu cek eksekusi di WebNN/WebGPU/CPU dengan input acak dan intuition benchmark kasar.

Opsi B — manual fake inputs

JS
const fakeInputs = model.getInputDetails().map(({ shape, dtype }) =>
  tf.ones(shape, dtype)
);

const outputs = await runWithTfjsTensors(model, fakeInputs);
console.log(outputs);
tf.dispose(outputs);
tf.dispose(fakeInputs);

Expected output: run sukses, output shape sesuai getOutputDetails(), tidak ada op-not-supported di backend target (atau terlihat jelas fallback-nya).

Step 8: Hardening production (memory, fallback, ukuran model)

Kenapa ini penting: demo 5 menit beda dunia dengan tab yang nyala 5 jam di HP user.

Memory lifecycle

  • Tiap Tensor yang Teman-Teman buat, rencanakan delete()
  • Di TF.js, manfaatkan tf.tidy / tf.dispose
  • Hindari menyimpan referensi tensor GPU di state React tanpa cleanup

Fallback strategy

JS
async function loadModelSmart(url) {
  try {
    return await loadAndCompile(url, { accelerator: 'webgpu' });
  } catch (err) {
    console.warn('WebGPU compile failed, fallback to wasm', err);
    return await loadAndCompile(url, { accelerator: 'wasm' });
  }
}

Model terlalu besar

Gejala: Aborted(), gagal alokasi, load hang.

Yang biasa MUGHU lakukan:

  • quantize weights (AI Edge Quantizer) dengan hati-hati
  • jaga compute di float32/float16 sesuai dukungan
  • pastikan I/O tetap float32/int32
  • potong resolusi input / pakai backbone lebih kecil untuk web
  • pertimbangkan split pipeline (client light model + server heavy model)

Platform notes (WebNN)

Kalau nekat WebNN:

  • Chromium + flags WebNN
  • JSPI enabled saat loadLiteRt
  • OS dependency (DirectML di Windows, Apple Silicon di macOS, dsb.)

Ini bagus untuk eksperimen NPU, tapi MUGHU belum akan menjanjikan ke stakeholder sebagai “bekerja di semua browser user Indonesia” tanpa feature detection ketat.

Error umum dan troubleshooting (yang paling sering kehalang)

1) Wasm 404 / gagal load runtime

Gejala: error saat loadLiteRt
Cek: path /wasm/, CDN, CORS, cache service worker
Fix: host static eksplisit; verifikasi URL di browser langsung

2) Operation not supported

Gejala: gagal compile/run di webgpu/webnn
Kenapa: coverage op backend khusus < CPU
Fix:

  • fallback wasm
  • tulis ulang op bermasalah di model asal
  • uji ulang dengan model tester

3) Shape mismatch

Gejala: throw saat run, atau output nonsense
Fix: cetak getInputDetails(), samakan batch/H/W/C, periksa transpose

4) Unsupported tensor type

Gejala: reject I/O non float32/int32
Fix: cast di pre/post-processing; jaga interface model

5) Hasil “jalan tapi akurasi aneh”

Ini klasik.

Checklist MUGHU:

  • mean/std normalisasi sama seperti training
  • RGB vs BGR
  • range [0,1] vs [0,255]
  • NCHW vs NHWC
  • urutan class label file

6) Memory naik pelan-pelan

Gejala: tab semakin berat
Fix: audit semua tensor path; pastikan delete() / dispose() di finally

7) JSPI / WebNN confusions

Gejala: WebNN path gagal misterius
Fix: loadLiteRt(path, { jspi: true }) + flags browser + devicePreference yang masuk akal

Tips praktis dari pengalaman MUGHU (biar nggak kena lubang yang sama)

  1. Kunci golden sample
    Satu gambar + expected top-5 dari Python. Tiap ubah pre-processing, bandingkan.

  2. Benchmark di device target Indonesia yang realistis
    Jangan cuma MacBook kencang. Pinjam HP Android mid-range. Tes juga di Chrome Windows kantor.

  3. Throttle kamera
    30fps model berat di semua device itu ambisius. Kadang 10–15fps + UX pintar lebih sehat.

  4. Pisahkan cold start vs steady latency
    Compile/load beda cerita dari per-frame run. Komunikasi ini ke product manager biar ekspektasi waras.

  5. Feature detection
    Deteksi WebGPU; tampilkan mode “akurat tapi lebih lambat” saat fallback CPU.

  6. Versioning artifact
    Version-kan .tflite + config pre-processing bareng. Jangan model v3 dipasangkan mean/std v1.

  7. Keamanan & privasi
    Kalau proses KTP lokal, jelaskan ke user apa yang diupload. Trust is part of UX.

  8. Jangan overclaim NPU
    WebNN exciting, tapi production roll-out butuh telemetry dan escape hatch.

Contoh arsitektur aplikasi yang MUGHU pakai berulang kali

Pola modular

  • modelLoader.tsloadLiteRt + loadAndCompile + cache promise
  • preprocess.ts — TF.js tidy graph
  • infer.tsrunWithTfjsTensors / model.run
  • postprocess.ts — top-k, threshold, mapping label
  • dispose.ts — satu pintu cleanup

Pseudo-struktur folder

TEXT
src/
  ml/
    loadRuntime.ts
    loadModel.ts
    preprocess.ts
    infer.ts
    labels.json
  pages/
    DemoCam.tsx
public/
  wasm/
  models/
    resnet18_web.tflite

Kenapa dipisah: biar UI engineer nggak ikut berantakan saat runtime ML berubah.

Kapan LiteRT.js terasa overkill (transparansi E-E-A-T)

MUGHU nggak akan maksa LiteRT.js untuk semua hal.

Pertimbangkan opsi lain kalau:

  • cuma butuh rules + klasik image processing
  • model terlalu besar untuk budget memori browser target
  • tim belum siap maintain artifact conversion
  • kebutuhan utama justru training interaktif di browser (bukan inference production)

Runtime yang bagus tetap kalah oleh model packaging discipline yang jelek. Itu fakta lapangan.

Sinyal strategi untuk lead engineering & product

Kalau Teman-Teman perlu narasi ke stakeholder non-teknis:

  • Efisiensi biaya: pindahkan sebagian workload inference ke device user.
  • Kecepatan iterasi multi-platform: satu keluarga model .tflite untuk web & mobile edge.
  • Risk privacy: kurangi eksposur data sensitif ke server.
  • Time-to-market: interop TF.js mempercepat migrasi bertahap, bukan big bang rewrite.
  • Trade-off jujur: investasi awal di conversion, Wasm hosting, dan observability client.

Referensi konsep WebAssembly secara umum bisa dibaca di Wikipedia: WebAssembly untuk bekal komunikasi ke tim yang belum akrab istilah Wasm.

Latihan terarah: mini project 90 menit

Kalau Teman-Teman mau “kerasa nempel”, ikuti latihan ini.

  1. Install @litertjs/core
  2. Host wasm/
  3. Pakai model .tflite kecil (klasifikasi)
  4. Jalankan fake input
  5. Sambungkan satu HTMLImageElement
  6. Tampilkan top-5 ke UI
  7. Ukur waktu run di Chrome Performance/logs
  8. Paksa fallback wasm dan bandingkan

Yang dipelajari:

  • path Wasm
  • shape discipline
  • cleanup
  • perbedaan accelerator secara kasatmata

Pola migrasi dari TensorFlow.js (tanpa drama)

MUGHU biasanya ajukan migrasi bertahap:

  1. Parity phase: model LiteRT di-shadow di staging, bandingkan output vs TF.js model lama
  2. Partial traffic: fitur non-kritis pindah dulu
  3. GPU path default + CPU fallback
  4. Hapus dead code graph model lama setelah metrik stabil

Ini lebih sehat daripada “minggu ini ganti semua”.

Catatan soal GenAI di web (ekspektasi vs realita)

Ekosistem LiteRT secara luas memang dorong GenAI on-device (termasuk jalur model terbuka seperti keluarga Gemma di stack edge). Di web, arahnya menarik—termasuk wacana runtime LLM di sisi JS—tapi MUGHU sarankan pisahkan dua agenda:

  • Agenda A (sekarang): vision/audio/classical ML mid-size yang jelas ROI-nya di LiteRT.js
  • Agenda B (bertahap): GenAI on-device web setelah budget memori, quant, dan UX cold-start beres

Campur aduk agenda bikin demo GenAI gagal menodai adopsi fitur klasifikasi yang mestinya sudah cuan.

Checklist rilis production LiteRT.js

Sebelum bilang “sudah production”:

  • Wasm di-host dengan cache strategy sadar versi
  • Model artifact versioned
  • Feature detect WebGPU/WebNN
  • Fallback wasm teruji
  • Parity test vs baseline Python
  • Memory audit di sesi 30–60 menit
  • Logging client untuk compile fail / op fail (tanpa kirim data sensitif)
  • Dokumentasi internal shape + normalisasi
  • Opsi nonaktifkan kamera AI di device lemah (graceful degradation)

Snippet “all-in-one” yang rapi untuk onboarding tim

JS
import { loadLiteRt, loadAndCompile, Tensor } from '@litertjs/core';

export async function createClassifier({
  wasmPath = '/wasm/',
  modelUrl = '/models/model.tflite',
  accelerator = 'webgpu',
} = {}) {
  await loadLiteRt(wasmPath);

  let model;
  try {
    model = await loadAndCompile(modelUrl, { accelerator });
  } catch (e) {
    if (accelerator !== 'wasm') {
      model = await loadAndCompile(modelUrl, { accelerator: 'wasm' });
    } else {
      throw e;
    }
  }

  async function predictFloat32NCHW(float32Array, shape = [1, 3, 224, 224]) {
    const input = new Tensor(float32Array, shape);
    try {
      const outputs = await model.run(input);
      const out = outputs[0];
      try {
        const data = await out.data();
        return data;
      } finally {
        out.delete();
      }
    } finally {
      input.delete();
    }
  }

  return { model, predictFloat32NCHW };
}

Kenapa pola ini bagus: API kecil, cleanup terjaga, fallback ada, onboarding engineer baru lebih cepat.

Kesalahan “kelihatan sepele” yang mahal di tim Indonesia (dan di mana-mana)

  • Nyimpan model 100MB+ tanpa strategi quant/CDN regional, lalu heran user di luar kota load-nya lama.
  • Ngetes cuma di Wi-Fi kantor.
  • Menganggap WebGPU = semua user aman (padahal armada device heterogen).
  • Tidak mencatat versi model di hasil prediksi—ribet saat audit salah klasifikasi.
  • Menaruh pre-processing beda antara Android native dan web, lalu bilang “modelnya drift”.

Kalau satu hal yang MUGHU ingin ditempel di monitor: model yang sama + pre-processing yang sama + evaluasi yang sama.

Resources resmi yang worth dibuka saat stuck

  • Dokumentasi web LiteRT.js: developers.google.com/edge/litert/web
  • Paket npm @litertjs/core
  • Repo & sample di ekosistem Google AI Edge / LiteRT di GitHub
  • Get Started resmi (konversi, WebGPU/WebNN, pipeline TF.js)

Pakai docs resmi sebagai sumber kebenaran API; tulisan ini adalah peta jalan praktis + catatan lapangan.

Observability client yang nggak bikin privacy team panik

Satu hal yang sering ketinggalan pas fitur AI web “sudah jalan”: enggak ada yang tahu kenapa prediksi aneh di device user. Server log nggak bantu, karena inference-nya di browser. MUGHU biasanya pasang lapisan telemetry yang tipis tapi tajam.

Yang diukur:

  • Cold start: waktu loadLiteRt + loadAndCompile (pisahkan keduanya)
  • Warm run latency: p50/p95 waktu model.run
  • Accelerator terpakai: webgpu, webnn, atau wasm
  • Fallback rate: berapa persen sesi yang “turun kelas” ke CPU
  • Error class: gagal fetch Wasm, gagal compile, shape mismatch, OOM
  • Model version: string versi artifact yang ikut terkirim di event (bukan blob modelnya)

Yang nggak dikirim:

  • frame kamera
  • raw tensor input/output
  • data PII dari form

Cukup kirim metrik agregat + device hints kasar (kelas device, support WebGPU ya/tidak, OS major). Buat dashboard internal: “p95 run di Android Chrome mid-range” lebih berguna daripada rata-rata global yang menipu.

Strategi cache model & Wasm biar user di luar kota nggak putus asa

Di Indonesia, realita jaringannya campur: Wi-Fi kantor kencang, 4G di jalan macet. Model 20–40 MB yang “ringan” di laptop bisa terasa berat di HP entry-level.

Pola yang MUGHU pakai:

  1. Pisahkan origin cache untuk Wasm runtime dan model .tflite
  2. Versioned filename (model-v3-int8.tflite, bukan model.tflite yang di-overwrite)
  3. Service Worker cuma untuk asset yang memang immutable; jangan agresif cache HTML app shell tanpa strategi update
  4. Prefetch opsional setelah user idle di halaman yang relevan (bukan di first paint homepage)
  5. Progress UI jujur — “Mengunduh model 18 MB” lebih baik daripada spinner diam

Kalau model besar, prioritaskan quantisasi (INT8) sebelum mikirin trik CDN aneh-aneh. CDN regional tetap penting, tapi quant sering potong bandwidth lebih dramatis daripada ganti provider CDN tiap kuartal.

Debugging shape, layout, dan “kok outputnya aneh?”

Sebagian besar bug “model rusak” di web sebenarnya pre-processing beda. Khususnya saat migrasi dari TensorFlow.js ke LiteRT.js lewat runWithTfjsTensors.

Checklist debug 10 menit:

  1. Cetak model.getInputDetails() dan model.getOutputDetails()
  2. Cocokkan rank, dtype, min/max range (0–1 vs 0–255 vs ImageNet mean/std)
  3. Cek layout NCHW vs NHWC — ini klasik bikin skor acak tapi “kelihatan meyakinkan”
  4. Bandingkan satu sample fixed (gambar synthetic atau fixture) vs baseline Python/tflite interpreter
  5. Kalau pakai named input, pastikan nama tensor setelah konversi belum berubah

Trik lapangan: simpan satu golden test di CI browser (Playwright/Puppeteer) dengan input Float32Array deterministic. Bukan e2e kamera — terlalu flaky. Yang dicek: argmax class + toleransi numerik kecil pada top logits.

Perbandingan singkat: kapan tetap di TensorFlow.js, kapan pindah

Bukan soal “mana yang lebih keren”, tapi biaya perubahan vs manfaat.

Situasi Lebih masuk akal
Pipeline TF.js sudah matang, model kecil, latency OK Tetap TF.js
Model dari PyTorch, jalur TF.js berliku (ONNX → TF → TF.js) LiteRT.js
Butuh WebGPU/WebNN + fallback Wasm yang rapi LiteRT.js
Tim masih bereksperimen pre/post di TF.js Hybrid: LiteRT model + TF.js di sekitarnya
Hanya butuh demo sekali di hackathon Pilih stack yang tim paling hafal

Interop @litertjs/tfjs-interop cocok saat Teman-Teman mau ganti “otak” model tanpa bongkar seluruh pipeline visualisasi. Itu justru nilai jualnya: migrasi bedah kecil, bukan transplantasi total.

Studi mini: fitur scan produk di web commerce

Konteks fiktif tapi realistis (pola yang sering MUGHU temui di produk consumer Indonesia):

  • Masalah: foto produk buram, user di HP mid-range, server vision mahal di peak promo
  • Solusi: klasifikasi on-device untuk “kategori kasar” dulu; server cuma dipanggil kalau confidence rendah
  • Stack: ResNet-ish kecil → .tflite → LiteRT.js (webgpu default, wasm fallback)
  • Hasil tipikal yang masuk akal dikejar:
    • potong 30–50% request server untuk kasus “mudah”
    • latency prediksi lokal 30–120 ms di device menengah (sangat tergantung model & quant)
    • privacy: foto nggak selalu naik ke cloud

Yang bikin gagal di kasus mirip:

  • model terlalu besar biar “akurat di paper”
  • nggak ada threshold “minta foto ulang”
  • UI memblokir seluruh checkout saat model masih loading

Lesson: AI web yang baik itu asisten alur, bukan gerbang yang mengunci user.

Keamanan & trust: Wasm di browser itu kuat, tapi bukan sihir

WebAssembly bantu isolasi memori linear dan performa mendekati native di banyak skenario, tapi trust model web tetap berlaku: kode tetap jalan di client, user bisa inspect, model bisa diunduh. Jangan taruh “rahasia bisnis” semata-mata di bobot model publik.

Praktik aman yang relevan:

  • anggap model bisa diekstrak; lindungi yang benar-benar sensitif di server
  • patuhi Content-Security-Policy dengan sadar (setup Wasm + worker kadang butuh penyesuaian)
  • batasi frekuensi inference biar page nggak digoyang tab lain (dan hemat baterai)
  • beri kontrol user: matikan kamera AI, hapus cache model

Kalau Teman-Teman perlu bekal komunikasi ke security review, ringkasan konsep portabel Wasm dan batasan browser-nya ada di dokumentasi ekosistem W3C/WebAssembly dan artikel referensi seperti MDN Web Docs tentang WebAssembly.

Template “Definition of Done” untuk sprint AI web

Supaya backlog nggak cuma “integrate LiteRT.js”, MUGHU suka breakdown DoD per story:

Story: Load runtime & model

  • loadLiteRt sukses dari path self-host
  • gagal network → UI error actionable
  • model version muncul di debug panel internal

Story: Inference path

  • input pipeline documented (resize, crop, normalize)
  • Tensor.delete() di semua path sukses/gagal
  • fallback accelerator teruji di minimal 3 device profile

Story: Product behavior

  • confidence threshold + empty state
  • analytics event tanpa payload sensitif
  • parity sample set ≥ 50 fixture lolos toleransi

Ini kelihatan remeh, tapi justru yang bikin demo engineering berubah jadi fitur yang bisa dipegang QA.

FAQ yang biasanya muncul di channel engineering

Q: Harus WebGPU mulu?
Ngga. Defaultkan yang terbaik yang tersedia, tapi rancang seolah wasm tetap first-class.

Q: Boleh load model dari CDN npm langsung di production?
Boleh untuk spike. Production lebih aman self-host / CDN sendiri biar versi & cache kebaca.

Q: Satu model untuk Android native dan web?
Idealnya iya (.tflite yang sama), asalkan pre-processing diparify. Kalau beda crop policy, akurasi “aneh” itu wajar.

Q: Bagaimana soal multi-input model?
model.run mendukung array tensor atau map nama→tensor. Jangan tebak urutan—baca getInputDetails().

Q: Kapan mikirin WebNN?
Saat target device/browser yang Teman-Teman peduli sudah nunjukkan support stabil di telemetri real. Jangan jadikan WebNN single point of success di tahun pertama adopsi.

Snippet kecil: deteksi accelerator + log terstruktur

JS
export function pickAccelerator({
  preferWebGpu = true,
  preferWebNn = false,
} = {}) {
  // Feature detect disederhanakan; sesuaikan polyfill/browser target tim.
  const hasWebGpu = typeof navigator !== 'undefined' && 'gpu' in navigator;
  if (preferWebNn) return 'webnn';
  if (preferWebGpu && hasWebGpu) return 'webgpu';
  return 'wasm';
}

export function logInferenceMetric(event) {
  // event: { modelVersion, accelerator, compileMs, runMs, ok, errorCode }
  if (typeof window !== 'undefined' && window.__AI_METRICS__) {
    window.__AI_METRICS__.push({
      ...event,
      ts: Date.now(),
    });
  }
}

Pola ini memaksa tim bicara pakai angka, bukan feeling “kayaknya lebih cepet”.

Roadmap 30–60–90 hari buat tim yang serius

30 hari

  • spike model kecil end-to-end
  • putuskan self-host Wasm
  • golden test 1 fixture
  • dokumen shape & normalisasi 1 halaman

60 hari

  • shadow traffic / parity di staging
  • telemetry p95 + fallback rate
  • quantisasi & bandingkan quality drop
  • UI graceful degradation

90 hari

  • partial production traffic
  • budget model size resmi (mis. “≤ X MB gzip”)
  • runbook incident: model corrupt, compile fail massal, regresi akurasi
  • keputusan go/no-go hapus path TF.js lama (kalau ada)

Roadmap ini yang biasa MUGHU bawa ke meeting product biar AI web nggak cuma jadi “inisiatif keren tanpa owner metrik”.

Checklist handoff ke product & design (biar nggak cuma “modelnya jalan”)

Setelah roadmap 30–60–90 ada di meja, MUGHU biasanya bawa checklist handoff yang lebih “manusia” daripada ticket Jira. Engineering bisa bangga model compile-nya hijau, tapi user cuma lihat: lama loading, hasilnya kacau, atau tombolnya nge-freeze.

Yang perlu disepakati bareng product & design:

  • State visual yang jelas: idle, downloading model, compiling, ready, low confidence, error network, error device.
  • Copy yang jujur: “Sedang menyiapkan AI di perangkat…” jauh lebih baik daripada spinner kosong 8 detik.
  • Jalan keluar manual: selalu ada opsi isi form / pilih kategori / upload ulang tanpa AI.
  • Budget waktu UX: misalnya first meaningful inference ≤ 3 detik di 4G kota, ≤ 8 detik di 3G luar kota (target, bukan dogma).
  • Aksesibilitas: status loading dibacakan screen reader; error nggak cuma warna merah.

Di beberapa proyek e-commerce Indonesia, fitur scan produk “hidup” di demo, tapi drop-off melonjak di production karena state compiling WebGPU digabung dengan skeleton UI yang kelihatan seperti hang. Setelah state dipisah + ada tombol “Lewati AI”, conversion recovery-nya langsung kebaca di funnel.

Pola integrasi di monorepo & multi-app

Banyak tim Teman-Teman nggak cuma punya satu SPA. Ada storefront, seller dashboard, internal ops tool, kadang PWA terpisah. LiteRT.js cocok dipaket sebagai shared inference kit, bukan dicopy-paste per app.

Struktur yang cukup waras di monorepo:

TEXT
packages/ai-runtime/
  loadRuntime.ts
  pickAccelerator.ts
  modelRegistry.ts
  preprocess/
  telemetry.ts
apps/storefront/
apps/seller-web/

Isi modelRegistry idealnya deklaratif:

TS
export const models = {
  productScanV3: {
    url: '/models/product-scan-v3.tflite',
    version: '3.2.0',
    input: { width: 224, height: 224, mean: 127.5, std: 127.5 },
    maxConcurrent: 1,
  },
} as const;

Kenapa ini penting? Karena bug paling mahal biasanya muncul saat app A resize 224 center-crop, app B letterbox 256, padahal file .tflite-nya sama. Satu registry = satu sumber kebenaran pre-process.

Kalau app berbeda release cycle, pin model version di config remote (feature flag), bukan hardcode di bundle JS. Runtime Wasm boleh di-bump pelan-pelan; model boleh digulir lebih cepat asal golden test lolos.

Worker, main thread, dan “kenapa tab Chrome di Windows office lag?”

Inference di main thread itu godaan besar waktu spike: codingnya pendek, hasilnya kelihatan. Di device menengah—laptop kantor 8 GB RAM, Chrome kebuka 20 tab—main thread yang keisi compile + run model rasanya kayak UI “ngunyah karet”.

Praktik yang MUGHU pakai:

  1. Load & compile di Worker (atau path setara) kalau alur memungkinkan.
  2. Main thread cuma kirim input ringkas (ImageBitmap / ArrayBuffer) dan terima hasil angka/label.
  3. Batasi antrean: satu job aktif + satu pending; sisanya drop atau coalesce.
  4. Jangan fire inference tiap frame kamera tanpa throttle (16 ms vs 200 ms beda banget soal panas & baterai).

Contoh kontrak pesan yang simple:

JS
// main → worker
{ type: 'infer', requestId, modelId, tensorBuffer, shape }

// worker → main
{ type: 'result', requestId, ok: true, scores, runMs }
// atau
{ type: 'result', requestId, ok: false, errorCode: 'COMPILE_FAIL' }

Ingat: transfer buffer pakai postMessage dengan transfer list biar nggak dobel memory. Di HP entry-level, dobel copy tensor besar itu cukup buat tab ke-kill OOM tanpa error yang “sopan”.

Biaya, kapasitas server, dan hitungan yang suka dilupakan

Salah satu alasan pindah sebagian workload ke LiteRT.js memang biaya. Tapi jangan cuma hitung “GPU server yang dihemat”.

Hitung juga:

  • Bandwidth model: 5 MB model × 100 ribu user unik / bulan = angka yang bikin finance mengerutkan kening kalau cache miss-nya jelek.
  • CDN egress vs origin: self-host model di object storage + CDN biasanya lebih murah dan lebih mudah di-invalidate.
  • Support cost: error “AI nggak jalan di HP saya” yang masuk CS tanpa runbook = biaya manusia.
  • Battery & heat complaints: jarang masuk dashboard engineering, sering masuk review Play/App store buat WebView wrapper.

Rule of thumb kasar yang sering MUGHU pakai di slide stakeholder:

Skenario Server-only Hybrid (LiteRT.js + server)
Kasus mudah 60–70% Semua naik ke API Selesai di device
Kasus sulit / fraud-ish Model besar di server Escalation path
Privacy foto Perlu policy ketat Default lokal, opt-in cloud

Angka pastinya beda per bisnis. Yang penting ada unit economics per 1.000 inference, bukan cuma “AI-nya keren”.

Versi model, rollback, dan parade “tadi malam akurasinya aneh”

Model ML beda dari string copy UI. Gagal deploy model bisa diam-diam: app tetap “sukses” inference, cuma labelnya melenceng.

Minimal pipeline release model:

  1. Artifact imutabel: product-scan-3.2.0.tflite + checksum.
  2. Canary: 1–5% traffic internal / user flag.
  3. Guardrail otomatis: distribusi top-1 label, rate low-confidence, rate fallback server.
  4. Rollback satu toggle: kembalikan pointer versi tanpa full redeploy frontend kalau memungkinkan.

Simpan modelVersion di setiap event telemetry. Tanpa itu, debugging regresi akurasi cuma berujung saling tuduh antara data science dan web.

Untuk pre-process yang sensitif, simpan juga hash singkat dari config normalisasi. Pernah ada kasus mean/std “diperbaiki” di notebook, web masih pakai angka lama, dan seminggu penuh tim mikir hardware acceleration-nya rusak.

Kolaborasi data science ↔ web: kontrak yang bikin tidur nyenyak

MUGHU suka memaksa satu dokumen pendek (boleh 1 halaman Notion/Markdown internal) sebelum model dianggap “siap web”:

  • nama input/output & urutan
  • dtype & layout (NHWC vs yang lain)
  • rentang nilai pixel setelah normalisasi
  • label map + apakah ada background class
  • threshold default yang disarankan (bukan angka sakti)
  • set 20–50 gambar lolos / gagal / edge dengan ekspektasi

Tanpa kontrak itu, web engineer terpaksa tebak-tebakan dari file flatbuffer—bisa, tapi lambat dan rawan salah. Kalau model multi-head, tulis eksplisit head mana yang dipakai product v1. Jangan biarkan “nanti pakai semua output” tanpa prioritas.

Kalau Teman-Teman butuh rujukan format & cara kerja model di perangkat yang selaras ekosistem TensorFlow Lite / LiteRT, dokumentasi resmi di TensorFlow Lite guide masih jadi pijakan bagus buat nyambungin mental model mobile native dengan runtime web.

Uji di device yang “ada di rumah user”, bukan cuma di MacBook M-series

Lab device Indonesia itu realitanya campur aduk: Chrome Android di Helio G-series, Samsung browser, iOS Safari beberapa major version ke belakang, plus laptop Windows office.

Matriks uji minimal yang worth dianggarkan:

  • 1 HP flagship 1–2 tahun terakhir
  • 1 HP menengah harga 2–3 jutaan
  • 1 HP entry / lawas yang masih laku di user base
  • 1 desktop integrated GPU
  • 1 kondisi throttling (charge 20%, mode hemat baterai)

Catat compileMs, runMs, RSS kasar, dan apakah fallback ke wasm terjadi. Kalau cuma uji di mesin dev kencang, angka p95 production akan “mengejutkan” dengan cara yang nggak menyenangkan.

Safari iOS sering jadi plot twist: fitur GPU path beda napas dengan Chrome Android. Makanya desain product harus tetap enak di path Wasm—bukan cuma di path tercepat.

Snippet: guard memory & timeout inference

Ini pola kecil yang sering menyelamatkan session panjang (scan berkali-kali di satu halaman):

JS
export async function runWithBudget(model, inputTensor, {
  timeoutMs = 2500,
} = {}) {
  const resultPromise = model.run(inputTensor);
  let timer;
  try {
    const outputs = await Promise.race([
      resultPromise,
      new Promise((_, reject) => {
        timer = setTimeout(() => reject(new Error('INFER_TIMEOUT')), timeoutMs);
      }),
    ]);
    return outputs;
  } finally {
    clearTimeout(timer);
    try { inputTensor.delete(); } catch (_) {}
  }
}

Timeout di sini bukan buat “nyalahin model”, tapi buat kembalikan kontrol ke UI. User lebih maafkan pesan “Gagal memproses, coba lagi” daripada page yang membeku tanpa kepastian.

Metrik sukses yang patut digantung di channel #ai-web

Supaya LiteRT.js nggak jadi proyek “keren di engineering blog internal”, pilih 5 metrik yang dibaca bareng product:

  1. Attach rate: % sesi yang berhasil load runtime + model.
  2. Fallback rate: % pindah ke server / path manual.
  3. p95 runMs per accelerator (webgpu vs wasm).
  4. Effective accuracy proxy: % hasil diterima user (bukan cuma top-1 model).
  5. Cost per 1.000 sesi (egress model + API escalation).

Kalau attach rate bagus tapi acceptance user jelek, masalahnya di UX atau threshold. Kalau runMs bagus tapi fallback tinggi, curigai compile fail, CSP, atau device split.

Kesimpulan

LiteRT.js baru benar-benar “siap product” saat engineering berhenti mengandalkan tebakan: kontrak model yang eksplisit, threshold yang diuji dengan set lolos/gagal/edge, dan prioritas head yang jelas di multi-head. Di atas fondasi itu, performa on-device di web diukur dari perangkat yang benar-benar dipakai user Indonesia—bukan hanya MacBook M-series—lengkap dengan catatan compile, run, memori, dan frekuensi fallback ke Wasm. Tanpa matriks itu, angka lab terasa meyakinkan, sementara p95 production jadi kejutan yang mahal.

Pola kecil seperti budget timeout dan pembersihan tensor justru yang menjaga sesi panjang tetap manusiawi: user lebih menerima “coba lagi” daripada halaman membeku. Di sisi product, lima metrik bersama—attach rate, fallback rate, p95 runMs per accelerator, acceptance hasil, dan biaya per 1.000 sesi—memisahkan proyek demo dari sistem yang bisa dioperasikan. Attach bagus tapi acceptance jelek menunjuk ke UX atau threshold; run cepat tapi fallback tinggi biasanya mengarah ke compile, CSP, atau fragmentasi perangkat.

Langkah paling pragmatis: kunci kontrak model dulu, uji di flagship–menengah–entry plus kondisi throttling, pasang guard runtime, lalu gantung metrik di channel yang dibaca bareng product. Dari situ LiteRT.js berubah dari “bisa jalan di browser” menjadi jalur on-device yang terukur, hemat eskalasi server, dan tetap nyaman meski path GPU tidak tersedia. Untuk memperdalam mental model akselerasi di browser sambil merancang fallback yang sehat, rujuk juga dokumentasi WebGPU di MDN—lalu iterasi di device user, bukan di mesin terkuat di meja Anda.


Referensi

Developers. (2026). LiteRT for Web with LiteRT.js.

Developers. (2026). LiteRT.js, Google's high performance Web AI Inference.

GitHub. (2026). google-ai-edge/LiteRT.

Developers. (2026). Get started with LiteRT.js.

GitHub. (2026). LiteRT/litert/js/README.md.

Npmjs. (2026). @litertjs/core.

AI. (2026). LiteRT for Web with LiteRT.js.

X. (2026). Meet LiteRT.js: @Google’s new Edge AI.

Dev. (2026). Maximizing WebAI Performance: A Deep Dive into LiteRT.js.

Developers. (2026). LiteRT: The Universal Framework for On-Device AI.

Komentar (0)

Belum ada komentar. Jadilah yang pertama berbagi pendapat!

Tinggalkan komentar