feat(ocr): mobile on-device TrOCR-handwritten — Retry mit Handwriting-Modell #421

Closed
opened 2026-05-28 14:19:02 +02:00 by pm-bot · 2 comments
Collaborator

Kontext

Spike #77 wurde am 2026-05-28 als Technical-Yes / Business-No geschlossen. Der Privacy-Grund fiel weg (eigener Server = trusted, Einkaufszettel ≠ sensitive), und der getestete Modell-Cut (trocr-small-printed) hat CER 0.51 auf echten handgeschriebenen Einkaufszetteln (#416).

Nach v0.5.0-Ship zeigte sich aber: Fuzzy-Match kann Garbage-OCR nicht retten, wenn Roh-Confidence bei 5-35% liegt (Screenshot vom Stakeholder). Web bleibt mit EasyOCR brauchbar für gedruckte Listen; handgeschriebene Listen sind weiter unlesbar.

Stakeholder-Entscheidung: handgeschriebene OCR mobile-only akzeptabel, weil:

  • Server hat keine GPU für TrOCR-large-handwritten (10-30s/Zeile auf CPU)
  • On-device Pixel-class-Hardware schafft small-Modelle in <1s (Spike-Tag-5: 449ms warm für small-printed)
  • Trade-off: ~98 MB APK-Größe für funktionsfähige Handwriting-OCR

Was Spike-#77 ÜBER bleibt

Im Repo (auf archivierter Branch archive/spike-77-ocr-mobile):

  • apps/mobile/src/services/ocr-service.ts — Singleton mit ORT-RN + KV-cache Greedy-Decode (10 grüne Specs)
  • apps/mobile/src/services/ocr-model-assets.ts — Metro asset-handle wrapper
  • apps/mobile/app/ocr-spike.tsx — Debug-Screen
  • apps/mobile/plugins/with-onnxruntime-package.js — Expo prebuild plugin
  • Metro-Config: .onnx als asset-ext registriert
  • TrOCR-Greedy-Decode mit decoder_with_past-Threading verifiziert (bit-identisch mit no-past)

Aufgabe

Pivot-Hypothese: Die TrOCR-Pipeline-Mechanik aus Spike-#77 ist solide; nur das Modell war falsch. Xenova/trocr-small-handwritten ist Drop-in-kompatibel (gleiche Architektur, gleiche Config-Werte, ONNX-int8 vorhanden, gleicher Encoder-Input).

Verifizierte Drop-in-Kompatibilität (Xenova/trocr-small-handwritten):

  • decoder_layers: 6 (wie small-printed)
  • image_size: 384
  • decoder_start_token_id: 2
  • eos_token_id: 2
  • tokenizer.json vorhanden
  • encoder_model_quantized.onnx: 22 MB
  • decoder_model_quantized.onnx: 38 MB
  • decoder_with_past_model_quantized.onnx: 37 MB
  • Bundle-Total: ~98 MB (vs. 76 MB small-printed)

Daher: kein ONNX-Export, kein Python-Step. Nur File-Download + MODEL_REPO-Konstante tauschen.

Akzeptanzkriterien

  • Branch feat/4XX-ocr-handwritten-mobile von main mit Spike-77-Scaffolding
  • MODEL_REPO = 'Xenova/trocr-small-handwritten' in ocr-service.ts
  • 3 ONNX-Files in apps/mobile/assets/ocr-model/ (gitignored, EAS-bundled)
  • pnpm --filter @mrrmlab/mobile typecheck + ocr-service.spec.ts grün
  • EAS-Build erzeugt funktionsfähige APK auf Pixel
  • /ocr-spike Route liefert nicht-leeres OCR-Ergebnis auf einem echten handschriftlichen Einkaufszettel-Crop
  • CER auf den 77 Real-Daten-Crops aus #416 dokumentiert (eval-tooling wiederverwenden)

