Canarim BERT Nheengatu: decisões de desenvolvimento e uso responsável
Eu desenvolvi o dominguesm/canarim-bert-nheengatu como um encoder BERT publicado em dezembro de 2023 para nheengatu (yrl). O checkpoint expõe uma cabeça de masked language modeling (MLM) e a tarefa fill-mask: dado um contexto com [MASK], distribui probabilidade sobre tokens que poderiam ocupar a posição. Ele não é tradutor, chatbot, gramática normativa nem fonte de autoridade sobre a língua. Seu valor potencial está em oferecer representações contextuais para pesquisa e aplicações supervisionadas, como a variante posterior de etiquetagem de classes gramaticais [1][2].
No repositório GitHub, publiquei README, licença e imagens, mas não incluí o corpus, o código de preparação, o script de treinamento, os logs nem os checkpoints intermediários [1]. A arquitetura e a inferência permanecem verificáveis; para reproduzir o treinamento, uma próxima versão precisa incorporar esses materiais.
Ficha técnica
| Propriedade | Valor publicado ou calculado |
|---|---|
| Idioma declarado | Nheengatu, ISO 639-3 yrl |
| Tarefa | fill-mask / MLM |
| Classe | BertForMaskedLM |
| Encoder | 12 camadas, 12 cabeças por camada, dimensão oculta 768 |
| Camada intermediária | 3.072 dimensões, ativação GELU |
| Contexto máximo do modelo | 128 posições, com posições absolutas |
| Vocabulário na configuração | 32.768 entradas |
| Itens realmente publicados no tokenizer | 17.003, incluindo 5 especiais |
Parâmetros no safetensors | 110.946.560 em float32 |
| Dropout configurado | 0 para estados ocultos e probabilidades de atenção |
| Licença declarada | divergente: CC BY-SA 4.0 no GitHub; CC BY 4.0 no Hub |
O formato é semelhante ao BERT Base, mas não idêntico: o BERT Base original usava até 512 posições e vocabulário de 30.522 itens na versão inglesa uncased [7]. Aqui, 128 posições reduzem memória e custo quadrático da atenção, mas limitam o contexto a no máximo 126 tokens de conteúdo quando [CLS] e [SEP] são adicionados.
O checkpoint que publiquei soma 110.946.560 parâmetros. Embeddings somam 25.267.200; cada bloco encoder, 7.087.872; os 12 blocos, 85.054.464; transformação e viés da cabeça MLM, 624.896. A matriz de saída é compartilhada com os embeddings:
A língua e o que um corpus representa
O nheengatu descende do tupinambá, uma língua da família Tupi-Guarani, e desenvolveu-se historicamente como Língua Geral Amazônica em situações intensas de contato. Foi língua de comunicação entre povos indígenas distintos, colonizadores e seus descendentes; perdeu espaço para o português sobretudo no século XIX, mas permanece vivo principalmente no Alto Rio Negro brasileiro e na Colômbia, com presença residual na Venezuela [3][4]. A descrição de Cruz focaliza variedades faladas por povos Baré, Warekena e Baniwa; trabalhos de Avila, Navarro e CompLin registram também léxico, ortografias e processos contemporâneos de ensino e revitalização [3][5][6].
“Nheengatu”, portanto, não designa um texto uniforme. Há variação regional, geracional e ortográfica, além de uma documentação escrita que atravessa séculos. Impressos missionários, vocabulários oitocentistas, transcrições de fala, literatura, gramáticas, dicionários e uma tradução constitucional contemporânea respondem a finalidades e relações de poder diferentes. Misturá-los pode ampliar cobertura histórica, mas também pode fazer o modelo tratar grafias antigas, português, linguagem religiosa e variedades específicas como se fossem uma única distribuição atual.
Um modelo treinado em publicações disponíveis não representa automaticamente todas as comunidades falantes. A própria abundância documental é seletiva: escrita publicada tende a favorecer instituições, autores e gêneros que tiveram meios de registro. Material oral, uso cotidiano, variedades locais e conhecimento que não deve circular fora de seu contexto podem estar ausentes por boas razões. Cobertura técnica e legitimidade comunitária são dimensões distintas.
Como reuni o corpus de treinamento
Reuni textos de livros, artigos e sites, preparei o material e publiquei a mesma bibliografia nos cards em inglês e português [2]. A lista reúne mais de quarenta referências, mas na primeira versão não associei cada fonte a páginas, trechos, contagens de tokens, variedade ou papel no corpus.
| Grupo de fontes | Exemplos que citei | Questão de proveniência |
|---|---|---|
| Registros históricos e missionários | Faria (1858), Magalhães (1876), Costa (1898), Hartt, Rodrigues, Platzmann | grafias históricas, OCR e contexto colonial |
| Lendas, mitos e literatura | Amorim, Leggenda dell'Jurupary, Orico, Brilhos na floresta, Jaguanhenhém | autoria, tradução, direitos e possível conteúdo cultural sensível |
| Gramáticas e estudos linguísticos | Moore, Facundes e Pires (1994), Cruz (2011), Rodrigues e Cabral (2011) | exemplos citados não equivalem ao texto integral da língua |
| Dicionários e vocabulários | Ayrosa, Mello, Masucci, Barros e Lessa, Muller et al. (2019) | pares bilíngues e verbetes não têm distribuição de prosa contínua |
| Texto público contemporâneo | Constituição brasileira em nheengatu (2023) | domínio jurídico e forte repetição terminológica |
| Estudos sobre tupi e línguas gerais | obras sobre “língua brasílica”, tupi antigo e história linguística | língua, período e variedade precisam ser identificados por item |
Publiquei a lista como inventário bibliográfico, não como manifesto de dados. Na versão inicial, não registrei identificador de arquivo, edição, URL estável, licença por fonte, responsável pela extração, comunidade relacionada, intervalo de páginas, modalidade, variedade, data, método de OCR, contagem e regra de inclusão. Também não registrei proporções de português e outros idiomas, deduplicação entre reedições, separação entre treino e avaliação e permissões. Com esse registro, hoje não consigo calcular o tamanho do corpus nem reproduzir o treinamento.
No GitHub, publiquei dois arquivos de logotipo que apontam para o mesmo objeto binário e três imagens com curvas e matriz de confusão do modelo POS posterior; não preservei uma curva de MLM. Apliquei CC BY-SA 4.0 ao repositório, mas essa licença não relicencia automaticamente cada texto-fonte [1].
Renderizando diagrama...
A escolha do WordPiece e a limitação das normalizações
WordPiece divide uma forma em unidades de vocabulário; continuações recebem o prefixo ##. Isso permite representar palavras não memorizadas por combinações menores e compartilhar parâmetros entre formas relacionadas. O custo é que uma palavra pode ocupar várias posições. Em línguas com poucos dados, um tokenizer especializado pode reduzir essa fragmentação, mas isso precisa ser medido: Rust et al. encontraram associação entre adequação do vocabulário, fertilidade e desempenho downstream em comparações controladas [8].
Configurei BertPreTokenizer, WordPiece, [UNK], prefixo ## e limite de 100 caracteres por palavra. No normalizador serializado, incluí duas substituições: conversão de pares de aspas graves ou apóstrofos em aspas duplas e redução de dois ou mais espaços a um. Também mantive do_lower_case: true e strip_accents: null na configuração de carregamento [2].
Deixei uma divergência entre as duas configurações: solicitei conversão para minúsculas em tokenizer_config.json, mas não incluí essa operação na sequência de normalização de tokenizer.json. O comportamento pode variar conforme a versão e o carregador usados, sobretudo no tratamento de caixa, acentos e aspas. Na versão inicial, não preservei um script que identifique qual caminho usei durante o treino.[2]
Também deixei uma incompatibilidade dimensional: configurei 32.768 embeddings, mas publiquei 17.003 itens em vocab.txt e tokenizer.json. Assim, 15.765 IDs, equivalentes a 12.107.520 posições escalares na matriz de embeddings, não são emitidos pelo tokenizer; se a cabeça MLM selecionar um deles, não haverá peça correspondente para decodificá-lo fielmente. Não preservei se usei um vocabulário maior no treino, removi itens depois ou apenas superdimensionei a configuração.
Este código torna as divergências visíveis antes de qualquer experimento:
from transformers import AutoConfig, AutoTokenizer
MODEL = "dominguesm/canarim-bert-nheengatu"
tokenizer = AutoTokenizer.from_pretrained(MODEL)
config = AutoConfig.from_pretrained(MODEL)
print(type(tokenizer).__name__, tokenizer.is_fast)
print(tokenizer.backend_tokenizer.normalizer)
print(tokenizer.tokenize("Aé urikú takuwa yawé."))
print("tokenizer:", len(tokenizer), "embeddings:", config.vocab_size)
assert config.max_position_embeddings == 128Não normalize acentos, caixa ou grafia por conta própria sem protocolo linguístico. Compare explicitamente NFC e NFD, grafia de Avila, variantes históricas e formas usadas por cada comunidade; guarde tanto o original quanto a transformação, nunca apenas o texto sobrescrito.
Como defini o pré-treinamento MLM
Treinei e publiquei o checkpoint como BertForMaskedLM. Para um conjunto M de posições avaliadas, token original x_i e representação contextual h_i, a perda é a entropia cruzada média nessas posições:
O BERT original selecionava 15% dos tokens; entre os selecionados, substituía 80% por [MASK], 10% por token aleatório e mantinha 10% inalterados. Também treinava next sentence prediction [7]. Esses são fatos sobre o BERT original, não sobre esta execução. Na primeira publicação do Canarim, não registrei probabilidade ou estratégia de máscara, whole-word masking, uso de NSP, tamanho e sobreposição dos blocos, lote, épocas, passos, otimizador, taxa de aprendizado, scheduler, semente, hardware, perdas ou conjunto de validação [1][2]. Dropout zero e comprimento 128 pertencem à configuração final, mas não descrevem todo o treino.
Hoje consigo reproduzir a inferência com a versão pública, mas ainda não o pré-treinamento completo nem o caminho corpus-tokenizer-pesos. Sem esse registro, também não atribuo uma mudança de qualidade a uma decisão específica.
Uso correto de fill-mask
No exemplo que publiquei, ocultei o conectivo de “Aé urikú takuwa yawé resewara ti usú upinaitika.” e apresentei a glosa “Ele tinha febre, por isso não foi pescar”. O modelo atribuiu 0,4123 a tẽ e 0,1178 a resewara; candidatos seguintes tiveram probabilidades bem menores [2]. Esse resultado mostra associação contextual aprendida, não tradução correta nem juízo de gramaticalidade. A soma exibida do top_k não precisa ser um, pois o restante da massa está nos demais tokens.
from transformers import pipeline
MODEL = "dominguesm/canarim-bert-nheengatu"
preencher = pipeline(
"fill-mask",
model=MODEL,
tokenizer=MODEL,
top_k=5,
)
texto = "Aé urikú takuwa yawé [MASK] ti usú upinaitika."
for candidato in preencher(texto):
print(candidato["token_str"], f'{candidato["score"]:.4f}')Use exatamente [MASK], mantenha a entrada dentro de 128 posições e registre a versão do Transformers, o normalizador, os tokens e a data de acesso ao modelo. Peça revisão de falantes para interpretar resultados. Um token frequente pode ser provável e ainda ser inadequado para a variedade, gênero, intenção ou situação cultural.
Relação com Universal Dependencies e POS
O UD_Nheengatu-CompLin é outro projeto: um treebank morfossintático construído a partir de fontes publicadas, fala espontânea, gramáticas, fábulas, mitos, cursos e dicionários. As sentenças foram extraídas de PDFs, transcritas de imagens ou convertidas de transcrição fonética para uma ortografia baseada em Avila. O analisador baseado em regras Yauti produziu análises iniciais, revisadas manualmente [9][10]. Essa proveniência é melhor documentada, mas não me permite concluir que o treebank inteiro integrou o MLM.
Depois, usei o encoder e o tokenizer deste modelo no canarim-bert-postag-nheengatu, ajustando uma cabeça BertForTokenClassification em uma cópia do UD dividida em 1.068/134/134 sentenças [11]. No teste de 1.353 tokens, obtive F1 micro 0,9202, macro 0,8293 e ponderado 0,9187. Classes frequentes tiveram resultados altos; PROPN obteve F1 0,5143 em 21 exemplos e INTJ, 0,5000 em quatro. O macro F1 evidencia melhor essa fragilidade que a acurácia dominada por classes comuns e pontuação.
Os números são do ajuste POS, não do MLM isolado. Não conduzi baseline com pesos aleatórios, BERT multilíngue ou ablação de tokenizer; logo, não medi quanto o pré-treinamento contribuiu. No Hub, rotulei tecnicamente a tarefa como NER e usei etiquetas B-ADJ etc., embora semanticamente seja POS. Também deixei uma divergência de licença: CC BY-NC 4.0 nos metadados e CC BY-NC-SA 4.0 no texto, seguindo o treebank.
O UD é evolutivo. A versão 2.14, posterior ao ajuste, já tinha 1.470 sentenças; a versão 2.18 tem 2.839 sentenças, 26.444 tokens de superfície e outra divisão.[9] Usei um recorte anterior de 1.336 sentenças e não preservei publicamente sua composição exata. Em uma nova execução, pretendo fixar a release do UD e publicar os índices permitidos dos splits.
Renderizando diagrama...
Roteiro de validação para a próxima versão
Uma avaliação útil deve publicar os dados permitidos, a origem por sentença e intervalos de confiança, além de impedir que a mesma obra ou reedição apareça em treino e teste.
Fertilidade. Para palavras ortográficas , conte quantos WordPieces cada uma produz:
Reporte média, mediana, p95 e distribuição por fonte, época, variedade, gênero, caixa e ortografia. Compare o tokenizer publicado com mBERT e tokenizers treinados somente no conjunto de treino, mantendo o texto igual. Fertilidade menor economiza posições, mas não me permite concluir melhor análise morfológica.
Cobertura. Meça 1 - palavras_com_UNK / N, cobertura de caracteres e proporção de sentenças sem [UNK]. Separe formas acentuadas, decomposição Unicode, hífens, clíticos, nomes próprios, empréstimos e grafias históricas. Compare também o tokenizer rápido com o carregamento literal de tokenizer.json. Os 17.003 itens contra 32.768 embeddings devem aparecer no relatório, não ser ocultados por uma taxa de [UNK] favorável.
MLM e pseudo-perplexidade. Perplexidade autoregressiva não é bem definida para BERT. Para cada sequência de teste, pode-se mascarar um token por vez e calcular pseudo-log-verossimilhança e pseudo-perplexidade [12]:
Use as mesmas posições elegíveis, contexto e política de normalização; agregue por documento, não só por token. Como a PPPL depende da tokenização, não compare números crus entre vocabulários diferentes. Acrescente perda por palavra e por caractere, bootstrap por obra e conjuntos separados por fonte, período e comunidade. Um teste realmente externo deve vir de fonte não usada na bibliografia de treino e ter autorização compatível.
POS extrínseco. Refaça o ajuste com ao menos cinco sementes e compare: encoder congelado, encoder completo, inicialização aleatória de mesma arquitetura, mBERT e ablação do pré-treinamento. Use validação cruzada agrupada por obra para evitar memorização de estilo. Publique macro F1, F1 por classe, matriz de confusão e desempenho por variedade; documente como rótulos de palavra são alinhados a subpalavras. A avaliação deve ser cocriada com falantes, incluindo critérios de utilidade que uma métrica UD não captura.
Limitações iniciais, licenças e governança indígena
Representatividade e dano. A mistura temporal e genérica pode privilegiar linguagem colonial, missionária, jurídica ou lexicográfica. O modelo pode reproduzir estereótipos, associações religiosas e formas ofensivas, ou completar narrativas sensíveis fora do contexto. Também pode memorizar trechos raros. Não o use para validar identidade, substituir professores e tradutores, decidir grafia “correta”, atribuir autoria ou publicar conhecimento restrito.
Limites técnicos. Contexto de 128, dropout zero, normalizadores conflitantes e diferença entre tokenizer e matriz de embeddings exigem testes. Não publiquei resultados MLM, baseline, avaliação por variedade, teste de memorização ou estimativa de incerteza. Escores fill-mask não são calibrados para decisões e não medem verdade.
Licenças. No arquivo LICENSE e no README do GitHub, publiquei CC BY-SA 4.0; no frontmatter dos dois cards do Hub, publiquei CC BY 4.0 [1][2]. Como deixei essa divergência, recomendo registrá-la e adotar a interpretação compatível mais conservadora até que eu a corrija. Pesos, código, tokenizer, textos-fonte e saídas são camadas jurídicas distintas. A licença do artefato não elimina direitos autorais dos autores, direitos coletivos, privacidade, termos de acervo ou protocolos comunitários.
Os princípios CARE complementam a abertura técnica com Benefício Coletivo, Autoridade para Controlar, Responsabilidade e Ética [13]. Aplicá-los aqui requer ações verificáveis:
| Princípio | Aplicação ao projeto |
|---|---|
| Benefício Coletivo | definir usos com comunidades; financiar ferramentas locais, ensino, infraestrutura e formação; medir benefícios decididos por falantes |
| Autoridade para Controlar | participação decisória sobre coleta, acesso, treino, redistribuição, usos futuros e retirada; protocolos específicos por povo e coleção |
| Responsabilidade | manter relações de longo prazo, atribuir autores e comunidades, devolver dados e resultados em formatos úteis e fortalecer capacidade local |
| Ética | avaliação comunitária de benefícios e danos durante todo o ciclo; proteção de narrativas, pessoas e conhecimentos sensíveis; mecanismo público de contestação |
Não registrei nos cards evidência de consulta, consentimento coletivo, repartição de benefícios, governança compartilhada ou procedimento de remoção. Isso não me permite concluir ausência fora do repositório; delimita apenas o que documentei. Em uma próxima versão, pretendo constituir conselho comunitário remunerado, produzir datasheet por fonte, usar níveis de acesso quando abertura for inadequada, publicar contato e prazo para retirada, e versionar exclusões também nos derivados. “Disponível online” não significa livre para treinamento irrestrito.
Reprodutibilidade mínima
Hoje consigo reproduzir a inferência com a versão pública, mas ainda não o treinamento. Em uma próxima publicação, pretendo acrescentar: manifesto fonte-trecho-licença-permissão; variedade, gênero e autoria; arquivos de origem; texto original e transformações reversíveis; OCR e taxa de erro; deduplicação; splits agrupados por obra; código e ambiente; construção exata do WordPiece; reconciliação entre 17.003 e 32.768; máscara MLM, hiperparâmetros, sementes e hardware; curvas de treino; avaliação externa; modelo de governança CARE; e histórico de consentimento, restrição e retirada.
Apresento o Canarim BERT Nheengatu como um artefato raro e potencialmente útil, não como uma documentação completa da língua. Para fortalecer seu uso científico, procuro tratar arquitetura, tokenizer e resultados com precisão; para orientar seu uso social, considero indispensável que falantes e povos relacionados tenham autoridade real sobre dados, finalidades e benefícios.
Referências
- Domingues, M. Canarim-Bert-Nheengatu: README, assets e licença. GitHub, 2023–2024. Repositório.
- Domingues, M. Canarim-Bert-Nheengatu: cards em inglês e português, configuração, tokenizer e pesos. Hugging Face, 2023. Modelo e arquivos.
- Alencar, L. F. Nheengatu. CompLin, 2022. Descrição e referências.
- Moore, D.; Facundes, S.; Pires, N. Nheengatu (Língua Geral Amazônica), its History, and the Effects of Language Contact. UC Berkeley, 1994. eScholarship.
- Cruz, A. Fonologia e gramática do nheengatú: a língua falada pelos povos Baré, Warekena e Baniwa. LOT, 2011. PDF.
- Avila, M. T. Proposta de dicionário nheengatu-português. Tese de doutorado, USP, 2021. DOI.
- Devlin, J. et al. BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding. NAACL-HLT, 2019. ACL Anthology.
- Rust, P. et al. How Good is Your Tokenizer? On the Monolingual Performance of Multilingual Language Models. ACL-IJCNLP, 2021. ACL Anthology.
- de Alencar, L. F. A Universal Dependencies Treebank for Nheengatu. PROPOR, 2024. ACL Anthology; ver também o treebank.
- de Alencar, L. F. Yauti: A Tool for Morphosyntactic Analysis of Nheengatu within the Universal Dependencies Framework. STIL, 2023. DOI.
- Domingues, M. Canarim-Bert-PosTag-Nheengatu. Hugging Face, 2023. Modelo.
- Salazar, J. et al. Masked Language Model Scoring. ACL, 2020. ACL Anthology.
- Carroll, S. R. et al. The CARE Principles for Indigenous Data Governance. Data Science Journal, 19:43, 2020. DOI.
BibTeX
@misc{domingues2023canarimbert,
author = {Domingues, Maicon},
title = {Canarim-Bert-Nheengatu},
year = {2023},
howpublished = {Hugging Face and GitHub},
url = {https://huggingface.co/dominguesm/canarim-bert-nheengatu}
}
@inproceedings{devlin2019bert,
author = {Devlin, Jacob and Chang, Ming-Wei and Lee, Kenton and Toutanova, Kristina},
title = {BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding},
booktitle = {Proceedings of NAACL-HLT},
pages = {4171--4186},
year = {2019},
doi = {10.18653/v1/N19-1423}
}
@inproceedings{rust2021tokenizer,
author = {Rust, Phillip and Pfeiffer, Jonas and Vuli{\'c}, Ivan and Ruder, Sebastian and Gurevych, Iryna},
title = {How Good is Your Tokenizer? On the Monolingual Performance of Multilingual Language Models},
booktitle = {Proceedings of ACL-IJCNLP},
pages = {3118--3135},
year = {2021},
doi = {10.18653/v1/2021.acl-long.243}
}
@inproceedings{alencar2024treebank,
author = {de Alencar, Leonel Figueiredo},
title = {A Universal Dependencies Treebank for Nheengatu},
booktitle = {Proceedings of PROPOR 2024},
volume = {2},
pages = {37--54},
year = {2024},
url = {https://aclanthology.org/2024.propor-2.8/}
}
@inproceedings{alencar2023yauti,
author = {de Alencar, Leonel Figueiredo},
title = {Yauti: A Tool for Morphosyntactic Analysis of Nheengatu within the Universal Dependencies Framework},
booktitle = {Anais do XIV STIL},
pages = {135--145},
year = {2023},
doi = {10.5753/stil.2023.234131}
}
@inproceedings{salazar2020mlmscoring,
author = {Salazar, Julian and Liang, Davis and Nguyen, Toan Q. and Kirchhoff, Katrin},
title = {Masked Language Model Scoring},
booktitle = {Proceedings of the 58th ACL},
pages = {2699--2712},
year = {2020},
doi = {10.18653/v1/2020.acl-main.240}
}
@article{carroll2020care,
author = {Carroll, Stephanie Russo and others},
title = {The CARE Principles for Indigenous Data Governance},
journal = {Data Science Journal},
volume = {19},
pages = {43},
year = {2020},
doi = {10.5334/dsj-2020-043}
}
@phdthesis{avila2021dicionario,
author = {Avila, Marcel Twardowsky},
title = {Proposta de dicionário nheengatu-português},
school = {Universidade de São Paulo},
year = {2021},
doi = {10.11606/T.8.2021.tde-10012022-201925}
}