--- license: gemma language: - en pipeline_tag: text-generation base_model: google/gemma-4-E2B tags: - error-correction - frozen-backbone - capability-preservation - logit-adjustment - parameter-efficient - gemma - apple-silicon - on-device-ai - cehri model-index: - name: Prajna-CRNv2 results: - task: type: question-answering name: CEHRI Exam (original, 60 Qs) dataset: type: custom name: CEHRI-60 metrics: - type: accuracy value: 53.3 - task: type: question-answering name: CEHRI Exam (reworded, 120 Qs) dataset: type: custom name: CEHRI-120-reworded metrics: - type: accuracy value: 43.3 - task: type: multiple-choice name: MMLU (sampled, N=200) dataset: type: cais/mmlu name: MMLU metrics: - type: accuracy value: 62.5 - task: type: question-answering name: BoolQ (sampled, N=200) dataset: type: google/boolq name: BoolQ metrics: - type: accuracy value: 72.0 --- # πͺ· Prajna-CRNv2 β Safe Error Correction for Language Models
> **π Paper published: [arXiv:2609.16145](https://arxiv.org/abs/2609.16145)** **Fix a frozen model's errors without breaking what it already does well.** Prajna-CRNv2 is a tiny correction module (34M params, 0.73% of the base) that sits on top of a **fully frozen Gemma-4-E2B** and learns to adjust its logits where it detects errors. The base model is never updated β not one gradient, not one weight. What you get is error correction with **zero measurable capability loss**, trained end-to-end on a Mac Mini M4. ``` corrected_logits = base_logits + gate * up(gelu(down(hidden))) ``` Built by [eulogik](https://github.com/eulogik) Β· Code + paper: [github.com/eulogik/prajna](https://github.com/eulogik/prajna) ## β¨ Why it matters Fine-tuning fixes errors but causes forgetting β the **correctionβcapability tradeoff**. A LoRA baseline on the same exam corrects more (83.3%) yet destroys 30β75% of base capabilities (MMLU 62.5% β 32%, car-wash 75% β 0%). Prajna-CRNv2 corrects **53.3%** while matching the frozen base **exactly** on every tested benchmark. For deployment, a model that fixes some errors and stays reliable beats one that fixes more and breaks reasoning. ## π Results | | CEHRI Original (60) | CEHRI Reworded (120) | MMLU (200) | BoolQ (200) | Car-wash (8) | |---|---|---|---|---|---| | **Frozen base** | 11.7% | β | 62.5% | 72.0% | 75.0% | | **Prajna-CRNv2** | **53.3%** | **43.3%** | **62.5%** (Ξ=0) | **72.0%** (Ξ=0) | **75.0%** (Ξ=0) | | LoRA baseline (6.6M) | 83.3% | 77.5% | 32.0% (β30.5pp) | 55.0% (β17pp) | 0% (β75pp) | A hidden-state injection sweep (1.6M-param variant at layers 4/7) confirms ~53% as the **ceiling** for frozen-base methods β deeper injection helps (30% β 50%) but never beats logit correction. See the paper for the full story, including ablations and limitations.   ### Injection-depth sweep (experimental) | Variant | Training | CEHRI Original | CEHRI Reworded | Capability | |---|---|---|---|---| | Deep layer 4 (1.6M) | SFT-only | 30.0% | 28.3% | not probed | | Deep layer 7 (1.6M) | SFT-only | 50.0% | 55.8% | intact (small probe) | | Deep layer 7 (1.6M) | SFT + DPO | 50.0% | 55.0% | destroyed (MMLU 13%) | | **Logit CRN v2 (34M)** | SFT + DPO | **53.3%** | 43.3% | intact |  ## π Quickstart ```bash pip install torch transformers ``` ```python import torch, sys sys.path.insert(0, ".") # for crn_v2.py from crn_v2 import CRNv2 model = CRNv2(device="mps" if torch.backends.mps.is_available() else "cpu") model.load("crn_v2_dpo.pt") # 34M correction weights (this repo) print(model.generate("What is the capital of France?")) # Or correct a draft answer: print(model.correct("What is 2+2?", "5")) ``` Or use the interactive demo: ```bash python inference.py python inference.py --prompt "What is 2+2?" --draft "5" ``` Requirements: Python 3.10+, PyTorch 2.0+, ~10GB RAM (Gemma-4-E2B loads in float16; set `HF_HOME` to an external disk if space is tight). ## π Files | File | Size | Purpose | |---|---|---| | `crn_v2_dpo.pt` | 130 MB | Trained correction weights (rank-128, SFT+DPO, KL Ξ»=0.1) | | `crn_v2.py` | β | Architecture (`LogitCorrection` + `CRNv2`) | | `crn_deep.py` | β | Experimental hidden-state injection variant (code only) | | `inference.py` | β | Interactive demo / single-shot correction | | `config.json` | β | Model + training metadata | ## π¬ Training - **Stage 1 β SFT (2,000 steps):** anchor-weighted answer-only CE (anchor 4Γ, EOS 5Γ) + KL preservation (Ξ»=0.1) on 83,400 error-correction pairs. AdamW, LR 3e-4, cosine decay. - **Stage 2 β DPO (500 steps):** reference-free preference of the correct answer over the frozen base's wrong answer (Ξ²=0.1, LR 5e-6). - **Hardware:** Apple M4, 16GB, MPS β ~25 min end-to-end. Base frozen throughout. ## π€ FAQ **Is the base model modified?** No. Every base parameter is frozen; only the 34M correction module trains. **Why 53.3% and not higher?** Frozen-base correction has a real ceiling (~53% here) β closing the gap to weight-modifying methods costs capabilities. We publish the boundary as carefully as the headline; see Limitations in the paper. **Does it generalize?** The exam prompts appear verbatim in training (in-distribution: 53.3%); the reworded exam measures near-duplicate correction (43.3%). Neither tests out-of-distribution generalization β stated openly. **Can I retrain it?** Yes β full pipeline (data, SFT+DPO trainers, evals) in the [GitHub repo](https://github.com/eulogik/prajna). ## π License Weights + code released under [Gemma terms](https://huggingface.co/google/gemma-4-E2B/blob/main/LICENSE) (as required by the base model). Research use. See the [paper](https://github.com/eulogik/prajna/tree/main/docs/paper) for methods, ablations, and limitations. *πͺ· Prajna β "wisdom": fix errors, keep knowledge.*