A couple of weeks ago, I revisited an old project: a face mask classifier I originally built in Keras.
In my last article, I retrained it three different ways:
✅ Classic deep learning (TensorFlow inside SageMaker Studio)
⚙️ Low-code SageMaker Canvas
🧠 Fully managed Rekognition Custom Labels
This time, I wanted to see if I could make the model run entirely in the browser. Not just for fun, but because it felt like a win on multiple fronts: it would remove backend inference costs since there’d be no server running 24/7; keep the webcam feed local to the user’s machine, improving privacy; and create a live demo anyone could try instantly, without waiting on an API call or spinning up infrastructure.
Here’s how that turned out, and why it was trickier than I first thought.
⚙️ Step 1: Converting my Keras model for TensorFlow.js
My original classifier was trained in SageMaker Studio, saved in the latest Keras v3 format.
Problem: TensorFlow.js only supports converting the old Keras v2 .h5 format.
So the first thing I had to do:
Retrain the model (same code, but explicitly save it to .h5)
Use the CLI:
tensorflowjs_converter \
--input_format keras \
my_model.h5 \
./model_web/
That produced a browser-ready model.json + weight files.
Loading it in JS was simple:
const model = await tf.loadLayersModel('/model_web/model.json');
This felt like a small win — but the model only takes cropped face images.
Next problem: how do I detect faces?
📦 Step 2: Adding face detection
In the original pipeline, I used a YOLOv3 model to detect faces, then classified them.
But YOLOv3 is heavy for browser use.
I needed something smaller, that worked in TensorFlow.js.
Luckily, TensorFlow.js has some pretrained lightweight face detectors.
I picked one, tested it on the webcam stream, and it worked surprisingly well:
Detect faces → crop → run classifier → draw predictions
All in real time.
Suddenly, I had a browser app that could see your face and tell if you were wearing a mask — without sending anything to a server.
🚫 Honorable Mention: Why Canvas & Rekognition models didn’t make it
At this point, I was hoping I could also bring over the models I built in SageMaker Canvas and Rekognition to run directly in the browser. But pretty quickly, I ran into hard limits: SageMaker Canvas only lets you export a model meant for Python or TensorFlow Serving, with no option to get a .h5 or SavedModel that I could convert for TensorFlow.js; and Rekognition Custom Labels doesn’t let you download the trained model at all — it’s locked behind AWS’s API. Since the whole goal was to keep everything frontend-only and client-side, these two paths just didn’t fit. It was a good reminder that the more managed and abstracted a tool is, the less portable your model ends up being.
🧰 Step 3: Building the demo & making it repeatable
With the model running locally in the browser, I wanted to take the next step: actually host it online so anyone could try it, and make deployments effortless. To do that, I built a small React frontend that grabs the webcam feed, detects faces, runs the mask classifier, and draws the predictions on screen in real time. Then I wrote some Terraform to handle the infrastructure: provisioning a public S3 bucket for static hosting, a CloudFront distribution for global CDN, and IAM roles to support CI/CD. Finally, I set up GitHub Actions so that every time I push to the repository, it automatically builds the site and deploys it to S3.
Now it’s fully repeatable:
terraform apply
And it’s live.
✅ Wrapping it up
In the end, what started as an old Keras side project turned into a modern, privacy‑friendly browser demo — running real‑time face detection and mask classification entirely on the client. To clean up the frontend, I rebuilt it using Solid.js for fast reactivity, styled it with Tailwind CSS and daisyUI, and added subtle animations with auto‑animate and solid‑transition‑group to make the UI feel more alive.
I even tried to get it working on mobile devices, but ran into a familiar wall: the model was just too big to run smoothly in the browser on most phones. At that point, training a new, smaller model felt like it deserved to be its own project — and I decided to leave it for another day.
Still, I’m happy with how it turned out: a repeatable, low‑cost, fully frontend ML demo that anyone can try without sending a single frame to a backend. And while it’s not production‑ready, it’s proof that with the right tools and some cloud glue, you can bring even an old deep learning project back to life — and make it feel brand new.
If you’ve tried something similar, run into the same Keras/TensorFlow.js headaches, or have ideas on building lighter models for mobile, I’d love to hear about it in the comments!
You can try the live demo here → Face Mask Classifier Demo, and if you’re curious about my other projects, check out my portfolio at retanatech.com.
Top comments (0)