A CNN trained on MNIST served through a Flask API with a live HTML5 canvas UI.
digit-recognizer/
├── train_model.py ← Train CNN, saves mnist_model.h5
├── app.py ← Flask backend (serves UI + /predict API)
├── requirements.txt ← Python dependencies
└── templates/
└── index.html ← HTML5 canvas frontend
pip install -r requirements.txtpython train_model.py- Downloads MNIST automatically (~12 MB)
- Trains for up to 15 epochs with early stopping
- Target accuracy: 99%+
- Saves →
mnist_model.h5 - Time: ~5 min CPU · ~1 min GPU · ~2 min Google Colab
python app.pyOpen → http://localhost:5000
| Route | Method | Body | Response |
|---|---|---|---|
/ |
GET | — | HTML UI |
/predict |
POST | {"image": "<base64 PNG>"} |
{"digit": 7, "confidence": 0.99, "all_confidences": {...}} |
/health |
GET | — | {"status": "ok", "model_loaded": true} |
Input (28×28×1)
└─ Conv2D(32, 3×3, relu) + BatchNorm
└─ Conv2D(32, 3×3, relu) + MaxPool(2×2) + Dropout(0.25)
└─ Conv2D(64, 3×3, relu) + BatchNorm
└─ Conv2D(64, 3×3, relu) + MaxPool(2×2) + Dropout(0.25)
└─ Flatten
└─ Dense(256, relu) + BatchNorm + Dropout(0.5)
└─ Dense(10, softmax)
- Draw large, centered digits that fill most of the canvas
- Use a smooth, consistent stroke
- Accuracy drops for tiny or off-center digits (like real MNIST training data)
!pip install flask flask-cors pillow pyngrok
# After training:
from pyngrok import ngrok
import subprocess, threading
def run():
subprocess.run(["python", "app.py"])
threading.Thread(target=run, daemon=True).start()
public_url = ngrok.connect(5000)
print("Public URL:", public_url)