SLM-100M Português (LLaMA-style)
Small Language Model de ~100M parâmetros pré-treinado em ~2B tokens de
português do FineWeb2 (subset PT). Projeto da disciplina Aprendizado
Profundo II (PUCRS — Escola Politécnica).
Diferente do
modelo anterior em inglês,
este foi projetado especificamente para português: tokenizer BPE byte-level
treinado em corpus PT, arquitetura ampliada (12 camadas, n_embd=768) e regularização
adicional (z-loss).
Resultados
| Métrica | Valor |
|---|
| Val loss | 3.183 |
| Val perplexity | 24.12 |
| Best val_loss (durante treino) | 3.112 (ppl 22.48) |
| Train loss final | 3.143 |
| Tokens vistos | ~1.97B |
| Tempo de treino | ~10.5h em RTX 5060 Ti |
| Throughput médio | ~58K tokens/s |
Curvas completas no
Weights & Biases.
Arquitetura
Decoder-only transformer (estilo LLaMA), com algumas mudanças em relação ao
modelo anterior em inglês para escala maior e melhor estabilidade:
| Componente | Escolha |
|---|
| Camadas (n_layer) | 12 |
| Dimensão (n_embd) | 768 |
| Heads de Query | 12 |
| Heads de Key/Value | 4 (GQA, ratio 3:1) |
| Dim do FFN (SwiGLU) | 2048 (≈8/3 × n_embd) |
| Context length | 1024 |
| Vocabulário | 32.000 |
| Positional Encoding | RoPE (θ=10000) |
| Normalização | RMSNorm (pre-norm, ε=1e-5) |
| Ativação | SwiGLU |
| Embeddings | Compartilhadas com LM head (tied) |
| Z-loss | coeficiente 1e-4 (estabilidade do softmax final) |
Total de parâmetros: 100.092.672 (~100M)
Diferenças vs modelo inglês de 55M
| Aspecto | Modelo EN (55M) | Modelo PT (100M) |
|---|
| Camadas | 10 | 12 |
| n_embd | 512 | 768 |
| n_head / n_kv_head | 8 / 4 | 12 / 4 |
| Vocab | 50.304 (GPT-2 BPE) | 32.000 (BPE byte-level treinado em PT) |
| Z-loss | não usado | coef 1e-4 |
Dataset
FineWeb2 — subset português
(
HuggingFaceFW/fineweb-2)
Corpus web em português filtrado por qualidade, parte do pipeline FineWeb da
HuggingFace. Usado em streaming até atingir ~2B tokens, divididos em:
- Train: 2.100.000.085 tokens (~4.2 GB em uint16)
- Val: 2.067.198 tokens (~4 MB)
Tokenizer
BPE byte-level treinado do zero no corpus FineWeb2-pt, com vocabulário de
32.000 tokens. Diferente do tokenizer GPT-2 usado no modelo anterior (que
foi treinado em inglês e tinha eficiência ~2-3x pior em português), este
tokenizer é otimizado para a distribuição de caracteres e padrões morfológicos
do português brasileiro.
Comparativo de eficiência (tokens necessários para frase exemplo):
| Frase | GPT-2 BPE (50k) | PT BPE (32k) |
|---|
| "O direito tributário brasileiro é complexo." | 14 tokens | ~10 tokens |
Configuração de Treino
| Hiperparâmetro | Valor |
|---|
| Otimizador | AdamW (β₁=0.9, β₂=0.95) |
| Weight decay | 0.1 (seletivo: apenas em params 2D+) |
| LR pico → mínimo | 6e-4 → 6e-5 |
| Schedule | Warmup linear 750 steps + cosine decay |
| Gradient clipping | 1.0 |
| Batch size (por step) | 8 sequências |
| Gradient accumulation | 16 |
| Batch efetivo | 128 sequências = 131.072 tokens/step |
| Max steps | 15.000 |
| Mixed precision | bfloat16 (autocast) |
| Compilação | torch.compile ativado |
Como Usar
Este checkpoint requer o código do modelo do repositório:
https://github.com/cjfbr/slm-pretraining
O tokenizer está incluído neste repositório HF (tokenizer.json), formato
tokenizers da HuggingFace.
1import torch
2from tokenizers import Tokenizer
3from huggingface_hub import hf_hub_download
4
5from slm.model import GPT
6from slm.config import ModelConfig
7
8REPO = "cjfb75/slm-100m-pt-llama-style"
9
10# Baixar tokenizer e checkpoint
11tokenizer_path = hf_hub_download(REPO, "tokenizer.json")
12ckpt_path = hf_hub_download(REPO, "pretrain_final.pt")
13
14# Tokenizer
15tokenizer = Tokenizer.from_file(tokenizer_path)
16
17# Modelo
18cfg = ModelConfig(
19 vocab_size=32000,
20 n_layer=12,
21 n_embd=768,
22 n_head=12,
23 n_kv_head=4,
24 ffn_hidden_dim=2048,
25 block_size=1024,
26)
27model = GPT(cfg)
28ckpt = torch.load(ckpt_path, weights_only=False, map_location="cuda")
29model.load_state_dict(ckpt["model"])
30model.eval().cuda()
31
32# Geração
33prompt = "A capital do Brasil é"
34ids = tokenizer.encode(prompt).ids
35input_ids = torch.tensor([ids], dtype=torch.long, device="cuda")
36with torch.no_grad():
37 out = model.generate(input_ids, max_new_tokens=100, temperature=0.8, top_k=50)
38print(tokenizer.decode(out[0].cpu().tolist()))
Limitações Conhecidas
- Modelo pequeno (~100M): capacidade limitada de raciocínio complexo
ou conhecimento factual amplo
- Pré-treino apenas: não passou por SFT ou RLHF, então pode alucinar
fatos e não segue instruções consistentemente
- Distribuição do FineWeb2: viés para texto web em geral; subdomínios
como código fonte ou texto jurídico/médico podem ter qualidade reduzida
- Repetição: comportamento típico de modelos pequenos pode ocorrer em
geração longa; mitigado parcialmente por
top_k e temperature adequados
Referências de Comparação
| Modelo | Params | Tokens | Val PPL em PT |
|---|
| Este modelo | 100M | 1.97B | 24.1 |
| Modelo prévio (EN→PT cross-lingual) | 55M | 524M EN | (incoerente, ver análise) |
| Sabiá-7B (referência grande) | 7B | 1.4T | ~15 |
Equipe
- Cristiano Ferrazzo (PUCRS — Escola Politécnica)
Licença
MIT. Use livre para fins acadêmicos e comerciais.
Citação
Se usar este modelo em trabalho acadêmico:
1@misc{slm100m_pt_2026,
2 author = {Ferrazzo, Cristiano},
3 title = {SLM-100M Portuguese: Small Language Model for Brazilian Portuguese},
4 year = {2026},
5 publisher = {HuggingFace},
6 url = {https://huggingface.co/cjfb75/slm-100m-pt-llama-style}
7}