77 25K 222

Canarim-7B

Como adaptei o Llama 2 7B ao português com pré-treinamento continuado em 16 bilhões de tokens.

Canarim-7B: adaptação contínua do Llama 2 para português

A oferta reduzida de modelos-base dedicados ao português motivou o Canarim-7B. Continuei o pré-treinamento do Llama 2 7B, criado pela Meta, com 16 bilhões de tokens do subconjunto em português do CC-MAIN-2023-23 e publiquei o resultado no Hugging Face. A principal contribuição é a adaptação linguística preservando a arquitetura LlamaForCausalLM, seus 6.738.415.616 parâmetros e contexto nominal de 4.096 tokens.[1][2]

Usei pré-treinamento continuado, não uma inicialização aleatória em 16 bilhões de tokens. Publiquei o Canarim-7B como modelo-base, sem ajuste para seguir instruções ou alinhamento conversacional. Para esse treinamento, usei dominguesm/CC-MAIN-2023-23, não o corpus posterior chamado apenas dominguesm/canarim.[1]

Os cálculos a seguir partem dos números que publiquei. Quando dependem de hipóteses, identifico-os como estimativas; não preencho os detalhes que deixei sem registro por analogia com outros treinamentos.

Identidade e configuração

Configurei e publiquei o modelo com as seguintes propriedades:

PropriedadeValor publicado
ClasseLlamaForCausalLM
Parâmetros6.738.415.616
Camadas Transformer32
Dimensão oculta4.096
Cabeças de atenção32
Cabeças de chave/valor32
Dimensão intermediária11.008
Vocabulário32.000
Contexto máximo4.096 tokens
AtivaçãoSiLU, na unidade SwiGLU herdada
NormalizaçãoRMSNorm, epsilon = 10^-5
PosiçõesRoPE, theta = 10.000, sem scaling
Precisão declaradaFP16
Embeddings de entrada/saídanão compartilhados

Como usei 32 cabeças de consulta e 32 de chave/valor, esta variante mantém atenção multi-head comum, não grouped-query attention. Preservei do Llama 2 RMSNorm, ativações SwiGLU, rotary positional embeddings e o contexto de 4.096 tokens.[2] Também mantive o tokenizer no formato Llama, com <unk>, <s> e </s> nos IDs 0, 1 e 2 e vocabulário de 32 mil peças. Não configurei um pad_token próprio.[1]

Não documentei no card: taxa e agenda de aprendizado, otimizador, batch global, comprimento efetivo das sequências de treino, número de épocas, ordem dos documentos, seed, clipping, warm-up, mistura ou remoção de domínios, deduplicação textual, filtros de qualidade, perda final, perplexidade, hardware, duração, consumo energético e checkpoints intermediários. A arquitetura conhecida não torna conhecida a receita de treino.

Da web aos pesos

Renderizando diagrama...

O snapshot CC-MAIN-2023-23

O Common Crawl informa que CC-MAIN-2023-23 foi capturado de 27 de maio a 11 de junho de 2023. O arquivo completo contém 3,1 bilhões de páginas, 390 TiB sem compressão, 44 milhões de hosts e 35 milhões de domínios registrados. Esses números descrevem a captura global, não o subconjunto português nem o material efetivamente consumido pelo treinamento.[4]

Publiquei dominguesm/CC-MAIN-2023-23 com 16.899.389 exemplos em 196 shards Parquet, cerca de 97,6 GB de tamanho lógico e 18,5 GB para download. Usei apenas as colunas text, url e crawl_timestamp e declarei o conjunto como português sob CC BY 4.0.[5] Na primeira versão, não documentei a consulta de seleção linguística, o extrator de HTML, os limiares, a deduplicação, os filtros de PII/toxicidade, os domínios excluídos nem a correspondência exata entre os 16 bilhões de tokens e todos os shards disponíveis.

