Views
No views yet
1{
2 "entries": [
3 {
4 "title": "Vorwort",
5 "authors": [],
6 "printed_page_number": "vii",
7 "skip": true
8 },
9 {
10 "title": "1. Introduction",
11 "authors": ["Jane Doe"],
12 "printed_page_number": "1",
13 "skip": false
14 }
15 ]
16}skip marks a line that isn't an actual chapter — front matter (e.g.
a preface, list of contributors), back matter (e.g. bibliography,
index), or a part/section divider. It's still emitted as its own
entry with its own title/page, never omitted; only its own true/false
correctness is excluded from evaluation's precision/recall/F1 match
key (see "Results" below) — the entry itself is still scored on
title+page like any other.numind/NuExtract3 — same architecture,
same AutoModelForImageTextToText/AutoProcessor loading path, same
template-mode prompt contract (see below). No PEFT dependency needed to
run it.{title, authors, printed_page_number, skip} entries from a
scanned table-of-contents page (1-3 pages, rendered to an image no
larger than 1200px on its longer side). Trained on German-language
academic book TOCs sourced from the Deutsche Nationalbibliothek (DNB);
expect degraded quality outside that domain (other languages, other
document types, non-TOC pages).common.py and prepare_data.py's
render_pages_to_pngs from the training repo rather than
reconstructing the prompt by hand, since even small prompt drift will
hurt output quality. Minimal usage:1import json
2import torch
3from PIL import Image
4from transformers import AutoModelForImageTextToText, AutoProcessor
5
6repo_id = "cmboulanger/nuextract3-toc"
7processor = AutoProcessor.from_pretrained(repo_id, trust_remote_code=True)
8model = AutoModelForImageTextToText.from_pretrained(
9 repo_id, trust_remote_code=True, dtype=torch.bfloat16
10).to("cuda")
11
12template = {"entries": [{"title": "verbatim-string", "authors": ["string"],
13 "printed_page_number": "verbatim-string", "skip": "boolean"}]}
14instructions = "..." # see common.py's _INSTRUCTIONS for the full text
15messages = [{"role": "user", "content": [
16 {"type": "text", "text": "Extract every table-of-contents entry from this page."},
17 {"type": "image", "image": Image.open("toc-page.png").convert("RGB")},
18]}]
19
20inputs = processor.apply_chat_template(
21 messages, template=json.dumps(template), instructions=instructions,
22 enable_thinking=False, add_generation_prompt=True,
23 tokenize=True, return_dict=True, return_tensors="pt",
24).to("cuda")
25generated = model.generate(**inputs, max_new_tokens=4096, do_sample=False)
26completion = generated[:, inputs["input_ids"].shape[1]:]
27print(processor.batch_decode(completion, skip_special_tokens=True)[0])printed_page_number
both match a ground-truth entry):Baseline (zero-shot numind/NuExtract3) | This checkpoint (LoRA, 3 epochs) | Δ | |
|---|---|---|---|
| Precision | 0.6131 | 0.7555 | +0.142 |
| Recall | 0.7590 | 0.7533 | −0.006 |
| F1 | 0.6783 | 0.7544 | +0.076 |
RESULTS.md in the training repo.dataset_stats.py/RESULTS.md for the full breakdown
(entries/book, page-count distribution, skip ratio).