midnight-static / docs /FINETUNE.md
cajpany's picture
Upload folder using huggingface_hub
fc9b7e2 verified
|
Raw
History Blame Contribute Delete
4.2 kB
# FINETUNE.md β€” `midnight-static-writer` LoRA
Goal: Nemotron 3 Nano 4B that writes *idiomatic, performable* radio scripts
in our schema on the first try. Guided decoding already guarantees validity;
the LoRA buys genre voice, pacing, castability, and SFX/music prompt quality.
## Dataset spec
- **Size**: 400 examples. 60 per genre Γ— 6 genres + 40 adversarial.
- **Format**: chat SFT β€” `[system: writer prompt w/ genre pack][user: premise]
[assistant: schema-valid JSON]`. Assistant turn is raw JSON, no markdown
fences (the runtime never sees fences; don't train them in).
- **Premise diversity** (per genre, roughly even):
- object-centric ("a phone that only receives calls from 1962")
- relationship-centric ("two rival lighthouse keepers, one light")
- place-centric ("the last petrol pump before the salt flats")
- one-word premises ("static", "monsoon") β€” users will do this
- overlong rambling premises (train truncation-to-essence behavior)
- **Adversarial 40**: premises that tempt rule-breaking β€” real celebrity
names (writer must genericize), gore-bait (must go atmospheric), requests
for 10-minute epics (must compress), non-English premises (Hinglish for
RAAT, translate-then-write otherwise).
- **hindi_melodrama**: dialogue in romanized Hinglish ONLY (Kokoro constraint).
Filmi idiom: "Kasam khao!", interrupted weddings, lost-and-found lockets.
## Generation procedure (Codex-attributed β€” this is prize evidence)
1. `modal/gen_dataset.py` drives generation: golden fixture for the genre as
the style exemplar + premise from a seeded premise bank (write ~70
premises/genre by hand+Codex; cheap, high-leverage).
2. Generator model: anything goes at dev time (no param cap on tooling) β€”
use the strongest model available to you; quality of training data is
the single biggest lever in this project.
3. **Validation gauntlet** (auto-reject):
- `Script.model_validate()` + cross-field checks from SCHEMA.md
- runtime estimate 55–95s
- voice-roster distinctness: no two cast members share a VoiceID
- banned-content regex (slurs list, explicit terms)
- dedupe: title trigram overlap <0.6 vs accepted set
4. **Human pass**: skim 5 random samples/genre. You are checking for
*performability* β€” read a scene aloud. If it's stilted, fix the genre
pack prompt, regen that genre. Budget: 45 minutes, no more.
5. Publish dataset to HF Hub (`ik-labs/midnight-static-scripts`) β€” this is
the "Sharing is Caring" bonus criterion and blog material.
## Training runbook (`modal/finetune.py`)
- **Framework**: Unsloth, QLoRA 4-bit base, LoRA r=16, alpha=32,
dropout=0.05, target modules: q,k,v,o,gate,up,down projections.
- **Hyperparams**: 3 epochs, lr 2e-4 cosine, batch 8 (grad-accum to fit),
max_seq_len 4096, packing off (examples are whole conversations).
- **Hardware**: Modal A100-40GB, expected wall time ≀45 min, cost β‰ˆ a few
dollars of the $250 credit.
- **Outputs**: LoRA adapter β†’ HF Hub `ik-labs/midnight-static-writer`
(public β€” Bonus Quest "Well-Tuned" criterion) + merged fp16 checkpoint
pushed privately for vLLM serving (vLLM can serve base+adapter too;
merged is simpler on ZeroGPU β€” decide by what cold-starts faster).
## Eval (30 minutes, not a research project)
Hold out 5 premises/genre (never in training). For base vs LoRA, score:
1. **Validity-unassisted**: generate WITHOUT guided decoding; % parseable.
(Proxy for how hard the grammar must fight the model. LoRA should
roughly double base.)
2. **Performability spot-check**: render 6 broadcasts (one per genre)
end-to-end; listen. Ship/no-ship is a vibe call β€” you have ears.
3. **Roster discipline**: % scripts using β‰₯2 distinct deliveries and a
narrator-type. LoRA target β‰₯80%.
If LoRA underperforms base on listening test β†’ ship base + grammar, keep the
published dataset/adapter for the Bonus Quest narrative, and say so honestly
in the blog (negative results are good Field Notes content).
## Day-1 dependency
VoiceID enum must be verified against installed Kokoro voices BEFORE dataset
generation. The LoRA memorizes the roster; a renamed voice after training =
silent miscasting forever.