O corte temporal precisa ser lido em camadas. O card do Canarim resume o corte como “meados de 2023”; para a adaptação portuguesa, a data observável mais precisa é o fim da captura, 11 de junho de 2023. Já o Llama 2 foi treinado em 2 trilhões de tokens de fontes públicas, com corte em setembro de 2022 segundo seu artigo.[2] Logo, o Canarim combina conhecimento herdado até o corte do modelo-base com uma etapa portuguesa de maio/junho de 2023. Isso não garante que toda informação anterior esteja presente, nem que nenhuma string com data futura apareça: páginas podem conter calendários, previsões ou texto republicado, e “data de captura” não é “data de autoria”.

O outro dataset chamado Canarim

Depois, criei dominguesm/canarim com 342.818.651 documentos de múltiplas iterações do Common Crawl, cerca de 1,09 TB, deduplicação inicial por URL e extração de HTML para Markdown com Trafilatura.[6] Esse corpus pertence ao mesmo ecossistema de dados em português, mas não foi a fonte do treinamento descrito aqui. Para o Canarim-7B, usei CC-MAIN-2023-23.

O que os 16 bilhões de tokens fazem

Em modelagem causal, cada sequência tokenizada x1:Tx_{1:T} é fatorada da esquerda para a direita:

pθ(x1:T)=t=1Tpθ(xtx<t).p_\theta(x_{1:T})=\prod_{t=1}^{T}p_\theta(x_t\mid x_{<t}).

A perda de uma sequência é a entropia cruzada causal:

Lseq(θ)=t=1Tlogpθ(xtx<t).\mathcal{L}_{\mathrm{seq}}(\theta)=-\sum_{t=1}^{T}\log p_\theta(x_t\mid x_{<t}).

Uma máscara triangular impede cada posição de olhar tokens futuros. O treinamento ajusta θ\theta para aumentar a probabilidade do próximo token real; não ensina diretamente “responder corretamente”, “seguir ordens” ou “recusar pedidos perigosos”. A perplexidade é a exponencial da perda média por token,

PPL=exp ⁣(L),\operatorname{PPL}=\exp\!\left(\overline{\mathcal{L}}\right),

mas não publiquei essa perda nem a perplexidade do Canarim. Depois do treino, geração é a repetição do mesmo mecanismo: calcular logits do próximo token, selecionar ou amostrar um token, anexá-lo ao contexto e continuar.

No pré-treinamento continuado, preservei a parametrização e iniciei a otimização nos pesos do Llama 2. Isso é muito diferente de treinar 6,7 bilhões de parâmetros aleatórios em apenas 16 bilhões de tokens: o checkpoint já havia absorvido o sinal de 2 trilhões de tokens. A etapa adicional desloca a distribuição em direção ao português, mas pode também provocar esquecimento parcial de capacidades anteriores se a mistura, o learning rate ou o número de passos forem agressivos. Como não publiquei curvas de validação em português e nos idiomas-base, não consigo quantificar adaptação versus esquecimento.

Escala e custo: derivação e estimativas

Tokens por parâmetro

Usando o número exato de parâmetros publicado e os 16 bilhões reportados:

DadicionalP=160000000006738415616=2,3745tokens por parametro.\frac{D_{\mathrm{adicional}}}{P}=\frac{16\,000\,000\,000}{6\,738\,415\,616}=2{,}3745 \quad\text{tokens por parametro}.

Esse é um cálculo do estágio adicional, não uma conclusão de que o modelo foi subtreinado. Se contabilizarmos também os 2 trilhões de tokens declarados para o Llama 2 base, sob a hipótese simplificadora de que o checkpoint inicial percorreu exatamente esse total:

DacumuladoP=2000bi+16bi6,738bi=299,19tokens por parametro.\frac{D_{\mathrm{acumulado}}}{P}=\frac{2\,000\,\mathrm{bi}+16\,\mathrm{bi}}{6{,}738\,\mathrm{bi}}=299{,}19 \quad\text{tokens por parametro}.

Os 16 bilhões acrescentam

162000=0,8%\frac{16}{2\,000}=0{,}8\%

