← all posts
// efficiency · overfitting

Recognize local fine-tuning overfit early

So the loss curve keeps dropping and everyone treats that as permission to ship the adapter. It isn't. A small fine-tuning set gives every repeated example and narrow template outsized pull on the output, and a falling number can't tell you whether the model learned the task or memorized your prompts. Before touching a launch flag, decide what "improve" means: latency, jobs per hour, resident model capacity, energy per task, fewer corrections downstream. Picture a LoRA pass tightening structured domain responses on a home rig. "Faster" alone gives no stopping point, and the loss chart keeps falling long after the adapter stops generalizing beyond what you showed it.

the eval set has to argue back

Pin everything first: model artifact, tokenizer, prompt template, runtime build, launch command, sampling settings. Build the eval set from the real workload, awkward cases included; run once cold if users hit that path, then warm long enough to expose cache effects, queueing, thermal drift. Check held-out task success, paraphrased prompts, refusal shifts, and untouched capabilities for quiet regressions. Record phase timings, not one total: queue wait, model load, prefill, first token, decode rate, memory, power, retry or repair rate. Raw token speed is a diagnostic: automation cares about completed records per hour, coding cares about review time, chat cares about p50 and p95 first-token latency on realistic prompts. A setup that wins a short warm benchmark can lose the day once model swaps and long contexts arrive.

the runtime is too forgiving to trust

The quiet failure is picking the checkpoint with the lowest training loss and calling it done. Local runtimes are almost too accommodating: they offload layers, page memory, eat a cache miss, queue a request, or drop to a generic kernel rather than fail loudly, hiding a degraded configuration from you. Read the logs, check where tensors landed, and confirm the optimization is active for the shapes and context lengths in use.

Change one variable at a time unless comparing whole systems, and keep outputs, not just metrics: quantization, context compression, sampling, model swaps can shave time off the clock while changing the answer underneath. Run the quality gate on every candidate, not just the config you liked on vibes. A shorter answer needs a completeness check, not applause; a faster extractor needs a count of valid records, not parseable braces.

Weigh operational cost: startup, upgrades, observability, rebuilding the box after a disk dies. A five-percent gain riding on an undocumented patch or manual cache-warming is a bad trade for anything shared. Boring configurations age well.

Stop at the checkpoint that generalizes across wording and still passes the base capabilities you didn't retrain. Write the decision down with the workload and date, and name the retest trigger: a new model family, a driver update, a different traffic mix. Skip that and old numbers turn into folklore. Leave headroom once you clear the target: free memory for prompt variance, spare queue capacity, thermal margin against throttling.

A falling loss number is a rumor, not a verdict, until the held-out set corroborates it.

One rule, if you keep only one: never promote a checkpoint on training loss alone.

#overfitting#lora#evals