docs: Formeln im Fließtext (pdf2md --formulas), Tempo, Qwen mit 8 Plätzen

- README: Ablauf für PDF-Bücher mit --formulas, Quelle pdf2md --formulas, Satzzeichen nach
  eingebetteten Formeln, Stand Corral (10 %: 79 % automatisch, ~2 h ganzes Buch), Pilot 70 → ~24 min,
  Einstellung pdftext, crops/ und bericht/ im Arbeitsordner, 8B-Modell gemessen und verworfen
- BEDIENUNGSANLEITUNG: llama-server --parallel 8 -c 32768, pix2text auf freiester GPU,
  pdf2md --formulas, Statuszeile mit Zeiten je Stufe, Dauer, EPUB mit --from-md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-10-10 03:35:05 +02:00
commit be6ba0b926
2 changed files with 76 additions and 19 deletions

View file

@ -32,7 +32,7 @@ Zwei Vision-Sprachmodelle lesen jede Formel, je eines pro Grafikkarte (je ~18–
M=~/endeavour_home/lm_studio/models/lmstudio-community/Qwen3-VL-30B-A3B-Instruct-GGUF
CUDA_VISIBLE_DEVICES=1 ~/.local/bin/llama-server \
-m $M/Qwen3-VL-30B-A3B-Instruct-Q4_K_M.gguf --mmproj $M/mmproj-Qwen3-VL-30B-A3B-Instruct-F16.gguf \
--host 127.0.0.1 --port 8011 -ngl 99 -c 16384 --parallel 4
--host 127.0.0.1 --port 8011 -ngl 99 -c 32768 --parallel 8
# Modell B: Gemma 4 auf GPU 2, Port 8012
M=~/nvme2n1p7_home/huggingface/models/gemma4
@ -41,7 +41,8 @@ CUDA_VISIBLE_DEVICES=2 ~/.local/bin/llama-server \
--host 127.0.0.1 --port 8012 -ngl 99 -c 16384 --parallel 4
```
Gemma braucht auf GPU 2 rund 17,5 GB. Laufen dort Chatterbox-TTS und der STT-Server, reicht der Speicher
Qwen läuft mit 8 Plätzen zu je 4096 Tokens (zusammen 32768) und belegt rund 22,6 GB; `run` stellt bis zu
8 Anfragen gleichzeitig. Gemma braucht auf GPU 2 rund 17,5 GB. Laufen dort Chatterbox-TTS und der STT-Server, reicht der Speicher
nicht (Gemma bricht beim ersten Bild mit „out of memory“ ab); dann vorher stoppen und danach wieder starten:
```bash
@ -63,7 +64,8 @@ pip install --no-deps pix2tex munch # nur für post_p
pip uninstall -y onnxruntime && pip install onnxruntime-gpu # für die GPU
```
Das Modell (~300 MB) wird beim ersten Lauf nach `~/.pix2text` geladen. Gerät wählen mit
Das Modell (~300 MB) wird beim ersten Lauf nach `~/.pix2text` geladen. Ohne Angabe nimmt pix2text die
Grafikkarte mit dem meisten freien Speicher und liest die Formeln gebündelt. Gerät festlegen mit
`FORMULA_P2T_DEVICE=cpu` oder `cuda:N` (`N` zählt innerhalb von `CUDA_VISIBLE_DEVICES`).
Gemma (Port 8012) wird nur für Formeln gefragt, bei denen pix2text und Qwen uneinig sind. Läuft Gemma
@ -86,7 +88,16 @@ cd ~/Python_Programs/epub2md
python3 epub2md.py buch.epub output/buch
```
Bei PDFs mit pdf2md immer `--images` (oder `--epub`) angeben, sonst gibt es keine Formelbilder.
Bei PDFs mit pdf2md immer `--images` (oder `--epub`) angeben, sonst gibt es keine Formelbilder. Für
Mathebücher **`--formulas`** verwenden: Dann findet pdf2md jede Formel auf der Seite, auch im Fließtext und
in Merkkästen, und schneidet sie als Bild aus (braucht pix2text, siehe oben):
```bash
cd ~/Python_Programs/pdf2md
python3 pdf2md.py --formulas --epub buch.pdf Output/buch/buch.md
```
Das dauert bei 350 Seiten gut 10 Minuten (Corral: 9239 Formeln).
### Schritt 2: Formeln erkennen und prüfen
@ -101,10 +112,11 @@ Bei pdf2md zusätzlich die Original-PDF angeben. Dann schneidet das Programm jed
python3 formula_img2latex.py run Output/buch.md --pdf buch.pdf
```
Das Programm arbeitet in Paketen zu 50 Formeln und meldet nach jedem Paket den Stand:
Das Programm arbeitet in Paketen zu 50 Formeln und meldet nach jedem Paket den Stand und die Zeiten je
Stufe (die Stufen laufen teils gleichzeitig, daher ist die Summe größer als die Paketzeit):
```text
100/1505 verarbeitet: automatisch ersetzt 68 (68%), Review 28, bleibt Bild/keine Formel 4
100/940 verarbeitet: automatisch ersetzt 78 (78%), Review 20, bleibt Bild/keine Formel 2 [Paket 35 s; pix2text 3 s, Qwen 30 s, Prüfung 14 s, Gemma 21 s]
```
Am Ende steht eine Übersicht je Status, beim Gehrke-Brückenkurs zum Beispiel:
@ -116,10 +128,10 @@ Am Ende steht eine Übersicht je Status, beim Gehrke-Brückenkurs zum Beispiel:
pending 539 ← Abbildungen/Symbole, nicht geprüft
```
Dauer: Mit der früheren Regel (Version 0.2.0, mit GLM) etwa 5 Minuten je 50 Formeln, ein Buch mit 1500
Formelbildern also rund 2,5 Stunden. Mit der jetzigen Regel liest pix2text eine Formel in ~0,15 s und Qwen
in ~0,8 s, Gemma nur bei Uneinigkeit; an 2 × 50 Testformeln dauerte das Lesen im Mittel 1,5–2,3 s je
Formel (ohne Bildprüfung). Ein ganzes Buch ist damit noch nicht gemessen.
Dauer: etwa 0,8 s je Formel, also 35–50 Sekunden je Paket (Corral mit `--formulas`: 940 Formeln in
13 Minuten, das ganze Buch mit 9239 Formeln rund 2 Stunden). Am längsten braucht die Bestätigung durch Qwen.
Der Scan liest beim ersten Mal alle Bilder ein (Corral: 6 Minuten); beim Fortsetzen entfällt er, solange
sich das Markdown nicht geändert hat.
Abbrechen (Strg+C) und erneut starten ist kein Problem: Bereits gelesene Formeln werden nicht noch einmal
gefragt, der Lauf setzt fort. `--chunk 100` ändert die Paketgröße, `--limit 200` verarbeitet nur die ersten
200 Bilder.
@ -163,7 +175,14 @@ python3 formula_img2latex.py apply ~/Python_Programs/epub2md/output/buch
```
Aus `![…](../media/images/0042-…jpg)` wird `$L = \{-\sqrt{2};\sqrt{2}\}$` im Text bzw. `$$…$$` als eigener
Absatz. Die Bilddateien bleiben liegen.
Absatz. Die Bilddateien bleiben liegen. Hat die Formelerkennung bei einer Formel im Text ein Satzzeichen
mit ausgeschnitten, steht es danach als normaler Text hinter der Formel (`$a^{x}$,`).
Bei pdf2md-Büchern baut `pdf2md.py --from-md` das EPUB neu, mit allen Formeln als MathML:
```bash
cd ~/Python_Programs/pdf2md && python3 pdf2md.py --from-md Output/buch/buch.md
```
**Danach die Gesamtdatei neu bauen**, sie enthält sonst noch die Bilder:

View file

@ -7,6 +7,9 @@ LaTeX ersetzt – **aber nur, wenn zwei unabhängige Erkenner dieselbe Formel le
pix2text, bestätigt vom Bildmodell Qwen; bei Uneinigkeit darf Gemma pix2text bestätigen) und ein grober
Bildabgleich nicht widerspricht. Alles andere geht in eine Review-Galerie oder bleibt Bild.
Für PDF-Bücher findet `pdf2md --formulas` jede Formel auf der Seite, auch im Fließtext und in Merkkästen,
und schneidet sie als Bild aus; formula_img2latex übersetzt sie dann ebenso (siehe [Quellen](#quellen)).
Schritt-für-Schritt-Anleitung: [BEDIENUNGSANLEITUNG.md](BEDIENUNGSANLEITUNG.md). Änderungen je Version:
[CHANGELOG.md](CHANGELOG.md). Hintergrund und ursprüngliche Planung: `Idee/`.
@ -131,7 +134,8 @@ Gehrke, Brückenkurs Mathematik (EPUB, 1505 Formelbilder): siehe [Stand](#stand)
```text
scan Bildverweise in chapters/*.md (bzw. pdf2md-Markdown) finden, Formel/Abbildung vorklassifizieren
run in Paketen zu 50: pix2text, dann Qwen lesen, prüfen, Gemma nur für Uneinige, prüfen;
nach jedem Paket eine Statuszeile (Regel vlm3: Qwen + Gemma, GLM nur für Einige)
nach jedem Paket eine Statuszeile mit Zeiten je Stufe (Regel vlm3: Qwen + Gemma, GLM nur
für Einige). Die GPUs lesen schon das nächste Paket, während die CPU das vorige prüft.
review Zweifelsfälle im Browser: Original / Render / Overlay / Diff, LaTeX korrigieren und neu prüfen
apply angenommene Formeln ins Markdown schreiben (aus einer Sicherung, idempotent)
revert Markdown-Dateien auf den Stand vor apply zurücksetzen
@ -148,6 +152,17 @@ python3 formula_img2latex.py apply output/buch
python3 epub2md_merge.py output/buch --force # Gesamtdatei danach neu bauen
```
PDF-Buch mit allen Formeln, auch im Fließtext:
```bash
cd ~/Python_Programs/pdf2md
python3 pdf2md.py --formulas --epub buch.pdf Output/buch/buch.md # Formeln als Bilder + Liste
cd ~/Python_Programs/formula_img2latex
python3 formula_img2latex.py run ~/Python_Programs/pdf2md/Output/buch/buch.md --pdf buch.pdf
python3 formula_img2latex.py apply ~/Python_Programs/pdf2md/Output/buch/buch.md
cd ~/Python_Programs/pdf2md && python3 pdf2md.py --from-md Output/buch/buch.md # EPUB mit MathML
```
Status je Formel: `auto_accepted`, `needs_review`, `rejected_keep_image`, `render_failed`, `no_candidate`,
`not_formula`, nach Review `accepted_by_human`, `corrected_by_human`, `kept_by_human`.
@ -155,10 +170,10 @@ Status je Formel: `auto_accepted`, `needs_review`, `rejected_keep_image`, `rende
| Engine | Standard | Konfiguration |
| --- | --- | --- |
| `local` | llama.cpp `http://127.0.0.1:8011/v1` (Qwen3-VL-30B-A3B-Instruct Q4_K_M + mmproj) | `FORMULA_LOCAL_URL`, `FORMULA_LOCAL_MODEL` |
| `local` | llama.cpp `http://127.0.0.1:8011/v1` (Qwen3-VL-30B-A3B-Instruct Q4_K_M + mmproj), 8 parallele Anfragen | `FORMULA_LOCAL_URL`, `FORMULA_LOCAL_MODEL` |
| `local2` | llama.cpp `http://127.0.0.1:8012/v1` (Gemma-4-26B-A4B-it Q4_0 + mmproj) | `FORMULA_LOCAL2_URL`, `FORMULA_LOCAL2_MODEL` |
| `cloud` | OpenRouter, `z-ai/glm-4.6v` (nur Regel `vlm3`) | `OPENROUTER_API_KEY`, `FORMULA_CLOUD_MODEL` |
| `p2t` | pix2text MFR 1.5 (ONNX) im Prozess, erste sichtbare GPU, sonst CPU | `FORMULA_P2T_DEVICE` (`auto`, `cpu`, `cuda:N`), `FORMULA_P2T_MODEL` |
| `p2t` | pix2text MFR 1.5 (ONNX) im Prozess, die sichtbare GPU mit dem meisten freien Speicher, sonst CPU; gebündelt nach Pixelbudget | `FORMULA_P2T_DEVICE` (`auto`, `cpu`, `cuda:N`), `FORMULA_P2T_MODEL` |
pix2text auf der GPU braucht `onnxruntime-gpu` statt `onnxruntime` (cuDNN kommt aus den nvidia-Paketen
von torch). Für `post_process` wird `pix2tex` ohne seine Abhängigkeiten installiert
@ -169,6 +184,11 @@ von torch). Für `post_process` wird `pix2tex` ohne seine Abhängigkeiten instal
Wiederholungsschleifen bis 165 s). Jede Lesart wird mit Modell, Prompt-Version und Nachdenk-Einstellung
gespeichert; dieselbe Frage wird nie zweimal gestellt, ein abgebrochener Lauf setzt dort fort.
Qwen-Server mit `--parallel 8 -c 32768` (je Platz 4096 Tokens) starten; `run` stellt bis zu 8 Anfragen
gleichzeitig (BEDIENUNGSANLEITUNG). Gemessen und verworfen: Qwen3-VL-8B statt 30B-A3B ist nicht schneller
(das MoE-Modell rechnet je Token nur ~3B Parameter) und liest etwas schlechter (Göllmann 42/44 statt 44/45
automatisch).
Kosten der Cloud-Stufe (nur Regel `vlm3`): GLM liest nur Formeln, bei denen Qwen und Gemma einig sind. Gehrke: 967
Anfragen, Ø 2,6 s, zusammen rund 0,15–0,20 $.
@ -193,7 +213,9 @@ Sicherheit: Kandidaten kommen von Modellen und gelten als unsicher. Vor pdflatex
<ausgabe>.formulas/ # neben der Ausgabe, weil epub2md --force die Ausgabe ersetzt
├── workspace.json # Quelle, Schrift, Einstellungen, apply-Zustand
├── formulas/f-<sha12>-<d|i>.json # je Bild und Darstellung: Lesarten, Prüfung, Entscheidung
├── crops/<id>.png # Original je Formel, einmal ausgeschnitten (PDF-Quellen)
├── review/<id>-{orig,render,rigid,diff}.png
├── bericht/ # Ergebnisseite (tools/buch_bericht.py)
└── backup/ # Markdown-Dateien vor dem ersten apply
```
@ -201,7 +223,8 @@ Die Datensätze hängen am SHA-256 des Bildes: Ein erneuter epub2md-Lauf verlier
Einstellungen in `workspace.json` → `settings.consensus_thresholds`: `require_third` (1),
`bold_relevant` (0), `structural` (0), `arbiter` (0), `arbiter_margin` (5), `veto_ncc` (0,65),
`veto_scale_dev` (0 = aus), `min_p_mean`/`min_p_min` (0).
`veto_scale_dev` (0 = aus), `min_p_mean`/`min_p_min` (0), `pdftext` (0: die PDF-Textebene bestätigt nie;
gemessen: in 12 von 319 Fällen fehlten dort Punkte, Striche oder Indizes, die Qwen sah).
## Quellen
@ -209,9 +232,13 @@ Einstellungen in `workspace.json` → `settings.consensus_thresholds`: `require_
| --- | --- | --- |
| epub2md-Ordner | `conversion-report.json`; Warnungen `formula-image` markieren sichere Formeln | `--math auto`: `$…$`/`$$…$$`, `--math tex`: `\(…\)`/`\[…\]`; deutsche Bücher: `3{,}6` |
| pdf2md (`<name>.md` + `<name>_images/` oder `--split`-Ordner) | Bildname `<pdf>-<seite>-<box>`; mit `--pdf` per Template-Matching auf der Seite gefunden und mit 600 dpi aus dem Vektor-PDF neu ausgeschnitten | `$…$`/`$$…$$` |
| pdf2md `--formulas` | Bildname `<pdf>-<seite>-f<nr>.png` (300 dpi), Liste `<name>_images/formulas-*.json` mit Seite, Rechteck, Art (im Text/abgesetzt) und PDF-Text; das Bild wird direkt verwendet | `$…$`/`$$…$$` |
Codeblöcke werden nie verändert. Inline-Formeln, die pdf2md als Glyphensalat im Fließtext ausgibt,
sind nicht Teil dieser Version.
Mit `pdf2md --formulas` findet die Formelerkennung von pix2text (MFD) jede Formel auf der Seite, auch im
Fließtext und in Merkkästen; pdf2md schneidet sie zeichengenau aus dem Text (statt Glyphensalat wie `x4n`).
Ein Satzzeichen am Ende einer eingebetteten Formel wird vor dem Vergleich abgetrennt und als Text hinter
die Formel gesetzt (`$a^{x}$,`). Codeblöcke werden nie verändert. Formeln in Tabellen erfasst die
Erkennung noch nicht.
## Werkzeuge zum Einstellen
@ -234,6 +261,13 @@ sind nicht Teil dieser Version.
## Stand
**Formeln im Fließtext** (unveröffentlicht, nach 0.4.0): Corral mit `pdf2md --formulas`: 9239 Formelbilder
(davon ~88 % eingebettet). Stichprobe 10 % (940): **747 automatisch (79 %)**, im Text 83 %, abgesetzte
Box-Bilder (Herleitungen, Kästen) nur ~29 %; 174 Review, 19 keine Formel; 13 Minuten, hochgerechnet ~2 h
für das ganze Buch. Beschleunigung am Pilot (869 Formeln): 70 → ~24 Minuten, Entscheidungen zu 863/876
gleich (die Abweichungen kommen von den Modellen selbst). Qualität ist hier ohne bekannte Lösung –
vor dem Einsatz eine Stichprobe der übernommenen Formeln von Hand prüfen.
Version 0.4.0 (Regel `p2t`, mehrzeilige Normalform) ist an Göllmann Band 1 und 2 gemessen (siehe
[Messung](#messung)), aber noch **nicht am ganzen Gehrke** gelaufen.
@ -274,8 +308,11 @@ Grenzen und offene Punkte:
- Fettdruck wird nicht geprüft (Vorgabe).
- Die Messung umfasst 2 × 150 Formeln eines Buches ohne Textausschnitt; „0 Fehler“ bedeutet eine
Fehlerquote sehr wahrscheinlich unter ~2 %.
- pdf2md-Bücher: der Ablauf ist umgesetzt (600-dpi-Neuausschnitt, Euler-Schrift für Hefferon), aber im
Konsens-Modus noch nicht an einem ganzen Buch getestet.
- pdf2md-Bücher: am ganzen Corral getestet (ohne `--formulas` 0.4.0, mit `--formulas` 10 %); Formeln in
Tabellen fehlen noch.
- Einzelne Riesenausschnitte (Grafiken, dreizeilige Herleitungen mit völlig anderer Lesart) werden ohne
Bildvergleich abgelehnt: über 2,5 MP oder mehr als 2,5-fach falsche Proportionen; breite Originale werden
für den Vergleich auf 1600 px verkleinert.
## Installation
@ -312,6 +349,7 @@ formula_img2latex/
├── render.py pdflatex-Batch, Schrift-Presets, Rasterung
├── imageio.py Originale laden (PNG/GIF/JPG/SVG, Transparenz, Tönung)
├── sources/ epub2md.py, pdf2md.py, base.py (Markdown-Scan, Begrenzer, Dezimalkomma)
├── structure.py Strukturvergleich mit sympy (optional, aus)
├── pdfcrop.py Formelbild auf der PDF-Seite finden, 600-dpi-Neuausschnitt
├── classify.py Formel / unklar / Abbildung
├── checks.py Pandoc/MathML-Prüfung