ao contador nominal do pré-treinamento-base. Apesar de pequenos no total, eles são concentrados em português e podem ter efeito desproporcional na adaptação linguística. Comparar diretamente 299299 com uma regra compute-optimal também é inadequado: as leis de escala de Hoffmann et al. tratam treinamento desde o início sob orçamento fixo, enquanto aqui há especialização contínua de um modelo já treinado além do ponto compute-optimal original.[7]

FLOPs do estágio adicional

Uma aproximação comum para Transformers densos é

C6PD,C\approx 6PD,

cobrindo forward e backward nos principais produtos matriciais.[7] Com P=6,738415616×109P=6{,}738415616\times10^9 e D=16×109D=16\times10^9:

C6×6,738415616×109×16×109=6,47×1020 FLOPs.C\approx 6\times 6{,}738415616\times10^9\times16\times10^9 =6{,}47\times10^{20}\ \mathrm{FLOPs}.

Isso é estimativa, não telemetria. A fórmula omite ou simplifica atenção dependente do comprimento, embeddings, recomputação de ativações, comunicação e operações auxiliares. Para converter em tempo, suponha, apenas como cenário, GPUs A100 com pico FP16 denso de 312 TFLOP/s e eficiência efetiva (MFU) entre 35% e 45%.[13]

HipóteseResultado aproximado
Limite ideal a 312 TFLOP/s576 GPU-horas
45% do pico1.280 GPU-horas
35% do pico1.646 GPU-horas
8 GPUs, 45% do pico6,7 dias
8 GPUs, 35% do pico8,6 dias

O treinamento real pode estar fora desse intervalo porque não publiquei o hardware, a quantidade de GPUs, o paralelismo nem a MFU. Apresento a conta apenas como ordem de grandeza. Ela cobre somente os 16 bilhões de tokens adicionais, não o custo anterior do Llama 2 base, aquisição de dados, tokenização, tentativas, avaliações ou armazenamento.

Em inferência FP16, os pesos ocupam teoricamente

6738415616×2=13,48 GB,6\,738\,415\,616\times2=13{,}48\ \mathrm{GB},

valor compatível com o consumo atribuído aos pesos no resultado do leaderboard português.[8] Ainda são necessários memória do runtime, buffers e cache KV; portanto, “13,5 GB de pesos” não garante execução confortável em uma GPU de 16 GB. Quantização a 4 bits reduziria o piso bruto para cerca de 3,37 GB, mas escalas, metadados e buffers elevam o uso real e podem alterar a qualidade.

Uso: continuação, poucos exemplos e geração

Como modelo-base, o Canarim não conhece por treinamento supervisionado uma convenção estável de system/user/assistant. O uso mais natural é completar texto. Para classificação, few-shot significa colocar exemplos resolvidos no próprio prompt; nenhum gradiente é calculado. Os exemplos demonstram o formato e deslocam as probabilidades da continuação.

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
 
MODEL_ID = "dominguesm/canarim-7b"
 
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
model = AutoModelForCausalLM.from_pretrained(
    MODEL_ID,
    torch_dtype=torch.float16,
    device_map="auto",
)
 
prompt = """Classifique o sentimento como positivo, negativo ou neutro.
 
Texto: O atendimento foi rápido e resolveu meu problema.
Sentimento: positivo
 
Texto: O produto chegou quebrado e ninguém respondeu.
Sentimento: negativo
 
Texto: A reunião foi transferida para terça-feira.
Sentimento: neutro
 
Texto: Gostei muito do livro e já recomendei aos amigos.
Sentimento:"""
 
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
with torch.inference_mode():
    output = model.generate(
        **inputs,
        max_new_tokens=8,
        do_sample=False,
        eos_token_id=tokenizer.eos_token_id,
        pad_token_id=tokenizer.eos_token_id,
    )
 
continuacao = output[0, inputs.input_ids.shape[1]:]
print(tokenizer.decode(continuacao, skip_special_tokens=True).strip())

