HuggingFace Transformers: Ekosistem İçin Pratik Bir Kılavuz
SarılmaYüz ve Makine Öğrenimi için referans platform haline geldi
modern. 500.000'den fazla önceden eğitilmiş model, 100.000'den fazla veri seti ve kitaplık ile
transformers, datasets, peft, accelerate
e optimum, çoğunun dayandığı altyapıyı temsil eder
Mevcut NLP ve Bilgisayarla Görme araştırma ve geliştirmesinin.
Bu yazımızda HuggingFace ekosistemini pratik ve sistematik bir şekilde inceleyeceğiz: Hub'da doğru modeli seçmekten ince ayar için Trainer API'sine kadar, Büyük veri kümelerini yönetmek, modeli optimize etmek ve dağıtmak için. Ayrıca özel eğitim döngüleri, özel geri aramalar gibi gelişmiş modelleri de göreceğiz. üretim ve MLOps sistemleriyle entegrasyon için optimize edilmiş çıkarım.
Bu serinin yedinci yazısı Modern NLP: BERT'ten Yüksek Lisans'a. BERT (Madde 2) ve duyarlılık analizine (Madde 3) aşina olunduğunu varsayar.
Ne Öğreneceksiniz
- HuggingFace ekosistemi: ana kütüphaneler ve bunların ne zaman kullanılacağı
- Model Merkezi: modelleri arayın, filtreleyin ve yükleyin
- AutoClass API: AutoModel, AutoTokenizer, AutoConfig
- API işlem hattı: ortak görevler için sıfır yapılandırma çıkarımı
- Veri Kümeleri Kitaplığı: Büyük veri kümelerini yükleme, değiştirme ve akışa alma
- API Eğitmeni: Günlüğe kaydetme, geri aramalar ve kontrol noktası oluşturma ile ince ayarları tamamlayın
- Yerel PyTorch ile özel eğitim döngüleri
- PEFT ve LoRA: az parametreyle etkili ince ayar
- Hızlandırın: dağıtılmış eğitim ve karma hassasiyet
- Çıkarım optimizasyonu: ONNX, BitsAndBytes, nicemleme
- Push to Hub: Modelleri ve veri kümelerini herkese açık olarak paylaşın
- WandB, MLflow ve MLOps sistemleriyle entegrasyon
1. HuggingFace Ekosistemi
HuggingFace ekosistemi birçok ayrı fakat entegre kütüphaneden oluşur. Tekerleği yeniden icat etmekten kaçınmak için her senaryoda hangisinin kullanılacağını anlamak çok önemlidir. ve topluluğun çalışmalarından en iyi şekilde yararlanın.
Ana Kütüphaneler ve Kullanım Senaryoları
| Kitaplık | Kapsam | Tipik Senaryo | Kurulum |
|---|---|---|---|
transformers |
Modeller, belirteçler, eğitim | BERT'in ince ayarı, çıkarım hattı | pip install transformers |
datasets |
Veri kümesi yönetimi | Yükleme, ön işleme, akış | pip install datasets |
peft |
Verimli ince ayar | LoRA, Önek Ayarı, P-Ayarı | pip install peft |
accelerate |
Dağıtılmış eğitim | Çoklu GPU, TPU, karma hassasiyet | pip install accelerate |
optimum |
Çıkarım optimizasyonu | ONNX dışa aktarma, niceleme, TensorRT | pip install optimum |
evaluate |
Standart NLP ölçümleri | BLEU, ROUGE, F1, doğruluk, sıra | pip install evaluate |
trl |
LLM için RLHF ve SFT | Eğitim takibi, ödül modellemesi | pip install trl |
safetensors |
Ağırlıklar için güvenli format | Hızlı ve güvenli kaydetme/yükleme | pip install safetensors |
sentence-transformers |
Cümle yerleştirmeleri | Anlamsal benzerlik, kümeleme, RAG | pip install sentence-transformers |
tokenizers |
Hızlı tokenizasyon | BPE, WordPiece, Unigram özel | pip install tokenizers |
Doğru kütüphaneyi seçmek bağlama bağlıdır. Hızlı prototipleme kullanımı için
pipeline() da transformers. Üretim düzeyinde ince ayar için
kullanmak Trainer ile datasets. Sınırlı GPU'lara sahip büyük modeller için
kullanmak peft. Optimize edilmiş çıkarım kullanımı için optimum.
2. Model Merkezi: Doğru Modeli Bulmak
Il SarılmaYüz Merkezi 500.000'den fazla modele ev sahipliği yapıyor. Doğru olanı bulun
mevcut filtrelerin ve adlandırma kurallarının anlaşılmasını gerektirir. Bir model tanımlanır
itibaren username/model-name, dil, görev, çerçeve ve veri kümesi etiketleriyle.
from huggingface_hub import HfApi, list_models, ModelFilter
import pandas as pd
api = HfApi()
# Cerca modelli per task e lingua
models = list(list_models(
filter=ModelFilter(
task="text-classification",
language="it", # italiano
),
sort="downloads",
direction=-1, # decrescente
limit=10
))
print("Top 10 modelli italiani per text-classification:")
for i, model in enumerate(models, 1):
print(f" {i}. {model.modelId} "
f"(downloads: {model.downloads:,}, likes: {model.likes})")
# Cerca modelli BERT italiani specificamente
bert_it_models = list(list_models(
search="bert italian",
sort="downloads",
direction=-1,
limit=5
))
# Carica informazioni dettagliate su un modello
model_info = api.model_info("dbmdz/bert-base-italian-cased")
print(f"\nModello: {model_info.modelId}")
print(f"Task: {model_info.pipeline_tag}")
print(f"Tag: {model_info.tags}")
print(f"Downloads/mese: {model_info.downloads:,}")
# Confronta modelli per benchmark
print("\n=== Modelli Italiani Consigliati per Task ===")
italian_models = {
"sentiment": [
"neuraly/bert-base-italian-cased-sentiment",
"MilaNLProc/feel-it-italian-sentiment",
"morenolq/bert-base-italian-cased-sentiment"
],
"ner": [
"osiria/bert-base-italian-uncased-ner",
"Babelscape/wikineural-multilingual-ner"
],
"embeddings": [
"nickprock/sentence-bert-base-italian-uncased",
"paraphrase-multilingual-mpnet-base-v2"
],
"base_models": [
"dbmdz/bert-base-italian-cased",
"dbmdz/bert-base-italian-uncased",
"idb-ita/gilberto-uncased-from-camembert"
]
}
for task, models_list in italian_models.items():
print(f"\n{task.upper()}:")
for m in models_list:
print(f" - {m}")
Merkezden Şablon Seçme Kriterleri
- Aylık indirmeler: topluluğun benimsenmesinin ve güvenilirliğinin göstergesi
- Görev etiketleri: modelin göreve özel bir başlığı olduğunu doğrulayın (örn.
text-classification) - Model kartları: eğitim belgeleri, kullanılan veri kümeleri, kıyaslamalar, sınırlamalar
- Dil: hedef dili desteklediğinden emin olun (etiket
it,multilingual) - Boyut: performans ile hızı dengeleyin. Modeller
base(110M) 3-4 kat daha hızlıdırlarge(340M) - Veri eğitimi: Yeni modeller genellikle aynı mimaride bile eski modellerden daha iyi performans gösteriyor
3. AutoClass API: Esnek Yükleme
Le Otomatik Sınıf herhangi bir HuggingFace modelini yüklemenize izin verir
Temel mimariden bağımsız olarak aynı API ile.
Bu dosya sayesinde mümkün config.json her modele eşlik eden
ve başlatılacak tam sınıfı belirtir.
from transformers import (
AutoModel,
AutoModelForSequenceClassification,
AutoModelForTokenClassification,
AutoModelForCausalLM,
AutoModelForSeq2SeqLM,
AutoModelForQuestionAnswering,
AutoModelForMaskedLM,
AutoTokenizer,
AutoConfig,
AutoFeatureExtractor
)
import torch
# Carica configurazione senza scaricare i pesi (molto veloce)
config = AutoConfig.from_pretrained("bert-base-uncased")
print(f"Architettura: {config.architectures}")
print(f"Hidden size: {config.hidden_size}")
print(f"Num layers: {config.num_hidden_layers}")
print(f"Num attention heads: {config.num_attention_heads}")
print(f"Vocab size: {config.vocab_size}")
# Tokenizer (funziona per qualsiasi modello)
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
# Codifica testo
inputs = tokenizer(
"HuggingFace e fantastico!",
return_tensors="pt", # "pt" per PyTorch, "tf" per TensorFlow, "np" per NumPy
truncation=True,
max_length=128,
padding="max_length"
)
print(f"\nToken IDs shape: {inputs['input_ids'].shape}") # [1, 128]
# Modello base (senza testa task-specifica) - per feature extraction
model_base = AutoModel.from_pretrained("bert-base-uncased")
with torch.no_grad():
outputs = model_base(**inputs)
hidden_states = outputs.last_hidden_state # [1, 128, 768]
cls_embedding = hidden_states[:, 0, :] # CLS token [1, 768]
print(f"CLS embedding shape: {cls_embedding.shape}")
# Modello con testa per classificazione
model_clf = AutoModelForSequenceClassification.from_pretrained(
"distilbert-base-uncased-finetuned-sst-2-english"
)
print(f"\nModello classificazione labels: {model_clf.config.id2label}")
# Tabella delle AutoClass per task
autoclass_map = {
"AutoModelForSequenceClassification": "Classificazione testo, sentiment",
"AutoModelForTokenClassification": "NER, POS tagging",
"AutoModelForQuestionAnswering": "Extractive QA (SQuAD-style)",
"AutoModelForCausalLM": "Generazione testo (GPT-style)",
"AutoModelForSeq2SeqLM": "Traduzione, summarization (T5/mBART)",
"AutoModelForMaskedLM": "Masked language modeling (BERT)",
"AutoModelForMultipleChoice": "Multiple choice (SWAG, HellaSwag)",
}
print("\nMappa AutoClass -> Task:")
for cls, task in autoclass_map.items():
print(f" {cls}: {task}")
# Opzioni avanzate di caricamento
model_optimized = AutoModelForSequenceClassification.from_pretrained(
"bert-base-uncased",
num_labels=3,
torch_dtype=torch.float16, # fp16 per risparmiare memoria GPU (~50%)
device_map="auto", # distribuisce automaticamente su GPU disponibili
low_cpu_mem_usage=True, # carica parametri progressivamente
attn_implementation="flash_attention_2" # Flash Attention 2 se disponibile
)
4. API Ardışık Düzeni: Hızlı Çıkarım
La API ardışık düzenleri ve HuggingFace şablonunu kullanmanın en kolay yolu. Tokenizasyon, çıkarım ve son işlemeyi otomatik olarak gerçekleştirir. Prototipleme için idealdir ancak toplu işleme ile üretimde de kullanılabilir.
from transformers import pipeline
import torch
# =========================================
# Task 1: Text Classification / Sentiment
# =========================================
sentiment = pipeline(
"sentiment-analysis",
model="distilbert-base-uncased-finetuned-sst-2-english",
device=0 if torch.cuda.is_available() else -1 # GPU se disponibile
)
results = sentiment(["I love this product!", "This is terrible.", "It's okay I guess."])
for r in results:
print(f" Label: {r['label']}, Score: {r['score']:.3f}")
# =========================================
# Task 2: Named Entity Recognition
# =========================================
ner = pipeline(
"ner",
model="dslim/bert-base-NER",
aggregation_strategy="simple" # aggrega token dello stesso entity
)
entities = ner("Apple CEO Tim Cook announced a new iPhone in Cupertino.")
for ent in entities:
print(f" '{ent['word']}' -> {ent['entity_group']} ({ent['score']:.3f})")
# =========================================
# Task 3: Question Answering
# =========================================
qa = pipeline("question-answering", model="deepset/roberta-base-squad2")
result = qa(
question="Chi ha fondato Tesla?",
context="Elon Musk ha co-fondato Tesla Motors nel 2003 insieme a Martin Eberhard."
)
print(f"\nQA Answer: '{result['answer']}' (score={result['score']:.3f})")
# =========================================
# Task 4: Text Generation
# =========================================
generator = pipeline(
"text-generation",
model="gpt2",
max_new_tokens=80,
num_return_sequences=2,
do_sample=True,
temperature=0.8,
top_p=0.95,
repetition_penalty=1.2
)
outputs = generator("Il futuro dell'intelligenza artificiale e")
for i, out in enumerate(outputs):
print(f"\nGeneration {i+1}: {out['generated_text']}")
# =========================================
# Task 5: Zero-Shot Classification
# =========================================
zero_shot = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
result = zero_shot(
"L'economia italiana ha subito una contrazione dello 0.5% nel Q3 2024.",
candidate_labels=["economia", "politica", "sport", "tecnologia", "salute"]
)
print("\nZero-shot classification:")
for label, score in zip(result['labels'][:3], result['scores'][:3]):
print(f" {label}: {score:.3f}")
# =========================================
# Task 6: Summarization
# =========================================
summarizer = pipeline("summarization", model="facebook/bart-large-cnn",
min_length=30, max_length=130)
text = """
L'intelligenza artificiale generativa ha rivoluzionato il settore tecnologico nel 2024.
I modelli di linguaggio di grandi dimensioni come GPT-4, Claude e Gemini hanno dimostrato
capacità sorprendenti nel ragionamento, nella scrittura creativa e nella risoluzione di problemi
complessi. Le aziende di tutto il mondo stanno integrando queste tecnologie nei loro processi
produttivi, dalla customer service all'analisi dei dati, dalla generazione di codice alla
creazione di contenuti multimediali.
"""
summary = summarizer(text)[0]['summary_text']
print(f"\nSummary: {summary}")
# =========================================
# Task 7: Translation
# =========================================
translator = pipeline("translation_it_to_en", model="Helsinki-NLP/opus-mt-it-en")
italian_text = "Il machine learning sta trasformando il mondo moderno."
translated = translator(italian_text)[0]['translation_text']
print(f"\nTranslation: {translated}")
# =========================================
# Batch Processing per Performance
# =========================================
print("\n=== Batch Processing ===")
texts = [
"Ottimo prodotto, lo consiglio!",
"Pessima qualità, non lo ricomprero.",
"Nella media, niente di speciale."
] * 100 # 300 testi
# Batch inference e molto più efficiente di loop singoli
sentiment_batch = pipeline(
"sentiment-analysis",
model="distilbert-base-uncased-finetuned-sst-2-english",
batch_size=32 # processa 32 testi alla volta
)
results_batch = sentiment_batch(texts)
print(f"Processati {len(results_batch)} testi")
5. Veri Kümeleri Kitaplığı: Verimli Veri Yönetimi
Kütüphane datasets Apache Arrow'u arka uç olarak kullanıyor, bu da onu
büyük veriler için son derece verimlidir. Tüm işlemler tembel ve hafıza haritalıdır,
RAM'a sığmayan veri kümeleriyle çalışmanıza olanak tanır.
from datasets import (
load_dataset,
Dataset,
DatasetDict,
concatenate_datasets,
interleave_datasets,
Features,
Value,
ClassLabel
)
import pandas as pd
from typing import Dict, List
# =========================================
# Caricamento da HuggingFace Hub
# =========================================
# Dataset pubblico con split
sst2 = load_dataset("glue", "sst2")
print("SST-2 dataset:", sst2)
print("Training size:", len(sst2["train"]))
print("Features:", sst2["train"].features)
# Con streaming (per dataset enormi - non scarica tutto)
wiki_stream = load_dataset(
"wikipedia",
"20220301.it",
split="train",
streaming=True,
trust_remote_code=True
)
# Prendi solo 5 esempi senza scaricare tutto il dataset
for i, example in enumerate(wiki_stream.take(5)):
print(f"Titolo: {example['title']} - Lunghezza: {len(example['text'])} chars")
# =========================================
# Creazione da sorgenti locali
# =========================================
# Da dizionario Python
data = Dataset.from_dict({
"text": [
"Ottimo prodotto, lo consiglio!",
"Pessima qualità, non vale i soldi.",
"Prodotto nella media, niente di eccezionale.",
"Fantastimo! Superato le aspettative."
],
"label": [1, 0, 0, 1]
})
# Da pandas DataFrame con tipi espliciti
df = pd.DataFrame({
"text": ["Sample text 1", "Sample text 2"],
"label": [0, 1],
"split": ["train", "train"]
})
dataset_from_df = Dataset.from_pandas(df)
# Da file con schema esplicito
features = Features({
"text": Value("string"),
"label": ClassLabel(names=["negativo", "positivo"]),
"confidence": Value("float32")
})
dataset_json = load_dataset("json", data_files="data.jsonl", features=features)
# =========================================
# Manipolazione avanzata
# =========================================
# map: tokenizzazione parallela
def tokenize_function(examples, tokenizer, max_length=128):
return tokenizer(
examples["text"],
truncation=True,
padding="max_length",
max_length=max_length,
return_token_type_ids=False
)
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
tokenized = data.map(
lambda x: tokenize_function(x, tokenizer),
batched=True, # processa batch per efficienza
batch_size=1000, # 1000 esempi per batch
num_proc=4, # usa 4 processi paralleli
remove_columns=["text"] # rimuovi colonne non necessarie
)
tokenized.set_format("torch") # converte in PyTorch tensors
# filter: rimuove esempi corti
long_texts = data.filter(
lambda x: len(x["text"].split()) > 5,
num_proc=4
)
# Balancing: sovracampionamento classe minoritaria
class_0 = data.filter(lambda x: x["label"] == 0)
class_1 = data.filter(lambda x: x["label"] == 1)
# Ripeti classe_0 per bilanciare
if len(class_0) < len(class_1):
factor = len(class_1) // len(class_0)
class_0_repeated = concatenate_datasets([class_0] * factor)
balanced = concatenate_datasets([class_0_repeated, class_1]).shuffle(seed=42)
# train_test_split
splits = data.train_test_split(test_size=0.2, seed=42, stratify_by_column="label")
train_ds = splits["train"]
test_ds = splits["test"]
print(f"\nTrain: {len(train_ds)}, Test: {len(test_ds)}")
# =========================================
# DatasetDict: gestione multi-split
# =========================================
dataset_dict = DatasetDict({
"train": train_ds,
"test": test_ds,
"validation": data.select(range(2))
})
# Salva e ricarica (formato Arrow efficiente)
dataset_dict.save_to_disk("./data/my_dataset")
loaded = DatasetDict.load_from_disk("./data/my_dataset")
# =========================================
# Statistiche e ispezione
# =========================================
print("\n=== Statistiche Dataset ===")
print(f"Numero esempi: {len(data)}")
print(f"Distribuzione label: {data.to_pandas()['label'].value_counts().to_dict()}")
print(f"Lunghezza media testi: {data.to_pandas()['text'].str.len().mean():.0f} chars")
6. API Eğitmeni: İnce Ayarı Tamamlayın
La API Eğitmenleri ve HuggingFace'te eğitim için üst düzey soyutlama. Eğitim döngülerini, değerlendirmeyi, kontrol noktası oluşturmayı, günlüğe kaydetmeyi ve çok daha fazlasını yönetir. Karma hassasiyeti, gradyan birikimini, dağıtılmış eğitimi ve kullanıma hazır özellikleri destekler WandB, TensorBoard ve MLflow ile entegrasyon.
from transformers import (
AutoModelForSequenceClassification,
AutoTokenizer,
TrainingArguments,
Trainer,
EarlyStoppingCallback,
TrainerCallback,
TrainerControl,
TrainerState
)
from datasets import load_dataset
import evaluate
import numpy as np
import torch
MODEL = "distilbert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(MODEL)
model = AutoModelForSequenceClassification.from_pretrained(MODEL, num_labels=2)
# Preparazione dataset
dataset = load_dataset("glue", "sst2")
def tokenize(examples):
return tokenizer(
examples["sentence"],
truncation=True,
padding="max_length",
max_length=128
)
tokenized = dataset.map(
tokenize,
batched=True,
remove_columns=["sentence", "idx"]
)
tokenized.set_format("torch")
# Metriche composite
accuracy = evaluate.load("accuracy")
f1 = evaluate.load("f1")
def compute_metrics(eval_pred):
logits, labels = eval_pred
preds = np.argmax(logits, axis=-1)
probs = torch.softmax(torch.tensor(logits), dim=-1).numpy()
acc = accuracy.compute(predictions=preds, references=labels)["accuracy"]
f1_score = f1.compute(predictions=preds, references=labels, average="binary")["f1"]
# Aggiungi calibration metric (ECE - Expected Calibration Error)
from sklearn.calibration import calibration_curve
# Semplificato: usa solo le metriche base
return {"accuracy": acc, "f1": f1_score}
# TrainingArguments: configurazione completa
args = TrainingArguments(
# I/O e checkpoint
output_dir="./results/distilbert-sst2",
logging_dir="./logs",
logging_steps=50,
logging_strategy="steps",
# Epochs e batch
num_train_epochs=5,
per_device_train_batch_size=32,
per_device_eval_batch_size=64,
# Learning rate schedule
learning_rate=2e-5,
lr_scheduler_type="cosine", # cosine, linear, cosine_with_restarts, polynomial
warmup_ratio=0.1, # 10% di warm-up steps
weight_decay=0.01, # L2 regularization
# Valutazione e salvataggio
eval_strategy="epoch", # "no", "steps", "epoch"
save_strategy="epoch",
load_best_model_at_end=True,
metric_for_best_model="f1",
greater_is_better=True,
save_total_limit=3, # mantieni solo i 3 migliori checkpoint
# Ottimizzazione computazionale
fp16=True, # mixed precision FP16
# bf16=True, # alternativa su hardware recente (A100, RTX3090+)
dataloader_num_workers=4,
gradient_accumulation_steps=2, # batch effettivo = 32*2 = 64
# gradient_checkpointing=True, # riduce memoria a costo di +30% calcolo
max_grad_norm=1.0, # gradient clipping
# Reporting
report_to="none", # "wandb", "tensorboard", "mlflow", "comet_ml"
# Seed e reproducibilita
seed=42,
data_seed=42,
)
# =========================================
# Custom Callback: monitoring avanzato
# =========================================
class TrainingMonitorCallback(TrainerCallback):
def __init__(self, patience: int = 3):
self.patience = patience
self.best_metric = None
self.steps_without_improvement = 0
def on_evaluate(self, args, state: TrainerState, control: TrainerControl, metrics, **kwargs):
current_metric = metrics.get("eval_f1", 0)
if self.best_metric is None or current_metric > self.best_metric:
self.best_metric = current_metric
self.steps_without_improvement = 0
print(f"\n[Callback] Nuovo best F1: {current_metric:.4f}")
else:
self.steps_without_improvement += 1
print(f"\n[Callback] No improvement ({self.steps_without_improvement}/{self.patience})")
def on_log(self, args, state: TrainerState, control: TrainerControl, logs=None, **kwargs):
if logs and "loss" in logs:
if state.global_step % 200 == 0:
print(f" Step {state.global_step}: loss={logs['loss']:.4f}")
# Trainer con callbacks multipli
trainer = Trainer(
model=model,
args=args,
train_dataset=tokenized["train"],
eval_dataset=tokenized["validation"],
compute_metrics=compute_metrics,
callbacks=[
EarlyStoppingCallback(
early_stopping_patience=2,
early_stopping_threshold=0.001
),
TrainingMonitorCallback(patience=3)
]
)
# Training e valutazione
train_result = trainer.train()
print(f"\nTraining completato!")
print(f"Train loss: {train_result.training_loss:.4f}")
print(f"Train time: {train_result.metrics['train_runtime']:.1f}s")
print(f"Samples/sec: {train_result.metrics['train_samples_per_second']:.1f}")
# Valutazione finale
metrics = trainer.evaluate(eval_dataset=tokenized["validation"])
print(f"Validation F1: {metrics['eval_f1']:.4f}")
print(f"Validation Acc: {metrics['eval_accuracy']:.4f}")
# Salva tutto
trainer.save_model("./models/distilbert-sst2-final")
tokenizer.save_pretrained("./models/distilbert-sst2-final")
# Log history
import pandas as pd
log_history = pd.DataFrame(trainer.state.log_history)
print(f"\nLog history columns: {list(log_history.columns)}")
7. PyTorch ile Özel Eğitim Döngüsü
Trainer API'sinin yeterli olmadığı ileri düzey durumlar için bir eğitim döngüsü yazabiliriz. tüm optimizasyonları korurken özelleştirilmiştir. Bu size en fazla kontrolü sağlar kayıp fonksiyonları özel, örnekleme stratejileri, müfredat öğrenimi vb.
from transformers import AutoModelForSequenceClassification, AutoTokenizer, get_linear_schedule_with_warmup
from torch.optim import AdamW
from torch.utils.data import DataLoader
from datasets import load_dataset
import torch
import numpy as np
from tqdm import tqdm
# =========================================
# Setup
# =========================================
MODEL = "bert-base-uncased"
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
EPOCHS = 3
BATCH_SIZE = 32
LR = 2e-5
tokenizer = AutoTokenizer.from_pretrained(MODEL)
model = AutoModelForSequenceClassification.from_pretrained(MODEL, num_labels=2).to(DEVICE)
# Dataset
dataset = load_dataset("glue", "sst2")
def tokenize(examples):
return tokenizer(examples["sentence"], truncation=True, padding="max_length", max_length=128)
tokenized = dataset.map(tokenize, batched=True, remove_columns=["sentence", "idx"])
tokenized.set_format("torch")
train_loader = DataLoader(
tokenized["train"],
batch_size=BATCH_SIZE,
shuffle=True,
num_workers=4,
pin_memory=True # velocizza trasferimento CPU->GPU
)
val_loader = DataLoader(tokenized["validation"], batch_size=64, num_workers=4)
# Optimizer con weight decay selettivo (no bias e LayerNorm)
no_decay = ["bias", "LayerNorm.weight", "LayerNorm.bias"]
optimizer_grouped = [
{"params": [p for n, p in model.named_parameters() if not any(nd in n for nd in no_decay)],
"weight_decay": 0.01},
{"params": [p for n, p in model.named_parameters() if any(nd in n for nd in no_decay)],
"weight_decay": 0.0}
]
optimizer = AdamW(optimizer_grouped, lr=LR, eps=1e-8)
# Learning rate scheduler con warmup
total_steps = len(train_loader) * EPOCHS
warmup_steps = int(total_steps * 0.1)
scheduler = get_linear_schedule_with_warmup(
optimizer,
num_warmup_steps=warmup_steps,
num_training_steps=total_steps
)
# Mixed precision scaler
scaler = torch.cuda.amp.GradScaler(enabled=torch.cuda.is_available())
# =========================================
# Training Loop
# =========================================
best_f1 = 0.0
for epoch in range(EPOCHS):
model.train()
total_loss = 0
progress_bar = tqdm(train_loader, desc=f"Epoch {epoch+1}/{EPOCHS}")
for step, batch in enumerate(progress_bar):
# Sposta batch su device
batch = {k: v.to(DEVICE) for k, v in batch.items()}
# Mixed precision forward pass
with torch.cuda.amp.autocast(enabled=torch.cuda.is_available()):
outputs = model(**batch)
loss = outputs.loss
# Backward pass con scaler
scaler.scale(loss).backward()
# Gradient clipping
scaler.unscale_(optimizer)
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
scaler.step(optimizer)
scaler.update()
optimizer.zero_grad()
scheduler.step()
total_loss += loss.item()
progress_bar.set_postfix({"loss": f"{loss.item():.4f}", "lr": f"{scheduler.get_last_lr()[0]:.2e}"})
avg_loss = total_loss / len(train_loader)
# Validation
model.eval()
all_preds, all_labels = [], []
with torch.no_grad():
for batch in val_loader:
batch = {k: v.to(DEVICE) for k, v in batch.items()}
outputs = model(**batch)
preds = torch.argmax(outputs.logits, dim=-1)
all_preds.extend(preds.cpu().numpy())
all_labels.extend(batch["labels"].cpu().numpy())
from sklearn.metrics import f1_score, accuracy_score
f1 = f1_score(all_labels, all_preds)
acc = accuracy_score(all_labels, all_preds)
print(f"\nEpoch {epoch+1}: loss={avg_loss:.4f}, val_f1={f1:.4f}, val_acc={acc:.4f}")
# Salva best model
if f1 > best_f1:
best_f1 = f1
model.save_pretrained("./models/best_model")
tokenizer.save_pretrained("./models/best_model")
print(f" Salvato nuovo best model (F1={f1:.4f})")
8. PEFT: LoRA ile Verimli İnce Ayar
Kütüphane PEFT (Parametre Açısından Verimli İnce Ayar) yapmanıza izin verir Parametrelerin yalnızca küçük bir kısmını güncelleyerek büyük modellere ince ayar yapma. LoRA (Düşük Sıralı Uyarlama) ve en çok kullanılan yöntem: güncellemeleri ayrıştırır ağırlıkların iki düşük dereceli matrisin çarpımı olarak kullanılması, eğitilebilir parametrelerin azaltılması %99 civarında.
Karşılaştırmalı PEFT yöntemleri
| Yöntem | Eğitilebilir Parametreler | Hafıza | Performans | Kullanım Örneği |
|---|---|---|---|---|
| Tam İnce Ayar | %100 | Yüksek (7B için >40 GB) | Maksimum | Büyük veri kümesi, kurumsal GPU |
| LoRA (r=16) | ~%0,5 | Düşük (-70%) | Neredeyse tam eve eşit | Tüketici GPU'su (8-24 GB) |
| QLoRA | ~%0,5 (4bit modeli) | Çok düşük (-85%) | Biraz daha düşük | GPU 8-16GB, büyük modeller |
| Önek Ayarı | ~%0,1 | Çok düşük | Aşağı | Nesil, Yüksek Lisans |
| Hızlı Ayarlama | ~%0,01 | Asgari | Değişken | Büyük Yüksek Lisanslar (>10B) |
| Bağdaştırıcı Katmanları | ~%1-3 | Düşük | İyi | Çok görevli, modüler |
from peft import (
LoraConfig,
get_peft_model,
TaskType,
PeftModel,
prepare_model_for_kbit_training,
get_peft_config
)
from transformers import AutoModelForSequenceClassification, BitsAndBytesConfig
import torch
# =========================================
# LoRA Standard
# =========================================
model = AutoModelForSequenceClassification.from_pretrained(
"roberta-base",
num_labels=3
)
# Configurazione LoRA
lora_config = LoraConfig(
task_type=TaskType.SEQ_CLS,
r=16, # rank della decomposizione
lora_alpha=32, # scaling factor (alpha/r = scaling ratio)
lora_dropout=0.1, # dropout sui layer LoRA
target_modules=["query", "value", "key"], # layer da modificare
# Alternativa: target_modules="all-linear" per tutti i layer lineari
bias="none", # "none", "all", "lora_only"
inference_mode=False
)
peft_model = get_peft_model(model, lora_config)
peft_model.print_trainable_parameters()
# trainable params: 888,578 || all params: 125,535,234 || trainable%: 0.71%
# =========================================
# QLoRA: LoRA con quantizzazione 4-bit
# =========================================
bnb_config = BitsAndBytesConfig(
load_in_4bit=True, # quantizza il modello a 4bit
bnb_4bit_use_double_quant=True, # double quantization per efficienza
bnb_4bit_quant_type="nf4", # NormalFloat4 (migliore per LM)
bnb_4bit_compute_dtype=torch.bfloat16
)
# Solo per modelli grandi (>1B parametri)
model_4bit = AutoModelForSequenceClassification.from_pretrained(
"bert-large-uncased",
quantization_config=bnb_config,
device_map="auto",
num_labels=3
)
# Prepara per QLoRA training
model_4bit = prepare_model_for_kbit_training(model_4bit)
lora_config_qlora = LoraConfig(
task_type=TaskType.SEQ_CLS,
r=16,
lora_alpha=32,
lora_dropout=0.05,
target_modules=["query", "value"],
bias="none"
)
peft_4bit_model = get_peft_model(model_4bit, lora_config_qlora)
peft_4bit_model.print_trainable_parameters()
# =========================================
# Salvataggio e caricamento LoRA
# =========================================
# Salva solo i pesi LoRA (molto leggeri ~1-5MB)
peft_model.save_pretrained("./models/roberta-lora-classification")
# Caricamento: base model + adapter LoRA
base = AutoModelForSequenceClassification.from_pretrained("roberta-base", num_labels=3)
model_with_lora = PeftModel.from_pretrained(base, "./models/roberta-lora-classification")
model_with_lora.eval()
# Merge per inference più veloce (elimina overhead LoRA)
merged = model_with_lora.merge_and_unload()
merged.save_pretrained("./models/roberta-merged") # salva modello completo fuso
9. Hızlandırın: Dağıtılmış Eğitim
Hızlandırın eğitimin karmaşıklığını otomatik olarak yönetir farklı donanım yapılandırmaları: tek CPU, tek GPU, çoklu GPU, çok düğümlü, TPU, karışık hassasiyetle. Kod minimum düzeyde değişir.
# accelerate_training.py
# Avvio: accelerate launch accelerate_training.py
# Multi-GPU: accelerate launch --num_processes 4 accelerate_training.py
# Config: accelerate config (wizard interattivo)
from accelerate import Accelerator
from accelerate.utils import set_seed, ProjectConfiguration
from transformers import AutoModelForSequenceClassification, AutoTokenizer, get_cosine_schedule_with_warmup
from torch.optim import AdamW
from torch.utils.data import DataLoader
from datasets import load_dataset
import torch
from tqdm import tqdm
# =========================================
# Inizializzazione Accelerate
# =========================================
project_config = ProjectConfiguration(
project_dir="./accelerate_project",
logging_dir="./logs"
)
accelerator = Accelerator(
mixed_precision="fp16", # "no", "fp16", "bf16"
gradient_accumulation_steps=4, # accumula gradienti per batch più grandi
log_with="tensorboard", # logging integrato
project_config=project_config
)
# Importante: usa accelerator.print per evitare output duplicati su multi-GPU
accelerator.print(f"Training su: {accelerator.device}")
accelerator.print(f"Num processi: {accelerator.num_processes}")
accelerator.print(f"Mixed precision: {accelerator.mixed_precision}")
set_seed(42)
MODEL = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(MODEL)
model = AutoModelForSequenceClassification.from_pretrained(MODEL, num_labels=2)
# Dataset
dataset = load_dataset("glue", "sst2")
def tokenize(examples):
return tokenizer(examples["sentence"], truncation=True, padding="max_length", max_length=128)
tokenized = dataset.map(tokenize, batched=True, remove_columns=["sentence", "idx"])
tokenized.set_format("torch")
train_loader = DataLoader(tokenized["train"], batch_size=32, shuffle=True, num_workers=4)
val_loader = DataLoader(tokenized["validation"], batch_size=64, num_workers=4)
optimizer = AdamW(model.parameters(), lr=2e-5, weight_decay=0.01)
total_steps = (len(train_loader) // accelerator.gradient_accumulation_steps) * 3
scheduler = get_cosine_schedule_with_warmup(optimizer, num_warmup_steps=total_steps//10, num_training_steps=total_steps)
# Prepara TUTTI gli oggetti con Accelerate
model, optimizer, train_loader, val_loader, scheduler = accelerator.prepare(
model, optimizer, train_loader, val_loader, scheduler
)
# =========================================
# Training loop con gradient accumulation
# =========================================
for epoch in range(3):
model.train()
total_loss = 0
for step, batch in enumerate(tqdm(train_loader, desc=f"Epoch {epoch+1}")):
# Accumulation context manager
with accelerator.accumulate(model):
outputs = model(**batch)
loss = outputs.loss
accelerator.backward(loss) # invece di loss.backward()
if accelerator.sync_gradients:
# Gradient clipping (solo quando si aggiornano i pesi)
accelerator.clip_grad_norm_(model.parameters(), 1.0)
optimizer.step()
scheduler.step()
optimizer.zero_grad()
total_loss += loss.item()
avg_loss = total_loss / len(train_loader)
accelerator.print(f"\nEpoch {epoch+1}: avg_loss={avg_loss:.4f}")
# Salvataggio checkpoint (gestisce correttamente multi-GPU)
accelerator.save_state(f"./checkpoints/epoch_{epoch+1}")
# Salvataggio modello finale
unwrapped_model = accelerator.unwrap_model(model) # rimuove wrapper Accelerate
unwrapped_model.save_pretrained(
"./models/final_model",
save_function=accelerator.save
)
10. Hub'a Aktarın: Şablonları Paylaşın
from huggingface_hub import HfApi, login, create_repo
from transformers import AutoModelForSequenceClassification, AutoTokenizer
# Autenticazione (usa token da https://huggingface.co/settings/tokens)
login(token="hf_YOUR_TOKEN_HERE")
# =========================================
# Metodo 1: Trainer API (push automatico)
# =========================================
from transformers import TrainingArguments
training_args = TrainingArguments(
output_dir="tuo-username/bert-italian-sentiment", # formato: username/repo-name
push_to_hub=True,
hub_strategy="every_save", # "end", "every_save", "checkpoint", "all_checkpoints"
hub_token="hf_YOUR_TOKEN",
)
# =========================================
# Metodo 2: Push manuale dopo training
# =========================================
model = AutoModelForSequenceClassification.from_pretrained("./models/distilbert-sst2-final")
tokenizer = AutoTokenizer.from_pretrained("./models/distilbert-sst2-final")
# Push modello e tokenizer
model.push_to_hub("tuo-username/bert-italian-sentiment")
tokenizer.push_to_hub("tuo-username/bert-italian-sentiment")
# =========================================
# Metodo 3: HfApi completo con Model Card
# =========================================
api = HfApi()
# Crea repository se non esiste
create_repo(
repo_id="tuo-username/bert-italian-sentiment",
private=False, # True per repository privato
exist_ok=True
)
# Crea Model Card completa
model_card = """---
language:
- it
tags:
- sentiment-analysis
- bert
- italian
- transformers
license: apache-2.0
metrics:
- f1
- accuracy
model-index:
- name: bert-italian-sentiment
results:
- task:
type: text-classification
name: Sentiment Analysis
dataset:
name: SENTIPOLC 2016
type: custom
metrics:
- type: f1
value: 0.924
name: F1 Score
- type: accuracy
value: 0.931
name: Accuracy
---
# BERT Italian Sentiment Analysis
Modello BERT fine-tuned per sentiment analysis in italiano, basato su `dbmdz/bert-base-italian-cased`.
## Utilizzo
```python
from transformers import pipeline
sentiment = pipeline("sentiment-analysis", model="tuo-username/bert-italian-sentiment")
result = sentiment("Ottimo prodotto, lo consiglio!")
print(result) # [{'label': 'POSITIVE', 'score': 0.998}]
```
## Metriche
| Metrica | Valore |
|---------|--------|
| F1 | 0.924 |
| Accuracy | 0.931 |
## Training
- **Base model**: dbmdz/bert-base-italian-cased
- **Dataset**: 50.000 recensioni in italiano
- **Epochs**: 5
- **Batch size**: 32
- **Learning rate**: 2e-5
## Limitazioni
- Addestrato su recensioni di prodotti. Performance può variare su altri domini.
- Non adatto per ironia/sarcasmo sottile.
"""
# Carica README
api.upload_file(
path_or_fileobj=model_card.encode(),
path_in_repo="README.md",
repo_id="tuo-username/bert-italian-sentiment"
)
print("Model card caricata con successo!")
11. Üretimde Çıkarım İçin Optimizasyon
Üretimde çıkarımın hızlı, verimli ve ölçeklenebilir olması gerekir. SarılmaYüz farklı optimizasyon stratejileri sunar: ONNX çalışma zamanı, statik/dinamik nicemleme, TorchScript ve Metin Çıkarım Sunucusu (TGI/TEI).
from optimum.onnxruntime import ORTModelForSequenceClassification
from optimum.exporters.onnx import main_export
from transformers import AutoTokenizer
import torch
import time
import numpy as np
# =========================================
# Export ONNX con ottimizzazione
# =========================================
main_export(
model_name_or_path="./models/distilbert-sst2-final",
output="./models/onnx-optimized",
task="text-classification",
optimize="O2" # O1: base, O2: extended, O3: layout opt, O4: full + float16
)
# Carica e usa il modello ONNX
ort_model = ORTModelForSequenceClassification.from_pretrained(
"./models/onnx-optimized",
provider="CPUExecutionProvider" # "CUDAExecutionProvider" per GPU
)
tokenizer = AutoTokenizer.from_pretrained("./models/distilbert-sst2-final")
# =========================================
# Benchmark: PyTorch vs ONNX vs Quantizzato
# =========================================
texts = ["This product is absolutely amazing!"] * 200
def benchmark_model(model, tokenizer, texts, batch_size=32, num_runs=5):
"""Misura latenza media su batch di testi."""
times = []
for _ in range(num_runs):
start = time.perf_counter()
for i in range(0, len(texts), batch_size):
batch = texts[i:i+batch_size]
inputs = tokenizer(batch, return_tensors='pt', padding=True,
truncation=True, max_length=128)
with torch.no_grad():
if hasattr(model, '__call__'):
_ = model(**inputs)
times.append(time.perf_counter() - start)
return np.mean(times), np.std(times)
# Test ONNX
avg_time, std_time = benchmark_model(ort_model, tokenizer, texts)
print(f"ONNX (200 testi): {avg_time*1000:.1f}ms ± {std_time*1000:.1f}ms")
# =========================================
# Quantizzazione dinamica PyTorch
# =========================================
from transformers import AutoModelForSequenceClassification
pt_model = AutoModelForSequenceClassification.from_pretrained(
"./models/distilbert-sst2-final"
)
pt_model.eval()
# Quantizzazione dinamica INT8 (nessun dataset di calibrazione necessario)
quantized_model = torch.quantization.quantize_dynamic(
pt_model,
{torch.nn.Linear}, # quantizza solo layer lineari
dtype=torch.qint8 # INT8
)
# Confronto dimensioni
import os
pt_size = sum(p.numel() * p.element_size() for p in pt_model.parameters()) / 1e6
print(f"\nDimensione PyTorch FP32: {pt_size:.1f}MB")
# INT8 e circa 4x più piccolo
# =========================================
# Serving con Text Embeddings Inference (TEI)
# =========================================
# Docker: docker run -p 8080:80 ghcr.io/huggingface/text-embeddings-inference:latest
# --model-id BAAI/bge-base-en-v1.5 --pooling mean
# Esempio client per TEI
import requests
def get_embeddings_tei(texts: list, url: str = "http://localhost:8080") -> np.ndarray:
"""Chiama Text Embeddings Inference server."""
response = requests.post(
f"{url}/embed",
json={"inputs": texts, "normalize": True}
)
response.raise_for_status()
return np.array(response.json())
# embeddings = get_embeddings_tei(["Test sentence"]) # Richiede TEI server attivo
print("\nTEI server endpoint: POST http://localhost:8080/embed")
12. MLOps ile entegrasyon: WandB ve MLflow
Üretim düzeyinde bir bağlamda eğitim izlenmeli ve versiyonlanmalıdır ve tekrarlanabilir. HuggingFace Trainer ana uygulamalarla yerel olarak bütünleşir MLOps araçları.
import os
import wandb
import mlflow
import mlflow.pytorch
from transformers import (
AutoModelForSequenceClassification,
AutoTokenizer,
TrainingArguments,
Trainer
)
# =========================================
# Integrazione WandB
# =========================================
wandb.init(
project="bert-italian-sentiment",
name="distilbert-sst2-run1",
config={
"model": "distilbert-base-uncased",
"learning_rate": 2e-5,
"epochs": 3,
"batch_size": 32,
"dataset": "SST-2"
},
tags=["bert", "sentiment", "italian", "fine-tuning"]
)
# Il Trainer usa automaticamente WandB se disponibile
args_wandb = TrainingArguments(
output_dir="./results",
report_to="wandb", # abilita WandB logging
run_name="distilbert-run1", # nome nella dashboard WandB
num_train_epochs=3,
# ... altri parametri
)
# =========================================
# Integrazione MLflow
# =========================================
mlflow.set_tracking_uri("./mlflow_runs")
mlflow.set_experiment("bert-nlp-experiments")
with mlflow.start_run(run_name="distilbert-sst2"):
# Log parametri
mlflow.log_params({
"model": "distilbert-base-uncased",
"lr": 2e-5,
"epochs": 3,
"batch_size": 32
})
# Trainer con MLflow
args_mlflow = TrainingArguments(
output_dir="./results",
report_to="mlflow",
num_train_epochs=3,
)
model = AutoModelForSequenceClassification.from_pretrained("distilbert-base-uncased", num_labels=2)
tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")
trainer = Trainer(model=model, args=args_mlflow)
# trainer.train() # avvia training con MLflow tracking
# Log metriche e artefatti
mlflow.log_metrics({"eval_f1": 0.924, "eval_accuracy": 0.931})
# Salva modello come artefatto MLflow
mlflow.pytorch.log_model(
model,
"model",
registered_model_name="bert-italian-sentiment"
)
print("MLflow run completato!")
print(f"Run ID: {mlflow.active_run().info.run_id}")
HuggingFace ile Yaygın Anti-Desenler
- Toplu işleme kullanmayın: Tek tek metinlerde boru hattını döngü halinde çağırın ve tüm partiyi geçmekten 10-50 kat daha yavaş
- Modeli her çağrıya yükleyin: modeli hafızada yüklü tutun ve yeniden kullanın; diskten yükleme saniyeler sürer
- Maksimum_uzunluğu yoksay: kesme olmadan, uzun diziler belleği katlanarak tüketir; her zaman ayarlar
truncation=True - Kullanma
torch.no_grad()çıkarımda: PyTorch gereksiz yere degradeler biriktiriyor ve belleği boşa harcıyor - Değerlendirme moduna dönüştürmeyin: BatchNorm ve Dropout, eğitim ve çıkarımda farklı davranır; her zaman arar
model.eval() - Her zaman padding="max_length" kullanın: sabit uzunluktaki dolgu atıklarının hesaplanması; çıkarımda dinamik dolgu kullanın
- Kelime boyutunu göz ardı edin: Geniş kelime dağarcığına sahip katmanların yerleştirilmesi model belleğine hakim olabilir
Sonuçlar ve Sonraki Adımlar
HuggingFace ekosistemi modern NLP için fiili standart haline geldi.
Ana kütüphanelerini bilin — transformers, datasets,
peft, accelerate — ve her şey için temel
2025'te NLP mühendisi veya ML mühendisi.
Ekosistemin gücü bileşenler arasındaki entegrasyonda yatmaktadır: veri kümeleri sağlar Veriler, modeli transformatörler, parametre optimizasyonunu geliştirin, hızlandırın donanım ölçeklenebilirliği ve optimum üretim çıkarımı. Her kütüphane yapabilir bağımsız olarak veya diğerleriyle birlikte kullanılabilir.
Önemli Noktalar
- Amerika Otomatik Sınıf herhangi bir mimariyi aynı kodla yüklemek için
- La API ardışık düzenleri ve hızlı prototipleme için mükemmeldir; Amerika
batch_sizeüretim için - La API Eğitmenleri Özelleştirilebilir geri aramalarla standart ince ayar vakalarının %90'ını yönetir
- Il özel eğitim döngüsü ve özel kayıp fonksiyonları, müfredat öğrenimi ve ileri eğitim için gereklidir
- PEFT/LoRA belleği büyük ölçüde azaltır: neredeyse eşdeğer performansla parametrelerin ~%0,5'i
- Hızlandırın kodu değiştirmeden dağıtılmış eğitime izin verir
- ONNX Yerel PyTorch'a kıyasla CPU çıkarımında 2-5 kat hızlanma sunar
- Entegrasyon WandB veya MLflow Deneylerin izlenebilirliği için başlangıçtan itibaren
Modern NLP Serisi devam ediyor
- Öncesi: Metin Sınıflandırması: Çoklu etiket ve Çoklu sınıf — BERT ile metin sınıflandırması
- Sonraki: LLM'yi Yerel Olarak İnce Ayarlama: Tüketici GPU'sunda LoRA — LLM 7B+ için gelişmiş QLoRA
- Madde 9: Anlamsal Benzerlik ve Metin Eşleştirme — SBERT, FAISS, yoğun erişim
- Madde 10: Üretimde NLP Modellerinin İzlenmesi — sürüklenme tespiti, otomatik yeniden eğitim
- İlgili seri: Yapay Zeka Mühendisliği/RAG — RAG boru hattı için HuggingFace Gömmeleri
- İlgili seri: Gelişmiş Derin Öğrenme — nicemleme ve model optimizasyonu







