Token Classification
Transformers
Safetensors
English
bert
ner
named-entity-recognition
job-postings
distilled
Instructions to use AchrafSoltani/jobbert-ner-haiku-v1 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use AchrafSoltani/jobbert-ner-haiku-v1 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("token-classification", model="AchrafSoltani/jobbert-ner-haiku-v1")# Load model directly from transformers import AutoTokenizer, AutoModelForTokenClassification tokenizer = AutoTokenizer.from_pretrained("AchrafSoltani/jobbert-ner-haiku-v1") model = AutoModelForTokenClassification.from_pretrained("AchrafSoltani/jobbert-ner-haiku-v1", device_map="auto") - Notebooks
- Google Colab
- Kaggle
Initial upload: s4_jobbert_haiku (paper release 2026-04)
Browse files- README.md +136 -0
- config.json +63 -0
- model.safetensors +3 -0
- special_tokens_map.json +7 -0
- tokenizer.json +0 -0
- tokenizer_config.json +58 -0
- training_args.bin +3 -0
- vocab.txt +0 -0
README.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: cc-by-nc-4.0
|
| 3 |
+
language:
|
| 4 |
+
- en
|
| 5 |
+
library_name: transformers
|
| 6 |
+
pipeline_tag: token-classification
|
| 7 |
+
tags:
|
| 8 |
+
- ner
|
| 9 |
+
- named-entity-recognition
|
| 10 |
+
- job-postings
|
| 11 |
+
- distilled
|
| 12 |
+
- bert
|
| 13 |
+
metrics:
|
| 14 |
+
- f1
|
| 15 |
+
- precision
|
| 16 |
+
- recall
|
| 17 |
+
---
|
| 18 |
+
|
| 19 |
+
# jobbert-ner-haiku-v1
|
| 20 |
+
|
| 21 |
+
Distilled Named Entity Recognition model for English-language job postings. One of six students produced for the paper *Distributed Agentic NER on Spark: A Teacher-Student Pipeline for Large-Scale Entity Extraction from Job Postings* (Soltani 2026).
|
| 22 |
+
|
| 23 |
+
- **Teacher:** Claude Haiku 4.5 (labels acquired via AWS Bedrock)
|
| 24 |
+
- **Architecture:** jjzha/jobbert-base-cased fine-tuned for 8-class token classification
|
| 25 |
+
- **Student identifier:** `s4_jobbert_haiku`
|
| 26 |
+
- **Artefact size:** ~820 MB
|
| 27 |
+
|
| 28 |
+
Latency is materially lower than the spaCy students (~15 ms vs ~44 ms per document on the gold set). F1 is materially lower because the 512-token window cannot reach the trailing part of most postings.
|
| 29 |
+
|
| 30 |
+
## Intended use
|
| 31 |
+
|
| 32 |
+
Entity extraction from English-language job-posting descriptions into an eight-type schema:
|
| 33 |
+
|
| 34 |
+
`SKILL`, `JOB_TITLE`, `COMPANY`, `LOCATION`, `EXPERIENCE_LEVEL`, `EDUCATION`, `CERT`, `COMPENSATION`.
|
| 35 |
+
|
| 36 |
+
Appropriate downstream applications include posting indexing for search and analytics, skill-demand aggregation for labour-market research, cost-quality-speed benchmarking of distilled NER, and teaching use in NLP / distillation courses.
|
| 37 |
+
|
| 38 |
+
## Out-of-scope use
|
| 39 |
+
|
| 40 |
+
Not suitable for:
|
| 41 |
+
|
| 42 |
+
- CVs or résumés (different register; a CV-trained model should be used instead).
|
| 43 |
+
- Non-English postings.
|
| 44 |
+
- Fully-automated candidate screening or hiring decisions; downstream ranking or filtering should be built only after an application-side schema and bias review (see *Ethical considerations*).
|
| 45 |
+
- Medical, legal, financial or other high-stakes decision support.
|
| 46 |
+
- Posting text from languages or locales for which the underlying teacher labels were not representative.
|
| 47 |
+
|
| 48 |
+
## Training
|
| 49 |
+
|
| 50 |
+
- **Teacher labels:** 5,000 stratified postings labelled by Claude Haiku 4.5 in a single run at temperature 0. `max_tokens` was raised from 4,096 to 8,192 mid-run after two truncation failures on entity-dense postings; final labels from the fixed-ceiling run were used.
|
| 51 |
+
- **Curator:** 80/10/10 train/dev/test split by `md5(job_link) mod 10`, so Sonnet- and Haiku-trained students see the same posting partitions.
|
| 52 |
+
- **Hardware:** one NVIDIA A10G 24 GB GPU (AWS g5.xlarge).
|
| 53 |
+
- **Training seed:** 42.
|
| 54 |
+
- **Principal hyperparameters and full training spec:** `pipeline/training/experiments/specs/s4_jobbert_haiku.yaml` in the accompanying project repository.
|
| 55 |
+
|
| 56 |
+
## Evaluation
|
| 57 |
+
|
| 58 |
+
Sonnet-trained students evaluate on all 516 gold postings; Haiku-trained students evaluate on 515 because one posting was dropped by the curator for zero-entity teacher output during the Haiku run. Metric: micro-F1 over exact `(text, type)` tuples; character-offset matching is relaxed. Entities are deduplicated within a posting before comparison.
|
| 59 |
+
|
| 60 |
+
| Overall | Value |
|
| 61 |
+
|---|---|
|
| 62 |
+
| Micro-F1 | **0.2844** |
|
| 63 |
+
| Precision | 0.3838 |
|
| 64 |
+
| Recall | 0.2259 |
|
| 65 |
+
| 95% CI | [0.276, 0.293] (entity-level delta method) |
|
| 66 |
+
| Latency mean (eval hardware) | 15.28 ms / document |
|
| 67 |
+
| Latency p99 (eval hardware) | 17.6 ms / document |
|
| 68 |
+
| Text coverage | first 512 BERT tokens (~first third of an average posting at 3,996 characters mean length) |
|
| 69 |
+
| Postings evaluated | 515 (of the 516-posting gold set) |
|
| 70 |
+
|
| 71 |
+
### Per-entity-type
|
| 72 |
+
|
| 73 |
+
| Entity type | P | R | F1 |
|
| 74 |
+
|---|---|---|---|
|
| 75 |
+
| COMPANY | 0.636 | 0.470 | 0.540 |
|
| 76 |
+
| JOB_TITLE | 0.615 | 0.473 | 0.535 |
|
| 77 |
+
| LOCATION | 0.552 | 0.458 | 0.501 |
|
| 78 |
+
| COMPENSATION | 0.235 | 0.067 | 0.104 |
|
| 79 |
+
| EDUCATION | 0.192 | 0.030 | 0.051 |
|
| 80 |
+
| CERT | 0.202 | 0.062 | 0.095 |
|
| 81 |
+
| EXPERIENCE_LEVEL | 0.066 | 0.014 | 0.023 |
|
| 82 |
+
| SKILL | 0.106 | 0.096 | 0.101 |
|
| 83 |
+
|
| 84 |
+
### Teacher comparison
|
| 85 |
+
|
| 86 |
+
The teacher (Claude Haiku 4.5) reaches micro-F1 = 0.5411 against the same gold set (95% bootstrap CI [0.524, 0.558]). The student trails the teacher by 0.257 points absolute (47.4% relative). See paper §4.3 for the full comparison and the error-mode analysis of this student's residuals.
|
| 87 |
+
|
| 88 |
+
## Usage
|
| 89 |
+
|
| 90 |
+
```python
|
| 91 |
+
from transformers import AutoTokenizer, AutoModelForTokenClassification, pipeline
|
| 92 |
+
|
| 93 |
+
tokenizer = AutoTokenizer.from_pretrained("AchrafSoltani/jobbert-ner-haiku-v1")
|
| 94 |
+
model = AutoModelForTokenClassification.from_pretrained("AchrafSoltani/jobbert-ner-haiku-v1")
|
| 95 |
+
ner = pipeline("token-classification", model=model, tokenizer=tokenizer,
|
| 96 |
+
aggregation_strategy="simple")
|
| 97 |
+
|
| 98 |
+
text = 'Senior Machine Learning Engineer at Acme Corp in Berlin. Requires 5+ years of experience with PyTorch, AWS, and Kubernetes. MSc in Computer Science preferred. Salary $140,000 – $180,000.'
|
| 99 |
+
for ent in ner(text):
|
| 100 |
+
print(ent["word"], "->", ent["entity_group"])
|
| 101 |
+
|
| 102 |
+
# Note: the BERT base tokeniser has a 512-token window; very long postings
|
| 103 |
+
# are truncated. For full-text coverage, use the spaCy variant.
|
| 104 |
+
```
|
| 105 |
+
|
| 106 |
+
## Ethical considerations
|
| 107 |
+
|
| 108 |
+
This model extracts entities from job postings, a document class whose downstream consumers are typically hiring, ranking, or matching systems. Three cautions are transplanted from paper §6:
|
| 109 |
+
|
| 110 |
+
- **Schema-induced bias.** SKILL over-extraction is inherited from the LLM teacher; soft-skill phrases ("communication skills", "interpersonal skills") and generic tools ("Excel", "CRM") are over-represented relative to a tighter gold standard. A downstream ranker that treats such phrases as filters is encoding the teacher's lexical habits as a hiring criterion and is not recommended without a schema review at the application layer.
|
| 111 |
+
- **Contested ground truth.** A vendor benchmark in the paper against LinkedIn's own `job_skills.csv` on 938,028 jointly-present postings yielded 9.56% agreement and 56.44% discovery: the two extraction schemas produce largely non-overlapping views of the same corpus. Neither constitutes a ground truth; the numbers measure schema divergence, not model quality.
|
| 112 |
+
- **Consent and licensing.** The training corpus is a publicly-released Kaggle redistribution of scraped LinkedIn postings. Individuals named in postings (recruiters, hiring managers) did not consent to having their role descriptions re-processed for research. The model is licensed CC BY-NC 4.0 for research and non-commercial evaluation only; any commercial deployment requires a separate legal and ethical review against the data-provenance chain.
|
| 113 |
+
|
| 114 |
+
## Limitations
|
| 115 |
+
|
| 116 |
+
- Trained and evaluated on English-language LinkedIn postings from a publicly-released 2024 Kaggle redistribution; generalisation to other platforms (Indeed, Stack Overflow, regional job boards) or other languages is unevaluated.
|
| 117 |
+
- Gold set is single-annotator (516 postings). Intra-annotator stability was scheduled to be measured one week after the main annotation pass; users should treat the reported F1 as having an un-quantified annotator-noise floor until that number lands.
|
| 118 |
+
- Output schema is locked to the eight types above. Finer-grained or taxonomy-aligned schemas require re-training against new labels.
|
| 119 |
+
- The underlying BERT tokeniser has a 512-token window; the average gold-set posting is 3,996 characters, so approximately the first third of a typical posting is in context. Entities that appear only in the tail (often qualifications, certifications, benefits) are systematically missed. For full-text coverage, prefer the spaCy variant.
|
| 120 |
+
|
| 121 |
+
## Citation
|
| 122 |
+
|
| 123 |
+
```bibtex
|
| 124 |
+
@unpublished{soltani2026distilledner,
|
| 125 |
+
author = {Achraf Soltani},
|
| 126 |
+
title = {Distributed Agentic NER on Spark: A Teacher-Student Pipeline for Large-Scale Entity Extraction from Job Postings},
|
| 127 |
+
year = {2026},
|
| 128 |
+
note = {Advisor: Prof.\ Hanine Mohamed},
|
| 129 |
+
url = {https://github.com/AchrafSoltani/distributed-agentic-ner-on-spark},
|
| 130 |
+
}
|
| 131 |
+
```
|
| 132 |
+
|
| 133 |
+
## Licence
|
| 134 |
+
|
| 135 |
+
- Model weights: **CC BY-NC 4.0** — research and non-commercial evaluation only.
|
| 136 |
+
- Source code in the accompanying repository: **Apache 2.0**.
|
config.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"BertForTokenClassification"
|
| 4 |
+
],
|
| 5 |
+
"attention_probs_dropout_prob": 0.1,
|
| 6 |
+
"classifier_dropout": null,
|
| 7 |
+
"dtype": "float32",
|
| 8 |
+
"gradient_checkpointing": false,
|
| 9 |
+
"hidden_act": "gelu",
|
| 10 |
+
"hidden_dropout_prob": 0.1,
|
| 11 |
+
"hidden_size": 768,
|
| 12 |
+
"id2label": {
|
| 13 |
+
"0": "O",
|
| 14 |
+
"1": "B-SKILL",
|
| 15 |
+
"2": "I-SKILL",
|
| 16 |
+
"3": "B-JOB_TITLE",
|
| 17 |
+
"4": "I-JOB_TITLE",
|
| 18 |
+
"5": "B-COMPANY",
|
| 19 |
+
"6": "I-COMPANY",
|
| 20 |
+
"7": "B-LOCATION",
|
| 21 |
+
"8": "I-LOCATION",
|
| 22 |
+
"9": "B-EXPERIENCE_LEVEL",
|
| 23 |
+
"10": "I-EXPERIENCE_LEVEL",
|
| 24 |
+
"11": "B-EDUCATION",
|
| 25 |
+
"12": "I-EDUCATION",
|
| 26 |
+
"13": "B-CERT",
|
| 27 |
+
"14": "I-CERT",
|
| 28 |
+
"15": "B-COMPENSATION",
|
| 29 |
+
"16": "I-COMPENSATION"
|
| 30 |
+
},
|
| 31 |
+
"initializer_range": 0.02,
|
| 32 |
+
"intermediate_size": 3072,
|
| 33 |
+
"label2id": {
|
| 34 |
+
"B-CERT": 13,
|
| 35 |
+
"B-COMPANY": 5,
|
| 36 |
+
"B-COMPENSATION": 15,
|
| 37 |
+
"B-EDUCATION": 11,
|
| 38 |
+
"B-EXPERIENCE_LEVEL": 9,
|
| 39 |
+
"B-JOB_TITLE": 3,
|
| 40 |
+
"B-LOCATION": 7,
|
| 41 |
+
"B-SKILL": 1,
|
| 42 |
+
"I-CERT": 14,
|
| 43 |
+
"I-COMPANY": 6,
|
| 44 |
+
"I-COMPENSATION": 16,
|
| 45 |
+
"I-EDUCATION": 12,
|
| 46 |
+
"I-EXPERIENCE_LEVEL": 10,
|
| 47 |
+
"I-JOB_TITLE": 4,
|
| 48 |
+
"I-LOCATION": 8,
|
| 49 |
+
"I-SKILL": 2,
|
| 50 |
+
"O": 0
|
| 51 |
+
},
|
| 52 |
+
"layer_norm_eps": 1e-12,
|
| 53 |
+
"max_position_embeddings": 512,
|
| 54 |
+
"model_type": "bert",
|
| 55 |
+
"num_attention_heads": 12,
|
| 56 |
+
"num_hidden_layers": 12,
|
| 57 |
+
"pad_token_id": 0,
|
| 58 |
+
"position_embedding_type": "absolute",
|
| 59 |
+
"transformers_version": "4.57.6",
|
| 60 |
+
"type_vocab_size": 2,
|
| 61 |
+
"use_cache": true,
|
| 62 |
+
"vocab_size": 28996
|
| 63 |
+
}
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9a9db19f30e39ce0a3bfdc1c499a6958b073555bee0315e26e95fe15c2554698
|
| 3 |
+
size 430954348
|
special_tokens_map.json
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cls_token": "[CLS]",
|
| 3 |
+
"mask_token": "[MASK]",
|
| 4 |
+
"pad_token": "[PAD]",
|
| 5 |
+
"sep_token": "[SEP]",
|
| 6 |
+
"unk_token": "[UNK]"
|
| 7 |
+
}
|
tokenizer.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
tokenizer_config.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"added_tokens_decoder": {
|
| 3 |
+
"0": {
|
| 4 |
+
"content": "[PAD]",
|
| 5 |
+
"lstrip": false,
|
| 6 |
+
"normalized": false,
|
| 7 |
+
"rstrip": false,
|
| 8 |
+
"single_word": false,
|
| 9 |
+
"special": true
|
| 10 |
+
},
|
| 11 |
+
"100": {
|
| 12 |
+
"content": "[UNK]",
|
| 13 |
+
"lstrip": false,
|
| 14 |
+
"normalized": false,
|
| 15 |
+
"rstrip": false,
|
| 16 |
+
"single_word": false,
|
| 17 |
+
"special": true
|
| 18 |
+
},
|
| 19 |
+
"101": {
|
| 20 |
+
"content": "[CLS]",
|
| 21 |
+
"lstrip": false,
|
| 22 |
+
"normalized": false,
|
| 23 |
+
"rstrip": false,
|
| 24 |
+
"single_word": false,
|
| 25 |
+
"special": true
|
| 26 |
+
},
|
| 27 |
+
"102": {
|
| 28 |
+
"content": "[SEP]",
|
| 29 |
+
"lstrip": false,
|
| 30 |
+
"normalized": false,
|
| 31 |
+
"rstrip": false,
|
| 32 |
+
"single_word": false,
|
| 33 |
+
"special": true
|
| 34 |
+
},
|
| 35 |
+
"103": {
|
| 36 |
+
"content": "[MASK]",
|
| 37 |
+
"lstrip": false,
|
| 38 |
+
"normalized": false,
|
| 39 |
+
"rstrip": false,
|
| 40 |
+
"single_word": false,
|
| 41 |
+
"special": true
|
| 42 |
+
}
|
| 43 |
+
},
|
| 44 |
+
"clean_up_tokenization_spaces": true,
|
| 45 |
+
"cls_token": "[CLS]",
|
| 46 |
+
"do_basic_tokenize": true,
|
| 47 |
+
"do_lower_case": false,
|
| 48 |
+
"extra_special_tokens": {},
|
| 49 |
+
"mask_token": "[MASK]",
|
| 50 |
+
"model_max_length": 1000000000000000019884624838656,
|
| 51 |
+
"never_split": null,
|
| 52 |
+
"pad_token": "[PAD]",
|
| 53 |
+
"sep_token": "[SEP]",
|
| 54 |
+
"strip_accents": null,
|
| 55 |
+
"tokenize_chinese_chars": true,
|
| 56 |
+
"tokenizer_class": "BertTokenizer",
|
| 57 |
+
"unk_token": "[UNK]"
|
| 58 |
+
}
|
training_args.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:317532006ffd05f83060f7f729e946a5f8d3211e77546051640bb7a9750a3f2d
|
| 3 |
+
size 5969
|
vocab.txt
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|