andyP commited on
Commit
5955a93
·
verified ·
1 Parent(s): 3410150

Upload gbert-base-contact-ner (company_research.contact gpu model)

Browse files
Files changed (6) hide show
  1. README.md +126 -0
  2. config.json +78 -0
  3. impressum.json +1 -0
  4. model.safetensors +3 -0
  5. tokenizer.json +0 -0
  6. tokenizer_config.json +16 -0
README.md ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ language: de
4
+ base_model: deepset/gbert-base
5
+ pipeline_tag: token-classification
6
+ library_name: transformers
7
+ tags:
8
+ - token-classification
9
+ - ner
10
+ - german
11
+ - contact-information
12
+ - imprint
13
+ - web-extraction
14
+ ---
15
+
16
+ # gbert-base-contact-ner
17
+
18
+ A German token-classification model that finds contact details in the text of company web pages: street, postal
19
+ code, city, country, phone, fax, email, opening hours, location label, department and contact person. It is
20
+ [`deepset/gbert-base`](https://huggingface.co/deepset/gbert-base) fine-tuned on LLM-labeled contact pages. It is the
21
+ `gpu` extraction model of the `company_research.contact` package.
22
+
23
+ ## Labels
24
+
25
+ 11 fields in BIO format, 23 labels in total (`O` plus `B-`/`I-` for each field):
26
+
27
+ `street`, `plz` (postal code), `city`, `country`, `phone`, `fax`, `email`, `opening_hours`, `location_label`,
28
+ `department`, `person`.
29
+
30
+ The model outputs character spans of the input text only. It never rewrites or normalizes a value.
31
+
32
+ ## Training data
33
+
34
+ - Pages of 800 German-language company websites, labeled by LLM agents (Claude Opus) against a written labeling
35
+ guide. Every labeled value appears verbatim on its page. The labels were not verified by humans; one clean-up pass
36
+ covered flagged sites only.
37
+ - The sites are German (399), Swiss (346) and Austrian (55), split by domain: 480 train, 160 dev, 160 test.
38
+ This model was trained on the train split (565 labeled pages) and tuned on dev. The 55 Austrian sites are all in
39
+ the test split, so the model never saw AT data during training.
40
+ - Input is the page as markdown text (not raw HTML).
41
+
42
+ ## Training
43
+
44
+ - Base model `deepset/gbert-base`, token classification head with 23 labels.
45
+ - Pages are cut into windows of 512 tokens (510 plus `[CLS]` and `[SEP]`) with an overlap of 128 tokens. Training
46
+ uses the windows that contain a labeled value plus an equal number of randomly drawn windows without any.
47
+ - AdamW, learning rate 3e-5, weight decay 0.01, batch size 4 with 4 gradient-accumulation steps, up to 8 epochs
48
+ with early stopping (patience 2) on dev seqeval F1.
49
+
50
+ ## Evaluation
51
+
52
+ All numbers are agreement with the LLM-made labels on the 160 held-out test sites (153 of them have contact data),
53
+ from the experiments report of the Impressum project (section 12). Scores are set-based: per site, the predicted
54
+ values are compared with the labeled values after normalization (phones to E.164, emails lowercased, PLZ digits only,
55
+ text casefolded with whitespace and punctuation cleaned). Micro F1 pools all fields. The differences under about 3
56
+ points between rows of the report are noise at this test size.
57
+
58
+ **Extraction on the right pages** (labeled contact pages given; this model alone, F1):
59
+
60
+ | micro | street | plz | phone | fax | email | opening hours | person |
61
+ |---|---|---|---|---|---|---|---|
62
+ | 70.2 | 64.9 | 88.0 | 88.9 | 80.6 | 70.7 | 48.9 | 80.5 |
63
+
64
+ The report does not list per-field scores for city, country, location label or department for this model alone.
65
+ Street and email are its weaker fields among those listed (a regex and a CRF do better there; the pipeline routes those
66
+ fields to them), and opening hours are hard for every method tried.
67
+
68
+ **End to end** (report section 12.7). These numbers are for the whole `company_research.contact` `gpu` pipeline,
69
+ not for this model alone: contact-page detection, hybrid extraction (this model for PLZ, city, phone, hours,
70
+ department and person; a CRF for street and label; regex for fax, email and country), grouping into locations and
71
+ departments, structured-data parsing and social links. Micro F1 over all site fields: **73.6** overall;
72
+ 71.0 on DE, 80.0 on CH, 72.9 on AT.
73
+
74
+ ## How to use
75
+
76
+ ### With `company_research.contact`
77
+
78
+ ```python
79
+ from company_research import contact
80
+
81
+ result = contact.from_site("https://www.example.de", device="gpu")
82
+ ```
83
+
84
+ `device="gpu"` needs the package's `gpu` extra (torch and transformers); the package is not on PyPI.
85
+ It downloads this model on first use and runs on CUDA when available (otherwise on the CPU, much slower). The `cpu` device uses a different, smaller
86
+ set of models without a transformer.
87
+
88
+ ### With `transformers`
89
+
90
+ The model was trained on windows, so long pages must be windowed at inference as well. The reference implementation
91
+ is `company_research/contact/gbert.py` (`windows`, `decode`, `predict`). In short:
92
+
93
+ 1. Tokenize the page text without special tokens, keeping character offsets
94
+ (`tok(text, add_special_tokens=False, return_offsets_mapping=True)`).
95
+ 2. Make windows of 510 tokens whose starts are 382 tokens apart (overlap 128); add `[CLS]` and `[SEP]` to each.
96
+ 3. Run the model, apply softmax, and average the probabilities of tokens that are covered by several windows.
97
+ 4. Take the argmax per token and merge `B-x`/`I-x` runs into character spans using the offsets.
98
+
99
+ ```python
100
+ from transformers import AutoModelForTokenClassification, AutoTokenizer
101
+
102
+ tok = AutoTokenizer.from_pretrained("andyP/gbert-base-contact-ner")
103
+ model = AutoModelForTokenClassification.from_pretrained("andyP/gbert-base-contact-ner").eval()
104
+ ```
105
+
106
+ ## Limitations
107
+
108
+ - German-language company pages (imprint, contact and similar pages). Other languages and page types are untested.
109
+ - The labels come from an LLM and were not verified by humans, so the scores measure agreement with those labels,
110
+ not with human judgment.
111
+ - Weaker fields: street (64.9) and email (70.7) in the scores above; opening hours (48.9) are the hardest.
112
+ Typical errors in the project's spot-check of the full pipeline were missed values, values of third parties (for
113
+ example the web agency named in the imprint), spans cut inside words and navigation text.
114
+ - The model does not group values into locations or departments, and it does not tell contact pages from other
115
+ pages. The pipeline does that.
116
+ - Input must be the page text as markdown, as the training data was. Raw HTML will perform worse.
117
+
118
+ ## Privacy
119
+
120
+ The training pages are public company websites. They contain names and business contact details of contact persons,
121
+ so the training data includes personal data of that kind. The model outputs spans copied from the text you give it
122
+ and does not generate text.
123
+
124
+ ## License
125
+
126
+ MIT, as the base model.
config.json ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_cross_attention": false,
3
+ "architectures": [
4
+ "BertForTokenClassification"
5
+ ],
6
+ "attention_probs_dropout_prob": 0.1,
7
+ "bos_token_id": null,
8
+ "classifier_dropout": null,
9
+ "dtype": "float32",
10
+ "eos_token_id": null,
11
+ "hidden_act": "gelu",
12
+ "hidden_dropout_prob": 0.1,
13
+ "hidden_size": 768,
14
+ "id2label": {
15
+ "0": "O",
16
+ "1": "B-street",
17
+ "2": "I-street",
18
+ "3": "B-plz",
19
+ "4": "I-plz",
20
+ "5": "B-city",
21
+ "6": "I-city",
22
+ "7": "B-country",
23
+ "8": "I-country",
24
+ "9": "B-phone",
25
+ "10": "I-phone",
26
+ "11": "B-fax",
27
+ "12": "I-fax",
28
+ "13": "B-email",
29
+ "14": "I-email",
30
+ "15": "B-opening_hours",
31
+ "16": "I-opening_hours",
32
+ "17": "B-location_label",
33
+ "18": "I-location_label",
34
+ "19": "B-department",
35
+ "20": "I-department",
36
+ "21": "B-person",
37
+ "22": "I-person"
38
+ },
39
+ "initializer_range": 0.02,
40
+ "intermediate_size": 3072,
41
+ "is_decoder": false,
42
+ "label2id": {
43
+ "B-city": 5,
44
+ "B-country": 7,
45
+ "B-department": 19,
46
+ "B-email": 13,
47
+ "B-fax": 11,
48
+ "B-location_label": 17,
49
+ "B-opening_hours": 15,
50
+ "B-person": 21,
51
+ "B-phone": 9,
52
+ "B-plz": 3,
53
+ "B-street": 1,
54
+ "I-city": 6,
55
+ "I-country": 8,
56
+ "I-department": 20,
57
+ "I-email": 14,
58
+ "I-fax": 12,
59
+ "I-location_label": 18,
60
+ "I-opening_hours": 16,
61
+ "I-person": 22,
62
+ "I-phone": 10,
63
+ "I-plz": 4,
64
+ "I-street": 2,
65
+ "O": 0
66
+ },
67
+ "layer_norm_eps": 1e-12,
68
+ "max_position_embeddings": 512,
69
+ "model_type": "bert",
70
+ "num_attention_heads": 12,
71
+ "num_hidden_layers": 12,
72
+ "pad_token_id": 0,
73
+ "tie_word_embeddings": true,
74
+ "transformers_version": "5.16.1",
75
+ "type_vocab_size": 2,
76
+ "use_cache": true,
77
+ "vocab_size": 31102
78
+ }
impressum.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"name": "gbert_ner", "hf_id": "deepset/gbert-base", "max_len": 512, "stride": 128, "fields": ["street", "plz", "city", "country", "phone", "fax", "email", "opening_hours", "location_label", "department", "person"]}
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:66f501c8644499d84d80e2848c6843f02b3f08a56ceada192a4f0256c4fccb36
3
+ size 437442444
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend": "tokenizers",
3
+ "cls_token": "[CLS]",
4
+ "do_lower_case": false,
5
+ "is_local": false,
6
+ "local_files_only": false,
7
+ "mask_token": "[MASK]",
8
+ "max_len": 512,
9
+ "model_max_length": 512,
10
+ "pad_token": "[PAD]",
11
+ "sep_token": "[SEP]",
12
+ "strip_accents": false,
13
+ "tokenize_chinese_chars": true,
14
+ "tokenizer_class": "BertTokenizer",
15
+ "unk_token": "[UNK]"
16
+ }