Ashybalka/xlm-roberta-taxonomy-sales-de
XLM-RoBERTa Job Taxonomy — Sales (German)
   
Fine-tuned xlm-roberta-base for classifying German sales and distribution job listings into 8 sales subcategories.
Part of the JobBlast taxonomy model family — a system for automated classification of German-language job postings. This model provides fine-grained classification within the Sales & Distribution top-level category, distinguishing field sales, inside sales, retail, key account management, technical sales, business development, sales leadership, and sales operations that the broader main taxonomy collapses into a single bucket.
Test Metrics
Evaluated on a held-out test set of 1,115 German sales job listings.
Per-class results
The gap between F1 macro (0.879) and F1 weighted (0.927) reflects the underlying class imbalance — Retail & Store Sales alone makes up 45% of the test set and reaches F1 0.982, while smaller and semantically harder categories (Sales Management, Sales Operations, Technical Sales) sit in the 0.81–0.85 range.
Label Schema
Key disambiguations
- Field Sales vs Inside Sales is decided by where the work happens:
Außendienst(travel, on-site customer visits) → Field Sales;Innendienst/Telesales(office or phone) → Inside Sales. - Sales Management & Leadership requires personnel / team responsibility (Führungsverantwortung). An individual contributor with the title "Sales Manager" but no team goes to the relevant selling category (Field / Inside / Key Account), not here.
- Technical Sales & Sales Engineering is for technically complex, explanation-heavy products requiring an engineering background — distinct from general Field or Inside sales.
- Retail & Store Sales is point-of-sale work in a store (Einzelhandel), not B2B field sales.
- Sales Operations & Support is back-office / enablement with no own selling quota (CRM, order processing, sales controlling) — distinct from quota-carrying selling roles.
- Key Account Management focuses on existing strategic accounts; Business Development is about opening new markets and acquiring new customers.
Repository Structure
Ashybalka/xlm-roberta-taxonomy-sales-de/
├── config.json # shared — label map, model config
├── tokenizer.json # shared — fast tokenizer
├── tokenizer_config.json # shared
├── sentencepiece.bpe.model # shared
├── special_tokens_map.json # shared
├── test_metrics.json # evaluation results
├── classification_report.txt # full per-class report
│
├── pytorch/
│ ├── config.json # needed for from_pretrained(subfolder=)
│ └── model.safetensors # GPU inference / fine-tuning (~1.1 GB)
│
├── onnx/
│ └── model.onnx # CPU fp32 inference (~1.1 GB)
│
└── onnx-int8/
└── model_quantized.onnx # CPU INT8 quantized (~280 MB, 3-4× smaller)Usage
Input Format
[Job Title] [SEP] [Job Description]text = "Vertriebsmitarbeiter im Außendienst (m/w/d) [SEP] Betreuung von Bestandskunden " \
"in der Region Süd, Neukundenakquise, Reisetätigkeit, Firmenwagen wird gestellt."PyTorch (GPU / fine-tuning)
from transformers import pipeline
clf = pipeline(
"text-classification",
model="Ashybalka/xlm-roberta-taxonomy-sales-de",
subfolder="pytorch",
device=0, # GPU; -1 for CPU
)
result = clf("Verkäufer im Einzelhandel [SEP] Beratung von Kunden, Warenpräsentation und Kassentätigkeit in unserer Filiale.")
print(result)
# [{'label': 'Retail & Store Sales', 'score': 0.9831}]ONNX fp32 (CPU inference)
from optimum.onnxruntime import ORTModelForSequenceClassification
from transformers import AutoTokenizer, pipeline
model = ORTModelForSequenceClassification.from_pretrained(
"Ashybalka/xlm-roberta-taxonomy-sales-de",
subfolder="onnx"
)
tokenizer = AutoTokenizer.from_pretrained("Ashybalka/xlm-roberta-taxonomy-sales-de")
clf = pipeline("text-classification", model=model, tokenizer=tokenizer)
result = clf("Key Account Manager [SEP] Strategische Betreuung unserer Großkunden, Ausbau bestehender Geschäftsbeziehungen.")
print(result)
# [{'label': 'Key Account & Account Management', 'score': 0.9412}]ONNX INT8 (CPU, lightweight)
from optimum.onnxruntime import ORTModelForSequenceClassification
from transformers import AutoTokenizer, pipeline
model = ORTModelForSequenceClassification.from_pretrained(
"Ashybalka/xlm-roberta-taxonomy-sales-de",
subfolder="onnx-int8"
)
tokenizer = AutoTokenizer.from_pretrained("Ashybalka/xlm-roberta-taxonomy-sales-de")
clf = pipeline("text-classification", model=model, tokenizer=tokenizer)Direct ONNX Runtime (no transformers)
For production FastAPI services or environments without transformers:
import json
import numpy as np
import onnxruntime as ort
from huggingface_hub import snapshot_download
from tokenizers import Tokenizer
# download model
path = snapshot_download(
"Ashybalka/xlm-roberta-taxonomy-sales-de",
allow_patterns=["onnx/model.onnx", "tokenizer.json", "config.json"]
)
# load
session = ort.InferenceSession(f"{path}/onnx/model.onnx",
providers=["CPUExecutionProvider"])
tokenizer = Tokenizer.from_file(f"{path}/tokenizer.json")
tokenizer.enable_truncation(max_length=510)
tokenizer.no_padding()
with open(f"{path}/config.json") as f:
labels = [v for _, v in sorted(json.load(f)["id2label"].items(), key=lambda x: int(x[0]))]
vocab = tokenizer.get_vocab()
bos, eos = vocab["<s>"], vocab["</s>"]
def classify_sales(title: str, description: str) -> dict:
text = f"{title} [SEP] {description}"
encoding = tokenizer.encode(text, add_special_tokens=False)
ids = [bos] + encoding.ids + [eos]
mask = [1] * len(ids)
logits = session.run(None, {
"input_ids": np.array([ids], dtype=np.int64),
"attention_mask": np.array([mask], dtype=np.int64),
})[0][0]
exp = np.exp(logits - logits.max())
probs = exp / exp.sum()
idx = int(np.argmax(probs))
return {"category": labels[idx], "confidence": round(float(probs[idx]), 4)}
print(classify_sales(
"Vertriebsingenieur",
"Technische Beratung und Verkauf erklärungsbedürftiger Maschinen, Schnittstelle zwischen Kunde und Entwicklung."
))
# {'category': 'Technical Sales & Sales Engineering', 'confidence': 0.9145}Training Details
Class distribution in training data
Counts after capping the majority class at 5,000 samples:
Retail & Store Sales was capped from 8,339 raw samples down to 5,000 to limit its dominance. The remaining 11.2× imbalance ratio between Retail & Store Sales and Sales Management & Leadership is handled through balanced class weights at training time. Despite the imbalance, even the smaller selling categories (Key Account, Business Development) reach F1 ≥ 0.86 — soft-label training and class weighting compensate effectively when the LLM consensus on the class is clean.
Limitations
- Optimized for German sales job listings only — performance on other languages or non-sales jobs is not validated. Use the main taxonomy model first to route only listings tagged as
Sales & Distributioninto this classifier. - Sales Operations & Support (F1 0.838) has high recall (0.936) but lower precision (0.759) — generic administrative or back-office roles in a sales department are sometimes pulled into this class. This is the noisiest class by far: 57% of its training samples had inter-model disagreement (only 2/3 consensus), reflecting a genuinely fuzzy boundary with administration and sales support.
- Sales Management & Leadership (F1 0.809) is the weakest class — the boundary between an IC "Sales Manager" and a manager with team responsibility is often ambiguous in German job ads, where "Manager" does not reliably imply Führungsverantwortung. 41% of its training data had inter-model disagreement.
- Business Development & Strategic Sales (F1 0.860) overlaps with Key Account and Field Sales on growth-oriented roles — 35% inter-model disagreement in training.
- Technical Sales & Sales Engineering (F1 0.848) overlaps with Field Sales on technically-flavored outside-sales roles (27% disagreement); listings combining both signals may go either way.
- The model classifies the role described in the job ad, not the qualifications of any candidate.
- Inputs longer than 512 tokens are truncated — title and the first paragraph of the description carry most of the role signal.
Related Models
A typical JobBlast pipeline: the main model assigns the top-level category. Listings tagged as Sales & Distribution are passed to this model for fine-grained role classification (Field Sales, Retail, Key Account, etc.).
