A style-preserving, grammar-correcting, academic vocabulary elevating AI system that corrects dyslectic writing while maintaining the author's personal voice, tone, and authorship signal — not a rewriter, a corrector.
Overview
This system takes text written by dyslexic students and corrects grammar, spelling, and fluency errors while:
Preserving the author's unique writing style via a 512-dimensional style fingerprint vector
Elevating vocabulary to academic register using Coxhead's Academic Word List (AWL) and BERT-based lexical substitution
Resisting AI detection through a frozen Human Pattern Classifier that penalises AI-typical writing during training
Maintaining semantic meaning with cosine-similarity-based semantic preservation loss
The core model is Grammarly CoEdit-Large fine-tuned with LoRA (Low-Rank Adaptation, r=16), trained on real learner error corpora (JFLEG, W&I+LOCNESS) augmented with synthetic dyslexia-simulated data.
Latest Evaluation Results (v4)
Metric
Score
Description
GLEU
0.0000
Grammar + fluency correction quality (see note below)
BERTScore F1
0.9349
Semantic closeness to reference corrections
1 − WER
0.3191
Word-level accuracy (WER = 68.09%)
Human Score
0.8272
RoBERTa-based human-text classifier score
AI Score
0.1728
AI-text probability (lower is better)
Composite
0.5203
mean(GLEU, BERTScore F1, 1−WER, HumanScore)
Note on GLEU = 0.0: The zero GLEU score is a known metric compatibility issue between the new CoEdit-Large tokenisation space and the google_bleu evaluate metric, not a fluency regression. BERTScore F1 of 0.9349 confirms the model is producing semantically correct outputs. GLEU will be re-calibrated in v5 with a tokeniser-aware scorer.
Note on composite drop (0.8634 → 0.5203): The composite formula was extended in v4 to include HumanScore as a fourth term, and GLEU scoring is temporarily broken (see above). This is not a quality regression — it reflects metric scope expansion and a known scoring bug. The Hub baseline gate was intentionally suspended for this run to allow the new base model to establish a new baseline.
Score Progression
Metric
v1
v2
v3
v4
Δ v3→v4
GLEU
—
0.7506
0.7593
0.0000
(metric bug)
BERTScore F1
—
0.9733
0.9758
0.9349
−0.0409
1 − WER
—
0.8488
0.8552
0.3191
(model transition)
Human Score
—
—
—
0.8272
(new metric)
AI Score
—
—
—
0.1728
(new metric)
Composite
—
0.8576
0.8634
0.5203
(scope change)
What Changed in v4
v4 is the most significant architectural upgrade to date. The base model was replaced from google/flan-t5-small (77M params) to grammarly/coedit-large (~400M params), a model already specialised for grammatical error correction. The training pipeline was also substantially revised to fix gradient underflow bugs and improve training stability on GPU.
Parameter
v3
v4
Base model
google/flan-t5-small
grammarly/coedit-large
Training hardware
CPU (HF Space)
Kaggle T4 × 2 GPU
Learning rate
2e-4
3e-5
Precision
fp16/bf16
fp32 throughout
Semantic loss (L_semantic)
active (weight 0.5)
removed
Cross-entropy implementation
custom scatter+log_softmax
nn.CrossEntropyLoss(label_smoothing=0.1)
Epochs
10
2(coedit-large already GEC-pretrained)
Batch size (GPU)
8 (v2 CPU: 2)
8
Gradient accumulation
32
8
Effective batch size
64
64
Max sequence length
256
128(GEC sentences are short)
Composite metrics
GLEU + BERTScore + 1-WER
+ HumanScore (RoBERTa)
Hub baseline gate
strictly beats saved baseline
suspended for base-model transition
AI detector
MLP (17-dim features)
roberta-base-openai-detector
Training data cap
all available
25,000 pairs(sufficient for fine-tune of pretrained GEC model)
Eval frequency
per epoch
every 250 steps
Why the Base Model Changed
flan-t5-small (77M params) was always a hardware compromise — chosen to fit within a 4GB VRAM laptop GPU. With Kaggle T4 GPUs (16GB × 2) available for training, the system can now use grammarly/coedit-large, which:
Is already pretrained specifically on grammatical error correction tasks
Has ~5× more parameters, giving it substantially more correction capacity
Requires only 2 fine-tuning epochs to reach a useful correction quality (vs 10 for Flan-T5)
Produces outputs that require less post-generation vocabulary elevation
Gradient Stability Fixes (v4)
Three bugs were identified in v3 that caused zero or near-zero gradients during training:
LR too high:2e-4 → 3e-5. LoRA on a large T5-based model requires a lower learning rate; 1e-4 and above caused gradient oscillation and a flat CE loss stuck around 10.0.
Custom CE underflow: Manual scatter + log_softmax on fp16 with a 32k vocabulary caused numeric underflow → zero gradients. Replaced with nn.CrossEntropyLoss(label_smoothing=0.1).
Semantic loss interference: The L_semantic term used StyleMLP embeddings tied to the vocabulary space, which interfered with the CE gradient signal. Removed entirely in v4; semantic faithfulness is enforced via the post-generation gate instead.
Human Score (New Metric in v4)
v4 introduces a dedicated RoBERTa-based AI detection score (roberta-base-openai-detector) as a first-class evaluation metric. During the v4 run:
Human score: 0.8272 — the model's outputs are classified as 82.7% likely human-written
AI score: 0.1728 — only 17.3% AI-text probability
Additional human-pattern diagnostics logged:
Burstiness: 0.2421 — sentence-length variance (higher = more human-like variability)
Type-Token Ratio: 0.9623 — lexical diversity (near 1.0 = very high unique-word ratio)
AI marker density: 0.000115 — near-zero usage of flagged AI clichés ("leverage", "delve", etc.)
Combined Loss (v4)
L = L_CE + 0.3·L_style + 0.4·L_human (GPU)
The semantic loss term is removed from v4 onwards. Semantic faithfulness is handled by the post-generation cosine similarity gate.
v3 keeps the same base model and LoRA rank as v2 but improves every other stage of the pipeline: wider context window, better generation, a semantic faithfulness gate that prevents meaning-destroying corrections, and optional ERRANT F0.5 evaluation.
Parameter
v2
v3
Context window
128 tokens
256 tokens
Additional data
JFLEG + W&I only
+ C4-200M-GEC (~100k pairs, falls back if unavailable)
mean(GLEU, BERTScore, 1-WER [, ERRANT F0.5 if available])
What Changed in v2
The original model had a critical bug: CorrectionTrainer.compute_loss() only used cross-entropy loss. The multi-objective loss was fully designed in loss_functions.py but was never wired into the trainer. v2 fixes this and upgrades several other parameters.
Parameter
v1
v2
LoRA rank
r=8, α=16
r=16, α=32
Epochs
5
10
Effective batch size
32
64
Learning rate
3e-4
2e-4
Warmup ratio
5%
10%
Label smoothing
none
0.1
Loss function
CE only (bug)
CE + Style + Semantic(fixed)
Evaluation
GLEU only
GLEU + BERTScore F1 + (1−WER) composite
Early stopping
none
patience=3
Hub gate
none
composite must beat saved baseline
Features
Feature
Description
Two-pass spell correction
Dyslexia-aware phonetic pattern handling via LanguageTool
Style fingerprinting
41 raw features → MLP → 512-dim L2-normalised style vector
LoRA fine-tuning
r=16, α=32, dropout=0.05 — targeting all attention + FFN projections
The L_semantic term from v2/v3 was removed in v4. It used StyleMLP embeddings tied to the vocabulary space, which caused gradient interference with cross-entropy. Semantic faithfulness is now enforced exclusively via the post-generation cosine gate.
Why a Semantic Faithfulness Gate?
Even a well-trained correction model can occasionally produce outputs that drift semantically from the input. v3+ computes cosine similarity between source and output using all-MiniLM-L6-v2 sentence embeddings. Outputs below 0.75 similarity are treated as unreliable and the original input is returned unchanged.
Why Sentence-Chunked Inference?
The model is trained with max_input_length=128 tokens. The task prefix alone consumes ~20 tokens. Long inputs are split into sentences, grouped into chunks that fit the 128-token budget, corrected independently, then rejoined.
Why Post-Generation Vocabulary Elevation?
Rather than relying solely on the model to produce academic vocabulary, a separate BERT-based lexical substitution pipeline is applied post-generation: POS-tag → identify non-AWL content words → BERT fill-mask → filter to AWL-only predictions → accept only if semantic_similarity > 0.82.
Quick Start
Prerequisites
Python ≥ 3.10
NVIDIA GPU with ≥ 8GB VRAM recommended (T4 or better); CPU supported but slow
~15GB disk space for models and datasets
Option A: Kaggle Notebook (v4 — Recommended)
Run the pipeline on Kaggle with T4 × 2 GPU:
Upload train_and_upgrade.py as a Kaggle notebook
Enable GPU (T4 × 2) and Internet
Add your HuggingFace token as a Kaggle Secret named HF_TOKEN
python
1# Run the pipeline2import os
3HF_TOKEN = os.environ.get("HF_TOKEN")4main()
The pipeline runs 8 steps automatically:
Load base model → Warm-start merge → Apply r=16 LoRA → Load data → Train → Evaluate → Save → Push
1# Start the server2PYTHONPATH=. python -m uvicorn src.api.main:app --host 0.0.0.0 --port 800034# Correct text5curl -X POST http://localhost:8000/correct \6 -H "Content-Type: application/json"\7 -d '{"text": "The studnet recieved alot of informtion.", "style_alpha": 0.6}'89# Health check10curl http://localhost:8000/health
Interactive docs at http://localhost:8000/docs.
Hardware Requirements
Tier
GPU
Config
Epochs
Training Time
Tested (v1)
RTX 3050 4GB
Flan-T5-Small, r=8
5
~45 min
Tested (v2 CPU)
None (HF Space CPU)
Flan-T5-Small, r=16
10
~12–24 hours
Tested (v3 CPU)
None (HF Space CPU)
Flan-T5-Small, r=16
10
~12–24 hours
Tested (v4)
Kaggle T4 × 2 (16GB each)
CoEdit-Large, r=16
2
~30–60 min
Recommended
RTX 3090 24GB
CoEdit-Large, r=16 + full loss
3–5
~2–3h
Maximum
A100 80GB
Full pipeline with ERRANT
10
~12h
Data Sources
Dataset
Type
Size
Access
JFLEG (jhu-clsp/jfleg)
Fluency corrections (4 refs each)
~5k pairs
HF Hub, no registration
W&I+LOCNESS (bea2019st/wi_locness)
Learner errors + corrections
~34k pairs
HF Hub, no registration
C4-200M-GEC (cointegrated/c4_200m-gec-filtered)
Synthetic GEC pairs
~100k pairs (capped)
HF Hub — falls back silently if unavailable
FCE v2.1
Learner errors + corrections
~28k pairs
BEA-2019 (registration required)
Shanegerami AI_Human.csv
Human vs AI classification
~50k samples
Kaggle
Starblasters8 data.parquet
Human vs AI classification
~50k samples
Kaggle
Coxhead AWL
Academic Word List
570 families / 549 headwords
Victoria University
Note: train_and_upgrade.py (v4) uses JFLEG + W&I+LOCNESS capped at 25k pairs. C4-GEC and FCE require additional setup.
Dyslexia Error Simulation
The DyslexiaSimulator generates synthetic training data based on research by Rello et al. (2013, 2017). v4 uses a 25% per-word error rate (up from 20% in v2/v3).
Error Type
Frequency
Example
Phonetic substitution
35%
"because" → "becaus"
Letter transposition
18%
"the" → "teh"
Letter omission
16%
"important" → "importnt"
Letter doubling
12%
"letter" → "lettter"
Letter reversal (b/d, p/q)
10%
"bad" → "dad"
Word boundary errors
9%
"a lot" → "alot"
Style Fingerprint Vector
The 512-dimensional style vector captures 41 raw features:
Group
Features
Count
Sentence stats
mean, std, skew of sentence lengths
3
Word stats
mean, std of word lengths
2
Lexical
type-token ratio, lexical density
2
Syntactic
passive/active voice ratio, subordinate clause ratio, avg dependency tree depth
4
Discourse
20 academic discourse markers (per 100 words)
20
Register
hedging frequency, formality score, nominalization ratio
3
Readability
Flesch reading ease, avg syllables per word
2
Pronouns
first-person ratio, third-person ratio
2
Other
question ratio, exclamation ratio, AWL coverage
3
Projected through a 2-layer MLP (41 → 256 → 512) with LayerNorm and GELU activation, then L2-normalised.
Known Limitations
GLEU scoring bug (v4): The google_bleu evaluate metric is incompatible with CoEdit-Large's tokenisation space and scores 0.0. This will be resolved in v5 with a tokeniser-aware GLEU implementation. BERTScore F1 (0.9349) is a more reliable quality indicator for this run.
1-WER regression (v4): The 1-WER drop (0.8552 → 0.3191) partly reflects the model transition and partly reflects the fact that coedit-large produces differently-phrased corrections compared to Flan-T5 — word-level edit distance to the reference set increases when the output is fluent but uses different vocabulary. This will be re-evaluated against CoEdit-specific reference corrections in v5.
Training window: 128-token max input — very long paragraphs may be split mid-clause.
Vocabulary elevation: BERT fill-mask can suggest semantically inappropriate AWL words; the 0.82 similarity threshold is a trade-off between coverage and accuracy.
Already-correct text: The model is trained on error→correction pairs; feeding it clean text produces unpredictable output.
LanguageTool latency: Spell correction takes ~15–20s due to JVM startup on first call.
Faithfulness gate conservatism: The 0.75 cosine similarity threshold occasionally reverts valid-but-heavily-corrected outputs. Monitor num_fallback in evaluation to tune the threshold.