Para Onde Foram 99% do Meu Dataset

Eu me propus a construir um dataset com alguns milhões de exemplos de treinamento. Quando o pipeline terminou, ele me entregou um par de por cento disso — uma fração tão pequena que parecia um erro de digitação. Nada tinha quebrado. Nenhum erro tinha disparado. Os dados não falharam em ser gerados; eles silenciosamente jogaram quase tudo de si mesmos fora e, depois, reportaram sucesso.

O número que era pequeno demais para estar certo

A coisa estranha sobre esse tipo de bug é que ele não se anuncia. Um pipeline que quebra é barulhento. Um pipeline que silenciosamente produz pouco demais simplesmente termina, te entrega um arquivo e espera você perceber. Se eu não tivesse, por acaso, me lembrado de mais ou menos quantos exemplos eu esperava, talvez eu tivesse treinado sobre os sobreviventes e nunca soubesse que o resto havia sumido.

O único sintoma era uma contagem que estava errada por quase duas ordens de magnitude. E uma contagem errada é um dos sintomas mais fáceis do mundo de se passar batido, porque um número menor do que o esperado ainda parece um número real. Ele não dá a sensação de erro. Ele dá a sensação de resultado.

”Por que tem tão pouco?” é uma classe real de bug

Somos treinados para depurar coisas que quebram. Somos muito piores em depurar coisas que estão simplesmente ausentes — dados que deveriam existir e não existem, exemplos que deveriam ter sido criados e nunca foram. Não há stack trace para um caminho não percorrido. O pipeline fez exatamente o que eu mandei; só que aconteceu de aquilo que eu mandei descartar a maior parte da entrada pelo caminho.

Para onde os dados foram

A causa era quase constrangedoramente banal. Em algum ponto do processo, eu estava percorrendo a linha do tempo em passos largos — olhando para um momento, depois pulando um longo intervalo até o próximo, depois pulando de novo. Cada posição sobre a qual eu passava por cima era um exemplo em potencial que nunca foi examinado e nunca foi criado. Eu tinha definido aquele passo lá no começo, por uma razão da qual já não me lembro, e depois esqueci que ele estava ali.

Então o dataset não estava corrompido, nem filtrado, nem reduzido por limpeza. Ele simplesmente nunca tinha sido totalmente olhado. A esmagadora maioria dos dados disponíveis estava a um passo de distância da largura do laço, intocada, enquanto o pipeline marchava por cima dela e reportava que tinha terminado.

A perda silenciosa é o tipo perigoso

Esta é a parte à qual eu fico voltando. Uma falha barulhenta é um presente: ela te para, aponta para si mesma e exige atenção. Uma perda silenciosa não te dá nada disso. Ela produz uma saída que parece plausível, roda sem reclamar e silenciosamente muda a fundação sobre a qual tudo à jusante é construído. Você pode treinar um modelo, avaliá-lo e tirar conclusões dele, tudo em cima de um dataset que secretamente é um fragmento minúsculo e não representativo do que você pensava ter.

O perigo não é apenas que o número está errado. É que o número está errado e o sistema está feliz com isso — tudo verde, tudo rodando, tudo construído sobre uma base que te traiu logo no primeiro passo.

A correção: examine tudo, depois escolha o que manter

O reparo foi parar de pular. Em vez de cruzar a linha do tempo em passos largos e inspecionar apenas os pontos em que eu por acaso caía, fiz o processo considerar cada posição por vez — e então transformei a decisão sobre o que manter em um filtro explícito e deliberado, em vez de um subproduto acidental de um passo de amostragem. Os dados que descartei, agora eu descartei de propósito, por uma razão que eu conseguia dizer em voz alta. Os dados que mantive, mantive porque eu de fato tinha olhado para eles.

O dataset voltou a ficar próximo do tamanho que deveria ter. Nada de esperto fez isso acontecer. Eu simplesmente tinha parado de jogar dados fora sem querer.

A verificação mais barata no trabalho com dados

A lição é quase simples demais para parecer uma: compare o tamanho que você esperava com o tamanho que você obteve. É uma verificação de sanidade barata que eu vinha subutilizando feio, e ela teria pego isso em segundos. Uma grande diferença entre quantos dados eu achava que tinha e quantos dados de fato existem merece ser tratada como um bug — mesmo, especialmente, quando nada quebrou para te avisar.

Agora, a primeira coisa que faço com qualquer dataset não é olhar para o seu conteúdo. É olhar para a sua contagem e perguntar se aquele número é sequer plausível. Muitos dos piores problemas de dados que já tive não corromperam os dados. Eles apenas silenciosamente produziram menos do que eu acreditava e me deixaram construir sobre a diferença.

Um pipeline que perde a maior parte dos seus dados sem levantar a voz não está quebrando — está rodando exatamente como foi escrito, e ainda assim fazendo a coisa errada. O bug nunca foi uma falha na máquina. Ele estava na lacuna entre o que eu presumi e o que eu me dei ao trabalho de verificar.

— Sem sinais, sem retornos, isto não é aconselhamento de investimento.