CoolFace
Modelpublic

Ashybalka/xlm-roberta-taxonomy-sales-de

sourceHugging Faceapache-2.0updated 4mo agoView on Hugging Face
0likes9downloads
Model Card

XLM-RoBERTa Job Taxonomy — Sales (German)

![License](https://opensource.org/licenses/Apache-2.0) ![Language](https://huggingface.co/models?language=de) ![Base](https://huggingface.co/FacebookAI/xlm-roberta-base) ![Categories](https://huggingface.co/Ashybalka/xlm-roberta-taxonomy-sales-de)

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

MetricValue
Accuracy92.65%
F1 macro87.95%
F1 weighted92.72%

Evaluated on a held-out test set of 1,115 German sales job listings.

Per-class results

CategoryPrecisionRecallF1Support
Retail & Store Sales0.9820.9820.982500
Inside Sales & Telesales0.9510.8790.913132
Field Sales & Outside Sales0.9250.8760.900226
Key Account & Account Management0.8790.8920.88565
Business Development & Strategic Sales0.8520.8680.86053
Technical Sales & Sales Engineering0.8240.8750.84848
Sales Operations & Support0.7590.9360.83847
Sales Management & Leadership0.7600.8640.80944

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

LabelTypical signals in German job ads
Field Sales & Outside SalesAußendienst, Außendienstmitarbeiter, Vertrieb im Außendienst, Gebietsverkaufsleiter, Reisetätigkeit, Kundenbesuche vor Ort, Firmenwagen
Inside Sales & TelesalesInnendienst, Vertriebsinnendienst, Telesales, Telefonverkauf, Kundenbetreuung am Telefon, Angebotserstellung, Auftragsannahme
Retail & Store SalesVerkäufer, Verkäuferin, Einzelhandelskaufmann, Verkaufsberater, Filiale, Ladengeschäft, Kassentätigkeit, Warenpräsentation
Key Account & Account ManagementKey Account Manager, Account Manager, Großkundenbetreuung, Bestandskundenbetreuung, strategische Kundenbeziehungen
Technical Sales & Sales EngineeringVertriebsingenieur, Sales Engineer, Technischer Vertrieb, Applikationsingenieur, technische Beratung, erklärungsbedürftige Produkte
Business Development & Strategic SalesBusiness Development Manager, Geschäftsentwicklung, Neukundenakquise, Markterschließung, strategische Partnerschaften
Sales Management & LeadershipVertriebsleiter, Verkaufsleiter, Head of Sales, Führungsverantwortung, Teamführung, Vertriebssteuerung, Umsatzverantwortung
Sales Operations & SupportSales Operations, Vertriebsassistenz, Sales Support, CRM-Pflege, Auftragsabwicklung, Vertriebscontrolling, Angebotsmanagement

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]
python
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)

python
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)

python
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)

python
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:

python
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

ParameterValue
Base modelFacebookAI/xlm-roberta-base
Training samples11,186 German sales job listings (majority class Retail & Store Sales capped at 5,000)
LabelingLLM consensus (3-model voting: Qwen3-4B + Gemma-2-9B + Llama-3.1-8B)
Agreement filter2/3 or 3/3 required (≈81.6% at 3/3, ≈18.4% at 2/3 after capping)
Soft labelsVote distribution used as soft targets
Max length512 tokens
Learning rate2e-5
Epochs5 (early stopping)
Class weightingBalanced

Class distribution in training data

Counts after capping the majority class at 5,000 samples:

CategoryCountShare
Retail & Store Sales5,00044.7%
Field Sales & Outside Sales2,26220.2%
Inside Sales & Telesales1,32911.9%
Key Account & Account Management6575.9%
Business Development & Strategic Sales5314.7%
Technical Sales & Sales Engineering4854.3%
Sales Operations & Support4764.3%
Sales Management & Leadership4464.0%

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 & Distribution into 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

ModelCategoriesUse case
xlm-roberta-taxonomy-**main**-de21 top-levelIndustry / field classification
xlm-roberta-taxonomy-**it**-de14 IT subcategoriesDetailed IT role classification
xlm-roberta-taxonomy-**healthcare**-de11 healthcare subcategoriesFine-grained classification within healthcare jobs
xlm-roberta-taxonomy-**seniority**-de5 gradesExperience-level classification, orthogonal to industry
xlm-roberta-taxonomy-sales-de (this model)8 sales subcategoriesFine-grained classification within sales jobs

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.).