Para um experimento duradouro, registre a data de acesso, as versões das bibliotecas e os parâmetros de geração; em trabalhos formais, arquive também os artefatos utilizados. max_new_tokens limita somente a continuação, ao contrário de max_length, que inclui o prompt. do_sample=False torna a escolha gulosa e facilita a repetição do experimento. Para escrita aberta, pode-se usar amostragem, por exemplo do_sample=True, temperature=0.7 e top_p=0.9; isso aumenta diversidade, não factualidade. A configuração de geração publicada sugere temperatura 0,6 e top_p=0.9, mas esses são defaults operacionais, não parte do treinamento nem garantia de qualidade.[1]

Para benchmarks de múltipla escolha, gerar uma letra livre pode introduzir erros de formato. Protocolos como os usados nos leaderboards normalmente comparam log-verossimilhanças das continuações candidatas. Em termos simplificados, escolhem

argmaxc  logpθ(cprompt),\underset{c}{\operatorname{argmax}}\;\log p_\theta(c\mid\text{prompt}),

às vezes normalizando pelo comprimento. Por isso, uma pontuação do leaderboard não deve ser reproduzida com um chat prompt arbitrário e amostragem.

Avaliações oficiais publicadas

Renderizando diagrama...

Open Portuguese LLM Leaderboard

O resultado bruto associado ao card foi executado em 16-17 de fevereiro de 2024. O protocolo registra versão 1.1.0, FP16, uma GPU, batch 8, contexto útil de 4.064 tokens mais até 32 tokens gerados, ausência de chat template e 14.150 amostras sem truncamento. O backend do leaderboard é descrito como A100 80 GB.[8][9]

Tarefa e protocoloMétrica principalResultado (%)
ENEM, 3-shotacurácia25,96
BLUEX, 3-shotacurácia29,76
OAB Exams, 3-shotacurácia31,48
ASSIN2 RTE, 15-shotF1 macro71,96
ASSIN2 STS, 15-shotPearson13,33
FAQUAD NLI, 15-shotF1 macro49,09
HateBR, 25-shotF1 macro78,48
PT Hate Speech, 25-shotF1 macro63,73
tweetSentBR, 25-shotF1 macro62,38
Média simples dos nove scoresmétricas heterogêneas47,36

A média é 0,4735606549: uma média aritmética de nove métricas principais, não uma acurácia sobre 14.150 itens. Pearson de STS, F1 macro e acurácia têm significados diferentes. O resultado FAQUAD ilustra a diferença: F1 macro principal é 49,09%, enquanto a acurácia bruta registrada é 78,62%. Trocar a métrica mudaria muito a média.

Publiquei 25,96 no ENEM no resultado bruto e na tabela usada para calcular a média 47,36, mas também preservei 26,96 no model-index. Como (25,96 + os outros oito scores) / 9 = 47,36, mantenho 25,96 nesta comparação e não combino os dois registros.[1][8]

Open LLM Leaderboard legado

A avaliação global foi executada em 25 de janeiro de 2024, em FP16 e batch 1. O artefato reúne resultados e detalhes de execução para 28.659 amostras.[10]

Tarefa e protocoloMétrica usada na médiaResultado (%)
ARC Challenge, 25-shotacurácia normalizada51,96
HellaSwag, 10-shotacurácia normalizada77,52
MMLU, 5-shotacurácia40,92
TruthfulQA MC2, 0-shotMC240,03
Winogrande, 5-shotacurácia71,43
GSM8K, 5-shotacurácia exata9,93
Média simplesseis scores48,63

Essa suíte é majoritariamente em inglês. Ela mede retenção de capacidades gerais depois da adaptação, mas não substitui uma avaliação em português. acc_norm corrige viés de comprimento em ARC e HellaSwag; MC2 soma probabilidade atribuída às respostas verdadeiras de TruthfulQA; GSM8K exige correspondência da resposta matemática. A média de 48,63 é reproduzível a partir dos seis valores, mas não é diretamente comparável a 47,36 do leaderboard português. Uma diferença entre médias pode vir das tarefas, idioma, shots, métricas, prompts, versão do harness ou versão do modelo.

