Objetivo
Dominar o ecossistema Hugging Face para carregar, usar e adaptar modelos pré-treinados de estado da arte. Aprender a usar pipelines, tokenizers, AutoModel e o Hub para resolver tarefas reais de NLP sem treinar do zero.
1. O Ecossistema Hugging Face
Hugging Face é a plataforma que democratizou o acesso a LLMs. Com poucas linhas de código você acessa modelos que levaram meses e milhões de dólares para treinar.
Componentes principais:
transformers → modelos e tokenizers pré-treinados
datasets → datasets prontos para uso
accelerate → treinamento distribuído
peft → LoRA e outros métodos eficientes
tokenizers → tokenização rápida em Rust
hub → repositório de modelos (huggingface.co/models)
2. Instalação e Configuração
# Verificar instalação
# pip install transformers datasets accelerate
# pip install sentencepiece # para alguns tokenizers
import torch
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings("ignore")
torch.manual_seed(42)
np.random.seed(42)
sns.set_theme(style="whitegrid")
device = torch.device("cuda" if torch.cuda.is_available()
else "cpu")
print(f"Dispositivo: {device}")
# Verificar se transformers está disponível
try:
import transformers
print(f"Transformers versão: {transformers.__version__}")
HF_DISPONIVEL = True
except ImportError:
print("transformers não instalado.")
print("Execute: pip install transformers")
HF_DISPONIVEL = False
3. Pipeline API — A Forma Mais Simples
A Pipeline API encapsula tudo em uma única chamada: tokenização, modelo, pós-processamento.
if HF_DISPONIVEL:
from transformers import pipeline
print("=" * 55)
print("PIPELINE API — Uso mais simples possível")
print("=" * 55)
# ── Análise de Sentimentos ────────────────────────────
print("\n1. Análise de Sentimentos:")
print(" (carregando distilbert-base-uncased-finetuned-sst-2...)")
classificador = pipeline(
"sentiment-analysis",
model="distilbert-base-uncased-finetuned-sst-2-english",
device=0 if torch.cuda.is_available() else -1
)
textos_sentimento = [
"I love this product, it's amazing!",
"This is terrible, worst purchase ever.",
"It's okay, nothing special.",
"Absolutely fantastic experience!",
]
resultados_sent = classificador(textos_sentimento)
print(f"\n {'Texto':<45} {'Label':<12} {'Score'}")
print(f" {'-'*75}")
for texto, res in zip(textos_sentimento, resultados_sent):
print(f" {texto[:45]:<45} "
f"{res['label']:<12} "
f"{res['score']:.4f}")
# ── Geração de Texto ──────────────────────────────────
print("\n2. Geração de Texto com GPT-2:")
print(" (carregando gpt2...)")
gerador = pipeline(
"text-generation",
model="gpt2",
device=0 if torch.cuda.is_available() else -1
)
prompts = [
"The future of artificial intelligence",
"In machine learning, the most important",
]
for prompt in prompts:
resultado = gerador(
prompt,
max_new_tokens=30,
num_return_sequences=1,
temperature=0.8,
do_sample=True,
pad_token_id=50256
)
texto_gerado = resultado[0]["generated_text"]
print(f"\n Prompt: '{prompt}'")
print(f" Gerado: '{texto_gerado}'")
# ── NER (Named Entity Recognition) ───────────────────
print("\n3. NER — Reconhecimento de Entidades:")
print(" (carregando dbmdz/bert-large-cased-finetuned-conll03...)")
ner = pipeline(
"ner",
model="dbmdz/bert-large-cased-finetuned-conll03-english",
aggregation_strategy="simple",
device=0 if torch.cuda.is_available() else -1
)
texto_ner = ("Apple was founded by Steve Jobs "
"in Cupertino, California in 1976.")
entidades = ner(texto_ner)
print(f"\n Texto: '{texto_ner}'")
print(f"\n Entidades encontradas:")
for ent in entidades:
print(f" '{ent['word']}' → "
f"{ent['entity_group']} "
f"(conf: {ent['score']:.3f})")
# ── Question Answering ────────────────────────────────
print("\n4. Question Answering:")
print(" (carregando deepset/roberta-base-squad2...)")
qa = pipeline(
"question-answering",
model="deepset/roberta-base-squad2",
device=0 if torch.cuda.is_available() else -1
)
contexto = ("PyTorch is an open source machine learning "
"framework developed by Meta AI. It provides "
"automatic differentiation and GPU acceleration. "
"PyTorch was first released in 2016.")
perguntas = [
"Who developed PyTorch?",
"When was PyTorch released?",
"What does PyTorch provide?",
]
print(f"\n Contexto: '{contexto[:60]}...'")
for pergunta in perguntas:
resposta = qa(question=pergunta, context=contexto)
print(f"\n Q: {pergunta}")
print(f" A: {resposta['answer']} "
f"(conf: {resposta['score']:.3f})")
# ── Sumarização ───────────────────────────────────────
print("\n5. Sumarização:")
print(" (carregando facebook/bart-large-cnn...)")
sumarizador = pipeline(
"summarization",
model="facebook/bart-large-cnn",
device=0 if torch.cuda.is_available() else -1
)
texto_longo = """
Machine learning is a subset of artificial intelligence that
enables systems to learn from data and improve from experience
without being explicitly programmed. It focuses on developing
computer programs that can access data and use it to learn for
themselves. The process begins with observations or data, such
as examples, direct experience, or instruction, so that computers
can learn to make better decisions in the future. The primary
aim is to allow computers to learn automatically without human
intervention and adjust actions accordingly.
"""
resumo = sumarizador(
texto_longo,
max_length=60,
min_length=20,
do_sample=False
)
print(f"\n Original (truncado): '{texto_longo[:80].strip()}...'")
print(f" Resumo: '{resumo[0]['summary_text']}'")
else:
print("\nSimulando saídas do pipeline (sem transformers):")
print("""
Sentiment: "I love this!" → POSITIVE (0.9998)
Generation: "The future of AI..." → "...will transform every industry"
NER: "Apple" → ORG, "Steve Jobs" → PER, "Cupertino" → LOC
QA: "Who developed PyTorch?" → "Meta AI"
Summary: "Machine learning is..." → "ML enables systems to learn"
""")
4. Tokenizers em Detalhe
if HF_DISPONIVEL:
from transformers import AutoTokenizer
print("=" * 55)
print("TOKENIZERS — Entendendo a Tokenização")
print("=" * 55)
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
# Propriedades do tokenizer
print(f"\nTokenizer BERT:")
print(f" Tamanho do vocabulário: {tokenizer.vocab_size:,}")
print(f" Tokens especiais: {tokenizer.all_special_tokens}")
print(f" [CLS] id: {tokenizer.cls_token_id}")
print(f" [SEP] id: {tokenizer.sep_token_id}")
print(f" [MASK] id: {tokenizer.mask_token_id}")
print(f" [PAD] id: {tokenizer.pad_token_id}")
# Tokenizar texto simples
texto = "The quick brown fox jumps over the lazy dog."
tokens = tokenizer.tokenize(texto)
ids = tokenizer.encode(texto)
print(f"\nTexto: '{texto}'")
print(f"Tokens: {tokens}")
print(f"IDs: {ids}")
# Decodificar de volta
texto_decodificado = tokenizer.decode(ids,
skip_special_tokens=True)
print(f"Decodificado: '{texto_decodificado}'")
# Tokenização em batch com padding
textos = [
"Hello world",
"This is a much longer sentence with more tokens",
"Short",
]
encoded = tokenizer(
textos,
padding=True, # pad para mesmo comprimento
truncation=True, # truncar se muito longo
max_length=20,
return_tensors="pt" # retornar tensors PyTorch
)
print(f"\nBatch tokenizado:")
print(f" input_ids shape: {encoded['input_ids'].shape}")
print(f" attention_mask shape: {encoded['attention_mask'].shape}")
print(f"\n input_ids:")
for i, (texto, ids) in enumerate(zip(textos, encoded['input_ids'])):
print(f" '{texto[:25]}': {ids.tolist()}")
print(f"\n attention_mask (1=real, 0=padding):")
for i, (texto, mask) in enumerate(zip(textos, encoded['attention_mask'])):
print(f" '{texto[:25]}': {mask.tolist()}")
# Tokenizar par de sentenças (BERT)
sentenca_a = "What is the capital of France?"
sentenca_b = "Paris is the capital of France."
encoded_par = tokenizer(
sentenca_a, sentenca_b,
return_token_type_ids=True,
return_tensors="pt"
)
tokens_par = tokenizer.convert_ids_to_tokens(
encoded_par['input_ids'][0]
)
tipos = encoded_par['token_type_ids'][0].tolist()
print(f"\nPar de sentenças (BERT NSP):")
print(f" Token types (0=A, 1=B):")
for tok, tipo in zip(tokens_par, tipos):
print(f" {tok:<20} tipo={tipo}")
# Tokenizadores de subpalavras
print(f"\nTokenização de subpalavras:")
palavras_especiais = [
"tokenization", "unbelievable",
"artificialintelligence", "supercalifragilistic"
]
for palavra in palavras_especiais:
tokens_p = tokenizer.tokenize(palavra)
print(f" '{palavra}' → {tokens_p}")
else:
print("\nSimulando tokenização:")
print("""
Vocabulário BERT: 30.522 tokens
'tokenization' → ['token', '##iza', '##tion']
'unbelievable' → ['un', '##bel', '##iev', '##able']
""")
5. AutoModel — Carregando Modelos para Diferentes Tarefas
if HF_DISPONIVEL:
from transformers import (
AutoTokenizer,
AutoModel,
AutoModelForSequenceClassification,
AutoModelForTokenClassification,
AutoModelForQuestionAnswering,
AutoModelForCausalLM,
AutoModelForSeq2SeqLM,
)
print("=" * 55)
print("AutoModel — Diferentes Cabeças para Cada Tarefa")
print("=" * 55)
print("""
AutoModel → embeddings brutos
AutoModelForSequenceClassification → classificação de texto
AutoModelForTokenClassification → NER, POS tagging
AutoModelForQuestionAnswering → QA extrativa
AutoModelForCausalLM → geração autoregressiva
AutoModelForSeq2SeqLM → tradução, sumarização
""")
# Carregar BERT para extração de embeddings
print("Carregando BERT para extração de embeddings...")
tokenizer_bert = AutoTokenizer.from_pretrained(
"bert-base-uncased"
)
modelo_bert = AutoModel.from_pretrained(
"bert-base-uncased"
).to(device)
modelo_bert.eval()
print(f" Parâmetros: "
f"{sum(p.numel() for p in modelo_bert.parameters()):,}")
# Extrair embeddings
frases = [
"The bank is on the river bank.", # banco ambíguo
"I deposited money at the bank.",
"The cat sat on the mat.",
"The dog sat on the mat.",
]
embeddings = []
with torch.no_grad():
for frase in frases:
inputs = tokenizer_bert(
frase, return_tensors="pt",
truncation=True, max_length=64
).to(device)
outputs = modelo_bert(**inputs)
# CLS embedding: representação da frase inteira
cls_emb = outputs.last_hidden_state[:, 0, :].cpu()
embeddings.append(cls_emb.squeeze().numpy())
embeddings = np.array(embeddings)
# Calcular similaridades
from sklearn.metrics.pairwise import cosine_similarity
sim_matrix = cosine_similarity(embeddings)
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# Heatmap de similaridades
labels_frases = [f[:35] + "..." for f in frases]
sns.heatmap(
sim_matrix,
xticklabels=labels_frases,
yticklabels=labels_frases,
annot=True, fmt=".3f",
cmap="Blues", vmin=0.7, vmax=1.0,
ax=axes[0]
)
axes[0].set_title("Similaridade Cosseno entre Frases\n(BERT embeddings)")
axes[0].tick_params(axis="x", rotation=45)
# PCA dos embeddings
from sklearn.decomposition import PCA
pca = PCA(n_components=2)
coords = pca.fit_transform(embeddings)
cores_emb = ["steelblue", "steelblue",
"coral", "coral"]
for i, (coord, frase, cor) in enumerate(
zip(coords, frases, cores_emb)
):
axes[1].scatter(coord[0], coord[1], c=cor,
s=150, zorder=3)
axes[1].annotate(
f"F{i+1}", coord,
xytext=(5, 5), textcoords="offset points",
fontsize=10
)
axes[1].set_title("PCA dos Embeddings BERT\n"
"Azul=banco, Coral=gato/cachorro")
axes[1].set_xlabel("PC1")
axes[1].set_ylabel("PC2")
plt.tight_layout()
plt.show()
print("\nObservação semântica:")
print(f" sim('banco do rio', 'banco financeiro') = "
f"{sim_matrix[0,1]:.4f}")
print(f" sim('gato no tapete', 'cachorro no tapete') = "
f"{sim_matrix[2,3]:.4f}")
print(f" → Mesmo 'banco' em contextos diferentes tem "
f"embeddings diferentes!")
else:
print("\nSimulando extração de embeddings BERT:")
print("""
BERT: 110M parâmetros
Embedding shape: (1, 768) [CLS token]
sim('banco rio', 'banco financeiro') ≈ 0.821
sim('gato tapete', 'cachorro tapete') ≈ 0.934
""")
6. Fine-tuning com Hugging Face Trainer
if HF_DISPONIVEL:
from transformers import (
AutoTokenizer,
AutoModelForSequenceClassification,
TrainingArguments,
Trainer,
DataCollatorWithPadding,
)
from datasets import Dataset as HFDataset
import evaluate
print("=" * 55)
print("FINE-TUNING COM HUGGING FACE TRAINER")
print("=" * 55)
# Criar dataset sintético de classificação
np.random.seed(42)
n_exemplos = 1000
palavras_pos = ["great", "excellent", "amazing",
"wonderful", "fantastic", "love",
"perfect", "best", "awesome"]
palavras_neg = ["terrible", "awful", "horrible",
"worst", "hate", "disgusting",
"bad", "poor", "useless"]
palavras_neu = ["product", "received", "ordered",
"used", "bought", "tried", "the",
"is", "was", "and", "very", "quite"]
textos_ft, labels_ft = [], []
for _ in range(n_exemplos):
label = np.random.randint(0, 2)
if label == 1:
n_p, n_n = np.random.randint(2, 5), np.random.randint(0, 2)
else:
n_p, n_n = np.random.randint(0, 2), np.random.randint(2, 5)
n_neu = np.random.randint(4, 10)
palavras = (
list(np.random.choice(palavras_pos, n_p)) +
list(np.random.choice(palavras_neg, n_n)) +
list(np.random.choice(palavras_neu, n_neu))
)
np.random.shuffle(palavras)
textos_ft.append(" ".join(palavras))
labels_ft.append(label)
# Converter para Hugging Face Dataset
dados_dict = {"text": textos_ft, "label": labels_ft}
dataset_hf = HFDataset.from_dict(dados_dict)
# Dividir
split = dataset_hf.train_test_split(
test_size=0.2, seed=42
)
ds_treino_hf = split["train"]
ds_teste_hf = split["test"]
print(f"\nDataset:")
print(f" Treino: {len(ds_treino_hf)} exemplos")
print(f" Teste: {len(ds_teste_hf)} exemplos")
# Tokenizer e tokenização
tokenizer_ft = AutoTokenizer.from_pretrained(
"distilbert-base-uncased"
)
def tokenizar_funcao(exemplos):
return tokenizer_ft(
exemplos["text"],
truncation=True,
max_length=64,
padding=False # DataCollator faz padding dinâmico
)
ds_treino_tokenizado = ds_treino_hf.map(
tokenizar_funcao, batched=True
)
ds_teste_tokenizado = ds_teste_hf.map(
tokenizar_funcao, batched=True
)
# Carregar modelo para classificação
print("\nCarregando DistilBERT para classificação...")
modelo_ft = AutoModelForSequenceClassification.from_pretrained(
"distilbert-base-uncased",
num_labels=2,
id2label={0: "NEGATIVE", 1: "POSITIVE"},
label2id={"NEGATIVE": 0, "POSITIVE": 1}
).to(device)
# Data collator
data_collator = DataCollatorWithPadding(
tokenizer=tokenizer_ft
)
# Configurar treinamento
training_args = TrainingArguments(
output_dir="./resultados_ft",
num_train_epochs=3,
per_device_train_batch_size=32,
per_device_eval_batch_size=64,
warmup_steps=100,
weight_decay=0.01,
logging_dir="./logs",
logging_steps=50,
evaluation_strategy="epoch",
save_strategy="epoch",
load_best_model_at_end=True,
metric_for_best_model="accuracy",
report_to="none", # não usar wandb/tensorboard
)
# Função de métricas
metric_acc = evaluate.load("accuracy")
metric_f1 = evaluate.load("f1")
def calcular_metricas(eval_pred):
logits, labels = eval_pred
preds = logits.argmax(axis=-1)
acc = metric_acc.compute(
predictions=preds, references=labels
)
f1 = metric_f1.compute(
predictions=preds, references=labels,
average="weighted"
)
return {"accuracy": acc["accuracy"],
"f1": f1["f1"]}
# Treinar com Trainer
trainer = Trainer(
model=modelo_ft,
args=training_args,
train_dataset=ds_treino_tokenizado,
eval_dataset=ds_teste_tokenizado,
tokenizer=tokenizer_ft,
data_collator=data_collator,
compute_metrics=calcular_metricas,
)
print("\nIniciando fine-tuning com Hugging Face Trainer...")
trainer.train()
# Avaliar
resultados_eval = trainer.evaluate()
print(f"\nResultados no teste:")
print(f" Acurácia: {resultados_eval['eval_accuracy']:.4f}")
print(f" F1: {resultados_eval['eval_f1']:.4f}")
print(f" Loss: {resultados_eval['eval_loss']:.4f}")
# Salvar modelo
trainer.save_model("./modelo_sentimento_ft")
tokenizer_ft.save_pretrained("./modelo_sentimento_ft")
print("\nModelo salvo em './modelo_sentimento_ft'")
else:
print("\nSimulando fine-tuning com Trainer:")
print("""
Dataset: 800 treino, 200 teste
Épocas: 3
Resultado esperado:
Acurácia: ~0.94
F1: ~0.94
Loss: ~0.18
""")
7. Sentence Transformers — Embeddings de Alta Qualidade
if HF_DISPONIVEL:
from transformers import AutoTokenizer, AutoModel
print("=" * 55)
print("SENTENCE TRANSFORMERS — Embeddings de Sentenças")
print("=" * 55)
def mean_pooling(output, attention_mask):
"""
Mean pooling sobre os tokens com máscara de atenção.
Mais eficaz que apenas usar o [CLS] token.
"""
token_embs = output.last_hidden_state
mask_exp = attention_mask.unsqueeze(-1).expand(
token_embs.size()
).float()
soma = (token_embs * mask_exp).sum(1)
n_tokens = mask_exp.sum(1).clamp(min=1e-9)
return soma / n_tokens
def obter_embeddings(textos: list,
modelo, tokenizer,
device: torch.device,
batch_size: int = 16) -> np.ndarray:
"""Obtém embeddings para lista de textos."""
todos_embs = []
for i in range(0, len(textos), batch_size):
batch_textos = textos[i:i+batch_size]
encoded = tokenizer(
batch_textos,
padding=True, truncation=True,
max_length=128,
return_tensors="pt"
).to(device)
with torch.no_grad():
output = modelo(**encoded)
embs = mean_pooling(
output, encoded["attention_mask"]
)
# Normalizar L2
embs = torch.nn.functional.normalize(embs, p=2,
dim=1)
todos_embs.append(embs.cpu().numpy())
return np.vstack(todos_embs)
# Carregar modelo de sentence embeddings
print("\nCarregando modelo de sentence embeddings...")
tokenizer_se = AutoTokenizer.from_pretrained(
"sentence-transformers/paraphrase-MiniLM-L6-v2"
)
modelo_se = AutoModel.from_pretrained(
"sentence-transformers/paraphrase-MiniLM-L6-v2"
).to(device)
modelo_se.eval()
# Exemplos de use cases
print("\n1. Busca Semântica (Semantic Search):")
corpus_busca = [
"How to cook pasta?",
"Best restaurants in New York",
"Python programming tutorial",
"Machine learning algorithms explained",
"How to prepare spaghetti bolognese",
"Introduction to deep learning",
"Top 10 NYC dining spots",
"Neural network architecture",
]
queries = [
"cooking pasta recipe",
"deep learning tutorial",
"restaurants to eat in Manhattan",
]
embs_corpus = obter_embeddings(
corpus_busca, modelo_se, tokenizer_se, device
)
embs_query = obter_embeddings(
queries, modelo_se, tokenizer_se, device
)
sim_busca = cosine_similarity(embs_query, embs_corpus)
for query, sims in zip(queries, sim_busca):
top_k_idx = sims.argsort()[::-1][:3]
print(f"\n Query: '{query}'")
print(f" Top 3 resultados:")
for idx in top_k_idx:
print(f" [{sims[idx]:.3f}] '{corpus_busca[idx]}'")
print("\n2. Detecção de Paráfrase:")
pares_parafrase = [
("The weather is nice today.",
"It's a beautiful day outside."),
("I love machine learning.",
"I hate cooking food."),
("Python is a programming language.",
"Python is used for coding."),
]
for t1, t2 in pares_parafrase:
e1 = obter_embeddings([t1], modelo_se,
tokenizer_se, device)
e2 = obter_embeddings([t2], modelo_se,
tokenizer_se, device)
sim = cosine_similarity(e1, e2)[0][0]
eh_parafrase = "✓ Paráfrase" if sim > 0.75 else "✗ Diferente"
print(f"\n T1: '{t1[:40]}'")
print(f" T2: '{t2[:40]}'")
print(f" Sim: {sim:.4f} → {eh_parafrase}")
else:
print("\nSimulando Sentence Transformers:")
print("""
Busca Semântica:
Query: 'cooking pasta recipe'
Top: 'How to cook pasta?' (0.89), 'How to prepare spaghetti' (0.84)
Paráfrase:
'The weather is nice' / 'It's a beautiful day' → sim=0.84 ✓
'I love ML' / 'I hate cooking' → sim=0.12 ✗
""")
8. Geração Avançada com GPT-2
if HF_DISPONIVEL:
from transformers import (
GPT2LMHeadModel,
GPT2Tokenizer,
set_seed,
)
print("=" * 55)
print("GERAÇÃO AVANÇADA COM GPT-2")
print("=" * 55)
print("\nCarregando GPT-2...")
tokenizer_gpt2 = GPT2Tokenizer.from_pretrained("gpt2")
modelo_gpt2 = GPT2LMHeadModel.from_pretrained(
"gpt2"
).to(device)
modelo_gpt2.eval()
# Adicionar pad token
tokenizer_gpt2.pad_token = tokenizer_gpt2.eos_token
n_params_gpt2 = sum(
p.numel() for p in modelo_gpt2.parameters()
)
print(f"GPT-2 small: {n_params_gpt2/1e6:.0f}M parâmetros")
prompt = "Artificial intelligence will"
# Diferentes estratégias de decodificação
print(f"\nPrompt: '{prompt}'")
print("\nEstratégias de decodificação:")
print("-" * 55)
input_ids = tokenizer_gpt2.encode(
prompt, return_tensors="pt"
).to(device)
estrategias = {
"Greedy (determinístico)": dict(
max_new_tokens=30,
do_sample=False
),
"Beam Search (k=5)": dict(
max_new_tokens=30,
num_beams=5,
no_repeat_ngram_size=2,
do_sample=False
),
"Sampling (temp=0.7)": dict(
max_new_tokens=30,
do_sample=True,
temperature=0.7,
top_k=50
),
"Top-p / Nucleus (p=0.9)": dict(
max_new_tokens=30,
do_sample=True,
top_p=0.9,
top_k=0
),
"Top-k + Top-p (k=50, p=0.9)": dict(
max_new_tokens=30,
do_sample=True,
top_k=50,
top_p=0.9,
temperature=0.8
),
}
set_seed(42)
for nome, params in estrategias.items():
output = modelo_gpt2.generate(
input_ids,
pad_token_id=tokenizer_gpt2.eos_token_id,
**params
)
texto = tokenizer_gpt2.decode(
output[0], skip_special_tokens=True
)
# Mostrar apenas a parte gerada
gerado = texto[len(prompt):]
print(f"\n {nome}:")
print(f" {prompt}[{gerado.strip()}]")
# Gerar múltiplas sequências
print("\nGeração múltipla (5 sequências diferentes):")
outputs = modelo_gpt2.generate(
input_ids,
max_new_tokens=20,
do_sample=True,
temperature=1.0,
top_k=50,
num_return_sequences=5,
pad_token_id=tokenizer_gpt2.eos_token_id
)
for i, out in enumerate(outputs):
texto = tokenizer_gpt2.decode(out, skip_special_tokens=True)
gerado = texto[len(prompt):]
print(f" {i+1}: {prompt}[{gerado.strip()[:50]}]")
else:
print("\nSimulando GPT-2:")
print("""
Prompt: 'Artificial intelligence will'
Greedy: '...change the way we work and live forever'
Beam Search: '...transform every aspect of human society'
Sampling: '...reshape industries and create new opportunities'
Top-p: '...become increasingly important in our lives'
""")
9. Hub do Hugging Face
print("\n" + "=" * 55)
print("HUB DO HUGGING FACE — Navegando Modelos")
print("=" * 55)
print("""
O Hub (huggingface.co/models) tem +500.000 modelos.
Como encontrar o modelo certo:
Por tarefa:
text-classification → BERT, RoBERTa, DistilBERT
text-generation → GPT-2, GPT-J, LLaMA, Mistral
translation → Helsinki-NLP/opus-mt-*
summarization → facebook/bart-large-cnn
question-answering → deepset/roberta-base-squad2
sentence-similarity → sentence-transformers/*
zero-shot-classification → facebook/bart-large-mnli
fill-mask → bert-base-uncased
token-classification → dslim/bert-base-NER
Por idioma:
Inglês: bert-base-uncased, roberta-base
Português: neuralmind/bert-base-portuguese-cased
unicamp-dl/ptt5-base-portuguese-vocab
Multilingual: bert-base-multilingual-cased (104 idiomas)
xlm-roberta-base
Por tamanho (parâmetros):
Tiny: distilbert (~66M) — rápido, menos preciso
Base: bert-base (~110M) — equilíbrio
Large: bert-large (~340M) — mais preciso, mais lento
XL/XXL: GPT-2-XL (1.5B), GPT-J (6B), LLaMA (7B-70B)
Por eficiência:
distilbert-base → 40% menor que BERT, 97% performance
albert-base-v2 → parâmetros compartilhados, muito eficiente
mobile-bert → otimizado para mobile/edge
Modelos em português notáveis:
neuralmind/bert-base-portuguese-cased
→ BERT treinado em Wikipedia PT + BrWaC
→ Bom para: NER, classificação, QA
unicamp-dl/ptt5-base-portuguese-vocab
→ T5 adaptado para PT-BR
→ Bom para: geração, sumarização, tradução
pierreguillou/bert-base-cased-squad-v1.1-portuguese
→ Fine-tuned em QA em PT
""")
if HF_DISPONIVEL:
# Zero-shot classification (sem fine-tuning para novas classes!)
from transformers import pipeline as hf_pipeline
print("Zero-Shot Classification:")
print(" (classifica em categorias nunca vistas no treino)")
zero_shot = hf_pipeline(
"zero-shot-classification",
model="facebook/bart-large-mnli",
device=0 if torch.cuda.is_available() else -1
)
textos_zs = [
"The stock market crashed today.",
"Scientists discover new treatment for cancer.",
"The football team won the championship.",
]
categorias = ["finance", "health", "sports", "technology"]
for texto in textos_zs:
resultado = zero_shot(texto, categorias)
top_label = resultado["labels"][0]
top_score = resultado["scores"][0]
print(f"\n Texto: '{texto[:45]}...'")
print(f" Classe: {top_label} (conf: {top_score:.3f})")
else:
print("""
Zero-Shot (sem fine-tuning):
'Stock market crashed' → finance (0.93)
'New cancer treatment' → health (0.91)
'Football championship' → sports (0.97)
""")
10. Exemplo Completo: Sistema de NLP em Produção
print("\n" + "=" * 60)
print("SISTEMA NLP COMPLETO EM PRODUÇÃO")
print("=" * 60)
if HF_DISPONIVEL:
from transformers import pipeline as hf_pipeline
class SistemaNLPProducao:
"""
Sistema NLP completo usando múltiplos modelos HF.
Simula um sistema de análise de feedback de clientes.
"""
def __init__(self):
print("Inicializando sistema NLP...")
self.sentiment = hf_pipeline(
"sentiment-analysis",
model="distilbert-base-uncased-finetuned-sst-2-english",
device=0 if torch.cuda.is_available() else -1
)
self.ner = hf_pipeline(
"ner",
model="dbmdz/bert-large-cased-finetuned-conll03-english",
aggregation_strategy="simple",
device=0 if torch.cuda.is_available() else -1
)
self.zero_shot = hf_pipeline(
"zero-shot-classification",
model="facebook/bart-large-mnli",
device=0 if torch.cuda.is_available() else -1
)
print("Sistema pronto!")
def analisar_feedback(self, feedback: str) -> dict:
"""Análise completa de um feedback de cliente."""
# 1. Sentimento
sent = self.sentiment(feedback)[0]
# 2. Entidades
entidades = self.ner(feedback)
# 3. Categorização
categorias = ["product quality", "customer service",
"shipping", "pricing", "user experience"]
cat_result = self.zero_shot(feedback, categorias)
return {
"sentimento": sent["label"],
"confianca_sent": round(sent["score"], 3),
"entidades": [(e["word"], e["entity_group"])
for e in entidades],
"categoria": cat_result["labels"][0],
"conf_cat": round(cat_result["scores"][0], 3),
}
def processar_lote(self, feedbacks: list) -> list:
"""Processa múltiplos feedbacks."""
return [self.analisar_feedback(f) for f in feedbacks]
# Demonstrar o sistema
sistema = SistemaNLPProducao()
feedbacks_demo = [
"The product from Apple broke after 2 days. Terrible quality!",
"Amazing customer service from John! Very helpful and fast shipping.",
"Price is too high for what you get. Not worth it.",
]
print("\nAnálise de Feedbacks:")
print("=" * 60)
for feedback in feedbacks_demo:
resultado = sistema.analisar_feedback(feedback)
print(f"\n📝 Feedback: '{feedback[:55]}...'")
print(f" Sentimento: {resultado['sentimento']} "
f"({resultado['confianca_sent']:.3f})")
print(f" Categoria: {resultado['categoria']} "
f"({resultado['conf_cat']:.3f})")
if resultado['entidades']:
print(f" Entidades: {resultado['entidades']}")
else:
print("""
Sistema NLP simulado:
Feedback: 'Product from Apple broke...'
→ Sentimento: NEGATIVE (0.998)
→ Categoria: product quality (0.892)
→ Entidades: [('Apple', 'ORG')]
Feedback: 'Amazing customer service from John!'
→ Sentimento: POSITIVE (0.997)
→ Categoria: customer service (0.934)
→ Entidades: [('John', 'PER')]
Feedback: 'Price is too high...'
→ Sentimento: NEGATIVE (0.976)
→ Categoria: pricing (0.871)
→ Entidades: []
""")
# Resumo das melhores práticas
print("\n" + "=" * 60)
print("BOAS PRÁTICAS COM HUGGING FACE")
print("=" * 60)
print("""
1. ESCOLHA DO MODELO:
Comece com o menor modelo que atenda seus requisitos
DistilBERT > BERT quando performance ≈ mas latência importa
2. TOKENIZAÇÃO:
Sempre use o tokenizer do modelo (nunca tokenize manualmente)
Use truncation=True e max_length para evitar erros de memória
Use padding dinâmico com DataCollatorWithPadding
3. FINE-TUNING:
Use LoRA/PEFT para modelos grandes
Warm-up nas primeiras 6-10% das steps
Learning rate baixo: 2e-5 a 5e-5 para classificação
4. INFERÊNCIA:
model.eval() + torch.no_grad() sempre
Batch processing para throughput
.half() ou quantização para reduzir memória
5. PRODUÇÃO:
Salvar model + tokenizer juntos
Usar AutoModel para compatibilidade futura
Versionar com model card no Hub
6. CACHE:
Modelos são cacheados em ~/.cache/huggingface/
Use TRANSFORMERS_CACHE para mudar o diretório
Em produção, carregue o modelo uma vez e reutilize
""")
Resumo da Aula
- O ecossistema Hugging Face democratiza o acesso a LLMs com APIs simples e padronizadas
- A Pipeline API encapsula tokenização + modelo + pós-processamento em uma única chamada
- AutoTokenizer e AutoModel carregam automaticamente o tokenizer e modelo certos para cada checkpoint
- Tokenizers BPE dividem palavras em sub-tokens — nunca tokenize manualmente, sempre use o tokenizer do modelo
AutoModelForSequenceClassification,ForTokenClassification,ForCausalLMetc. adicionam a cabeça certa para cada tarefa- O Trainer do HF encapsula o loop de treinamento com métricas, checkpointing e early stopping
- Mean pooling sobre todos os tokens geralmente produz embeddings de sentença melhores que apenas o [CLS]
- Estratégias de decodificação: greedy (determinístico), beam search (qualidade), sampling (diversidade), top-k/top-p (equilíbrio)
- Zero-shot classification classifica em categorias novas sem fine-tuning usando MNLI
- Em produção: salvar modelo + tokenizer juntos, usar batch inference e quantização para eficiência
Exercícios
-
Explique a diferença entre
pipeline("sentiment-analysis")e usarAutoModelForSequenceClassificationdiretamente. Em qual situação você usaria cada abordagem?✓ Resposta:pipeline("sentiment-analysis")é uma abstração de alto nível que encapsula tokenização, inferência e pós-processamento em uma única chamada. É ideal para prototipagem rápida, uso simples e casos onde você não precisa de controle fino sobre o processo. Retorna resultados formatados diretamente.AutoModelForSequenceClassificationusado diretamente dá controle total sobre cada etapa: tokenização personalizada, acesso aos logits brutos antes do softmax, controle sobre batch size, integração em loops de treino customizados, e acesso às representações internas. É necessário quando você precisa de fine-tuning, quando quer integrar o modelo em uma pipeline mais complexa, quando precisa de performance máxima otimizando a tokenização, ou quando precisa de recursos não disponíveis no pipeline (como acessar embeddings de camadas intermediárias).Use pipeline para demonstrações, prototipagem e casos de uso simples. Use AutoModel direto para produção, fine-tuning e sistemas complexos.
-
Por que você deve sempre usar o tokenizer fornecido pelo modelo e nunca criar o seu próprio? O que aconteceria se você usasse o tokenizer do BERT para um modelo GPT-2?
✓ Resposta:Cada modelo usa um tokenizer específico que define o vocabulário, o esquema de tokenização (WordPiece para BERT, BPE para GPT) e os tokens especiais. Os pesos do modelo foram treinados com exatamente esses tokens — o embedding de índice 1024 representa uma sub-palavra específica, e o modelo aprendeu representações baseadas nessa correspondência.
Se você usasse o tokenizer do BERT para um modelo GPT-2: o vocabulário é completamente diferente (30.522 tokens no BERT vs 50.257 no GPT-2). A mesma palavra seria tokenizada em sub-tokens diferentes com IDs diferentes. O modelo GPT-2 receberia IDs que correspondem a sub-palavras completamente diferentes das que ele aprendeu a processar. O resultado seria lixo semântico — como dar a um culinário instruções em japonês quando ele só lê português.
-
Explique as quatro estratégias de decodificação: greedy, beam search, top-k sampling e top-p (nucleus) sampling. Quais são os trade-offs de cada uma em termos de qualidade e diversidade?
✓ Resposta:Greedy decoding: sempre escolhe o token com maior probabilidade. Determinístico, rápido, sem parâmetros. Desvantagem: frequentemente cai em loops e textos repetitivos porque escolhas localmente ótimas não são globalmente ótimas.
Beam search: mantém k hipóteses em paralelo ("beams"), escolhendo a sequência com maior probabilidade acumulada. Produz textos mais coerentes e gramaticalmente corretos. Desvantagem: textos previsíveis e pouco criativos, computacionalmente mais caro (k vezes mais).
Top-k sampling: sorteia o próximo token apenas entre os k mais prováveis. Mais diverso que greedy, evita tokens muito improváveis. Desvantagem: k fixo não é ideal — quando a distribuição é concentrada, k=50 ainda inclui tokens ruins; quando é flat, k=50 exclui tokens válidos.
Top-p (nucleus) sampling: inclui apenas tokens que cobrem uma massa de probabilidade cumulativa p. Adapta-se dinamicamente à incerteza do modelo. Com p=0.9, o número de tokens considerados varia: 2 tokens quando o modelo está confiante, 200 quando incerto. É o mais sofisticado e geralmente o melhor trade-off entre qualidade e diversidade.
-
O que é zero-shot classification e como o modelo BART-MNLI consegue classificar textos em categorias que nunca viu durante o treinamento? Qual é a limitação desta abordagem?
✓ Resposta:BART-MNLI foi treinado no dataset MNLI (Multi-Genre Natural Language Inference) para reconhecer relações entre pares de texto: entailment (hipótese é implicada pela premissa), contradiction (hipótese contradiz premissa) e neutral.
Para classificação zero-shot, reusa este conhecimento: dado um texto e uma categoria, formula a questão como NLI: "Este texto trata de {categoria}?" O score de entailment indica quão bem o texto se encaixa na categoria. Quando você passa categorias novas, o modelo usa seu conhecimento geral de linguagem para inferir se o texto implica cada categoria.
Limitação principal: o MNLI foi treinado em inglês — funciona mal para outros idiomas. O desempenho depende de quão bem a categoria pode ser descrita em uma hipótese de NLI — categorias abstratas como "humor" ou "ironia" são difíceis. Para categorias muito específicas do domínio (terminologia médica, legal, técnica), o modelo pode não ter visto exemplos suficientes e terá performance inferior ao fine-tuning. É significativamente mais lento que um modelo fine-tuned equivalente.
-
Compare mean pooling com a representação [CLS] para obter embeddings de sentenças. Por que mean pooling geralmente funciona melhor para modelos BERT padrão (não fine-tuned para sentence similarity)?
✓ Resposta:O [CLS] token foi treinado para capturar a representação global da sequência, mas apenas para a tarefa específica de NSP (Next Sentence Prediction) no BERT padrão. Para similaridade de sentenças, a representação [CLS] não foi otimizada e frequentemente captura características de NSP ao invés de similaridade semântica geral.
Mean pooling calcula a média de todos os tokens da sequência (excluindo padding), aproveitando a informação contextual de cada posição. Cada token contribui igualmente para a representação final, capturando aspectos diferentes da semântica da frase. Isso produz embeddings mais ricos e estáveis para comparação de sentenças.
No entanto, para modelos fine-tuned explicitamente para sentence similarity (como os da família sentence-transformers), o [CLS] pode ser igualmente bom ou melhor, pois foi treinado especificamente para capturar similaridade no [CLS]. A diferença é significativa apenas para modelos BERT "base" sem fine-tuning em similaridade de sentenças.
-
Você precisa construir um sistema de análise de sentimentos em português para comentários de produtos de e-commerce. Descreva passo a passo como você usaria o Hugging Face para isso, incluindo escolha do modelo, pré-processamento, fine-tuning e deploy.
✓ Resposta:Passo 1 — Escolha do modelo base:
neuralmind/bert-base-portuguese-casedpara português. É BERT treinado em português, o melhor ponto de partida para textos de e-commerce brasileiro.Passo 2 — Coleta e preparação dos dados: coletar comentários de produtos já rotulados (positivo/negativo/neutro). Verificar balanceamento de classes. Definir guidelines de anotação (como tratar comentários mistos).
Passo 3 — Tokenização:
tokenizer = AutoTokenizer.from_pretrained( "neuralmind/bert-base-portuguese-cased" ) encoded = tokenizer(textos, truncation=True, max_length=128, padding=True, return_tensors="pt")Passo 4 — Fine-tuning:
modelo = AutoModelForSequenceClassification.from_pretrained( "neuralmind/bert-base-portuguese-cased", num_labels=3 ) trainer = Trainer(modelo, TrainingArguments( num_train_epochs=3, learning_rate=2e-5, per_device_train_batch_size=32, warmup_ratio=0.1 ), train_dataset, eval_dataset, compute_metrics=...) trainer.train()Passo 5 — Avaliação: acurácia, F1 macro (classes desbalanceadas), análise de erros por categoria de produto.
Passo 6 — Deploy: salvar modelo e tokenizer, criar endpoint FastAPI ou Gradio, usar
model.half()ou quantização para reduzir latência, implementar batching para throughput, monitorar drift ao longo do tempo.