Text-Query (n-gram, Tibetan) soll relevante Seiten/Zeilen aus Pecha-Bildern finden, obwohl zunächst keine echten Bild-Text-Paare vorliegen.
- Bild-Encoder auf Stabi-Bildern selbstüberwacht vortrainieren.
- Text-Encoder auf Tibetan-Texten vortrainieren (char/subword-fokussiert, Unicode-sicher).
- Mit synthetischen und pseudo-gelabelten Paaren einen gemeinsamen Embedding-Raum lernen.
- Retrieval-Index bauen und iterativ mit besseren Paaren nachschärfen.
Warum:
- Sehr stark für Dokument-/Struktur-Features ohne Labels.
- Stabil beim Self-Supervised-Finetuning auf eigenen Scans.
- Gute Basis für spätere Zeilen-/Region-Embeddings.
Praktische Konfiguration:
- Input: zuerst
518oder448, später optional672für feine Druckdetails. - Pooling: CLS + mean pooling testen, meist mean stabiler für Retrieval.
- Output-Dim für Retrieval-Head:
768 -> 256oder384Projektion.
Alternative:
SigLIP/CLIP-Vision-Backbone, falls du schon CLIP-Tooling nutzt.
- Für echtes n-gram retrieval reicht ein reiner Page-Encoder meist nicht.
- Empfohlen ist ein Line Encoder (oder Region-Encoder) als primärer Retrieval-Encoder.
- Praktischer Kompromiss:
- erst Page-level self-supervised pretraining,
- dann Line-level fine-tuning auf synthetischen Line-Crops (mit bekanntem Text),
- optional zwei Heads behalten:
- Page-Head für coarse recall,
- Line-Head für präzises final retrieval.
Warum:
- Tibetan hat komplexe Unicode-Zeichenfolgen und Kombinationszeichen.
- Byte/Char-nahe Modelle sind robuster als reine ASCII-/Word-Pipelines.
- Funktioniert besser bei n-gram retrieval, wenn Orthographie variiert.
Praktische Optionen:
- ByT5-small/base (byte-level, Unicode-robust) + contrastive Head.
- SentencePiece-Unigram auf Tibetan-Korpus (8k-16k vocab) + Transformer Encoder.
- Hybrid: Char CNN/Transformer + Subword-Encoder fusionieren (optional später).
Empfohlene Startwahl:
- Wenn schnell robust gewünscht: ByT5-small.
- Wenn du volle Kontrolle willst: eigenes SentencePiece-Unigram + Encoder.
- Verwende NFC oder NFKC konsistent (nicht mischen).
- Pipeline-weit genau eine Norm erzwingen (Training + Inferenz + Indexing).
- Nicht auf ASCII-Grenzen verlassen.
- Tibetan Trenner (
་,།) explizit behandeln. - n-grams auf Unicode-Grapheme-Cluster oder normalisierten Zeichenfolgen bauen, nicht auf Bytestring-Slices.
- SentencePiece direkt auf normalisiertem Tibetan trainieren.
- Kontrolliere, dass seltene kombinierte Sequenzen nicht zerstört werden.
- Gleiche Normalize/Canonicalize-Logik für:
- Korpusindex
- Query
- Eval-Daten
- Sonst sinkt Recall künstlich stark.
Daten:
- Stabi-Rohbilder (
sbb_images) + crops/lines (falls vorhanden).
Methoden:
- DINO/SimCLR-style augmentations (crop, blur, contrast, JPEG artifacts).
- Dokument-spezifische Augs moderat halten (nicht zu starke geometrische Verzerrung).
Output:
- Checkpoints:
image_encoder_best.pt,image_encoder_last.pt - Embedding-Head checkpoint (für Retrieval kompatibel).
Daten:
- Alle verfügbaren Tibetan-Texte (auch klein ist ok).
- Optional synthetisch erzeugte Tibetan-Zeilen für Datenaufblähung.
Methoden:
- MLM/denoising oder contrastive text objectives.
- Ziel: robuste orthographische und n-gram-nahe Repräsentationen.
Output:
text_encoder_best.pt- Tokenizer-Artefakte (
sentencepiece.modeloder byte-level config).
- Rendered line image + exakt bekannter Text.
- Variiere Schrift, Dicke, Noise, Background, Scan-Artefakte.
- Nutze vorhandene Texture-LoRA für realistischere Bilder.
- Segmentierung/Line detector auf Stabi.
- Schwache Labels über:
- heuristische Zuordnung,
- VLM/OCR-Teacher (noisy),
- nearest-neighbor propagation.
- Image/Text jeweils eigener Encoder + Projektionskopf in gemeinsamen Raum.
- Loss: InfoNCE contrastive (+ hard negatives).
- Batch negatives + mined hard negatives aus ähnlichen Seiten.
Output:
dual_encoder_best(image/text + projection heads)- retrieval-ready embedding pipeline.
- Segmentiere Seite -> Zeilen/Blöcke.
- Bilde Image-Embeddings, speichere mit Metadaten (PPN, Seite, bbox).
- FAISS/HNSW Index bauen.
Nur "ähnliches Bild" ist nicht ausreichend. Jeder Index-Eintrag muss Quelle und Position mitführen.
Empfohlenes Record-Schema (pro Line/Region):
{
"id": "ppn337138764X_p0042_l0017",
"ppn": "337138764X",
"page_id": "0042",
"image_path": "sbb_images/default_abc123.jpg",
"bbox_xyxy": [312, 840, 1580, 932],
"split": "real",
"source_url": "https://content.staatsbibliothek-berlin.de/...",
"viewer_url": "https://digital.staatsbibliothek-berlin.de/werkansicht?PPN=337138764X&PHYSID=PHYS_0042"
}Bei Retrieval gibst du genau dieses Record zurück, damit der Treffer zitierbar und nachvollziehbar ist.
- Query normalisieren (Unicode-Regeln).
- n-grams erzeugen.
- Text-Embeddings rechnen.
- ANN Search + optional reranking.
- Output immer mit
ppn,page_id,bbox_xyxy,viewer_url.
Empfohlenes Top-K Response-Schema:
{
"query": {
"raw": "བཀྲ་ཤིས",
"normalized": "བཀྲ་ཤིས",
"normalization": "NFC",
"ngrams": ["བཀ", "ཀྲ", "ྲ་", "་ཤ", "ཤི", "ིས"]
},
"model_info": {
"image_encoder": "dinov2_vitb14_line_head_v3",
"text_encoder": "byt5_small_retrieval_v2",
"index_id": "faiss_lines_2026_02_13"
},
"top_k": 10,
"results": [
{
"rank": 1,
"score": 0.8731,
"distance": 0.1269,
"id": "ppn337138764X_p0042_l0017",
"ppn": "337138764X",
"page_id": "0042",
"line_id": "l0017",
"bbox_xyxy": [312, 840, 1580, 932],
"image_path": "sbb_images/default_abc123.jpg",
"crop_path": "index_crops/ppn337138764X_p0042_l0017.png",
"source_url": "https://content.staatsbibliothek-berlin.de/...",
"viewer_url": "https://digital.staatsbibliothek-berlin.de/werkansicht?PPN=337138764X&PHYSID=PHYS_0042",
"metadata": {
"split": "real",
"collection": "sbb",
"index_version": "2026-02-13"
}
}
]
}Hinweise:
scoreunddistancebeide speichern (für Debugging/Monitoring).idmuss stabil sein (ppn + page + line), damit Treffer reproduzierbar bleiben.viewer_urldirekt klickbar halten (für manuelle Verifikation).- Optional später Felder ergänzen:
ocr_text(falls verfügbar),rerank_score,evidence_spansfür explainability.
Code-Referenz:
- Pydantic-Schema liegt unter
tibetan_utils/retrieval_schema.py - Zentrales Root-Modell:
RetrievalResult
Metriken:
- Recall@K (K=1,5,10,50)
- MRR
- nDCG
Eval-Sets:
- Kleine manuelle Goldmenge (auch 200-500 Queries reichen für Start).
- Mix aus kurzen und längeren n-grams.
- Tag 1-2: Unicode-/Tokenizer-Pipeline finalisieren, Eval-Protokoll fixieren.
- Tag 2-4: Image encoder self-supervised pretraining.
- Tag 3-5: Text encoder pretraining.
- Tag 5-7: Synthetic paired data groß erzeugen.
- Tag 8-10: Dual-encoder alignment (synthetic + pseudo pairs).
- Tag 10-11: Hard-negative mining + zweiter Alignment-Run.
- Tag 11: Export
best+fastVarianten und Index-Prototyp.
image_encoder_besttext_encoder_bestdual_encoder_best- Tokenizer + Unicode normalization code (versioniert)
- Retrieval index builder scripts + eval scripts
- Kleinere distilled/fast Variante für lokale Iterationen
- Risiko: Kein echtes Alignment ohne Paare.
- Gegenmaßnahme: synthetic + pseudo pairs früh einbauen.
- Risiko: Unicode mismatch zwischen train/infer/index.
- Gegenmaßnahme: eine zentrale Normalisierungsfunktion, überall identisch nutzen.
- Risiko: Overfit auf Synthetic Look.
- Gegenmaßnahme: realistische Texture/scan-Augmentations + echte SBB crops beim Fine-Tuning.
- Image Encoder: DINOv2 ViT-B/14 (self-supervised auf Stabi).
- Text Encoder: ByT5-small (Unicode-robust) oder SP-Unigram + Transformer.
- Alignment: Dual-Encoder mit InfoNCE auf synthetic + pseudo pairs.
- Priorität: erst robuste Unicode/Text-Pipeline, dann Alignment.