Recognize handwritten Vietnamese from images into diacritic-correct Unicode text (line level; whole pages are routed → lines → text), with a trainable TrOCR core, a CRNN+CTC baseline, and an agentic preprocess → segment → recognize → post-correct pipeline.
NLP in Industry — Final Assignment. Author: Le Dinh Minh Quan (Student 23127460).
Vietnamese is the hard case for HTR: stacked diacritics — vowel modifiers (ă â ê ô ơ ư),
the consonant đ, and six tones (à á ả ã ạ). The TrOCR decoder is a language model that
must learn which diacritic bytes follow which letters — an NLP problem — and an agent
orchestrates the full image → text pipeline with a confidence-gated human-review fallback.
| Requirement | Where it is delivered |
|---|---|
| Business problem | docs/problem_definition.md |
| Dev infra & tooling | src/ package, pyproject.toml, requirements*.txt, Makefile, Docker, CI |
| Data management | 60K human-annotated real corpus (5CD-AI/Viet-Handwriting-OCR-v2) + synthetic line generator (data/synth.py) as the offline/CI spine; docs/data_description.md, docs/data_card.md |
| Model selection & optimization | TrOCR fine-tune + CRNN baseline to beat; CER/WER + diacritic metrics; docs/model_selection.md |
| Deployment | FastAPI /htr + Gradio + CLI + Docker + HF Space; docs/deployment.md |
| Agentic AI | deterministic FSM with 4 decision points + optional LLM brain; docs/agent_architecture.md |
| Continual learning & monitoring | docs/continual_learning_monitoring.md + monitoring/drift_report.py |
| Privacy & robustness | docs/privacy_robustness.md + analysis/robustness.py |
| Project management | docs/project_plan.md |
| Ethics | docs/ethics_statement.md |
| Report + slides | auto-generated report.pdf + slides.pptx (autopilot) |
handwriting image
│ preprocess (deskew · denoise · binarize · contrast) ── D1 quality routing
▼
page vs single-line ────────────────────────────────────── ── D2 routing
│ line segmentation (projection profile)
▼
recognize each line (TrOCR; CRNN/Tesseract/stub fallback) ── D3 confidence gate
│ Vietnamese post-correction (rule + optional neural) ── D4 acceptance
▼
text + per-line JSON (text · confidence · flag) + manifest
| Role | Id | License |
|---|---|---|
| HTR model (trained) | microsoft/trocr-base-handwritten (T4: -small) | MIT |
| Optional warm-start | duyle2408/trocr-vietnamese-handwriting | Apache-2.0 |
| Baseline | CRNN + CTC (trained here) / Tesseract vie | — |
| VN post-corrector | bmd1905/vietnamese-correction-v2 (mBART) | Apache-2.0 |
| Real data (PRIMARY) | 5CD-AI/Viet-Handwriting-OCR-v2 — 60,248 human-annotated lines (train 59,248 / test 1,000) | ⚠️ GATED + none declared (research-only) |
| Real data (fallback) | HenryBui/vietnamese_handwriting_line_ocr, manhha2502/Vietnamese_Handwriting_OCR | ⚠️ none (research-only) |
| Offline/CI spine + augmentation | synthetic line generator | code MIT |
| English sanity | Teklia/IAM-line | MIT |
⚠️ The primary real corpus
5CD-AI/Viet-Handwriting-OCR-v2is GATED (access must be requested + granted on the HF Hub) and has no declared license → research/educational use only. The fallback Vietnamese datasets likewise have no declared license. Any fine-tuned model inherits these restrictions. When the gated dataset is unreachable (offline / no token / access not granted) the loader gracefully skips it and training falls back to the synthetic spine + fallback datasets.
src/vnhtr/
├── config.py cli.py logging_utils.py
├── data/ corpus.py · synth.py · dataset.py · samples.py · download_dataset.py
├── models/ text_utils.py · vocab.py · trocr_model.py · baseline_crnn.py · postcorrect.py · recognizer.py · model_registry.py
├── preprocess/ image_ops.py · segmentation.py
├── training/ train_trocr.py · train_crnn.py · evaluate.py · tune.py · metrics.py
├── agent/ state.py · policy.py · tools.py · llm_orchestrator.py · htr_agent.py
├── api/ schemas.py · dependencies.py · main.py · ui.py · app_combined.py
├── analysis/ autoreport/ monitoring/ automation/ grading/
configs/ · data/ · models/ · tests/ · docs/ · notebooks/ · app/ · deploy/ · sample_data/
pip install -e ".[ml,vision,api,report]"
vnhtr data # sample images + synthetic preview
vnhtr demo-agent # run the agent on the sample page (offline-friendly)
vnhtr recognize --image sample_data/line_sample.png
vnhtr --config configs/train.yaml train # fine-tune TrOCR (auto-resumes)
vnhtr --config configs/train.yaml train-crnn # the CRNN baseline
vnhtr evaluate --which test # TrOCR vs baseline, CER/WER + diacritics
On Colab/GPU use the notebook (below) — it auto-profiles H100/A100/L4/T4.
vnhtr serve --ui --port 7860 # FastAPI /htr + /htr/batch + Gradio UI at /ui
vnhtr autopilot --no-train # eval → analysis → report.pdf + slides.pptx + bundle
vnhtr grade
A deterministic FSM with four decision points acting on intermediate outputs, plus an
optional LLM brain (anthropic) that validates its output and falls back to rules
(default = zero paid API):
Every step is timed + traced and a full manifest.json is written. See
docs/agent_architecture.md.
Open notebooks/VNHTR_Colab_Training_H100_AUTOPILOT.ipynb
— mounts Drive, installs Colab-safe deps (never touches torch), auto-profiles the GPU, trains
resume-safely, evaluates vs the baseline, runs the agent, and generates the report/slides.
Step-by-step: notebooks/COLAB_GUIDE.md.
pytest -q # CPU-only, no model/network downloads (synthetic render + stub recognizer)
docs/: problem_definition · data_description · data_card · model_selection · evaluation ·
agent_architecture · deployment · continual_learning_monitoring · privacy_robustness ·
project_plan · ethics_statement · architecture · model_card · slide_deck_outline · DESIGN_BRIEF.
MIT — see LICENSE. Pretrained models keep their own licenses (table above). The
real Vietnamese handwriting datasets are research/educational use only (no declared license);
the primary corpus 5CD-AI/Viet-Handwriting-OCR-v2 is additionally GATED (Hub access must be
requested + granted). Models trained on them inherit those restrictions.
5 commits
Python
59.9%
TeX
32.6%
Jupyter Notebook
6.2%
Recognize handwritten Vietnamese from images into diacritic-correct Unicode text (line level; whole pages are routed → lines → text), with a trainable TrOCR core, a CRNN+CTC baseline, and an agentic preprocess → segment → recognize → post-correct pipeline.
NLP in Industry — Final Assignment. Author: Le Dinh Minh Quan (Student 23127460).
Vietnamese is the hard case for HTR: stacked diacritics — vowel modifiers (ă â ê ô ơ ư),
the consonant đ, and six tones (à á ả ã ạ). The TrOCR decoder is a language model that
must learn which diacritic bytes follow which letters — an NLP problem — and an agent
orchestrates the full image → text pipeline with a confidence-gated human-review fallback.
| Requirement | Where it is delivered |
|---|---|
| Business problem | docs/problem_definition.md |
| Dev infra & tooling | src/ package, pyproject.toml, requirements*.txt, Makefile, Docker, CI |
| Data management | 60K human-annotated real corpus (5CD-AI/Viet-Handwriting-OCR-v2) + synthetic line generator (data/synth.py) as the offline/CI spine; docs/data_description.md, docs/data_card.md |
| Model selection & optimization | TrOCR fine-tune + CRNN baseline to beat; CER/WER + diacritic metrics; docs/model_selection.md |
| Deployment | FastAPI /htr + Gradio + CLI + Docker + HF Space; docs/deployment.md |
| Agentic AI | deterministic FSM with 4 decision points + optional LLM brain; docs/agent_architecture.md |
| Continual learning & monitoring | docs/continual_learning_monitoring.md + monitoring/drift_report.py |
| Privacy & robustness | docs/privacy_robustness.md + analysis/robustness.py |
| Project management | docs/project_plan.md |
| Ethics | docs/ethics_statement.md |
| Report + slides | auto-generated report.pdf + slides.pptx (autopilot) |
handwriting image
│ preprocess (deskew · denoise · binarize · contrast) ── D1 quality routing
▼
page vs single-line ────────────────────────────────────── ── D2 routing
│ line segmentation (projection profile)
▼
recognize each line (TrOCR; CRNN/Tesseract/stub fallback) ── D3 confidence gate
│ Vietnamese post-correction (rule + optional neural) ── D4 acceptance
▼
text + per-line JSON (text · confidence · flag) + manifest
| Role | Id | License |
|---|---|---|
| HTR model (trained) | microsoft/trocr-base-handwritten (T4: -small) | MIT |
| Optional warm-start | duyle2408/trocr-vietnamese-handwriting | Apache-2.0 |
| Baseline | CRNN + CTC (trained here) / Tesseract vie | — |
| VN post-corrector | bmd1905/vietnamese-correction-v2 (mBART) | Apache-2.0 |
| Real data (PRIMARY) | 5CD-AI/Viet-Handwriting-OCR-v2 — 60,248 human-annotated lines (train 59,248 / test 1,000) | ⚠️ GATED + none declared (research-only) |
| Real data (fallback) | HenryBui/vietnamese_handwriting_line_ocr, manhha2502/Vietnamese_Handwriting_OCR | ⚠️ none (research-only) |
| Offline/CI spine + augmentation | synthetic line generator | code MIT |
| English sanity | Teklia/IAM-line | MIT |
⚠️ The primary real corpus
5CD-AI/Viet-Handwriting-OCR-v2is GATED (access must be requested + granted on the HF Hub) and has no declared license → research/educational use only. The fallback Vietnamese datasets likewise have no declared license. Any fine-tuned model inherits these restrictions. When the gated dataset is unreachable (offline / no token / access not granted) the loader gracefully skips it and training falls back to the synthetic spine + fallback datasets.
src/vnhtr/
├── config.py cli.py logging_utils.py
├── data/ corpus.py · synth.py · dataset.py · samples.py · download_dataset.py
├── models/ text_utils.py · vocab.py · trocr_model.py · baseline_crnn.py · postcorrect.py · recognizer.py · model_registry.py
├── preprocess/ image_ops.py · segmentation.py
├── training/ train_trocr.py · train_crnn.py · evaluate.py · tune.py · metrics.py
├── agent/ state.py · policy.py · tools.py · llm_orchestrator.py · htr_agent.py
├── api/ schemas.py · dependencies.py · main.py · ui.py · app_combined.py
├── analysis/ autoreport/ monitoring/ automation/ grading/
configs/ · data/ · models/ · tests/ · docs/ · notebooks/ · app/ · deploy/ · sample_data/
pip install -e ".[ml,vision,api,report]"
vnhtr data # sample images + synthetic preview
vnhtr demo-agent # run the agent on the sample page (offline-friendly)
vnhtr recognize --image sample_data/line_sample.png
vnhtr --config configs/train.yaml train # fine-tune TrOCR (auto-resumes)
vnhtr --config configs/train.yaml train-crnn # the CRNN baseline
vnhtr evaluate --which test # TrOCR vs baseline, CER/WER + diacritics
On Colab/GPU use the notebook (below) — it auto-profiles H100/A100/L4/T4.
vnhtr serve --ui --port 7860 # FastAPI /htr + /htr/batch + Gradio UI at /ui
vnhtr autopilot --no-train # eval → analysis → report.pdf + slides.pptx + bundle
vnhtr grade
A deterministic FSM with four decision points acting on intermediate outputs, plus an
optional LLM brain (anthropic) that validates its output and falls back to rules
(default = zero paid API):
Every step is timed + traced and a full manifest.json is written. See
docs/agent_architecture.md.
Open notebooks/VNHTR_Colab_Training_H100_AUTOPILOT.ipynb
— mounts Drive, installs Colab-safe deps (never touches torch), auto-profiles the GPU, trains
resume-safely, evaluates vs the baseline, runs the agent, and generates the report/slides.
Step-by-step: notebooks/COLAB_GUIDE.md.
pytest -q # CPU-only, no model/network downloads (synthetic render + stub recognizer)
docs/: problem_definition · data_description · data_card · model_selection · evaluation ·
agent_architecture · deployment · continual_learning_monitoring · privacy_robustness ·
project_plan · ethics_statement · architecture · model_card · slide_deck_outline · DESIGN_BRIEF.
MIT — see LICENSE. Pretrained models keep their own licenses (table above). The
real Vietnamese handwriting datasets are research/educational use only (no declared license);
the primary corpus 5CD-AI/Viet-Handwriting-OCR-v2 is additionally GATED (Hub access must be
requested + granted). Models trained on them inherit those restrictions.
5 commits
Python
59.9%
TeX
32.6%
Jupyter Notebook
6.2%