Risiken / offene Fragen

  • CER unbekannt: trocr-small-handwritten ist primär auf IAM-Handwriting-Datensatz finetuned. Real-Einkaufszettel-CER könnte ähnlich schlecht sein wie small-printed. Falls > 0.3, eskalieren zu trocr-base-handwritten (4× Parameter, ~280 MB Bundle).
  • APK-Größe: 98 MB OCR-Bundle on top von ~30 MB Dev-Client ≈ 130 MB APK. Akzeptabel für mobile Einkaufslisten-App.
  • Latenz: small-printed warm = 449ms auf Pixel 8a. small-handwritten Architektur identisch → erwartete Latenz im gleichen Bereich.

Folge-Entscheidungspunkt

Nach Device-Test mit Real-Daten:

  • CER < 0.15: Ship als v0.5.1-Feature, Web bleibt EasyOCR
  • CER 0.15-0.30: Eval base-handwritten (Bundle ~280 MB) — Trade-off entscheiden
  • CER > 0.30: Pivot zu Cloud-VLM (Claude/GPT) für Mobile-Pfad — On-Device endgültig schließen
## Kontext Spike #77 wurde am 2026-05-28 als **Technical-Yes / Business-No** geschlossen. Der Privacy-Grund fiel weg (eigener Server = trusted, Einkaufszettel ≠ sensitive), und der getestete Modell-Cut (`trocr-small-printed`) hat CER 0.51 auf echten handgeschriebenen Einkaufszetteln (#416). Nach v0.5.0-Ship zeigte sich aber: **Fuzzy-Match kann Garbage-OCR nicht retten**, wenn Roh-Confidence bei 5-35% liegt (Screenshot vom Stakeholder). Web bleibt mit EasyOCR brauchbar für gedruckte Listen; handgeschriebene Listen sind weiter unlesbar. Stakeholder-Entscheidung: **handgeschriebene OCR mobile-only akzeptabel**, weil: - Server hat keine GPU für TrOCR-large-handwritten (10-30s/Zeile auf CPU) - On-device Pixel-class-Hardware schafft small-Modelle in <1s (Spike-Tag-5: 449ms warm für small-printed) - Trade-off: ~98 MB APK-Größe für funktionsfähige Handwriting-OCR ## Was Spike-#77 ÜBER bleibt Im Repo (auf archivierter Branch `archive/spike-77-ocr-mobile`): - `apps/mobile/src/services/ocr-service.ts` — Singleton mit ORT-RN + KV-cache Greedy-Decode (10 grüne Specs) - `apps/mobile/src/services/ocr-model-assets.ts` — Metro asset-handle wrapper - `apps/mobile/app/ocr-spike.tsx` — Debug-Screen - `apps/mobile/plugins/with-onnxruntime-package.js` — Expo prebuild plugin - Metro-Config: `.onnx` als asset-ext registriert - TrOCR-Greedy-Decode mit `decoder_with_past`-Threading verifiziert (bit-identisch mit no-past) ## Aufgabe **Pivot-Hypothese:** Die TrOCR-Pipeline-Mechanik aus Spike-#77 ist solide; nur das Modell war falsch. `Xenova/trocr-small-handwritten` ist Drop-in-kompatibel (gleiche Architektur, gleiche Config-Werte, ONNX-int8 vorhanden, gleicher Encoder-Input). **Verifizierte Drop-in-Kompatibilität (Xenova/trocr-small-handwritten):** - `decoder_layers`: 6 ✅ (wie small-printed) - `image_size`: 384 ✅ - `decoder_start_token_id`: 2 ✅ - `eos_token_id`: 2 ✅ - `tokenizer.json` vorhanden ✅ - `encoder_model_quantized.onnx`: 22 MB - `decoder_model_quantized.onnx`: 38 MB - `decoder_with_past_model_quantized.onnx`: 37 MB - **Bundle-Total: ~98 MB** (vs. 76 MB small-printed) Daher: **kein ONNX-Export**, kein Python-Step. Nur File-Download + `MODEL_REPO`-Konstante tauschen. ## Akzeptanzkriterien - [ ] Branch `feat/4XX-ocr-handwritten-mobile` von `main` mit Spike-77-Scaffolding - [ ] `MODEL_REPO = 'Xenova/trocr-small-handwritten'` in `ocr-service.ts` - [ ] 3 ONNX-Files in `apps/mobile/assets/ocr-model/` (gitignored, EAS-bundled) - [ ] `pnpm --filter @mrrmlab/mobile typecheck` + ocr-service.spec.ts grün - [ ] EAS-Build erzeugt funktionsfähige APK auf Pixel - [ ] `/ocr-spike` Route liefert nicht-leeres OCR-Ergebnis auf einem echten handschriftlichen Einkaufszettel-Crop - [ ] CER auf den 77 Real-Daten-Crops aus #416 dokumentiert (eval-tooling wiederverwenden) ## Risiken / offene Fragen - **CER unbekannt**: `trocr-small-handwritten` ist primär auf IAM-Handwriting-Datensatz finetuned. Real-Einkaufszettel-CER könnte ähnlich schlecht sein wie small-printed. Falls > 0.3, eskalieren zu `trocr-base-handwritten` (4× Parameter, ~280 MB Bundle). - **APK-Größe**: 98 MB OCR-Bundle on top von ~30 MB Dev-Client ≈ 130 MB APK. Akzeptabel für mobile Einkaufslisten-App. - **Latenz**: small-printed warm = 449ms auf Pixel 8a. small-handwritten Architektur identisch → erwartete Latenz im gleichen Bereich. ## Folge-Entscheidungspunkt Nach Device-Test mit Real-Daten: - **CER < 0.15**: Ship als v0.5.1-Feature, Web bleibt EasyOCR - **CER 0.15-0.30**: Eval `base-handwritten` (Bundle ~280 MB) — Trade-off entscheiden - **CER > 0.30**: Pivot zu Cloud-VLM (Claude/GPT) für Mobile-Pfad — On-Device endgültig schließen
Author
Collaborator

