grinpress ๐Ÿ—ž๏ธ๐Ÿพ

woof woof! hot off the press: tiny inky faces, freshly fetched :3

hiii, welcome to grinpress! it's a smol (33.86M params) text-to-image model, trained totally from scratch with rectified flow right in pixel space ๐Ÿพ. you tell it a color, a mood, and a lil word, and it barks back a 128ร—128 vintage-newspaper halftone face with your word stamped beside it, all inky and smudgy on old yellowed newsprint. bark! :3

a red smiley face with 'HELLO' next to it

final sample

๐ŸŽฎ try it live: huggingface.co/spaces/skyuu72/grinpress-demo (ZeroGPU, about 1 s per batch!) ๐Ÿพ

made with lots of tail wags by the puppygirl CEO of Quantara (quantara.cv) ๐Ÿพ๐Ÿ’›

Model ๐Ÿง ๐Ÿพ

part params details
U-Net 32.23M levels 128/64/32/16 with channels 64/128/192/256; 2 ResBlocks per level; AdaGN timestep conditioning (sinusoidal embedding into an MLP); self-attention and masked char-level cross-attention at the 32/16 levels and in the mid block
Text encoder 1.63M ASCII byte tokenizer (max 64 chars, full caption); learned embeddings + sinusoidal positions; 2-layer transformer (d=256); 10% CFG dropout to a learned null sequence
Total 33.86M see config.json

Flow: x_t = (1-t)ยทx0 + tยทฮต (t=0 is data, t=1 is noise). The network predicts v = ฮต โˆ’ x0 and is trained with MSE, with t sampled logit-normal. Sampling uses Euler integration from t=1 to t=0 with classifier-free guidance v = v_u + sยท(v_c โˆ’ v_u).

Training ๐Ÿ‹๏ธ๐Ÿพ

  • Data: 50k procedurally generated 128px images (generate_data.py): aged newsprint, a halftone face in one of 12 colors, a smiley/sad/meh expression, and 1โ€“8 characters of wood-type/serif text with ink bleed and distressed edges.
  • Schedule: 60k steps at batch 64. AdamW at lr 2e-4 with 1k warmup steps, then cosine decay. bf16 autocast and EMA (0.9999). The released weights are the EMA weights.
  • Hardware: a single A100 on Google Colab, about 7 h wall clock including 2 resumes from checkpoint.

Training progression (watch the pup learn!) :3

Fixed prompts and seeds at each checkpoint. Rows: red smiley 'HELLO', blue sad 'NEWS', green meh 'OK', yellow smiley 'XQ7'.

5k 20k 40k 60k

A fresh sample from the released weights (a pink sad face with 'HEY' next to it, 50 steps, CFG 5) ๐Ÿพ:

v1 sample

Every grid, saved every 5k steps, is in samples/. Layout and color settle early, and later steps mostly sharpen the letterforms; random strings like 'XQ7' are clearly cleaner at 60k.

Prompt format ๐Ÿฆด

a {color} {expression} face with '{text}' next to it
  • color: red, orange, yellow, green, teal, blue, navy, purple, pink, brown, gray, cyan
  • expression: smiley, sad, meh
  • text: 1โ€“8 ASCII characters (trained mostly on uppercase words and random letters/digits)

sample.py checks the prompt with a regex and gives a helpful error when it doesn't match.

Usage ๐Ÿพ

pip install torch numpy pillow opencv-python-headless
python sample.py --prompt "a pink sad face with 'HEY' next to it" \
    --checkpoint ema_final_bf16.pt --cfg_scale 5.0 --steps 50 --seed 0 --num_images 4 --out out.png

sample.py loads the ema entry of the checkpoint. Weights: ema_final_bf16.pt (about 68 MB, bf16 EMA; the loader upcasts it) and model.safetensors (the same bf16 EMA tensors, flat keys). woof, pick whichever you like! :3

Python:

import torch
from model import build_model
from sample import sample, parse_prompt
m = build_model().eval()
m.load_state_dict({k: v.float() for k, v in torch.load("ema_final_bf16.pt", map_location="cpu")["ema"].items()})
x = sample(m, parse_prompt("a teal meh face with 'OK' next to it")[3], 128, 50, 5.0, 0, "cpu")  # [-1,1]

Or with safetensors (pip install safetensors):

python sample.py --prompt "a navy smiley face with 'WOOF' next to it" --checkpoint model.safetensors --out woof.png

Training from scratch: see smiley_flow_colab.ipynb (it resumes from Drive across disconnects), or run_pipeline.sh.

Inference speed ๐Ÿ’จ

setup 50 steps + CFG (100 forward passes)
CPU, 8-thread Xeon, fp32 (measured) 26.8 s/img (25 steps: 13.3 s); peak RAM about 0.9 GB
A100, bf16 (estimate) about 0.5โ€“1 s/img at batch 1; about 15โ€“20 img/s batched
L4 (estimate) about 1โ€“1.5 s/img; about 6 img/s batched
T4 (estimate) about 1.5โ€“2.5 s/img; about 3 img/s batched

A single forward pass is 66.1 GFLOPs at 128px (measured with the torch FLOP counter). The GPU numbers are estimates assuming 30โ€“35% of peak throughput; they were not measured.

Limitations (she's a good girl, but...) ๐Ÿถ

  • Only the fixed procedural domain: one face plus a text string on newsprint. It is not a general-purpose image model.
  • Only 1โ€“8 characters of text and only the 12 trained colors. Prompts outside the template are rejected.
  • Letters are occasionally smudged or malformed, especially in long random strings and lowercase text.
  • 128px only. The code supports 256px, but these weights were not trained at that size.

License ๐Ÿ“œ๐Ÿพ

MIT. The fonts used to generate the training data are downloaded at runtime under their own OFL/Apache licenses and are not included.

arf arf, thanks for visiting! go make some inky lil faces :3 ๐Ÿพ๐Ÿ—ž๏ธ

Downloads last month
17
Safetensors
Model size
33.9M params
Tensor type
BF16
ยท
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ Ask for provider support

Space using skyuu72/grinpress 1