# Praktische Umsetzung von NER für die Verarbeitung von Lebensläufen: Von der Datenannotation bis zum Produktionsservice
Named Entity Recognition (NER) ist eine entscheidende Komponente moderner NLP-Systeme, insbesondere in der HR-Automatisierung. In diesem Artikel zerlegen wir die technischen Aspekte der Implementierung einer NER-Lösung zur Extraktion strukturierter Daten aus Lebensläufen, mit Fokus auf russischsprachige Texte und die Besonderheiten des Produktiveinsatzes.
Definition der Aufgabengrenzen
Vor der Entwicklung ist es essenziell, die Anforderungen klar zu formalisieren. Für ein HR-System sind die Schlüsselentitäten:
- Persönliche Daten (vollständiger Name, E-Mail, Telefon)
- Berufliche Fähigkeiten (Technologien, Tools)
- Finanzielle Parameter (erwartetes Gehalt mit Währung)
Wichtig ist zu beachten, dass Fähigkeiten in Lebensläufen oft ohne Trennzeichen aufgelistet werden (z. B. „Python SQL Docker“). Dies erfordert den Einsatz des BIO-Tagging-Schemas statt einfachem IO, damit das Modell benachbarte Entitäten korrekt trennen kann. Für Russisch ist die Handhabung von Kasusformen und Abkürzungen („JS“ statt „JavaScript“) entscheidend.
Definieren Sie präzise Regeln für jede Entität:
- SKILL: nur berufliche Begriffe (Soft Skills ausgeschlossen)
- SALARY: Betrag + Währung („150 Tsd. RUB“, „$2500“)
- PHONE: alle Nummernformate mit Ländervorwahl
Datenaufbereitung: Strategien und Tools
Suche nach fertigen Datensätzen
Erste Phase – prüfen vorhandener Ressourcen:
- Hugging Face Datasets
Filtern nach: Task=Token Classification, Language=Russian. Zum Zeitpunkt dieses Artikels wurden keine spezialisierten Datensätze für Lebensläufe gefunden. Englische Äquivalente (z. B. Resume Entities Dataset) erfordern Anpassung durch Übersetzung und Fine-Tuning.
- Kaggle and Zenodo
Suchen nach Keywords „Lebenslauf NER“, „CV-Entitäten“. Gefundene Datensätze enthalten oft:
* Unvollständige Annotation (nur Fähigkeiten)
* Fehlende russischsprachige Beispiele
* Unterschiedliche Tagging-Schemata (BIOES vs BIO)
- Synthetische Generierung
Bei knappen Daten Bibliotheken wie nlpaug nutzen für:
* Ersetzen realer Daten durch Äquivalente („Ivanov“ → „Petrov“)
* Einfügen von Tippfehlern in Kontaktdaten
* Generieren von Varianten von Fähigkeitsnamen („PyTorch“ → „pytorch“)
Manuelle Annotation in Label Studio
Wenn fertige Daten nicht reichen, eigenen Datensatz erstellen. Wichtige Schritte:
- Vorbereitung von PDF-Dokumenten
pdfplumber nutzen, um Text unter Erhalt der Struktur zu extrahieren:
```python
with pdfplumber.open('resume.pdf') as pdf:
text = '\n\n'.join([page.extract_text() for page in pdf.pages])
```
- Konvertierung zu JSON für Label Studio
Skript zur Konvertierung von PDF ins Plattformformat:
```python
import json
import os
def convert_to_ls_format(pdf_dir):
tasks = [{"text": open(f, 'r').read()}
for f in os.listdir(pdf_dir) if f.endswith('.txt')]
with open('import.json', 'w') as f:
json.dump(tasks, f, ensure_ascii=False, indent=2)
```
- Einrichtung der Annotation-Schnittstelle
In Label Studio Vorlage mit Tags erstellen:
```xml
<View>
<Text name="text" value="$text"/>
<Labels name="ner" toName="text">
<Label value="SKILL" background="#ffcc00"/>
<Label value="SALARY" background="#66ccff"/>
</Labels>
</View>
```
Konsistente Annotation ist entscheidend wichtig: Regeln für mehrdeutige Fälle festlegen (z. B. „C++“ – eine oder zwei Fähigkeiten). Zur Qualitätssteigerung zwei Annotatoren einbeziehen und Cohen’s Kappa-Metriken berechnen.
Modellauswahl und Training
Grundlegende Architekturen
Für russischsprachige Texte empfehlen wir folgende Ansätze:
- Fine-Tuning vortrainierter Modelle
* RuBERT (DeepPavlov) – optimal für Russisch
* mBERT – für mehrsprachigen Support, falls nötig
* Wichtiger Parameter: max_seq_length=512 (Lebensläufe haben oft lange Beschreibungen)
- Anpassung der Tokenisierung
Spezifische Begriffe zum Vokabular hinzufügen:
```python
tokenizer.add_tokens(["CI/CD", "ETL", "MLflow"])
model.resize_token_embeddings(len(tokenizer))
```
- Handhabung von Klassenungleichgewicht
Gewichtete Loss-Funktion nutzen:
```python
class_weights = compute_class_weight('balanced',
classes=np.unique(labels),
y=labels)
criterion = nn.CrossEntropyLoss(weight=torch.tensor(class_weights))
```
Evaluationsmetriken
Standardgenauigkeit ist für NER ungeeignet. Verfolgen:
- Token-level F1 – primäres Metrik
- Entity-level Precision/Recall – via
seqeval-Bibliothek - Verarbeitungsgeschwindigkeit – Tokens pro Sekunde auf CPU
Besondere Aufmerksamkeit auf Recall für die SALARY-Entität legen – ein Abfall hier führt zum Verlust kritischer Daten.
Produktiveinsatz
Service-Architektur
Empfohlenes Integrationsschema:
- Vorverarbeitung
* PDF/DOCX zu Text konvertieren (via antiword und pdf2text)
* Text normalisieren (zusätzliche Leerzeichen entfernen, Währungen kodieren)
- NER-Kern
```python
class NERServer:
def __init__(self):
self.model = AutoModelForTokenClassification.from_pretrained('ner_model')
def extract_entities(self, text):
inputs = tokenizer(text, return_tensors='pt', truncation=True)
outputs = self.model(**inputs)
# Process logits into entities
```
- Nachverarbeitung
* Tokens per BIO-Tags zu Entitäten gruppieren
* Formate validieren (Regex für E-Mail/Telefon)
* Fähigkeiten normalisieren („JS“ → „JavaScript“) via Mapping
Leistungsoptimierung
- Caching – für wiederholte Anfragen
- Batch-Verarbeitung – mehrere Lebensläufe zu einem Batch kombinieren
- Quantisierung – Modell zu FP16 via
torch.quantizationkonvertieren
Für Systeme mit hoher Last Task-Queue via RabbitMQ implementieren, um Timeouts bei der Verarbeitung großer Dateien zu vermeiden.
Wichtige Erkenntnisse
- Domänenadaption ist entscheidend: Ein auf Nachrichten trainiertes Modell scheitert bei Lebensläufen
- Annotation-Qualität bestimmt 80 % des Endergebnisses – in Annotatoren investieren
- BIO-Schema ist für Listen von Fähigkeiten ohne Trennzeichen zwingend erforderlich
- Validierung an Edge Cases – Handhabung nicht-standardisierter Formate testen („100k $“, „~2000 €“)
- Überwachung von Data Drift – Metriken auf neuen Lebensläufen regelmäßig neu berechnen
— Editorial Team
Noch keine Kommentare.