distilbert-jd-classifier

Fine-tuned distilbert-base-uncased that classifies a job description into one of four engineering tracks:

  • ai_ml
  • devops_sre
  • hardware_embedded
  • fullstack_swe

Built to solve a real problem: given a job posting, automatically pick which resume variant to send.

Results (held-out test set, n=40)

class precision recall f1
ai_ml 0.91 1.00 0.95
devops_sre 0.80 0.80 0.80
hardware_embedded 1.00 1.00 1.00
fullstack_swe 0.89 0.80 0.84
macro avg 0.90 0.90 0.90

confusion matrix

A note on the data quality lesson this project produced

The training set (400 rows, pulled from a Kaggle job-postings dataset plus an HF full-text search over a 33k-row job dataset for FPGA/VLSI/embedded roles) initially trained to 0.75 macro-F1. An audit of the worst misclassifications surfaced 3 mislabeled rows โ€” staffing-agency "Account Manager" / "Recruiter" postings that got swept into hardware_embedded because they mentioned FPGA/embedded as one of many industries the agency covers, even though the job itself has nothing to do with engineering.

Removing those 3 rows (0.75% of the data) took macro-F1 from 0.75 โ†’ 0.90. Code for the audit step: scripts/audit_labels.py in the GitHub repo.

Usage

from transformers import pipeline

clf = pipeline("text-classification", model="srijavuppala22/distilbert-jd-classifier", top_k=None)
clf(full_job_description_text, truncation=True, max_length=512)
# [{'label': 'ai_ml', 'score': 0.83}, {'label': 'devops_sre', 'score': 0.09}, ...]

Pass the full job description text, not a one-line summary โ€” see Limitations below.

Training details

  • Base model: distilbert-base-uncased
  • 3 epochs, lr=2e-5, batch size 16, max_length=512
  • Selection metric: macro-F1 (not accuracy โ€” classes are imbalanced enough that accuracy is misleading)
  • Trained locally on an Apple M3 (MPS backend), ~2 min/run

Limitations

  • Training data is 100% public/generic postings (Kaggle + HF), not real job-search data โ€” expect some accuracy loss on postings with unusual phrasing or hybrid roles (e.g. "MLOps Engineer" genuinely straddles ai_ml and devops_sre).
  • 4-class only; anything outside these tracks (sales, PM, data analyst, etc.) will be forced into the nearest of the 4.
  • Trained on full-length JD text (hundreds of words); confidence drops sharply on short one-line inputs. A one-sentence paraphrase of a job (e.g. "hiring an ML engineer for RAG pipelines") produces near-uniform, low-confidence scores across all 4 classes because it's out of distribution from what the model saw during training. Always pass the complete posting text.
  • On the 40-example held-out test set, macro-F1 measured between 0.85 and 0.90 across repeated eval runs (pipeline tokenization defaults vs. the explicit max_length=512 truncation used during training account for the small swing) โ€” treat 0.90 as the training-run number, not a guaranteed number for every inference path.

Repo

Full pipeline (data prep, weak labeling, audit, training script, Gradio demo): github.com/srijavuppala/jd-classifier-distilbert

Downloads last month
23
Safetensors
Model size
67M params
Tensor type
F32
ยท
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ Ask for provider support

Model tree for srijavuppala22/distilbert-jd-classifier

Finetuned
(12025)
this model