Downloads · 30 days
143
4% of all-time downloads
0xnbk/nbk-ats-semantic-v1-en
nbk-ats-semantic-v1-en is a sentence similarity model from 0xnbk. Use it when you need a score for how close two texts are. It is set up for sentence-transformers. The card lists the license as apache-2.0.
nbk-ats-semantic-v1-en is a fine-tuned sentence transformer optimized for ATS (Applicant Tracking System) applications. This model excels at measuring semantic similarity between resumes and job descriptions, enabling…
Downloads · 30 days
143
4% of all-time downloads
All-time downloads
4.1K
Public
Parameters
32.7M
274 MB on disk
Likes
2
Public
Click a slice to open those files.
.onnx143 MB · 52%
From the Hugging Face model README
nbk-ats-semantic-v1-en is a fine-tuned sentence transformer optimized for ATS (Applicant Tracking System) applications. This model excels at measuring semantic similarity between resumes and job descriptions, enabling accurate candidate-job matching across all professional domains.
| Format | Size | Use Case | Performance |
|---|---|---|---|
| SafeTensors | 125MB | HuggingFace/PyTorch deployment | Full precision |
| ONNX Full | 109MB | Cross-platform inference | Full precision |
| ONNX Quantized (INT8) | 27MB | Browser deployment | Minimal loss (~1-2%) |
| Ensemble Weights | 0.5MB | Score mapper (Ridge + Neural) | Required for ATS scoring |
Total Browser Package: ~28MB (ONNX quantized + ensemble weights) - optimized for client-side inference
Ensemble Model (Semantic + Score Mapper):
Semantic Model (Base):
8 Domains × 8 Jobs = 64 Test Cases:
Same-Domain Performance:
Average Same-Domain Score: 79.0% ✅
Cross-Domain Discrimination:
Overall Success Rate: 95% 🎉
Most transformer models limit context to 512 tokens (~2,000 characters), which is insufficient for professional documents:
| Document Type | Average Length | Traditional Models | This Model |
|---|---|---|---|
| Entry-Level Resume | 1,500 chars | ✅ Fits | ✅ Fits |
| Senior Resume | 4,500 chars | ❌ Truncated | ✅ Fits |
| Executive Resume | 8,000+ chars | ❌ Severely truncated | ✅ Fits |
| Job Description | 3,000-5,000 chars | ⚠️ Partially fits | ✅ Fits |
| Combined (Resume + Job) | 8,000-13,000 chars | ❌ Heavy truncation | ✅ Mostly fits |
Real-World Impact:
pip install sentence-transformers
from sentence_transformers import SentenceTransformer
from scipy.spatial.distance import cosine
# Load model
model = SentenceTransformer('0xnbk/nbk-ats-semantic-v1-en')
# Example: Resume-Job matching
resume = """
Senior Software Engineer with 8 years of experience in Python, Django, and React.
Led development of microservices architecture serving 10M+ users. Expert in AWS,
Docker, Kubernetes, and CI/CD pipelines. Strong background in agile methodologies
and cross-functional team leadership.
"""
job_description = """
We're seeking a Senior Backend Engineer with 5+ years Python experience.
Must have expertise in Django, microservices, and cloud platforms (AWS/GCP).
Experience with containerization (Docker/Kubernetes) and modern DevOps practices required.
"""
# Generate embeddings
resume_embedding = model.encode(resume)
job_embedding = model.encode(job_description)
# Calculate similarity
similarity = 1 - cosine(resume_embedding, job_embedding)
print(f"Semantic Similarity: {similarity:.3f}") # Expected: 0.85-0.95 (high match)
# Convert to ATS score (0-100)
ats_score = similarity * 100
print(f"ATS Score: {ats_score:.1f}%")
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('0xnbk/nbk-ats-semantic-v1-en')
# Process multiple long resumes efficiently
resumes = [
"... 8000+ character resume ...",
"... another long resume ...",
"... third resume ..."
]
job = "... detailed job description ..."
# Batch encode (handles long context automatically)
resume_embeddings = model.encode(resumes, batch_size=8, show_progress_bar=True)
job_embedding = model.encode(job)
# Calculate similarities
from sklearn.metrics.pairwise import cosine_similarity
similarities = cosine_similarity([job_embedding], resume_embeddings)[0]
# Rank candidates
for idx, score in sorted(enumerate(similarities), key=lambda x: x[1], reverse=True):
print(f"Candidate {idx+1}: {score*100:.1f}%")
For production ATS scoring, combine the semantic model with the ensemble score mapper:
from sentence_transformers import SentenceTransformer
from sklearn.linear_model import Ridge
from sklearn.neural_network import MLPRegressor
from sklearn.preprocessing import PolynomialFeatures
import numpy as np
import json
# Load semantic model
model = SentenceTransformer('0xnbk/nbk-ats-semantic-v1-en')
# Load ensemble weights from JSON (secure format, no pickle warnings)
with open('ridge_weights.json', 'r') as f:
ridge_data = json.load(f)
with open('neural_weights.json', 'r') as f:
neural_data = json.load(f)
with open('poly_features.json', 'r') as f:
poly_data = json.load(f)
# Reconstruct models from JSON
score_mapper = Ridge(alpha=ridge_data['alpha'])
score_mapper.coef_ = np.array(ridge_data['coefficients'])
score_mapper.intercept_ = ridge_data['intercept']
score_mapper.n_features_in_ = ridge_data['n_features_in']
neural_mapper = MLPRegressor(
hidden_layer_sizes=tuple(neural_data['hidden_layer_sizes']),
activation=neural_data['activation']
)
neural_mapper.coefs_ = [np.array(c) for c in neural_data['coefs']]
neural_mapper.intercepts_ = [np.array(i) for i in neural_data['intercepts']]
neural_mapper.n_features_in_ = neural_data['n_features_in']
poly_features = PolynomialFeatures(
degree=poly_data['degree'],
include_bias=poly_data['include_bias']
)
poly_features.n_features_in_ = poly_data['n_features_in']
poly_features.n_output_features_ = poly_data['n_output_features']
def predict_ats_score(resume_text, job_text):
# Generate embeddings
resume_emb = model.encode(resume_text)
job_emb = model.encode(job_text)
# Calculate base similarity
similarity = np.dot(resume_emb, job_emb) / (np.linalg.norm(resume_emb) * np.linalg.norm(job_emb))
# Create polynomial features
features = poly_features.transform([[similarity]])
# Ensemble prediction (Ridge + Neural Network)
ridge_pred = score_mapper.predict(features)[0]
neural_pred = neural_mapper.predict(features)[0]
# Dynamic ensemble (50-50 weighting, optimized during training)
final_score = (ridge_pred * 0.5 + neural_pred * 0.5)
return np.clip(final_score, 0, 100)
# Example usage
score = predict_ats_score(resume_text, job_text)
print(f"Final ATS Score: {score:.1f}%")
Hardware:
Hyperparameters:
Score Mapper Training:
This model was trained with ESCO (European Skills, Competences, Qualifications and Occupations) text normalization:
Example Normalizations:
This normalization is baked into the model's training data, so you don't need to apply it during inference.
The model was validated using:
The model is optimized for browser deployment using ONNX Runtime:
Quantized Model (27MB):
Deployment Example (ONNX Runtime Web):
// Using ONNX Runtime Web for browser deployment
import * as ort from 'onnxruntime-web';
// Load the quantized ONNX model
const session = await ort.InferenceSession.create('onnx/model_quantized.onnx');
// You'll need to tokenize the text and create embeddings
// Then calculate cosine similarity between resume and job embeddings
function cosineSimilarity(a, b) {
const dot = a.reduce((sum, val, i) => sum + val * b[i], 0);
const magA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0));
const magB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0));
return dot / (magA * magB);
}
// Calculate ATS score
const similarity = cosineSimilarity(resumeEmbedding, jobEmbedding);
console.log(`ATS Score: ${(similarity * 100).toFixed(1)}%`);
Note: For production browser deployment, you'll need to handle tokenization and implement the full inference pipeline. The ONNX quantized model provides the core embedding functionality optimized for client-side execution.
The model demonstrates excellent performance across all major professional domains:
Technology Domains:
Business Domains:
Healthcare & Life Sciences:
Professional Services:
@model{nbk_ats_semantic_v1,
author = {NBK},
title = {NBK ATS Semantic Model v1 (English)},
year = {2025},
publisher = {Hugging Face},
url = {https://huggingface.co/0xnbk/nbk-ats-semantic-v1-en}
}
@dataset{resume_ats_score_v1,
author = {NBK},
title = {Resume-ATS Score Dataset v1 (English)},
year = {2025},
publisher = {Hugging Face},
url = {https://huggingface.co/datasets/0xnbk/resume-ats-score-v1-en}
}
@software{jina_embeddings_v2_small,
author = {Jina AI},
title = {Jina Embeddings v2 Small English},
year = {2024},
publisher = {Hugging Face},
url = {https://huggingface.co/jinaai/jina-embeddings-v2-small-en}
}
This model is released under the Apache 2.0 License.
Copyright 2025 NBK (nbk.dev)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
For questions, suggestions, or collaboration opportunities: