Proofbird Grammar — German
gector-bert-de · on-device German grammar correction
Try it in your browser: type a sentence and see the corrections. The model runs on your own computer; nothing to install, and your text never leaves the page.
Version 2.0.0 · run 2026-11-08-1901 (1.x = run 2026-11-08-0749) · tag v2.0.0, the files the Proofbird app downloads. Pin it with revision="v2.0.0". Versions: a new training run raises the first number, changed guards or rules the second, card or metadata fixes the third.
A GECToR-style sequence tagger for German grammatical error correction, exported to ONNX (fp32) to run on the CPU. It is the on-device grammar model of Proofbird, a writing assistant for Windows, and it is published here so anyone can inspect what runs on their machine.
GECToR does not rewrite text. For each token it predicts one edit tag (keep, delete, replace with a word, append a word, change case, change a verb's form), and the edits are applied and the sentence re-tagged up to five times. The tagger only proposes local edits; it never paraphrases.
Quick start
No API key, no GPU. One file, quickstart.py, downloads the model and runs it with ONNX Runtime.
pip install onnxruntime tokenizers huggingface_hub
import importlib.util
from huggingface_hub import hf_hub_download
spec = importlib.util.spec_from_file_location("quickstart", hf_hub_download("proofbird/gector-bert-de", "quickstart.py"))
quickstart = importlib.util.module_from_spec(spec)
spec.loader.exec_module(quickstart)
model = quickstart.Gector("proofbird/gector-bert-de")
corrected, suggestions = model.correct("Meine Schwester sind sehr mude.")
print(corrected)
print(suggestions)
Meine Schwester ist sehr müde.
[{"start": 16, "length": 4, "original": "sind", "replacement": "ist"}, {"start": 26, "length": 4, "original": "mude", "replacement": "müde"}]
Each suggestion gives the character position in your text (start, length), what is there now (original) and what to put instead (replacement), so you can underline it and offer the fix. From the command line: python quickstart.py "Meine Schwester sind sehr mude." prints every step below.
What it corrects
Subject-verb agreement, including the verb's person after du and ihr (Die Kinder spielt → spielen,
Du hat → hast, Ihr ist → seid), capitalisation of nouns (keine zeit → Zeit), missing umlauts
(Ich hore → höre, sehr schon → schön), ß after a long vowel or diphthong (Strasse → Straße,
weiss → weiß) and the old spellings daß / muß → dass / muss, das / dass after a comma in both
directions (Ich hoffe, das du kommst → dass; Das ist das Buch, dass ich dir empfohlen habe → das), nicht war →
nicht wahr, würde / wurde in a past passive (dass er gestern gesehen würde → wurde), common confusables, doubled
words, and capitalisation at the start of a sentence.
How it was trained
- Base encoder:
dbmdz/bert-base-german-cased(MIT), by the MDZ Digital Library team at the Bavarian State Library. A tagging head (5 000 edit labels) and an error-detection head sit on top. - Data: synthetic only. 3 000 000 sentences from German Wikipedia
(
wikimedia/wikipedia,20231101.de) and 250 000 sentences from Tatoeba were corrupted by hand-written German error rules; about 10% stay clean, so the model learns to leave correct text alone. 45 000 additional template sentences teach patterns Wikipedia rarely contains (duandihrwith their verb forms,das/dasswith the same pronouns on both sides, tag questions, errors in a later clause), with correct twins so the model also learns what to leave alone. - No learner corpora and no non-commercial data of any kind. No user text was used.
- One epoch (95 685 steps, batch 64, learning rate 3e-5) on one NVIDIA L4. Run id
2026-11-08-1901.
How it was measured
| Check | Result |
|---|---|
| Gold set (278 hand-written sentences: 182 with one error each, 96 correct) | 178 fixed, 96 left alone, 8 missed, 0 made worse |
| False alarms on 4 000 everyday Tatoeba sentences (held out from training) | 17 changed (0.43%); 13 of them correct an error or an old spelling in Tatoeba's own text |
| Stability: the gold re-run with one extra token in front of each sentence | 3 sentences change result |
The gold score is with the apply-side guards in gector-guards.json (below). The model was trained for precision: a
missed error costs less than a wrong correction. The Tatoeba changes include real fixes of Tatoeba's text (muß →
muss, Du wird → wirst, Unsere Lehrer ist → sind) and four false alarms, for example den Talern → Tälern
and Können Sie mir das buchstabieren? → Buchstabieren. Known misses: nicht war and schon → schön at the end of a
long sentence (short ones are fixed), and hätte → hatte, which the model leaves alone because both are often right.
The guards keep man with the Konjunktiv I of instructions (Man nehme zwei Eier), das das after a form of sein
(Ist das das Haus von Anna?), a relative pronoun and an article after a comma (diejenige, die die Entscheidungen trifft) and a plural after die, meine and similar words (Ich stelle hier die Fragen). A sentence written
throughout with ss instead of ß (Swiss spelling) is left alone. It has not been measured on learner essays.
Files
| File | What it is |
|---|---|
model.onnx |
The tagger (fp32, opset 17). Inputs input_ids, attention_mask; outputs logits_labels [1, T, 5000] and logits_d [1, T, 2]. |
config.json |
The edit-label vocabulary (id2label). |
vocab.txt, tokenizer.json, tokenizer_config.json |
The base encoder's WordPiece tokenizer. |
gector-meta.json |
Export facts: encoder, tokenizer family, decoding defaults, run id, version. |
gector-guards.json |
Apply-side guards: rules that hold back an edit the model gets wrong in a known way (for example a verb edit that changes the person while the clause has no subject of that person). Part of the measured result. |
language-rules.json |
Language facts the runtime needs (sentence-final punctuation handling). |
verb-form-vocab.txt |
The German verb-form table for the $TRANSFORM_VERB_* tags (207 verbs, built for this model). |
quickstart.py |
A complete Python runner: download, tokenize, run, decode, apply, suggestions. See Quick start. |
quickstart.ipynb |
The same, as a notebook (the Open in Colab button). |
The Proofbird app runs the same algorithm in C# with ONNX Runtime; the files are standard, so any GECToR-style decoder can use them.
How it works, step by step
The model never sees letters and never writes text. It reads numbers (token ids) and answers, for every word, which edit to make: one of 5 000 tags such as $KEEP, $DELETE, $APPEND_sind, $REPLACE_essen or $TRANSFORM_VERB_P3P_P3S (change a verb's form). quickstart.py does everything around it. This is the real run of the example above.
1. Prepare the text. language-rules.json says the final full stop comes off before the model sees the sentence (it goes back on at the end): Meine Schwester sind sehr mude.
2. The request. The words are looked up in the model's dictionary (vocab.txt). A rare word is split into pieces; the edit is read at its first piece. [CLS] stands for a dummy first word, $START, so an edit on it can add a word at the very beginning; [SEP] marks the end.
words $START Meine Schwester sind sehr mude
tokens [CLS] Meine Schwester sind sehr mu ##de [SEP]
input_ids [102, 4747, 5659, 341, 843, 8130, 158, 103]
attention_mask [1, 1, 1, 1, 1, 1, 1, 1]
Two inputs, both whole numbers (int64), shape [1, 8]: one sentence of 8 tokens.
3. The response. Two outputs (float32): logits_labels [1, 8, 5000], a score for each of the 5 000 edits at every token, and logits_d [1, 8, 2], a score for "this word is correct" and "this word is wrong". A softmax turns each row into probabilities; the most probable edit at each word's first token is the one applied.
4. Pass by pass. The corrected sentence goes back in, until a pass changes nothing (at most five passes). Connected errors are fixed one after the other.
Pass 1: Meine Schwester sind sehr mude
| Word | Wrong | Chosen edit | Probability |
|---|---|---|---|
| $START | 0.0% | $KEEP | 100.0% |
| Meine | 0.0% | $KEEP | 100.0% |
| Schwester | 0.0% | $KEEP | 100.0% |
| sind | 45.0% | $KEEP | 55.1% |
| sehr | 0.0% | $KEEP | 100.0% |
| mude | 77.2% | $REPLACE_müde | 98.2% |
→ Meine Schwester sind sehr müde
Pass 2: Meine Schwester sind sehr müde
| Word | Wrong | Chosen edit | Probability |
|---|---|---|---|
| $START | 0.0% | $KEEP | 100.0% |
| Meine | 0.0% | $KEEP | 100.0% |
| Schwester | 0.1% | $KEEP | 99.9% |
| sind | 99.8% | $TRANSFORM_VERB_P3P_P3S | 99.8% |
| sehr | 0.0% | $KEEP | 100.0% |
| müde | 0.0% | $KEEP | 100.0% |
→ Meine Schwester ist sehr müde
Pass 3: Meine Schwester ist sehr müde
| Word | Wrong | Chosen edit | Probability |
|---|---|---|---|
| $START | 0.0% | $KEEP | 100.0% |
| Meine | 0.0% | $KEEP | 100.0% |
| Schwester | 0.0% | $KEEP | 100.0% |
| ist | 0.0% | $KEEP | 100.0% |
| sehr | 0.0% | $KEEP | 100.0% |
| müde | 0.0% | $KEEP | 100.0% |
→ Meine Schwester ist sehr müde — no change, so it stops.
5. The suggestions. The original and the final words are compared, and each changed stretch becomes one suggestion with its position in the original text (unchanged text keeps its own spacing), as in the Quick start output above.
6. Settings. Gector(repo, keep_confidence=0.0, min_error_prob=0.0) takes the two GECToR precision knobs (the Proofbird app runs with both at 0, and at most five passes):
keep_confidenceadds a bonus to$KEEPbefore choosing: higher means fewer, safer edits.min_error_probignores an edit the model is less sure of, and leaves the whole sentence alone when no word is at least that likely to be wrong. Withmin_error_prob=0.9the example is left as it is: the highest "wrong" probability in pass 1 is 77.2%, below 0.9.
What Proofbird adds
quickstart.py is the model on its own. The Proofbird app runs the same algorithm in C# and adds:
- Guards (
gector-guards.json, in this repository): per-language rules that hold back edits we measured as wrong in a known shape. The scores under How it was measured are with the guards. - Spelling, checked separately by the operating system's spell checker; the guards use it so a grammar edit is not made on a word that is misspelled.
- A card for each change that names the error ("Subject–verb agreement") and, on request, explains it.
Licence and attribution
The model weights and the files in this repository are released under the Apache License 2.0. If you redistribute the model or a model built from it, keep the NOTICE file with it (Apache-2.0, section 4(d)).
The training data carries its own terms. Wikipedia text is © Wikipedia contributors,
CC BY-SA 4.0. Tatoeba sentences are from
tatoeba.org, CC BY 2.0 FR. The base
encoder is dbmdz/bert-base-german-cased by the MDZ Digital Library team (dbmdz) at the Bavarian State Library, MIT
licence. The tagging scheme follows GECToR (Omelianchuk et al., 2020, GECToR – Grammatical Error Correction: Tag,
Not Rewrite); the German verb-form table was built for this model.
How to cite
If you use or build on this model, please cite it:
@misc{hartnett2026gectorde,
author = {Hartnett, Patrick Andrew},
title = {Proofbird GECToR grammar model (German)},
year = {2026},
publisher = {Hugging Face},
howpublished = {\url{https://huggingface.co/proofbird/gector-bert-de}},
note = {Proofbird, https://proofbird.app}
}
If you build on this model, a link back to this page is appreciated.
Contact
Published by Patrick Andrew Hartnett as personal work. Questions and reports: open a discussion on this repository.
- Downloads last month
- -
Model tree for proofbird/gector-bert-de
Base model
dbmdz/bert-base-german-cased