Pivot zu #423 — TrOCR-handwritten verworfen.

Device-Test mit handschriftlichem „Oregano" lieferte Output „consequences" (Total-Halluzination, CER ≈ 1.0). Root-Cause: IAM-Handwriting-Korpus ist English-Cursive → das Decoder-GPT-2 hat einen starken englischen Vokabular-Prior, der deutsche Wörter in plausible englische Tokens zwingt. Da -base-handwritten denselben Trainings-Korpus nutzt, wurde die größere Variante nicht mehr getestet (gleiche Failure-Mode erwartet).

Neuer Spike: #423 — Google ML Kit Text Recognition v2 (on-device, sprach-agnostisches Latin-Skript-Modell).

**Pivot zu #423** — TrOCR-handwritten verworfen. Device-Test mit handschriftlichem „Oregano" lieferte Output „consequences" (Total-Halluzination, CER ≈ 1.0). Root-Cause: IAM-Handwriting-Korpus ist English-Cursive → das Decoder-GPT-2 hat einen starken englischen Vokabular-Prior, der deutsche Wörter in plausible englische Tokens zwingt. Da `-base-handwritten` denselben Trainings-Korpus nutzt, wurde die größere Variante nicht mehr getestet (gleiche Failure-Mode erwartet). Neuer Spike: #423 — Google ML Kit Text Recognition v2 (on-device, sprach-agnostisches Latin-Skript-Modell).
Author
Collaborator

Geschlossen als „verworfen" — Pivot zu #423 / PR #424 (ML Kit) ist erfolgt und gemerged. TrOCR-handwritten ist nicht weiter verfolgt; die Use-Case-Lücke (on-device OCR deutsche Handschrift) wird durch ML Kit abgedeckt.

Geschlossen als „verworfen" — Pivot zu #423 / PR #424 (ML Kit) ist erfolgt und gemerged. TrOCR-handwritten ist nicht weiter verfolgt; die Use-Case-Lücke (on-device OCR deutsche Handschrift) wird durch ML Kit abgedeckt.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
admin-mrrm/mrrmlabapp#421
No description provided.