Também não se deve concluir “78,48% de segurança” a partir de HateBR. É F1 macro em uma classificação binária de ofensividade com 25 exemplos no contexto, não uma avaliação de geração tóxica. Da mesma forma, 40,03 em TruthfulQA é MC2 de múltipla escolha, não a probabilidade de toda continuação factual ser verdadeira.

Qualidade, contaminação e uso responsável de dados web

O risco mais imediato para avaliação é contaminação: uma questão, gabarito, paráfrase ou discussão pode existir no corpus de treino. O snapshot é posterior à publicação de benchmarks como OAB, ASSIN2, HateBR e TweetSentBR e contém páginas de toda a web. Na primeira versão, não comparei sistematicamente o corpus com os conjuntos de avaliação nem removi correspondências documentadas.[5] Portanto, os escores podem refletir alguma mistura de generalização, memorização e conhecimento herdado do Llama 2.

O corte ajuda apenas em casos estritamente posteriores. As provas ENEM 2023 e partes de BLUEX 2024 aparecem no protocolo português, enquanto a captura terminou em junho de 2023; essas edições finais não poderiam estar literalmente naquela captura se foram publicadas depois. Ainda assim, exemplos few-shot, versões preliminares, questões reaproveitadas e o modelo-base complicam inferências, e as demais edições anteriores continuam suscetíveis a vazamento. Uma avaliação de contaminação deve comparar o corpus com cada split de benchmark antes do treinamento, incluindo duplicatas aproximadas.

Dados web trazem ainda:

  • duplicatas exatas e aproximadas, que superam artificialmente domínios frequentes e favorecem memorização;
  • HTML residual, menus, spam, SEO, texto truncado, encoding incorreto e conteúdo multilíngue classificado como português;
  • PII, emails, telefones, endereços, segredos acidentais e conteúdo de pessoas que não consentiram com treinamento;
  • ódio, assédio, pornografia, automutilação, desinformação e instruções perigosas;
  • distribuição geográfica e socioeconômica desigual, com sobrerrepresentação de português brasileiro formal e de grandes sites;
  • material protegido por direitos autorais e páginas cujos termos não equivalem à licença do empacotamento.

Publiquei o dataset CC-MAIN-2023-23 sob CC BY 4.0, mas essa licença de empacotamento não transforma automaticamente cada página de terceiros em obra sob CC BY. Proveniência por URL e análise jurídica continuam necessárias. O próprio Common Crawl exige respeito a direitos autorais, privacidade e termos dos proprietários do conteúdo.[5][11]

Licença do modelo e limites de uso

Distribuí o Canarim-7B sob o Llama 2 Community License Agreement, versão de 18 de julho de 2023.[12] Ela concede direitos limitados para usar, reproduzir, modificar e distribuir, mas impõe condições: redistribuidores devem fornecer a licença e manter o aviso de atribuição; o uso deve obedecer à política de uso aceitável; outputs e materiais não podem ser usados para melhorar outro LLM que não seja Llama 2 ou derivado; e organizações que tinham mais de 700 milhões de usuários ativos mensais na data de lançamento precisam solicitar licença adicional à Meta. Não é correto resumir isso como licença permissiva padrão ou assumir compatibilidade automática com licenças open source.

Publiquei um modelo-base, sem camada de segurança conversacional. Ele pode completar premissas falsas, reproduzir estereótipos, gerar PII ou produzir conteúdo perigoso. Aplicações reais precisam de avaliação por domínio, limites de entrada/saída, filtros proporcionais ao risco, recuperação de fontes quando factualidade importa, monitoramento e revisão humana. Não deve ser usado como autoridade autônoma em saúde, direito, crédito, emprego ou segurança.

Contribuição, resultado e aprendizado

Com o Canarim-7B, continuei o Llama 2 7B em 16 bilhões de tokens portugueses ligados ao snapshot CC-MAIN-2023-23, preservei a arquitetura causal de 32 camadas e 4.096 tokens e publiquei o resultado como modelo-base. Também publiquei duas avaliações: 47,36 no protocolo português e 48,63 no Open LLM Leaderboard legado. O estágio adicional representa 2,37 tokens por parâmetro e aproximadamente 6,47 x 10^20 FLOPs sob a aproximação 6PD.

