Canarim-Instruct-PTBR: como construí 317 mil instruções em português
Eu construí o Canarim-Instruct-PTBR Dataset como uma coleção de exemplos para ajuste supervisionado de modelos de linguagem em português. Cada registro representa uma solicitação, um contexto opcional e a resposta esperada. A publicação reúne 317.932 registros: 316.413 em train e 1.519 em test. Escolhi o nome Canarim, uma forma regional de “canarinho”, pela presença familiar dessa ave no cotidiano brasileiro.[1]
Seu valor imediato é pragmático: em 2023, quando conjuntos de instruction tuning em português ainda eram escassos, publiquei centenas de milhares de pares já normalizados em três colunas e distribuídos como Parquet. Na primeira versão, alertei que poderiam existir erros de tradução. Essa limitação continua importante: há traduções literais, respostas factualmente frágeis, código deformado e tarefas que pedem capacidades não representáveis em texto. Neste artigo, explico como compus e harmonizei os dados, quais decisões tomei e o que pretendo melhorar.
| Propriedade | Valor verificado |
|---|---|
| Registros totais | 317.932 |
train | 316.413 |
test | 1.519 |
| Campos | instruction, input, output |
| Tamanho lógico | 113.787.388 bytes |
| Download Parquet | 63.510.092 bytes |
| Arquivos de dados | 2 |
| Idioma declarado | português (pt) |
| Licença atual | CC BY-NC 4.0 |
| DOI | 10.57967/hf/0983 |
Como compus os 316.413 exemplos de treino
Eu reuni cinco fatias de três linhagens principais: Alpaca traduzido, instructions-pt e a família Self-Instruct/Super-NaturalInstructions. As contagens que publiquei são:
As participações abaixo são apenas divisões dessas contagens pelo total de treino. Elas não representam taxas medidas antes da tradução, depois de filtros ou após deduplicação, pois não publiquei esses denominadores.
| Fatia declarada | Linhas | Parcela calculada de train |
|---|---|---|
dominguesm/alpaca-data-pt-br | 51.759 | 16,358% |
cahya/instructions-pt (train) | 57.692 | 18,233% |
HuggingFaceH4/self_instruct (train) | 74.350 | 23,498% |
helpful_instructions/self_instruct | 82.612 | 26,109% |
helpful_instructions/super_natural_instructions | 50.000 | 15,802% |
Renderizando diagrama...
1. Alpaca-Cleaned em português
Usei os 51.759 registros de treino de dominguesm/alpaca-data-pt-br, já organizados no esquema instruction/input/output. Eu havia criado esse conjunto como tradução automática de yahma/alpaca-cleaned, uma limpeza do Stanford Alpaca. O Alpaca original gerou aproximadamente 52 mil demonstrações com text-davinci-003, seguindo uma versão simplificada da receita Self-Instruct: vinte instruções por chamada, uma instância por instrução e sem separar tarefas classificatórias.[3]
A limpeza de origem tentou corrigir links ou imagens ausentes, saídas vazias, instruções fundidas, caracteres de controle e respostas erradas. Isso melhora a base inglesa, mas não valida a tradução. Incorporei os 51.759 registros em sua ordem original; por isso, a primeira linha do Canarim corresponde à primeira linha dessa fonte e a linha 51.758 encerra essa fatia.
2. cahya/instructions-pt
Ao incorporar cahya/instructions-pt, trabalhei com uma fonte que oferece apenas a indicação “More Information needed”, não declara licença e usa id: int64 mais text: string, em vez de campos estruturados. Ela reúne 57.692 linhas em train, 1.519 em test e 1.518 em validation.[4] A partir do formato User: ...\nAssistant: ..., removi os marcadores, coloquei as duas partes em instruction e output e deixei input vazio.
Usei as 1.519 linhas de test de cahya/instructions-pt como teste do Canarim, preservando redação e ordem. Não incorporei as 1.518 linhas de validation à soma publicada. Na primeira versão, não publiquei a receita de montagem nem uma semente de separação; portanto, o teste é uma partição herdada dessa fonte, não um split aleatório do conjunto misto.
3. Self-Instruct e Super-NaturalInstructions
O framework Self-Instruct começa com tarefas-semente escritas por pessoas, pede a um modelo que gere novas instruções e instâncias, filtra itens inválidos ou similares e realimenta o conjunto. O trabalho publicou cerca de 52 mil instruções e 82 mil instâncias; seus autores alertaram que, em uma inspeção de 200 instruções aleatórias, 46% podiam conter algum problema. Mesmo assim, ajustar GPT-3 com esses dados produziu ganho absoluto de 33 pontos em Super-NaturalInstructions sobre o modelo base, mostrando por que supervisão sintética se tornou atraente.[7]
HuggingFaceH4/self_instruct reformata a publicação original em prompt/completion, remove <|endoftext|> e executa train_test_split(test_size=0.1, seed=42). O resultado são 74.350 itens em treino e 8.262 em teste; o Canarim declara usar os 74.350 de treino.[5]
HuggingFaceH4/helpful_instructions agrega pares com prompt, completion e metadados de origem. O Canarim usa duas configurações: os 82.612 exemplos de self_instruct e 50 mil de super_natural_instructions.[6] A segunda linhagem vem de um benchmark de 1.616 tarefas, 76 tipos e instruções especializadas, cobrindo classificação, extração, reescrita e composição, entre outros gêneros.[8]
Existe um risco estrutural importante: helpful_instructions/self_instruct deriva do próprio HuggingFaceH4/self_instruct, que também incorporei separadamente. Na primeira versão, não medi nem publiquei a taxa de sobreposição entre essas duas fatias. Como tradução e parsing podem alterar as strings, uma próxima versão precisa medir duplicatas exatas e aproximadas antes do treinamento.
Como harmonizei os formatos e traduzi o conteúdo
As fontes chegam em três schemas: Alpaca já tem três campos; instructions-pt serializa turnos em text; as coleções H4 usam prompt/completion e, em helpful_instructions, meta. O destino reduz tudo a:
| Campo | Tipo | Interpretação operacional |
|---|---|---|
instruction | string | tarefa ou pergunta apresentada ao modelo |
input | string | contexto opcional; frequentemente "" |
output | string | resposta-alvo para perda supervisionada |
Concatenei as cinco fatias nesta ordem, iniciando-as nos índices 0, 51.759, 109.451, 183.801 e 266.413. Traduzi “Find the word that is closest in meaning to fear” como “Encontre a palavra que está mais próxima no significado de medo”. Para Super-NaturalInstructions, separei definição em instruction, instância em input e rótulo em output; em parte dos exemplos H4, mantive o texto de entrada anexado à instrução e deixei input vazio. Essa primeira harmonização não aplicou a mesma separação estrutural a todas as fatias.
Na primeira versão, descrevi o processo apenas como “translation and adaptation” e alertei sobre possíveis erros, mas não registrei o serviço ou modelo de tradução, versão, prompt, temperatura, processamento em lote, tentativas, política para trechos de código, glossário, normalização Unicode, tratamento de Output:/Input:, filtros, número de linhas rejeitadas nem revisão humana.[1] O resultado inclui sinais concretos de translationese: “linha de tags” para tagline, “não faça cram”, repetição de sinônimos e nomes alternando entre João e John. Há ainda saídas truncadas ou incoerentes, como uma resposta gerencial que termina abruptamente e uma área de círculo de raio quatro informada como 12,5664, em vez de aproximadamente 50,27.
Splits, escala e o que os números significam
Somando os dois splits,
Assim, treino representa 99,5222% e teste 0,4778% dos registros. Como usei o teste de uma única fonte, essa partição pode ter distribuição, estilo e dificuldade diferentes do treino misto; não a apresento como benchmark independente.
No card, informei 113.100.060 bytes lógicos para treino e 687.328 para teste, ou médias de 357,44 e 452,49 bytes por linha na representação da tabela. No conjunto, são
bytes por registro. Os dois Parquets somam 63.510.092 bytes, 55,81% do tamanho lógico. Essas razões não são comprimentos médios em tokens: incluem a codificação colunar e escondem grande variação entre respostas.
Carregamento e formatação do prompt
O carregamento básico é mostrado abaixo. Para tornar o experimento reproduzível sem expor identificadores internos, registre o DOI, a data de acesso, as contagens por split, as versões das bibliotecas e preserve uma cópia controlada dos arquivos usados.
from datasets import load_dataset
dados = load_dataset(
"dominguesm/Canarim-Instruct-PTBR-Dataset",
)
print(dados)
print(dados["train"][0])O template oficial usa uma variante do formato Alpaca. Tratar string vazia como ausência de contexto evita produzir uma seção Entrada inútil:
def formatar_exemplo(exemplo: dict[str, str]) -> str:
contexto = (exemplo.get("input") or "").strip()
if contexto:
cabecalho = (
"Abaixo está uma instrução que descreve uma tarefa, emparelhada "
"com uma entrada que fornece mais contexto. Escreva uma resposta "
"que conclua adequadamente a solicitação."
)
else:
cabecalho = (
"Abaixo está uma instrução que descreve uma tarefa. "
"Escreva uma resposta que conclua adequadamente a solicitação."
)
partes = [cabecalho, f"### Instruções:\n{exemplo['instruction'].strip()}"]
if contexto:
partes.append(f"### Entrada:\n{contexto}")
partes.append(f"### Resposta:\n{exemplo['output'].strip()}")
return "\n".join(partes)Em treinamento causal, a prática recomendável é mascarar da função de perda os tokens do cabeçalho, instrução e entrada, supervisionando somente a resposta. Caso contrário, o modelo também é otimizado para reproduzir o prompt. O truncamento deve reservar espaço para a saída e registrar quantos exemplos perderam conteúdo; cortar silenciosamente o final pode transformar respostas corretas em alvos incompletos.
Aprendizados da primeira versão: duplicação e qualidade
Na primeira versão, não registrei uma etapa de deduplicação do conjunto pronto. Aprendi que uma próxima versão deve começar preservando source, configuração, split e índice original em colunas auxiliares. Normalizar para comparação não significa sobrescrever o texto: a versão original deve continuar disponível para rastreabilidade.
import re
import unicodedata
def normalizar(texto: str) -> str:
texto = unicodedata.normalize("NFKC", texto or "").casefold()
return re.sub(r"\s+", " ", texto).strip()
def chave_normalizada(exemplo: dict[str, str]) -> tuple[str, ...]:
campos = ("instruction", "input", "output")
return tuple(normalizar(exemplo[c]) for c in campos)
vistos = set()
duplicatas = 0
for exemplo in dados["train"]:
chave = chave_normalizada(exemplo)
duplicatas += chave in vistos
vistos.add(chave)
print({"duplicatas_normalizadas": duplicatas})A chave normalizada encontra cópias textuais, mas não paráfrases, traduções alternativas ou respostas parcialmente repetidas. No segundo nível, pretendo usar shingles de tokens com MinHash/LSH e, separadamente, embeddings para gerar candidatos semânticos. Todo candidato precisa de regra de decisão registrada. Deduplicação antes de separar avaliação reduz memorização e vazamento; a literatura associa remoção de duplicatas a menor cópia literal, menos passos de treino e avaliação mais confiável.[9][10]
Renderizando diagrama...
Além da duplicação, pretendo fazer a QA medir por fonte: idioma previsto; caracteres corrompidos; proporção de entrada vazia; comprimento em caracteres e tokens; repetição interna; marcadores ingleses residuais; preservação de código; respostas vazias ou truncadas; solvabilidade sem recurso externo; correção de contas; consistência entre rótulo e opções; toxicidade; dados pessoais; e similaridade com benchmarks. Uma amostra humana estratificada por fonte, comprimento e tipo de tarefa deve classificar fidelidade da tradução, validade da instrução e utilidade da saída, reportando concordância entre anotadores e intervalos de confiança.
Escopo atual, licença e próximos passos
Criei o conjunto para ajuste supervisionado experimental de modelos em português, estudo de mistura de fontes e pesquisa sobre filtragem. Ele também serve como matéria-prima para uma versão menor e validada. Sem nova curadoria, não o recomendo como fonte de verdade factual, corpus médico/jurídico, benchmark de segurança ou avaliação imparcial. Modelos treinados nele podem reproduzir alucinações, anglicismos, vieses das fontes e políticas de resposta de GPT-3. A concentração de dados sintéticos não representa a diversidade social, regional e discursiva do português brasileiro.
Publiquei o conjunto sob CC BY-NC 4.0, permitindo compartilhamento e adaptação com atribuição, indicação de mudanças e uso não comercial. Adotei essa licença por causa das origens em gerações de modelos e das políticas da OpenAI.[1][11] Isso não resolve automaticamente toda a cadeia. alpaca-data-pt-br também declara CC BY-NC 4.0; os datasets H4 consultados declaram Apache-2.0; cahya/instructions-pt não declara licença em seu card. Licença de repositório, termos do serviço que gerou o conteúdo e direitos presentes em exemplos são camadas diferentes.
Para redistribuição ou treinamento, preserve atribuições, edições e datas de acesso de todas as fontes, documente modificações e não presuma autorização comercial. Dados pessoais, marcas, privacidade e outros direitos podem exigir permissões adicionais. Esta é uma leitura técnica dos artefatos, não aconselhamento jurídico.
Mantenho o Canarim-Instruct-PTBR como uma mistura ampla e acessível em português e como registro dos desafios que encontrei ao trabalhar com datasets sintéticos traduzidos. Para a próxima versão, meu objetivo não é apenas acrescentar linhas: pretendo publicar a receita, preservar proveniência por exemplo, medir a deduplicação, realizar avaliação humana e construir splits por grupos independentes. Essas são próximas etapas, não características da versão atual.
Referências
1. Domingues, M. Canarim-Instruct-PTBR-Dataset, DOI 10.57967/hf/0983: card, API, arquivos e amostras. Consulta em 24 jul. 2026.
2. Domingues, M. DominguesM/Canarim-Instruct-PTBR: README e ativo canarim.png, 2023.
3. Domingues, M. alpaca-data-pt-br; Taori, R. et al. Stanford Alpaca; Gururise. AlpacaDataCleaned, 2023.
4. Cahya. instructions-pt: card e arquivos, 2023.
5. Hugging Face H4. self_instruct: script de criação e arquivos, 2023.
6. Hugging Face H4. helpful_instructions: card e script do dataset, versão 1.0.0, 2023.
7. Wang, Y. et al. Self-Instruct: Aligning Language Models with Self-Generated Instructions. ACL 2023, arXiv:2212.10560.
8. Wang, Y. et al. Super-NaturalInstructions: Generalization via Declarative Instructions on 1600+ NLP Tasks. EMNLP 2022, p. 5085-5109, DOI 10.18653/v1/2022.emnlp-main.340.
9. Broder, A. Z. On the Resemblance and Containment of Documents. Compression and Complexity of SEQUENCES 1997, p. 21-29.
10. Lee, K. et al. Deduplicating Training Data Makes Language Models Better. ACL 2022, p. 8424-8445, DOI 10.18653/v1/2022.acl-long.577.
11. Creative Commons. Attribution-NonCommercial 4.0 International, texto resumido e código legal.
BibTeX
@dataset{domingues2023canarim_instruct,
author = {Maicon Domingues},
title = {Canarim-Instruct-PTBR-Dataset},
year = {2023},
publisher = {Hugging Face},
doi = {10.57967/hf/0983},
url = {https://huggingface.co/datasets/dominguesm/Canarim-Instruct-PTBR-Dataset}
}
@article{wang2023selfinstruct,
title = {Self-Instruct: Aligning Language Models with Self-Generated Instructions},
author = {Wang, Yizhong and Kordi, Yeganeh and Mishra, Swaroop and Liu, Alisa and Smith, Noah A. and Khashabi, Daniel and Hajishirzi, Hannaneh},
journal = {Proceedings of the 61st Annual Meeting of the Association for Computational Linguistics},
year = {2023},
eprint = {2212.10560},
archivePrefix = {arXiv},
url = {https://arxiv.org/abs/2212.10560}
}
@inproceedings{wang2022supernaturalinstructions,
title = {Super-NaturalInstructions: Generalization via Declarative Instructions on 1600+ NLP Tasks},
author = {Wang, Yizhong and Mishra, Swaroop and Alipoormolabashi, Pegah and others},
booktitle = {Proceedings of the 2022 Conference on Empirical Methods in Natural Language Processing},
year = {2022},
pages = {5085--5109},
doi = {10.18653/v1/2022.emnlp-main.340},
url = {https://aclanthology.org/2022.emnlp-main.340/}
}
@inproceedings{lee2022deduplicating,
title = {Deduplicating Training Data Makes Language Models Better},
author = {Lee, Katherine and Ippolito, Daphne and Nystrom, Andrew and Zhang, Chiyuan and Eck, Douglas and Callison-Burch, Chris and Carlini, Nicholas},
booktitle = {Proceedings of the 60th Annual Meeting of the Association for Computational Linguistics},
year = {2022},
pages = {8424--8445},
doi = {10.18653/v1/2022.acl-long.577},
url = {https://aclanthology.org/2022.acl-long.577/}
}