โ˜บ

Expression Reader

Teach a classifier your face โ€” in about ten seconds.

Video never leaves this tab 52 blendshapes โ†’ 5 classes Source โ†—
Live demo A classifier has already trained on synthetic blendshape data below โ€” real gradient descent, real held-out accuracy. Turn the camera on to retrain it on your own face.

1

Training

Loss and held-out accuracy, per epoch early stopping keeps the best-validating weights, not the last ones

Confusion matrix where the mistakes actually go โ€” more informative than the accuracy above

2

Record your own expressions

Turn the camera on, then hold each face for a couple of seconds. Forty frames per expression is plenty. It retrains automatically once two classes have samples.

?

How it works

The features are already good

MediaPipe returns 52 blendshape scores per frame โ€” how open the jaw is, how raised the left brow is, how far each mouth corner has pulled. That is a well-engineered 52-dimensional feature vector arriving at 30 frames a second, and it turns expression recognition from a computer vision problem into a plain supervised classification problem.

So the model can be small โ€” and hand-written

A multinomial logistic regression, trained with Adam, written from scratch. No TensorFlow.js, no autograd. The gradient of cross-entropy through a softmax is (p โˆ’ y), which is one line, and the whole thing trains in well under a second on a few hundred samples.

Why there is a rule baseline

The baseline is a hand-written mapping โ€” smile blendshapes mean happy, brow down means angry โ€” and it is labelled as rules everywhere it appears. Its job is to be the thing the trained model has to beat. Without a baseline, "84% accurate" is a number with no scale attached to it.

It refuses to learn from noise

Trained on 240 random vectors with random labels, the classifier reaches 42.8% on the training split and 31.7% held out โ€” against a 33% chance baseline. It memorises the training data and generalises not at all, which is exactly what it should do, and is why the held-out split exists. There is a test asserting it.