Machine Learning
LiteRT.js: ML di Browser Tanpa Server Mahal
Daftar isi
- Kenapa AI di browser sering terasa berat (dan kenapa itu penting)
- Problem yang sering muncul di production web AI
- Kenapa ini penting buat bisnis, bukan cuma “keren secara teknis”
- Apa itu LiteRT.js, dan bedanya dengan “sekadar library ML di web”
- Fitur inti yang bikin LiteRT.js relevan
- Getting Started: prasyarat sebelum coding
- Prasyarat teknis
- Prasyarat “product sense” (sering dilupakan)
- Istilah penting biar ngobrolnya nyambung
- Review jujur: kelebihan, kekurangan, dan buat siapa
- Overview singkat
- Key features yang kerasa di kerjaan harian
- Use case dunia nyata
- Kelebihan
- Kekurangan / batasan (ini penting buat trust)
- Cocok untuk
- Sebaiknya dihindari dulu kalau
- LiteRT.js vs opsi lain: perbandingan biar nggak salah pilih
- Best-for scenarios
- Rekomendasi per use case
- Studi kasus: dari lag di demo client jadi pipeline yang bisa di-demo ulang
- Background
- Challenge / Problem
- Approach
- Implementation (ringkas)
- Results (metrik yang masuk akal di lapangan)
- Key learnings
- Step 1: Siapkan project dan instal paket LiteRT.js
- Inisialisasi project
- Serve folder Wasm
- Step 2: Load runtime LiteRT.js (Wasm) dengan benar
- Checklist Step 2
- Step 3: Konversi model PyTorch ke .tflite (jalur yang lebih waras)
- Step 4: Load & compile model di browser
- Pilih accelerator dengan kepala dingin
- Step 5: Siapkan input tensor (di sinilah banyak orang salah)
- Tips layout
- Step 6: Integrasi ke pipeline TensorFlow.js existing
- Step 7: Tes dengan fake input sebelum sentuh UI
- Opsi A — Model Tester
- Opsi B — manual fake inputs
- Step 8: Hardening production (memory, fallback, ukuran model)
- Memory lifecycle
- Fallback strategy
- Model terlalu besar
- Platform notes (WebNN)
- Error umum dan troubleshooting (yang paling sering kehalang)
- 1) Wasm 404 / gagal load runtime
- 2) Operation not supported
- 3) Shape mismatch
- 4) Unsupported tensor type
- 5) Hasil “jalan tapi akurasi aneh”
- 6) Memory naik pelan-pelan
- 7) JSPI / WebNN confusions
- Tips praktis dari pengalaman MUGHU (biar nggak kena lubang yang sama)
- Contoh arsitektur aplikasi yang MUGHU pakai berulang kali
- Pola modular
- Pseudo-struktur folder
- Kapan LiteRT.js terasa overkill (transparansi E-E-A-T)
- Sinyal strategi untuk lead engineering & product
- Latihan terarah: mini project 90 menit
- Pola migrasi dari TensorFlow.js (tanpa drama)
- Catatan soal GenAI di web (ekspektasi vs realita)
- Checklist rilis production LiteRT.js
- Snippet “all-in-one” yang rapi untuk onboarding tim
- Kesalahan “kelihatan sepele” yang mahal di tim Indonesia (dan di mana-mana)
- Resources resmi yang worth dibuka saat stuck
- Observability client yang nggak bikin privacy team panik
- Strategi cache model & Wasm biar user di luar kota nggak putus asa
- Debugging shape, layout, dan “kok outputnya aneh?”
- Perbandingan singkat: kapan tetap di TensorFlow.js, kapan pindah
- Studi mini: fitur scan produk di web commerce
- Keamanan & trust: Wasm di browser itu kuat, tapi bukan sihir
- Template “Definition of Done” untuk sprint AI web
- FAQ yang biasanya muncul di channel engineering
- Snippet kecil: deteksi accelerator + log terstruktur
- Roadmap 30–60–90 hari buat tim yang serius
- Checklist handoff ke product & design (biar nggak cuma “modelnya jalan”)
- Pola integrasi di monorepo & multi-app
- Worker, main thread, dan “kenapa tab Chrome di Windows office lag?”
- Biaya, kapasitas server, dan hitungan yang suka dilupakan
- Versi model, rollback, dan parade “tadi malam akurasinya aneh”
- Kolaborasi data science ↔ web: kontrak yang bikin tidur nyenyak
- Uji di device yang “ada di rumah user”, bukan cuma di MacBook M-series
- Snippet: guard memory & timeout inference
- Metrik sukses yang patut digantung di channel #ai-web
- Kesimpulan
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
-
Inference terakselerasi di browser
- CPU: XNNPack lewat WebAssembly
- GPU: WebGPU (ML Drift di ekosistem LiteRT)
- NPU / hardware khusus: WebNN (masih experimental di banyak browser)
-
Kompatibilitas multi-framework
- Model dari PyTorch, JAX, atau TensorFlow bisa diarahkan ke format
.tfliteyang sama.
- Model dari PyTorch, JAX, atau TensorFlow bisa diarahkan ke format
-
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
.tfliteyang 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 WasmloadAndCompile()untuk load model + pilih acceleratorTensor+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
.tflitelintas 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
.tfliteuntuk 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
- Round-trip ke server bikin prediksi terasa lambat saat sinyal turun.
- Jalur konversi ke TF.js memakan waktu debug berhari-hari.
- Di beberapa device, WebGL path tidak stabil untuk target latency.
- Legal minta opsi “proses lokal dulu” untuk sebagian data visual.
Approach
- Kunci model ke format
.tflitesebagai 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)
- Convert ResNet-style classifier ke
.tflitevia alur LiteRT Torch. - Host
wasm/dan model di CDN internal. - Init
loadLiteRt→loadAndCompile(..., {accelerator: 'webgpu'}). - Samakan WebGPU device antara TF.js dan LiteRT.js.
runWithTfjsTensorsdi hot path kamera (throttle frame).- 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
mkdir litertjs-demo
cd litertjs-demo
npm init -y
npm install @litertjs/core
Kalau mau interop TF.js:
npm install @litertjs/tfjs-interop @tensorflow/tfjs @tensorflow/tfjs-backend-webgpu
Untuk ngetes model cepat:
npm install -D @litertjs/model-tester
Serve folder Wasm
File Wasm ada di:
node_modules/@litertjs/core/wasm/
Opsi praktis:
- copy folder
wasm/kepublic/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.
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):
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):
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.
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-GPUwasm: paling “aman” untuk coverage op & fallbackwebnn: untuk NPU/OS acceleration—siap-siap experimental flags
Load dari memory juga bisa (kalau Teman-Teman fetch sendiri):
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.
// 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:
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:
- Convert model asal ke
.tflite - Install
@litertjs/core+@litertjs/tfjs-interop - Aktifkan backend WebGPU di TF.js
- Samakan GPU device antara TF.js dan LiteRT.js
- Ganti
model.predict/executedenganrunWithTfjsTensors - Uji output parity
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:
// 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
npx model-tester
Ini membantu cek eksekusi di WebNN/WebGPU/CPU dengan input acak dan intuition benchmark kasar.
Opsi B — manual fake inputs
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
Tensoryang Teman-Teman buat, rencanakandelete() - Di TF.js, manfaatkan
tf.tidy/tf.dispose - Hindari menyimpan referensi tensor GPU di state React tanpa cleanup
Fallback strategy
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)
-
Kunci golden sample
Satu gambar + expected top-5 dari Python. Tiap ubah pre-processing, bandingkan. -
Benchmark di device target Indonesia yang realistis
Jangan cuma MacBook kencang. Pinjam HP Android mid-range. Tes juga di Chrome Windows kantor. -
Throttle kamera
30fps model berat di semua device itu ambisius. Kadang 10–15fps + UX pintar lebih sehat. -
Pisahkan cold start vs steady latency
Compile/load beda cerita dari per-frame run. Komunikasi ini ke product manager biar ekspektasi waras. -
Feature detection
Deteksi WebGPU; tampilkan mode “akurat tapi lebih lambat” saat fallback CPU. -
Versioning artifact
Version-kan.tflite+ config pre-processing bareng. Jangan model v3 dipasangkan mean/std v1. -
Keamanan & privasi
Kalau proses KTP lokal, jelaskan ke user apa yang diupload. Trust is part of UX. -
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.ts—loadLiteRt+loadAndCompile+ cache promisepreprocess.ts— TF.js tidy graphinfer.ts—runWithTfjsTensors/model.runpostprocess.ts— top-k, threshold, mapping labeldispose.ts— satu pintu cleanup
Pseudo-struktur folder
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
.tfliteuntuk 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.
- Install
@litertjs/core - Host
wasm/ - Pakai model
.tflitekecil (klasifikasi) - Jalankan fake input
- Sambungkan satu
HTMLImageElement - Tampilkan top-5 ke UI
- Ukur waktu
rundi Chrome Performance/logs - Paksa fallback
wasmdan bandingkan
Yang dipelajari:
- path Wasm
- shape discipline
- cleanup
- perbedaan accelerator secara kasatmata
Pola migrasi dari TensorFlow.js (tanpa drama)
MUGHU biasanya ajukan migrasi bertahap:
- Parity phase: model LiteRT di-shadow di staging, bandingkan output vs TF.js model lama
- Partial traffic: fitur non-kritis pindah dulu
- GPU path default + CPU fallback
- 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
wasmteruji - 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
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, atauwasm - 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:
- Pisahkan origin cache untuk Wasm runtime dan model
.tflite - Versioned filename (
model-v3-int8.tflite, bukanmodel.tfliteyang di-overwrite) - Service Worker cuma untuk asset yang memang immutable; jangan agresif cache HTML app shell tanpa strategi update
- Prefetch opsional setelah user idle di halaman yang relevan (bukan di first paint homepage)
- 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:
- Cetak
model.getInputDetails()danmodel.getOutputDetails() - Cocokkan rank, dtype, min/max range (0–1 vs 0–255 vs ImageNet mean/std)
- Cek layout NCHW vs NHWC — ini klasik bikin skor acak tapi “kelihatan meyakinkan”
- Bandingkan satu sample fixed (gambar synthetic atau fixture) vs baseline Python/
tfliteinterpreter - 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 (webgpudefault,wasmfallback) - 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
-
loadLiteRtsukses 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
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:
packages/ai-runtime/
loadRuntime.ts
pickAccelerator.ts
modelRegistry.ts
preprocess/
telemetry.ts
apps/storefront/
apps/seller-web/
Isi modelRegistry idealnya deklaratif:
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:
- Load & compile di Worker (atau path setara) kalau alur memungkinkan.
- Main thread cuma kirim input ringkas (ImageBitmap / ArrayBuffer) dan terima hasil angka/label.
- Batasi antrean: satu job aktif + satu pending; sisanya drop atau coalesce.
- Jangan fire inference tiap frame kamera tanpa throttle (16 ms vs 200 ms beda banget soal panas & baterai).
Contoh kontrak pesan yang simple:
// 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:
- Artifact imutabel:
product-scan-3.2.0.tflite+ checksum. - Canary: 1–5% traffic internal / user flag.
- Guardrail otomatis: distribusi top-1 label, rate low-confidence, rate fallback server.
- 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):
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:
- Attach rate: % sesi yang berhasil load runtime + model.
- Fallback rate: % pindah ke server / path manual.
- p95 runMs per accelerator (
webgpuvswasm). - Effective accuracy proxy: % hasil diterima user (bukan cuma top-1 model).
- 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