Seeking entry-level Data Science / Software Engineering roles

RésuméContact

ML Lab

Two convolutional networks, trained by me, running entirely in your browser: no server, no API, just ONNX and WebAssembly. Play Pictionary against the doodle model, then scroll down to see exactly how the digit model reads your handwriting, and peek at how both were built.

Doodle Duel

Pictionary against my model

6 prompts, 20 seconds each. Draw, and the CNN guesses live as the strokes land.

Round 1/6

The model was trained on over a million human doodles across 75 everyday objects, and the game only prompts the ones it proved most reliable at. It sees the same 28x28 image pipeline as the digit lab below, roughly 40 times a second while you draw.

Digit lab

The classic: draw a digit, or a whole number like 42, and watch the CNN score every stroke. Multi-digit numbers are split into per-digit images (leave a little space between digits), and the small grid shows exactly what the model receives after cropping, scaling, and centering, the same construction MNIST itself used. Trained on MNIST, so plain 1s and uncrossed 7s work best.

Loading the model (about 2 MB, runs entirely in your browser)...

Waiting for ink

What the model sees

Digit X-ray

The digit model again, but with its skull open: draw one digit and every panel updates with the real tensors flowing through the network in your browser, not an illustration. Follow the drawing through two rounds of convolution and pooling into the 128-number summary the classifier reads. Click any map to inspect it; on conv1 you also get the 3×3 kernel that produced it.

input · 28×28

What the network receives after the crop, scale, and center steps. One digit at a time here; the digit lab above handles whole numbers.

conv1 · 32 maps · 28×28

Each map is one 3×3 kernel slid across the whole drawing. Bright pixels mean the kernel matched the ink there: edges, stroke directions, pen endings.

pool1 · 32 maps · 14×14

Max-pooling keeps the strongest response in every 2×2 patch and halves the resolution. Exact stroke position starts to matter less than stroke existence.

conv2 · 64 maps · 14×14

Kernels here read all 32 pool1 maps at once, so they light up on combinations: corners, junctions, the opening of a loop.

pool2 · 64 maps · 7×7

The last picture-like tensor in the network. After this it is flattened into 3,136 numbers and handed to the classifier.

features · 128 numbers

The whole drawing compressed to the vector the final layer actually reads. The teach-your-handwriting panel in the digit lab trains on exactly this.

softmax · 10 probabilities

Green outline marks the busiest map in each layer, coral the one you selected. Layer maps are normalized per layer, so a nearly black map really is contributing little for this drawing.

Next door: the Attention Lab

CNNs are half the story. I also trained a small GPT from scratch on Shakespeare and exported its attention weights, so you can type a sentence and watch every head decide which characters to read. Same deal as this page: in your browser, no server.

Open the Attention Lab →

Under the hood

Both models are small convolutional networks I trained in PyTorch and exported to ONNX; inference runs in your browser through onnxruntime-web (WebAssembly), so nothing you draw ever leaves the page. The training code, notebooks, and evaluation gates live in the sketch-lab repo.

Doodle model

75 everyday objects, 13,500 training sketches each from the Quick, Draw! dataset. The game only prompts the 37 categories with the strongest measured robustness to real drawings; the rest are free-draw only.

Test accuracy
85.3%
Parameters
841k
ONNX size
3.4 MB
Canvas robustness
83.6%
Architecture
  1. Conv 3x3, 32 ch + ReLU + MaxPool 2x2
  2. Conv 3x3, 64 ch + ReLU + MaxPool 2x2
  3. Dropout 0.25
  4. FC 3136 to 256 + ReLU
  5. Dropout 0.5
  6. FC 256 to 75 + Softmax (in graph)

Input: 28x28 grayscale, [0,1], ink = 1. Normalization and softmax are baked into the ONNX graph (opset 17), so the browser sends raw ink. Trained 2026-08-21 with PyTorch 2.13.0, best of 8 epochs.

Doodle model: training and test loss and accuracy per epochDoodle model: test-set confusion matrix

Training notebook · sketch-lab on GitHub

Digit model

MNIST digits with affine and elastic augmentation for mouse-drawn strokes.

Test accuracy
99.4%
Parameters
422k
ONNX size
1.7 MB
Canvas robustness
99.2%
Architecture
  1. Conv 3x3, 32 ch + ReLU + MaxPool 2x2
  2. Conv 3x3, 64 ch + ReLU + MaxPool 2x2
  3. Dropout 0.25
  4. FC 3136 to 128 + ReLU
  5. Dropout 0.5
  6. FC 128 to 10 + Softmax (in graph)

Input: 28x28 grayscale, [0,1], ink = 1. Normalization and softmax are baked into the ONNX graph (opset 17), so the browser sends raw ink. Trained 2026-08-21 with PyTorch 2.13.0, best of 12 epochs.

Digit model: training and test loss and accuracy per epochDigit model: test-set confusion matrix

Training notebook · sketch-lab on GitHub

Doodle model trained on the Quick, Draw! dataset by Google Creative Lab, licensed CC BY 4.0.