Not Hotdog
A 136,416-parameter int8 CNN that decides whether an image is a hot dog,
built to run in a browser with hand-written JavaScript kernels and no
dependencies of any kind.
Results
Measured on the int8 model — the one that actually ships — not on the float
checkpoint.
| Split | n | accuracy | majority baseline | F1 | precision | recall |
|---|
| test | 3415 | 94.8% | 92.6% | 0.634 | 0.661 | 0.609 |
| adversarial | 150 | 81.3% | 90.7% | 0.176 | 0.150 | 0.214 |
The adversarial split is six classes held out entirely from training:
| class | correct | accuracy |
|---|
bratwurst | 34/40 | 85.0% |
chili_dog | 3/12 | 25.0% |
corn_dog | 8/10 | 80.0% |
dachshund | 40/40 | 100.0% |
hot_dog_bun | 31/40 | 77.5% |
hot_dog_wild | 0/2 | 0.0% |
sausage_roll | 6/6 | 100.0% |
Read F1, not accuracy. The evaluation sets are heavily negative, so predicting
"not a hot dog" unconditionally already scores the majority baseline above.
Architecture
96x96x3 input, MobileNet-style depthwise-separable stack, ReLU only, global
average pool, one logit. 14.0M MACs.
- weights: int8, per-output-channel symmetric, zero-point 0
- activations: uint8, per-tensor symmetric, zero-point 0
- accumulators: int32, requantized with a fixed-point multiply and shift
Trained by distilling a fine-tuned EfficientNet-B0 (T=4, alpha=0.7), then
quantization-aware training with BatchNorm folded into the convolutions.
Files
| file | what it is |
|---|
model_int8.npz | weights + layer graph, read by the NumPy reference |
model.js | the same weights, base64, as an ES module |
hotdog.js | the complete bundled engine — drop it in a page |
Limitations
Small model, and not subtle. Good at obvious hot dogs and obvious non-food,
much weaker at the boundary, which is what the adversarial numbers show. Clean
licence-clear hot dog images are scarce; positives were the binding constraint
throughout.
Licence
MIT.