The model ships in your browser
A note from my master's thesis. The winning classifier was 1.3 MB, and that one number decided the architecture — no server, no data leaving the device, and a cloud bill of zero. For this problem, where a model runs turned out to matter more than which model it was.
Serving a fine-tuned DistilBERT on a dedicated GPU runs about $3,000 a year — one instance, list prices, at the volume this thesis models. In that benchmark, the money bought a model that tied on clean data and lost by 5.7 F1 points on noisy data. So the interesting question stopped being which model and became where it runs.
The model that won — a linear classifier on TF-IDF — exports whole to ONNX, the open format the Linux Foundation maintains. The entire pipeline goes into one graph: tokenization, n-grams, TF-IDF weighting, the classifier. Input a raw description, out comes a category. The file is 1.3 MB.
Small enough, and standard enough, that it doesn't need a server. It runs in the browser through ONNX Runtime Web, on WebAssembly. Load the page, the model comes down with it, and classification happens in the tab. Three things follow from that, and none of them is about accuracy.
1 · The cloud bill is zero
Inference runs on the user's device, so the marginal cost of classifying a transaction is nothing. You pay to host a few static megabytes — which every provider serves free — and that's the line. It doesn't bend when traffic grows.
Read those as a thesis cost model, not a price list: one GPU instance, published rates, a fixed volume. What matters is the shape of each line, not the size of the number. Scale the workload up and every column grows — the GPU line multiplies with instances, the browser line stays flat at zero — and the GPU is still serving the model that came second on noisy data. At $3,000 the absolute figure is small; the point is that you pay it for negative accuracy.
2 · The data never leaves
A bank statement is about as personal as text gets — it leaks where you shop, what you earn, your health through the pharmacy line. Because inference is local, none of it is transmitted or stored. GDPR data minimization stops being a retention policy you promise to honor and becomes a property of the architecture. There's no server log to leak, because there's no server.
3 · The deployment is reversible
The same .onnx file runs in the browser, in Python, in Node, on the JVM. If volume ever forced a server-side API — integration with a third party, say — that's a change of runtime, not a change of model. No retraining, no reimplementation. You move the exact binary you already evaluated.
Where you run the model had more consequences than which model you ran.
Verify, don't assume
Exporting a model risks a different failure, one with no symptom: the deployed artifact stops matching the one you evaluated, and nothing tells you. The app keeps returning plausible answers while your metrics describe a model that's no longer running.
So the equivalence is checked, not trusted. The first export reproduced 99.95% of the original predictions — and that 0.05% wasn't rounding. It was descriptions where cleaning leaves single-character tokens — H-E-B, H&M — that scikit-learn drops and the graph kept. A silent divergence, caught only because I looked. Now the app re-runs 60 reference cases on every load and shows the result: 60 of 60, identical.
An exported model's equivalence is verified, not assumed. A wrong model that returns plausible answers has no symptom.
The same call, with a clean frame around it
This is a thesis, so read it as one: a scoped comparison on a defined problem, not a template to paste onto every system. None of it says "always run in the browser." It works here for one reason — the model is 1.3 MB, and it's that small because the previous stage showed a linear model already solves this particular task, short and separable transaction text, as well as anything larger. Put a model too big to run on the device behind a heavier workload and every line above flips. The architecture followed the finding; it didn't lead it.
This is the decision I make on production systems, just handed to me with an academic bow on top. The cheapest place to run inference that clears the bar wins — and "clears the bar" includes latency, privacy, and the bill that arrives on every request, forever. A 1.3 MB model let me put all of it on the device. A transformer 356× the size never could have.
What in your stack is sitting on a server only because nobody asked whether it needed to be?