lowestcase-uppestcase
PyTorch recreation of Tom Murphy VII's "Lowestcase and uppestcase letters: Advances in derp learning" (SIGBOVIK 2021, http://tom7.org/lowercase/lowercase.pdf, video: https://youtu.be/HLRdruqQfRk).
Two small CNNs (~0.3M params each) map 64×64 glyph signed distance fields between cases:
make_upper.pt: lowercase → uppercasemake_lower.pt: uppercase → lowercase
Trained on programagor/lowestcase-glyphs-sdf (320 Google Fonts, glyphs normalized to a 48×48 active area, small-caps fonts filtered out by uppercase≈lowercase IoU).
Loss
Paired L1 on real font pairs plus Tom's cycle trick: make_upper(x) (computed without gradient) becomes a training target for make_lower, and vice versa — each model learns to invert whatever the other currently does, which is what extends the concept below lowercase. No discriminator (CycleGAN minus the critic). Adam 2e-4, batch 64, 20,000 steps, cosine LR, single T4 (~2h17m). Final validation L1: 0.063 / 0.062. Note: the output head is linear — a sigmoid there saturates and both nets collapse to constant images.
What the models do when iterated (generations/)
- ↓ (make_lower iterated): a lowercase glyph first blobs, then shrinks monotonically toward a stable speck of dust — the lowestcase (ink fraction 0.33 → 0.018 over ~300 steps; see
lowest_*_abs.pngfor absolute scale). - ↑ (make_upper iterated): the glyph snaps into A/R/K-like forms and keeps wandering in a bounded orbit (ink ~0.06–0.08) without locking into a clean cycle within 400 steps — qualitatively Tom's limit-cycle behaviour, minus the clean period lock.
generations/ holds binarized zoomed galleries (lowest_a..z, uppest_a..z for a e g n s z), absolute-size strips, and manifest.json with per-iteration ink fractions.
Interactive demo: https://huggingface.co/spaces/programagor/lowestcase-uppestcase-demo
- Downloads last month
- 70