Na versão que preservei, não registrei receita completa de treino, avaliação de contaminação, inventário de filtros, curva de perda, comparação antes/depois com o Llama 2 7B ou vínculo direto com o dataset posterior canarim. Ainda uso o resultado para estudar adaptação linguística, geração e few-shot em português; o principal aprendizado foi a necessidade de preservar esses registros em futuras versões.

Referências

1. Domingues, M. Canarim-7B: card, API, config.json, generation_config.json e tokenizer. DOI 10.57967/hf/1356. Consulta em 24 jul. 2026.

2. Touvron, H. et al. Llama 2: Open Foundation and Fine-Tuned Chat Models. arXiv:2307.09288, 2023.

3. Hugging Face. Histórico de publicação de dominguesm/canarim-7b, 2023-2024.

4. Nagel, S.; Common Crawl Foundation. May/June 2023 crawl archive now available, 21 jun. 2023.

5. Domingues, M. CC-MAIN-2023-23-PT: card, API e arquivos, 2023.

6. Domingues, M. Canarim: A Large-Scale Dataset of Web Pages in the Portuguese Language. DOI 10.57967/hf/1605, 2023-2024.

7. Hoffmann, J. et al. Training Compute-Optimal Large Language Models. arXiv:2203.15556, 2022.

8. Garcia, E. A. S. Resultado bruto do Canarim-7B no Open Portuguese LLM Leaderboard, execução de 16 fev. 2024.

9. Garcia, E. A. S. Open Portuguese LLM Leaderboard e configuração de tarefas v1.1.0, 2024.

10. Hugging Face H4. Detalhes da avaliação dominguesm/canarim-7b e resultado de 25 jan. 2024, Open LLM Leaderboard legado.

11. Common Crawl Foundation. Terms of Use e Privacy Policy.

12. Meta Platforms. Llama 2 Community License Agreement incluído no checkpoint, versão de 18 jul. 2023; ver também a Acceptable Use Policy.

13. NVIDIA. NVIDIA A100 Tensor Core GPU Datasheet, especificação de pico FP16/BF16 sem sparsity.

BibTeX

@misc{domingues2023canarim7b,
  author    = {Maicon Domingues},
  title     = {canarim-7b},
  year      = {2023},
  publisher = {Hugging Face},
  doi       = {10.57967/hf/1356},
  url       = {https://huggingface.co/dominguesm/canarim-7b}
}
 
@misc{touvron2023llama2,
  author        = {Hugo Touvron and others},
  title         = {Llama 2: Open Foundation and Fine-Tuned Chat Models},
  year          = {2023},
  eprint        = {2307.09288},
  archivePrefix = {arXiv},
  primaryClass  = {cs.CL},
  url           = {https://arxiv.org/abs/2307.09288}
}
 
@misc{domingues2023ccmain202323,
  author    = {Maicon Domingues},
  title     = {{CC-MAIN-2023-23-PT}},
  year      = {2023},
  publisher = {Hugging Face},
  url       = {https://huggingface.co/datasets/dominguesm/CC-MAIN-2023-23}
}
 
@misc{garcia2024openptllm,
  author       = {Eduardo A. S. Garcia},
  title        = {Open Portuguese LLM Leaderboard},
  year         = {2024},
  publisher    = {Hugging Face},
  howpublished = {\url{https://huggingface.co/spaces/eduagarcia/open_pt_llm_leaderboard}}
}
 
@misc{hoffmann2022chinchilla,
  author        = {Jordan Hoffmann and others},
  title         = {Training Compute-Optimal Large Language Models},
  year          = {2022},
  eprint        = {2203.15556},
  archivePrefix = {arXiv},
  primaryClass  = {cs.CL},
  url           = {https://arxiv.org/abs/2203.15556}
}