Update README.md
Browse files
README.md
CHANGED
|
@@ -1,3 +1,107 @@
|
|
| 1 |
---
|
| 2 |
license: mit
|
| 3 |
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
license: mit
|
| 3 |
---
|
| 4 |
+
---
|
| 5 |
+
language: en
|
| 6 |
+
tags:
|
| 7 |
+
- text-classification
|
| 8 |
+
- onnx
|
| 9 |
+
- job-classification
|
| 10 |
+
- it
|
| 11 |
+
license: mit
|
| 12 |
+
base_model: intfloat/e5-base-v2
|
| 13 |
+
---
|
| 14 |
+
|
| 15 |
+
# IT vs Non-IT Job Title Classifier
|
| 16 |
+
|
| 17 |
+
Binary classifier that determines whether a job title belongs to an IT/tech role or not. Built on top of [intfloat/e5-base-v2](https://huggingface.co/intfloat/e5-base-v2) embeddings with a logistic regression head, exported to ONNX for fast, lightweight inference with no heavy ML dependencies at runtime.
|
| 18 |
+
|
| 19 |
+
## Repository contents
|
| 20 |
+
|
| 21 |
+
| File | Description |
|
| 22 |
+
|---|---|
|
| 23 |
+
| `e5_it_classifier.onnx` | Logistic regression classifier head (ONNX) |
|
| 24 |
+
|
| 25 |
+
The encoder (`intfloat/e5-base-v2`) is loaded separately at inference time — it is not bundled here since it is a public model.
|
| 26 |
+
|
| 27 |
+
## How it works
|
| 28 |
+
|
| 29 |
+
1. The job title is prefixed with `"query: "` — required by the e5-v2 instruction format
|
| 30 |
+
2. The prefixed title is encoded by `intfloat/e5-base-v2` with mean pooling and L2 normalization, producing a 768-dim embedding
|
| 31 |
+
3. The embedding is passed through the logistic regression ONNX model
|
| 32 |
+
4. The output is a probability for class `1` (IT) and class `0` (Non-IT)
|
| 33 |
+
|
| 34 |
+
## Training
|
| 35 |
+
|
| 36 |
+
- **Encoder:** `intfloat/e5-base-v2` via `sentence-transformers`, embeddings L2-normalized
|
| 37 |
+
- **Classifier:** `sklearn.linear_model.LogisticRegression(C=1.0, max_iter=1000, class_weight='balanced')`
|
| 38 |
+
- **Input:** job title only
|
| 39 |
+
- **Labels:** `1` = IT role, `0` = Non-IT role
|
| 40 |
+
- **Class balancing:** enabled via `class_weight='balanced'` to handle uneven label distribution
|
| 41 |
+
|
| 42 |
+
## Inference
|
| 43 |
+
|
| 44 |
+
### Python
|
| 45 |
+
|
| 46 |
+
```python
|
| 47 |
+
from sentence_transformers import SentenceTransformer
|
| 48 |
+
import onnxruntime as ort
|
| 49 |
+
import numpy as np
|
| 50 |
+
|
| 51 |
+
encoder = SentenceTransformer("intfloat/e5-base-v2")
|
| 52 |
+
sess = ort.InferenceSession("e5_it_classifier.onnx")
|
| 53 |
+
|
| 54 |
+
def classify(title: str) -> dict:
|
| 55 |
+
emb = encoder.encode(["query: " + title], normalize_embeddings=True)
|
| 56 |
+
probs = sess.run(["probabilities"], {"input": emb.astype(np.float32)})[0]
|
| 57 |
+
return {
|
| 58 |
+
"label": "IT" if probs[0][1] > probs[0][0] else "Non-IT",
|
| 59 |
+
"it_probability": float(probs[0][1]),
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
print(classify("Senior Software Engineer")) # IT
|
| 63 |
+
print(classify("Regional Sales Manager")) # Non-IT
|
| 64 |
+
```
|
| 65 |
+
|
| 66 |
+
### JavaScript / TypeScript (Bun or Node)
|
| 67 |
+
|
| 68 |
+
```typescript
|
| 69 |
+
import { pipeline } from "@huggingface/transformers";
|
| 70 |
+
import * as ort from "onnxruntime-node";
|
| 71 |
+
|
| 72 |
+
const extractor = await pipeline("feature-extraction", "intfloat/e5-base-v2", { quantized: false });
|
| 73 |
+
const session = await ort.InferenceSession.create("./e5_it_classifier.onnx");
|
| 74 |
+
|
| 75 |
+
async function classify(title: string) {
|
| 76 |
+
const output = await extractor("query: " + title, { pooling: "mean", normalize: true });
|
| 77 |
+
|
| 78 |
+
const results = await session.run({
|
| 79 |
+
input: new ort.Tensor("float32", output.data as Float32Array, [1, 768]),
|
| 80 |
+
});
|
| 81 |
+
|
| 82 |
+
const probs = results.probabilities.data as Float32Array;
|
| 83 |
+
return {
|
| 84 |
+
label: probs[1] > probs[0] ? "IT" : "Non-IT",
|
| 85 |
+
it_probability: probs[1],
|
| 86 |
+
};
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
console.log(await classify("Senior Software Engineer")); // IT
|
| 90 |
+
console.log(await classify("Regional Sales Manager")); // Non-IT
|
| 91 |
+
```
|
| 92 |
+
|
| 93 |
+
```bash
|
| 94 |
+
bun add @huggingface/transformers onnxruntime-node
|
| 95 |
+
# or
|
| 96 |
+
npm install @huggingface/transformers onnxruntime-node
|
| 97 |
+
```
|
| 98 |
+
|
| 99 |
+
## Intended use
|
| 100 |
+
|
| 101 |
+
Designed for automated job pipeline filtering — quickly classifying job titles as IT or non-IT before downstream enrichment or processing steps. Works well as a lightweight pre-filter given that it only requires a job title with no description needed.
|
| 102 |
+
|
| 103 |
+
## Limitations
|
| 104 |
+
|
| 105 |
+
- Trained and evaluated on job title text only — unusual or highly abbreviated titles may score less reliably
|
| 106 |
+
- English job titles only
|
| 107 |
+
- Edge cases like hybrid roles (e.g. "IT Sales Manager") may produce probabilities close to 0.5
|