As regras que tornam uma comparação legítima, e o catálogo completo dos enganos deste projeto — inclusive os que só apareceram porque alguém perguntou "comparado com o quê?".
Registrar só o que deu certo distorceria a leitura de tudo o que vem depois. E há também uma razão prática: metade das melhores decisões deste projeto veio de descobrir que estávamos errados. O regularizador de cosseno existe porque uma busca semântica falhou. A métrica de piso da Bússola (a primeira versão do leme, que só previa a direção do próximo estado; no código, compass) existe porque uma medida bonita se revelou vazia.
Esta apostila registra as regras e os erros. Quem repetir o projeto vai errar diferente — mas o tipo de erro se repete.
Toda comparação usa o mesmo treino.bin, o mesmo número de passos, o mesmo lote e a mesma semente 1337. O corpus do duelo está congelado em model/data/duelo_200mb/, com hash conferido.
E o script de empacotamento recusa sobrescrever dados existentes:
PARADO — ja existe um conjunto de dados aqui
treino.bin 115.1 MB
Sobrescrever isso quebra a comparabilidade com todo treino ja feito.
Sem essa trava, um corpus trocado no meio de uma série invalidaria tudo em silêncio — os números continuariam saindo, só não significariam mais a mesma coisa.
A validação oscila entre avaliações. No duelo, o modelo clássico piorou entre os passos 649 e 699 sem nenhuma causa real. Comparar o último passo de cada rodada compara ruído.
mini-moderno-reg1-lat1-duelo é feio e é certo: tamanho, arquitetura, regularizador, bússola, rodada. Seis meses depois, a pergunta "o que tinha nessa rodada?" se responde pelo rótulo, não pela memória.
O relatório detecta rodadas que não gastaram o mesmo orçamento e escreve PARCIAL no lugar da diferença percentual. Uma rodada parada no passo 100 contra outras de 700 mostraria um número enorme que não diz nada.
Esta regra nasceu de um erro, contado na seção 4. Um número sozinho não significa nada: 0,534 é excelente ou é nada, dependendo do piso.
| Erro | Consequência | Como foi pego |
|---|---|---|
| Centrar os dados no SigReg | o cone pontuava melhor que a gaussiana | teste sintético com resposta conhecida |
| Reportar a Bússola sem piso | ganho de +0,07 apresentado como +0,53 | perguntar "comparado com o quê?" |
| "O clássico começou a sobreajustar" | diagnóstico impossível | 0,09 época — nenhum token visto 2× |
| "Tokens mortos vão poluir o top-50" | hipótese plausível, não confirmada | medir em 6 prompts: 0 de 1,44 esperados |
| Comparar com o controle errado | −1,27% virou +1,06% ao trocar a base | montar a tabela com as duas colunas |
| "A perda latente é gratuita" | afirmado no passo 249; era +1,41% | melhor contra melhor, no fim |
open(arquivo, "w") no corpus | 60 MB de código apagados por erro em outra fonte | o arquivo virou 0 bytes |
| Cache de modelos sem teto | servidor morto, os error 1455 | a memória virtual encheu |
gerar_pdfs apontando para pasta renomeada | geração quebrada em silêncio | tentar gerar a coleção nova |
| Script de treino sem suporte a GPU | pagaria a placa por hora para treinar em CPU | ler o código antes de alugar |
| Tokenizar documento a documento | 178 min em vez de 22, para 8 GB | medir antes de rodar na nuvem |
Contado na apostila 03, mas vale a forma geral. A linha era:
Z = Z - Z.mean(0, keepdim=True) # "normalizar"
Uma normalização de rotina. Só que a anisotropia que queríamos medir é um deslocamento da origem — e centrar remove deslocamentos. O instrumento apagava o sinal antes de medi-lo.
O treino não reclamava: a perda descia, o modelo aprendia. O erro só apareceu ao rodar o medidor contra distribuições cuja resposta certa já sabíamos.
A Bússola prevê a direção do próximo estado. Medimos o cosseno entre a previsão e o alvo real: 0,534. Reportamos, por várias rodadas, como "0,534 contra ~0,00 do acaso".
Até alguém perguntar quanto daria sem preditor nenhum — só copiando o estado atual:
| Referência | Cosseno |
|---|---|
| cos( | 0,478 |
| cos( | 0,461 |
| alvo embaralhado — acaso verdadeiro | 0,206 |
| a Bússola rasa | 0,534 |
E o acaso nunca foi 0,00 — é 0,206, porque os próprios estados ocultos têm anisotropia residual. A Bússola rasa aprendia quase nada além de copiar a entrada, e cobrava 1,41% de qualidade por isso.
Os números vinham dizendo isso o tempo todo. Estavam escondidos atrás de uma métrica sem referência.
A correção foi estrutural, não editorial: o piso agora é calculado dentro do laço de treino e impresso ao lado da métrica, sempre. Não dá mais para reportar um sem o outro.
bussola 0.064 (piso 0.598 ganho -0.534)
Essa linha é de um modelo recém-inicializado: a bússola é pior que copiar o estado atual. Exatamente o que a métrica antiga esconderia.
A validação do modelo clássico subiu no fim do duelo. "Começou a sobreajustar" é a leitura automática — e era impossível: 700 passos × 8 192 tokens = 5,7 M de tokens num corpus de 60,3 M. 0,09 época. Nenhum token foi visto duas vezes.
A lição não é sobre sobreajuste. É que a explicação mais familiar chega primeiro, e às vezes a aritmética a descarta em dez segundos.
Por três avisos seguidos, comparei a rodada com bússola contra mini-moderno-duelo — o modelo sem regularizador. O controle correto era mini-moderno-reg1, que difere apenas pela bússola.
| Passo | vs sem-reg | vs reg1 (correto) |
|---|---|---|
| 99 | +0,04% | −1,27% |
| 149 | +0,85% | +1,06% |
| 199 | −0,30% | −0,69% |
Nenhuma conclusão final mudou, mas três relatos intermediários estavam errados. Montar a tabela com as duas colunas lado a lado tornou o engano óbvio — o que não era, olhando um número por vez.
Três dos itens do catálogo não são de método: são de engenharia. O que os une é que nenhum deles falha — o programa roda, devolve números, e só a placa sabe que algo está errado.
| Problema | Efeito na placa |
|---|---|
| O script de treino nunca move o modelo para a GPU | a placa fica ociosa e o treino roda em CPU, sem erro nenhum |
| Tokenização documento a documento num corpus grande | o pré-processamento domina o tempo antes do primeiro passo |
| Checkpoints salvos com tensores CUDA | pesos que não recarregam em máquina sem GPU |
Os três foram encontrados pelo mesmo gesto: ler o código que ia rodar, antes de rodá-lo. Nenhum apareceria em teste local — na CPU tudo funciona, só devagar.
A ideia central — um preditor latente que também serve de leme na geração — continua de pé. O que estas páginas mostram é que ela passou por um método feito justamente para encontrar seus pontos fracos.
Se a Bússola rasa entrega pouco, isso está escrito. Se a profunda entregar, o número virá com piso, com controle e com custo declarado. É o que torna a afirmação digna de crédito.
Com o método declarado, a apostila 07 faz a conta que decide o próximo passo:
quanto custa, de verdade, chegar à escala do GPT-3 — e por que o limite não é a placa.