beyoru commited on
Commit
c82958b
·
verified ·
1 Parent(s): 28ab698

Add README.md

Browse files
Files changed (1) hide show
  1. README.md +137 -0
README.md ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: cc-by-nc-4.0
3
+ language:
4
+ - en
5
+ - vi
6
+ base_model: google/gemma-4-E4B-it
7
+ pipeline_tag: token-classification
8
+ library_name: transformers
9
+ tags:
10
+ - information-extraction
11
+ - document-ai
12
+ - structured-output
13
+ - gemma4
14
+ ---
15
+
16
+ # gemmaExtract
17
+
18
+ **Pull typed fields out of a document in one forward pass. No text generation, no broken JSON.**
19
+
20
+ You give gemmaExtract a document and a list of fields you want. It returns each field's value, where that value sits in the text, whether the field is absent, and how confident it is. Values are read straight from the document (or computed from numbers in it), so the model cannot invent a string that is not there.
21
+
22
+ ```
23
+ document ──► one forward pass ──► {field: value, span, p_null, confidence}
24
+ ```
25
+
26
+ ## Quick start
27
+
28
+ ```python
29
+ import sys
30
+ from huggingface_hub import snapshot_download
31
+
32
+ path = snapshot_download("beyoru/gemmaExtract")
33
+ sys.path.insert(0, path)
34
+ from gemma_extract import GemmaExtract
35
+
36
+ model = GemmaExtract.from_pretrained(path) # needs a CUDA GPU, ~18 GB in bf16
37
+
38
+ doc = """INVOICE No: INV-2026-0042 Date: 15/01/2026
39
+ Seller: Northwind Office Supply Ltd.
40
+ 1. A4 paper (box) x10 45.00 450.00
41
+ 2. Toner cartridge x2 120.00 240.00
42
+ Subtotal: 690.00 Tax 10%: 69.00 TOTAL DUE: 759.00
43
+ Paid: 800.00"""
44
+
45
+ out = model.extract(doc, {
46
+ "invoice_no": {"type": "text", "instructions": "Invoice number"},
47
+ "date": {"type": "date", "instructions": "Invoice date"},
48
+ "items": {"type": "list", "instructions": "Names of the items bought"},
49
+ "total": {"type": "number", "instructions": "Total amount due"},
50
+ "po_number": {"type": "text", "instructions": "Purchase order number"},
51
+ })
52
+ ```
53
+
54
+ ```json
55
+ {
56
+ "invoice_no": {"value": "INV-2026-0042", "spans": [{"start": 12, "end": 25, "text": "INV-2026-0042"}], "null": false, "p_null": 0.0001},
57
+ "date": {"value": "2026-01-15", "guess": "15/01/2026", "null": false},
58
+ "items": {"value": ["A4 paper (box)", "Toner cartridge"], "null": false},
59
+ "total": {"value": 759.0, "guess": "759.00", "op": "none", "null": false},
60
+ "po_number": {"value": null, "null": true, "p_null": 1.0}
61
+ }
62
+ ```
63
+
64
+ Vietnamese documents work the same way:
65
+
66
+ ```python
67
+ model.extract("HÓA ĐƠN GIÁ TRỊ GIA TĂNG ... Ngày 20 tháng 10 năm 2026 ... Tổng cộng thanh toán: 3.685.000",
68
+ {"ngay": {"type": "date", "instructions": "Ngày lập hoá đơn"},
69
+ "tong": {"type": "number", "instructions": "Tổng cộng thanh toán"}})
70
+ # {"ngay": {"value": "2026-10-20"}, "tong": {"value": 3685000.0}}
71
+ ```
72
+
73
+ ## Field types
74
+
75
+ | type | returns | notes |
76
+ |---|---|---|
77
+ | `text` | string + character span | copied verbatim from the document |
78
+ | `list` | list of strings + spans | every item that matches |
79
+ | `number` | float | read from the document, or computed from numbers in it (`sum`, `diff`, `avg`, `count`, `div`, `mul`; operands are returned) |
80
+ | `date` | `YYYY-MM-DD` | day-first by default, Vietnamese and English formats |
81
+
82
+ Every field also gets `p_null` (probability the field is absent), `null`, `confidence` and `guess` (the best candidate, returned even when the field is judged absent).
83
+
84
+ Options:
85
+ - `null_threshold`: per request or per field. The default depends on the detected language (`en` 0.40, `vi` 0.80, any other language 0.80) and leans conservative: it rarely reports a present value as missing. Raise recall of absent fields by lowering it.
86
+ - `number_style`: `"en"` (1,234.5) or `"vi"` (1.234,5). By default it is detected from the document.
87
+
88
+ ## Results
89
+
90
+ Measured on half of an H200, bf16, batch 1, default null threshold.
91
+
92
+ **Reading comprehension with unanswerable questions** (1,000 held-out questions each, natural mix of answerable and unanswerable):
93
+
94
+ | | accuracy | absent field reported as present | present field reported as absent | F1 on answerable |
95
+ |---|---|---|---|---|
96
+ | SQuAD 2.0 validation (EN) | 79.3% | 147 / 495 | 9 / 505 | 0.93 |
97
+ | UIT-ViQuAD 2.0 validation (VI) | 81.4% | 63 / 318 | 16 / 682 | 0.91 |
98
+
99
+ **Other languages** (XQuAD, 300 questions per language, all answerable). The extraction head was not tuned for these languages; they come from the multilingual Gemma 4 backbone:
100
+
101
+ | language | EM | F1 | present field reported as absent |
102
+ |---|---|---|---|
103
+ | English | 70.3 | 86.6 | 1 / 300 |
104
+ | German | 60.3 | 80.4 | 2 / 300 |
105
+ | Spanish | 58.0 | 80.2 | 6 / 300 |
106
+ | Chinese | 64.7 | 84.1 | 4 / 300 |
107
+ | Russian | 61.3 | 79.5 | 7 / 300 |
108
+ | Thai | 63.3 | 84.1 | 5 / 300 |
109
+ | Arabic | 56.7 | 77.3 | 9 / 300 |
110
+ | Hindi | 59.3 | 77.0 | 2 / 300 |
111
+
112
+ (Absent-field counts use the threshold applied to each language: 0.40 for English, 0.80 otherwise.)
113
+
114
+ **Receipt fields** (SROIE test, 361 receipts, exact match):
115
+
116
+ | company | date | total | address (F1) |
117
+ |---|---|---|---|
118
+ | 96.4 | 98.9 | 93.4 | 67.5 |
119
+
120
+ **Speed**: the document is read once for all fields, so latency barely moves with the number of fields. Model pass for 1 / 5 / 10 fields: 52 / 53 / 54 ms (16 fields per pass; 20 fields take two passes, ~110 ms). A full `extract()` call on a 5-7 field invoice, including decoding and a small HTTP wrapper, takes ~150-180 ms.
121
+
122
+ ## Limitations
123
+
124
+ - **Arithmetic over the document** (e.g. change = paid − total) is partial: about 7 in 10 computed answers are right on English financial tables and about 1 in 2 on English narrative text; on Vietnamese documents it is not reliable yet and may return one of the operands instead. Copy-type numbers (totals, amounts printed on the document) are much more reliable.
125
+ - **Span-based**: answers that must be paraphrased or merged from scattered places (long free-form answers, multi-line addresses) are weaker than with a generative model.
126
+ - Up to **2,048 tokens per pass**; longer documents are truncated (`usage.truncated` tells you).
127
+ - Languages other than English and Vietnamese work (see the XQuAD table) but absent-field detection has only been checked in English and Vietnamese.
128
+ - Not supported yet: `time`, `duration`, `estimate`, `enum` fields and image input.
129
+ - Runs with `transformers` (≥ 5.17); there is no serving-engine integration yet.
130
+
131
+ ## How it works, briefly
132
+
133
+ A Gemma 4 E4B backbone whose global-attention layers attend in both directions, plus a small extraction head. The document comes first and the field schema after it; each field's description becomes a query that points to the start and end of its value in the document, decides whether the field is absent, and, for numbers, picks an operation and its operands. Nothing is decoded token by token.
134
+
135
+ ## License
136
+
137
+ CC BY-NC 4.0: free for non-commercial use with attribution; commercial use needs prior written permission from the author ([beyoru](https://huggingface.co/beyoru)). gemmaExtract is derived from Gemma 4 E4B (Apache 2.0); see `NOTICE` and `LICENSE-APACHE-2.0`.