Arjhine Ty

I scaled my training data 10x. My model got worse at saying it didn't know something.

Two of my own bugs caused that regression, not the model — and there was a third, real one hiding underneath them

Arjhine Ty

Arjhine Ty

August 15, 2026 · 5 min read

I scaled my training data 10x. My model got worse at saying it didn't know something.

The number that looked wrong

I run small-mind-companion as a real research project, not a demo: a small multimodal companion model, stretched through external memory, hybrid retrieval, and LoRA SFT→DPO post-training. The whole premise rests on one metric — does the model know when to say "I don't know" — so when I scaled the training data 10x (40 personas, 2242 SFT examples, 2277 DPO pairs, up from 202), that number is the first thing I checked.

It got worse. False-abstention on questions the model could actually answer went up, not down, after 10x more training data. That is backwards. More data making a calibration metric worse is the kind of result that either means something real and interesting, or means something in my pipeline is lying to me. I did not know which yet, so I did not write either conclusion down and went looking.

Bug one: a dedup step that ate 227 examples

The data-generation script runs a dedup pass before anything goes into the training set — sensible in general, wasteful duplicate examples don't help a model learn anything. The dedup was text-based: exact-match on the generated response string.

Abstention examples are, by design, templated. "I don't have any記録 of that" and its siblings look nearly identical across many different underlying questions, because the point of an abstention example is to teach a consistent shape of refusal, not memorize 227 different sentences. To a text-exact dedup pass, that consistency looks like 227 duplicates of the same example. It collapsed roughly 227 intended abstention training examples down to 1.

Scaling the data 10x didn't just fail to help abstention training — it deleted almost all of it, silently, before training ever started. Nothing downstream would have caught this on its own: the training run completes, the loss curves look normal, and the eval score is the only place the damage shows up — as a regression that looks like it came from more data, when it actually came from less.

Bug two: my own eval harness couldn't see the fix

Fixing the dedup step should have been the end of it. It wasn't. Retraining still showed the calibration regression, which meant either the fix didn't work or something else was also broken. I went and read actual model outputs instead of trusting the aggregate number a second time, and found the model had changed — its abstention phrasing was different from the v0 checkpoint's, and my rule-based abstention detector was matching against the old phrasing. It didn't recognize the model's new, correct refusals as refusals at all, so it scored them as wrong answers.

Two bugs, found in sequence, each hiding behind the other: a data bug that looked like a training regression, and an eval bug that made the fix for the data bug look like it hadn't worked.

Bug three, found only after the first two were gone

With both fixed, the model's real behavior was finally visible — and it had over-corrected. Freed from the dedup bug and scored by a detector that could actually see its new phrasing, the model was now hedging on questions it should have answered directly. A different problem, real this time, and only visible once the two upstream bugs stopped hiding it. Fixed separately, by rebalancing the ratio of abstention-to-answerable examples in the training data rather than touching the detector or the dedup step again.

Three real, sequential root causes, each one confirmed by reading actual model outputs rather than trusting an aggregate score — not one investigation that happened to turn up three unrelated things.

Where it landed

At 10x data scale, UAR reached 70.0% — 2x the v0 baseline of 33.75% — with false-abstention on answerable questions cut to 32.1% once all three bugs were fixed. DPO on top of that scale produced the cleanest preference-optimization signal anywhere in the project: a 24.7-point pairwise win-rate gap (45.7% vs 21.0%). On-policy distillation from a larger local teacher on top of the best checkpoint added another 3.3 points of pra_lenient (15.3%→18.6%) with UAR held flat — no new calibration regression, this time for real. Current best checkpoint: onebee-gf-distill-v1.

An old habit that caught a different bug

This was not the only time a metric that looked too good turned out to be wrong instead of right. Earlier in the project, a zero-context baseline — the model with no memory access at all — scored roughly 94% on personalized-recall questions. A model with no way to know the answer scoring 94% on recall is definitionally impossible, which is what made it a bug signal instead of a result worth reporting: a Python operator-precedence bug in a string-concatenation expression was silently dropping the gold answer from the judge's rubric whenever a probe had no listed alternatives, which was the common case.

Same discipline both times: an unusually good or unusually bad number is a reason to go read what the model, or the harness, actually did — not a reason to write the number down and move on.

What I'd tell you

  1. A calibration metric getting worse after more training data is not, on its own, evidence the extra data was bad. It is evidence something upstream of the metric changed. Check the data first.
  2. Dedup on generated text is dangerous for anything meant to be templated. Abstention, refusals, safety responses — anything whose whole point is a consistent shape will look like duplicates to an exact-match dedup pass.
  3. An eval harness can go stale the moment the model it's grading changes correctly. A detector tuned to one checkpoint's phrasing can silently misgrade the next checkpoint's better behavior as a regression.
  4. Fixing a regression can uncover a real one underneath it. Don't stop investigating at the first fix that makes the number move in the right direction.

What this doesn't show

This is the abstention side of one 10x scale-up, on one benchmark, with checkpoints that are still being iterated on — not a general claim about dedup strategies or eval harnesses beyond this project. The full architecture, the memory and retrieval system, the k-sweep, and the distillation results are written up on the project page and in the repo's docs/, including docs/proper_scale_results.md (the full results writeup) and docs/model_quirks.md (every bug in this post, plus the other 21, each with its own root cause and fix). The paper is still to come.