Exercícios Práticos - Treinamento de Foundation Models
NotaSobre estes exercícios
Estes exercícios complementam o Capítulo 2: Treinamento de Foundation Models.
Recomenda-se completar a leitura do capítulo antes de iniciar os exercícios práticos.
Agora que você compreende como foundation models são treinados, tokenização e dados de pré-treinamento, vamos aplicar esse conhecimento na prática.
Exercício 1: Análise de Eficiência de Tokenização
Objetivo: Entender o impacto da tokenização em diferentes idiomas e calcular custos de API.
Passo a Passo:
# Instalação necessária: pip install tiktoken transformers
import tiktoken
# Carregar tokenizer GPT-4
try:
enc = tiktoken.encoding_for_model("gpt-4")
except KeyError:
enc = tiktoken.get_encoding("cl100k_base")
def analyze_tokenization(text, language):
"""Analisa eficiência de tokenização para um texto"""
tokens = enc.encode(text)
token_count = len(tokens)
print(f"\n{'='*60}")
print(f"Idioma: {language}")
print(f"{'='*60}")
print(f"Texto original: {text}")
print(f"Número de tokens: {token_count}")
print(f"Caracteres: {len(text)}")
print(f"Razão caracteres/token: {len(text)/token_count:.2f}")
# Visualizar tokens
print("\nTokens decodificados:")
for i, token in enumerate(tokens[:10]): # Mostrar apenas primeiros 10
decoded = enc.decode([token])
print(f" Token {i}: '{decoded}' (ID: {token})")
if len(tokens) > 10:
print(f" ... e mais {len(tokens) - 10} tokens")
return token_count
# Teste 1: Comparar eficiência entre idiomas
print("\n🔍 TESTE 1: Eficiência Multilíngue\n")
texts = {
"Inglês": "The quick brown fox jumps over the lazy dog. Machine learning models require large datasets.",
"Português": "A rápida raposa marrom pula sobre o cachorro preguiçoso. Modelos de aprendizado de máquina requerem grandes conjuntos de dados.",
"Japonês": "素早い茶色の狐が怠け者の犬を飛び越える。機械学習モデルは大規模なデータセットを必要とする。",
"Espanhol": "El rápido zorro marrón salta sobre el perro perezoso. Los modelos de aprendizaje automático requieren grandes conjuntos de datos."
}
results = {}
for lang, text in texts.items():
results[lang] = analyze_tokenization(text, lang)
# Comparação
print(f"\n{'='*60}")
print("📊 COMPARAÇÃO DE EFICIÊNCIA")
print(f"{'='*60}")
baseline = results["Inglês"]
for lang, count in results.items():
efficiency = (count / baseline) * 100
print(f"{lang:12} {count:4} tokens ({efficiency:6.1f}% vs Inglês)")
# Teste 2: Estimar custos de API
print("\n\n💰 TESTE 2: Estimativa de Custos de API\n")
# Preços típicos (valores aproximados em USD por 1K tokens)
pricing = {
"GPT-4 Turbo": {"input": 0.01, "output": 0.03},
"GPT-3.5 Turbo": {"input": 0.0005, "output": 0.0015},
"Claude 3 Opus": {"input": 0.015, "output": 0.075},
"Claude 3 Haiku": {"input": 0.00025, "output": 0.00125}
}
# Simular prompt típico
prompt = texts["Português"]
expected_output_tokens = 200 # Resposta esperada
input_tokens = results["Português"]
print(f"Prompt: '{prompt[:50]}...'")
print(f"Tokens de input: {input_tokens}")
print(f"Tokens de output estimados: {expected_output_tokens}")
print(f"\nCustos estimados por requisição:\n")
for model, prices in pricing.items():
input_cost = (input_tokens / 1000) * prices["input"]
output_cost = (expected_output_tokens / 1000) * prices["output"]
total_cost = input_cost + output_cost
print(f"{model:20} ${total_cost:.6f} (input: ${input_cost:.6f} + output: ${output_cost:.6f})")
# Teste 3: Otimização de Prompt
print("\n\n✂️ TESTE 3: Otimização de Prompt para Reduzir Tokens\n")
verbose_prompt = """
Por favor, você poderia me ajudar a analisar o seguinte texto e me fornecer uma análise
completa e detalhada sobre o sentimento expresso no texto, incluindo se é positivo,
negativo ou neutro? Aqui está o texto que eu gostaria que você analisasse:
"Este produto é excelente! Recomendo fortemente."
Muito obrigado pela sua ajuda!
"""
optimized_prompt = """
Classifique o sentimento (positivo/negativo/neutro):
"Este produto é excelente! Recomendo fortemente."
"""
verbose_tokens = len(enc.encode(verbose_prompt))
optimized_tokens = len(enc.encode(optimized_prompt))
reduction = ((verbose_tokens - optimized_tokens) / verbose_tokens) * 100
print(f"Prompt verboso: {verbose_tokens} tokens")
print(f"Prompt otimizado: {optimized_tokens} tokens")
print(f"Redução: {reduction:.1f}%")
print(f"\nEconomia em 1000 requisições (GPT-4):")
saved_tokens = (verbose_tokens - optimized_tokens) * 1000
saved_cost = (saved_tokens / 1000) * pricing["GPT-4 Turbo"]["input"]
print(f" Tokens economizados: {saved_tokens:,}")
print(f" Custo economizado: ${saved_cost:.2f}")Desafios adicionais:
- Compare tokenizers diferentes: Use
AutoTokenizer.from_pretrained()para comparar GPT-4, LLaMA e Mistral - Analise código: Tokenize código Python/JavaScript e veja como diferentes tokenizers lidam com sintaxe
- Crie um otimizador de prompts: Função que sugere versões mais curtas mantendo o significado
Exercício 2: Explorando Dados de Pré-Treinamento
Objetivo: Entender a composição e qualidade de datasets usados para treinar foundation models.
Passo a Passo:
# Instalação: pip install datasets
from datasets import load_dataset
from collections import Counter
import re
# Carregar uma amostra do dataset C4 (usado para treinar T5, LLaMA)
print("📦 Carregando amostra do dataset C4 (Common Crawl)...\n")
# Carregar apenas uma pequena amostra para análise
dataset = load_dataset("c4", "en", split="train", streaming=True)
# Analisar primeiros 100 exemplos
sample_size = 100
texts = []
domains = []
print(f"Analisando {sample_size} documentos...\n")
for i, example in enumerate(dataset):
if i >= sample_size:
break
text = example['text']
url = example.get('url', '')
texts.append(text)
# Extrair domínio do URL
domain_match = re.search(r'https?://(?:www\.)?([^/]+)', url)
if domain_match:
domains.append(domain_match.group(1))
# Análise 1: Estatísticas de comprimento
print("="*60)
print("📊 ESTATÍSTICAS DE COMPRIMENTO")
print("="*60)
lengths = [len(text.split()) for text in texts]
avg_length = sum(lengths) / len(lengths)
min_length = min(lengths)
max_length = max(lengths)
print(f"Comprimento médio: {avg_length:.0f} palavras")
print(f"Comprimento mínimo: {min_length} palavras")
print(f"Comprimento máximo: {max_length} palavras")
# Análise 2: Distribuição de domínios
print(f"\n{'='*60}")
print("🌐 DISTRIBUIÇÃO DE DOMÍNIOS (Top 10)")
print(f"{'='*60}\n")
domain_counts = Counter(domains)
for domain, count in domain_counts.most_common(10):
percentage = (count / len(domains)) * 100
print(f"{domain:40} {count:3} ({percentage:5.1f}%)")
# Análise 3: Tipos de conteúdo (heurística simples)
print(f"\n{'='*60}")
print("📝 TIPOS DE CONTEÚDO (baseado em heurísticas)")
print(f"{'='*60}\n")
content_types = {
"Código": 0,
"Conversação/Forum": 0,
"Notícia/Artigo": 0,
"Técnico/Documentação": 0,
"Outros": 0
}
for text in texts:
# Heurísticas simples para classificar tipo de conteúdo
if any(keyword in text.lower() for keyword in ['def ', 'class ', 'function', 'import ', 'return']):
content_types["Código"] += 1
elif any(keyword in text.lower() for keyword in ['posted by', 'reply', 'comment', 'said:']):
content_types["Conversação/Forum"] += 1
elif any(keyword in text.lower() for keyword in ['according to', 'reported', 'published']):
content_types["Notícia/Artigo"] += 1
elif any(keyword in text.lower() for keyword in ['tutorial', 'documentation', 'api', 'parameter']):
content_types["Técnico/Documentação"] += 1
else:
content_types["Outros"] += 1
for content_type, count in content_types.items():
percentage = (count / len(texts)) * 100
print(f"{content_type:25} {count:3} ({percentage:5.1f}%)")
# Análise 4: Qualidade dos dados (heurísticas)
print(f"\n{'='*60}")
print("✅ QUALIDADE DOS DADOS")
print(f"{'='*60}\n")
quality_issues = {
"Muito curtos (< 50 palavras)": 0,
"Muita repetição": 0,
"Excesso de URLs": 0,
"Caracteres não-ASCII": 0
}
for text in texts:
words = text.split()
if len(words) < 50:
quality_issues["Muito curtos (< 50 palavras)"] += 1
# Detectar repetição (palavras duplicadas consecutivas)
if len(words) > 10:
repetitions = sum(1 for i in range(len(words)-1) if words[i] == words[i+1])
if repetitions > len(words) * 0.1: # Mais de 10% de repetição
quality_issues["Muita repetição"] += 1
# URLs
url_count = len(re.findall(r'http[s]?://', text))
if url_count > 5:
quality_issues["Excesso de URLs"] += 1
# Caracteres não-ASCII (pode indicar encoding issues)
non_ascii = sum(1 for c in text if ord(c) > 127)
if non_ascii > len(text) * 0.05: # Mais de 5%
quality_issues["Caracteres não-ASCII"] += 1
for issue, count in quality_issues.items():
percentage = (count / len(texts)) * 100
print(f"{issue:35} {count:3} ({percentage:5.1f}%)")
print(f"\n{'='*60}")
print("💡 INSIGHTS")
print(f"{'='*60}")
print("""
1. Datasets de pré-treinamento contêm conteúdo extremamente diverso
2. Qualidade varia significativamente entre documentos
3. Data cleaning é crucial para remover conteúdo problemático
4. Balanceamento de domínios afeta conhecimento do modelo
5. Comprimento dos documentos influencia context window necessário
""")Desafios adicionais:
- Compare datasets: Analise C4, Wikipedia, OpenWebText
- Data cleaning pipeline: Implemente filtros para remover conteúdo de baixa qualidade
- Análise de viés: Detecte viés de domínio/tópico no dataset
Exercício 3: Experimente com Tokenizers Diferentes
Objetivo: Comparar comportamento de diferentes estratégias de tokenização.
from transformers import AutoTokenizer
# Carregar diferentes tokenizers
tokenizers = {
"GPT-2": AutoTokenizer.from_pretrained("gpt2"),
"LLaMA 2": AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf"),
"Code Llama": AutoTokenizer.from_pretrained("codellama/CodeLlama-7b-hf"),
"Mistral": AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1")
}
# Teste 1: Texto natural
print("="*60)
print("TESTE 1: Texto Natural")
print("="*60)
text_natural = "The transformer architecture revolutionized natural language processing."
for name, tokenizer in tokenizers.items():
tokens = tokenizer.encode(text_natural)
print(f"\n{name}:")
print(f" Tokens: {len(tokens)}")
print(f" Decodificação: {tokenizer.convert_ids_to_tokens(tokens)[:10]}")
# Teste 2: Código
print(f"\n{'='*60}")
print("TESTE 2: Código Python")
print("="*60)
code = """
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
"""
for name, tokenizer in tokenizers.items():
tokens = tokenizer.encode(code)
print(f"\n{name}:")
print(f" Tokens: {len(tokens)}")
decoded_tokens = tokenizer.convert_ids_to_tokens(tokens)
print(f" Primeiros tokens: {decoded_tokens[:15]}")
print("\n💡 Observe que Code Llama tokeniza código mais eficientemente!")Questões para reflexão:
- Qual tokenizer é mais eficiente para texto em português?
- Como tokenizers otimizados para código diferem dos genéricos?
- Qual impacto isso tem em aplicações de agentes que processam código?