Hugging Face Transformers – Bewährte Methoden
Umfassender Leitfaden zur Verwendung der Hugging-Face-Transformers-Bibliothek, einschließlich Modellladung, Tokenisierung, Feintuning-Workflows, Pipeline-Nutzung, benutzerdefinierten Datensätzen und Bereitstellungsoptimierung.
Kurzreferenz
Wann diese Fertigkeit anwenden:
- Laden und Verwenden von vorab trainierten Transformern (BERT, GPT, T5, LLaMA usw.)
- Feintuning von Modellen auf benutzerdefinierten Daten
- Implementierung von NLP-Aufgaben (Klassifikation, Frage-Antwort, Generierung usw.)
- Optimieren der Inferenz (Quantisierung, ONNX usw.)
- Debuggen von Tokenisierungsproblemen
- Verwenden von Hugging-Face-Pipelines
- Bereitstellen von Transformern in der Produktion
Abgedeckte Modelle:
- Encoder: BERT, RoBERTa, DeBERTa, ALBERT
- Decoder: GPT-2, GPT-Neo, LLaMA, Mistral
- Encoder-Decoder: T5, BART, Flan-T5
- Vision: ViT, CLIP, Stable Diffusion
Teil 1: Muster zum Laden von Modellen
Muster 1: Einfaches Laden von Modellen
from transformers import AutoModel, AutoTokenizer
# Modell und Tokenizer laden
model_name = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModel.from_pretrained(model_name)
# Für bestimmte Aufgaben
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained(
model_name,
num_labels=3 # Für 3-Klassen-Klassifikation
)
Muster 2: Laden mit spezifischer Konfiguration
from transformers import AutoConfig, AutoModel
# Konfiguration ändern
config = AutoConfig.from_pretrained("bert-base-uncased")
config.hidden_dropout_prob = 0.2 # Benutzerdefiniertes Dropout
config.attention_probs_dropout_prob = 0.2
# Modell mit benutzerdefinierter Konfiguration laden
model = AutoModel.from_pretrained("bert-base-uncased", config=config)
# Oder Modell von Grund auf mit Konfiguration erstellen
model = AutoModel.from_config(config)
Muster 3: Laden quantisierter Modelle (speichereffizient)
from transformers import AutoModel, BitsAndBytesConfig
import torch
# 8-Bit-Quantisierung (50 % Speicherreduzierung)
quantization_config = BitsAndBytesConfig(load_in_8bit=True)
model = AutoModel.from_pretrained(
"meta-llama/Llama-2-7b-hf",
quantization_config=quantization_config,
device_map="auto" # Automatische Geräteplatzierung
)
# 4-Bit-Quantisierung (75 % Speicherreduzierung)
quantization_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_quant_type="nf4",
bnb_4bit_use_double_quant=True
)
model = AutoModel.from_pretrained(
"meta-llama/Llama-2-13b-hf",
quantization_config=quantization_config,
device_map="auto"
)
Muster 4: Laden von lokalem Pfad
# Modell lokal speichern
model.save_pretrained("./my-model")
tokenizer.save_pretrained("./my-model")
# Von lokalem Pfad laden
model = AutoModel.from_pretrained("./my-model")
tokenizer = AutoTokenizer.from_pretrained("./my-model")
Teil 2: Bewährte Methoden bei der Tokenisierung
Kritische Tokenisierungsmuster
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
# ✅ RICHTIG: Alle erforderlichen Argumente
tokens = tokenizer(
text,
padding=True, # Auf Längstes im Batch auffüllen
truncation=True, # Auf max_length kürzen
max_length=512, # Maximale Sequenzlänge
return_tensors="pt" # PyTorch-Tensoren zurückgeben
)
# Auf Komponenten zugreifen
input_ids = tokens['input_ids'] # Token-IDs
attention_mask = tokens['attention_mask'] # Padding-Maske
token_type_ids = tokens.get('token_type_ids') # Segment-IDs (BERT)
# ❌ FALSCH: Fehlende kritische Argumente
tokens = tokenizer(text) # Kein Padding, keine Kürzung, kein Tensor-Format!
Batch-Tokenisierung
# Mehrere Texte effizient tokenisieren
texts = ["Erster Text", "Zweiter Text", "Dritter Text"]
tokens = tokenizer(
texts,
padding=True, # Alle auf Längstes im Batch auffüllen
truncation=True,
max_length=128,
return_tensors="pt"
)
# Ergebnisform: [batch_size, max_length]
print(tokens['input_ids'].shape) # torch.Size([3, max_len_in_batch])
Umgang mit speziellen Token
# Spezielle Token hinzufügen
tokenizer.add_special_tokens({
'additional_special_tokens': ['[CUSTOM]', '[MARKER]']
})
# Modell-Embeddings entsprechend anpassen
model.resize_token_embeddings(len(tokenizer))
# Mit erhaltenen speziellen Token kodieren
text = "Hallo [CUSTOM] Welt"
tokens = tokenizer(text, add_special_tokens=True)
# Dekodieren
decoded = tokenizer.decode(tokens['input_ids'][0], skip_special_tokens=False)
Tokenisierung für verschiedene Aufgaben
# Textklassifikation (einzelne Sequenz)
tokens = tokenizer(
"Dieser Film war großartig!",
padding="max_length",
truncation=True,
max_length=128,
return_tensors="pt"
)
# Fragebeantwortung (Paar von Sequenzen)
frage = "Was ist die Hauptstadt von Frankreich?"
kontext = "Frankreich ist ein Land in Europa. Paris ist seine Hauptstadt."
tokens = tokenizer(
frage,
kontext,
padding="max_length",
truncation="only_second", # Nur den Kontext kürzen
max_length=384,
return_tensors="pt"
)
# Textgenerierung (Decoder-only-Modelle)
aufforderung = "Es war einmal"
tokens = tokenizer(aufforderung, return_tensors="pt")
# Für Generierungseingabe ist kein Padding erforderlich
Teil 3: Feintuning-Workflows
Muster 1: Einfaches Feintuning mit Trainer
from transformers import (
AutoModelForSequenceClassification,
AutoTokenizer,
Trainer,
TrainingArguments
)
from datasets import load_dataset
# 1. Datensatz laden
dataset = load_dataset("glue", "mrpc")
# 2. Modell laden
model = AutoModelForSequenceClassification.from_pretrained(
"bert-base-uncased",
num_labels=2
)
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
# 3. Datensatz tokenisieren
def tokenize_function(examples):
return tokenizer(
examples["sentence1"],
examples["sentence2"],
padding="max_length",
truncation=True,
max_length=128
)
tokenized_datasets = dataset.map(tokenize_function, batched=True)
# 4. Trainingsargumente definieren
training_args = TrainingArguments(
output_dir="./results",
evaluation_strategy="epoch",
learning_rate=2e-5,
per_device_train_batch_size=16,
per_device_eval_batch_size=16,
num_train_epochs=3,
weight_decay=0.01,
logging_dir="./logs",
logging_steps=100,
save_strategy="epoch",
load_best_model_at_end=True,
metric_for_best_model="accuracy",
)
# 5. Metriken definieren
from datasets import load_metric
import numpy as np
metric = load_metric("accuracy")
def compute_metrics(eval_pred):
logits, labels = eval_pred
predictions = np.argmax(logits, axis=-1)
return metric.compute(predictions=predictions, references=labels)
# 6. Trainer erstellen
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_datasets["train"],
eval_dataset=tokenized_datasets["validation"],
compute_metrics=compute_metrics,
)
# 7. Trainieren
trainer.train()
# 8. Speichern
trainer.save_model("./fine-tuned-model")
Muster 2: LoRA-Feintuning (parametereffizient)
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import LoraConfig, get_peft_model, TaskType
# Basismodell laden
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-2-7b-hf",
load_in_8bit=True, # 8-Bit für Speichereffizienz
device_map="auto"
)
# LoRA konfigurieren
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=8, # LoRA-Rang
lora_alpha=32, # LoRA-Alpha
lora_dropout=0.1,
target_modules=["q_proj", "v_proj"], # Welche Schichten angepasst werden
)
# LoRA anwenden
model = get_peft_model(model, lora_config)
# Trainierbare Parameter prüfen
model.print_trainable_parameters()
# Ausgabe: trainable params: 4.2M || all params: 6.7B || trainable%: 0.062%
# Mit Trainer trainieren (wie zuvor)
# Nur LoRA-Parameter werden aktualisiert!
Muster 3: Benutzerdefinierte Trainingsschleife
import torch
from torch.utils.data import DataLoader
from transformers import AdamW, get_scheduler
# Datenlader vorbereiten
train_dataloader = DataLoader(tokenized_datasets["train"], batch_size=16, shuffle=True)
eval_dataloader = DataLoader(tokenized_datasets["validation"], batch_size=16)
# Optimierer
optimizer = AdamW(model.parameters(), lr=2e-5)
# Lernraten-Scheduler
num_epochs = 3
num_training_steps = num_epochs * len(train_dataloader)
lr_scheduler = get_scheduler(
"linear",
optimizer=optimizer,
num_warmup_steps=500,
num_training_steps=num_training_steps
)
# Trainingsschleife
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)
for epoch in range(num_epochs):
model.train()
for batch in train_dataloader:
batch = {k: v.to(device) for k, v in batch.items()}
outputs = model(**batch)
loss = outputs.loss
loss.backward()
optimizer.step()
lr_scheduler.step()
optimizer.zero_grad()
# Evaluierung
model.eval()
for batch in eval_dataloader:
batch = {k: v.to(device) for k, v in batch.items()}
with torch.no_grad():
outputs = model(**batch)
# Metriken berechnen
Teil 4: Pipeline-Nutzung (High-Level-API)
Textklassifikations-Pipeline
from transformers import pipeline
# Pipeline laden
classifier = pipeline(
"text-classification",
model="distilbert-base-uncased-finetuned-sst-2-english"
)
# Einzelne Vorhersage
ergebnis = classifier("Ich liebe dieses Produkt!")
# [{'label': 'POSITIVE', 'score': 0.9998}]
# Batch-Vorhersage
ergebnisse = classifier([
"Hervorragender Service!",
"Schreckliche Erfahrung",
"Durchschnittliche Qualität"
])
Frage-Antwort-Pipeline
qa_pipeline = pipeline("question-answering", model="distilbert-base-uncased-distilled-squad")
ergebnis = qa_pipeline(
question="Was ist die Hauptstadt von Frankreich?",
context="Frankreich ist ein Land in Europa. Seine Hauptstadt ist Paris, eine schöne Stadt."
)
# {'score': 0.98, 'start': 49, 'end': 54, 'answer': 'Paris'}
Textgenerierungs-Pipeline
generator = pipeline("text-generation", model="gpt2")
ausgaben = generator(
"Es war einmal",
max_length=50,
num_return_sequences=3,
temperature=0.7,
top_k=50,
top_p=0.95,
do_sample=True
)
for ausgabe in ausgaben:
print(ausgabe['generated_text'])
Zero-Shot-Klassifikations-Pipeline
classifier = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
ergebnis = classifier(
"Dies ist ein Kurs über Python-Programmierung.",
candidate_labels=["Bildung", "Technologie", "Geschäft", "Sport"]
)
# {'sequence': '...', 'labels': ['education', 'technology', ...], 'scores': [0.85, 0.12, ...]}
Teil 5: Inferenzoptimierung
Optimierung 1: Batch-Verarbeitung
# ❌ LANGSAM: Eines nach dem anderen verarbeiten
for text in texts:
output = model(**tokenizer(text, return_tensors="pt"))
# ✅ SCHNELL: In Batches verarbeiten
batch_size = 32
for i in range(0, len(texts), batch_size):
batch = texts[i:i+batch_size]
inputs = tokenizer(batch, padding=True, truncation=True, return_tensors="pt")
outputs = model(**inputs)
Optimierung 2: Gemischte Genauigkeit (AMP)
from torch.cuda.amp import autocast, GradScaler
scaler = GradScaler()
for batch in dataloader:
optimizer.zero_grad()
# Vorwärtspass mit gemischter Genauigkeit
with autocast():
outputs = model(**batch)
loss = outputs.loss
# Rückwärtspass mit skalierten Gradienten
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
Optimierung 3: ONNX-Export
from transformers import AutoModelForSequenceClassification, AutoTokenizer
from optimum.onnxruntime import ORTModelForSequenceClassification
# Nach ONNX exportieren
model = AutoModelForSequenceClassification.from_pretrained("bert-base-uncased")
model.save_pretrained("./onnx-model", export=True)
# ONNX-Modell laden (schnellere Inferenz)
ort_model = ORTModelForSequenceClassification.from_pretrained("./onnx-model")
# Inferenz (2-3x schneller)
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
inputs = tokenizer("Hallo Welt", return_tensors="pt")
outputs = ort_model(**inputs)
Optimierung 4: Dynamische Quantisierung
import torch
# Modell auf int8 quantisieren
quantisiertes_modell = torch.quantization.quantize_dynamic(
model,
{torch.nn.Linear}, # Lineare Schichten quantisieren
dtype=torch.qint8
)
# 4x kleineres Modell, 2-3x schnellere Inferenz auf CPU
Teil 6: Häufige Probleme und Lösungen
Problem 1: CUDA-Speicher voll (Out of Memory)
Problem: RuntimeError: CUDA out of memory
Lösungen:
# Lösung 1: Batch-Größe reduzieren
training_args = TrainingArguments(
per_device_train_batch_size=8, # War 32
gradient_accumulation_steps=4, # Effektiver Batch = 8*4 = 32
)
# Lösung 2: Gradient-Checkpointing verwenden
model.gradient_checkpointing_enable()
# Lösung 3: 8-Bit-Modell verwenden
from transformers import BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(load_in_8bit=True)
model = AutoModel.from_pretrained("model-name", quantization_config=quantization_config)
# Lösung 4: Cache leeren
import torch
torch.cuda.empty_cache()
Problem 2: Langsame Tokenisierung
Problem: Tokenisierung ist der Engpass
Lösungen:
# Lösung 1: Schnelle Tokenizer verwenden
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased", use_fast=True)
# Lösung 2: Datensatz einmal tokenisieren und zwischenspeichern
tokenized_dataset = dataset.map(
tokenize_function,
batched=True,
num_proc=4, # Parallele Verarbeitung
remove_columns=dataset.column_names,
load_from_cache_file=True # Ergebnisse zwischenspeichern
)
# Lösung 3: Größere Batches für Tokenisierung verwenden
tokenizer(
texts,
padding=True,
truncation=True,
max_length=512,
return_tensors="pt",
batched=True, # Mehrere Texte auf einmal verarbeiten
batch_size=1000
)
Problem 3: Inkonsistente Ergebnisse
Problem: Modell liefert unterschiedliche Ergebnisse für dieselbe Eingabe
Lösung:
# Seeds für Reproduzierbarkeit setzen
import random
import numpy as np
import torch
seed = 42
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
# Cudnn deterministisch machen (kann langsamer sein)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
Zusammenfassung
Diese Fertigkeit deckt die gesamte Pipeline der Arbeit mit Hugging-Face-Transformern ab:
- Modellladung: Einfach, mit Konfiguration, quantisiert, lokal
- Tokenisierung: Padding, Kürzung, Batch, spezielle Token, aufgabenspezifisch
- Feintuning: Trainer, LoRA, benutzerdefinierte Schleifen
- Pipelines: Textklassifikation, Frage-Antwort, Generierung, Zero-Shot
- Optimierung: Batch, gemischte Genauigkeit, ONNX, Quantisierung
- Debugging: Speicher, Tokenisierung, Reproduzierbarkeit
Denken Sie immer daran:
padding=True,truncation=True,return_tensors="pt"für die meisten Aufgaben verwendendevice_map="auto"für große Modelle verwenden- Parameter-effiziente Methoden wie LoRA für Feintuning in Betracht ziehen
- Quantisierung für die Bereitstellung auf CPU oder begrenztem Arbeitsspeicher verwenden
- Seeds setzen für reproduzierbare Ergebnisse