Views
No views yet
1from transformers import pipeline, AutoModelForTokenClassification, AutoTokenizer
2
3tokenizer = AutoTokenizer.from_pretrained("gbpatentdata/patent_entities_ner")
4model = AutoModelForTokenClassification.from_pretrained("gbpatentdata/patent_entities_ner")
5
6
7def custom_recognizer(text, model=model, tokenizer=tokenizer, device=0):
8
9 # HF ner pipeline
10 token_level_results = pipeline("ner", model=model, device=0, tokenizer=tokenizer)(text)
11
12 # keep entities tracked
13 entities = []
14 current_entity = None
15
16 for item in token_level_results:
17
18 tag = item['entity']
19
20 # replace '▁' with space for easier reading (_ is created by the XLM-RoBERTa tokenizer)
21 word = item['word'].replace('▁', ' ')
22
23 # aggregate I-O-B tagged entities
24 if tag.startswith('B-'):
25
26 if current_entity:
27 entities.append(current_entity)
28
29 current_entity = {'type': tag[2:], 'text': word.strip(), 'start': item['start'], 'end': item['end']}
30
31 elif tag.startswith('I-'):
32
33 if current_entity and tag[2:] == current_entity['type']:
34 current_entity['text'] += word
35 current_entity['end'] = item['end']
36
37 else:
38
39 if current_entity:
40 entities.append(current_entity)
41
42 current_entity = {'type': tag[2:], 'text': word.strip(), 'start': item['start'], 'end': item['end']}
43
44 else:
45 # deal with O tag
46 if current_entity:
47 entities.append(current_entity)
48 current_entity = None
49
50 if current_entity:
51 # add to entities
52 entities.append(current_entity)
53
54 # track entity merges
55 merged_entities = []
56
57 # merge entities of the same type
58 for entity in entities:
59 if merged_entities and merged_entities[-1]['type'] == entity['type'] and merged_entities[-1]['end'] == entity['start']:
60 merged_entities[-1]['text'] += entity['text']
61 merged_entities[-1]['end'] = entity['end']
62 else:
63 merged_entities.append(entity)
64
65 # clean up extra spaces
66 for entity in merged_entities:
67 entity['text'] = ' '.join(entity['text'].split())
68
69 # convert to list of dicts
70 return [{'class': entity['type'],
71 'entity_text': entity['text'],
72 'start': entity['start'],
73 'end': entity['end']} for entity in merged_entities]
74
75
76
77example = """
78Date of Application, 1st Aug., 1890-Accepted, 6th Sept., 1890
79COMPLETE SPECIFICATION.
80Improvements in Coin-freed Apparatus for the Sale of Goods.
81I, CHARLES LOTINGA, of 33 Cambridge Street, Lower Grange, Cardiff, in the County of Glamorgan, Gentleman,
82do hereby declare the nature of this invention and in what manner the same is to be performed,
83to be particularly described and ascertained in and by the following statement
84"""
85
86ner_results = custom_recognizer(example)
87print(ner_results)| Full Entity | Precision | Recall | F1-Score |
|---|---|---|---|
| PER | 92.2% | 97.7% | 94.9% |
| OCC | 93.8% | 93.8% | 93.8% |
| ADD | 88.6% | 91.2% | 89.9% |
| DATE | 93.7% | 98.7% | 96.1% |
| FIRM | 64.0% | 94.1% | 76.2% |
| COMM | 77.1% | 87.1% | 81.8% |
| Overall (micro avg) | 89.9% | 95.3% | 92.5% |
| Overall (macro avg) | 84.9% | 93.8% | 88.9% |
| Overall (weighted avg) | 90.3% | 95.3% | 92.7% |
1@article{bct2025,
2 title = {300 Years of British Patents},
3 author = {Enrico Berkes and Matthew Lee Chen and Matteo Tranchero},
4 journal = {arXiv preprint arXiv:2401.12345},
5 year = {2025},
6 url = {https://arxiv.org/abs/2401.12345}
7}