Como os LLMs são treinados: tokenização, backpropagation e gradiente descendente
Treinar um LLM não é ensinar fatos, é treinar o modelo a prever uma palavra de cada vez. O texto cru vira uma sequência de tokens, cada um vira um embedding (um vetor denso treinado como qualquer outro peso), e a cada posição o modelo gera uma previsão do próximo token. O erro é medido pela entropia cruzada; o backpropagation propaga esse erro para trás, calculando o gradiente em relação a cada peso, incluindo as matrizes , , da atenção; e o otimizador (AdamW, que combina momentum e taxa adaptativa por parâmetro) ajusta os pesos aos poucos. O processo se repete em mini-batches por milhões de passos, até que a loss de validação pare de cair. O resultado não é conhecimento declarativo nos pesos, mas padrões estatísticos de linguagem: sintaxe, semântica, estilos e fatos capturados como co-ocorrências.
Antes de o ChatGPT responder qualquer coisa, ele passou por um processo que consumiu milhares de GPUs, semanas de treino e um dataset que caberia em centenas de discos rígidos. Mas a operação central desse processo é simples, quase infantil: dada uma sequência, qual a próxima palavra?
Parece improvável que uma tarefa tão banal produza um sistema que conversa, traduz e escreve código. Mas é ela, repetida bilhões de vezes, que grava nos pesos do modelo os padrões estatísticos da linguagem: a sintaxe, a semântica, os estilos, os fatos, os truques de raciocínio. O que o modelo "sabe" não está num banco de dados interno, e sim nos valores numéricos que ele aprendeu a calcular para reduzir o erro de previsão a cada token.
Este post percorre o caminho completo: como o texto cru vira exemplos numéricos, como o modelo calcula uma saída, como o erro é medido, como ele volta pelos parâmetros, e como o otimizador corrige os pesos, passo a passo, até o treino parar. Ao fim, fica claro por que treinar um LLM é um problema de compressão estatística, não de ensino direto.
O que treinar um LLM realmente quer dizer
Treinar um LLM (Large Language Model) é ajustar os pesos de uma rede neural para que ela minimize o erro ao prever o próximo token de uma sequência. A frase anterior contém três termos que merecem uma definição breve. Os pesos são os parâmetros numéricos do modelo, matrizes que transformam a entrada camada por camada; são o que o modelo aprende. O token é a unidade mínima de texto com que o modelo trabalha (pode ser uma palavra, um pedaço de palavra ou um caractere); o modelo não enxerga letras, e sim números que representam tokens. E prever o próximo token é a tarefa: dado um contexto, qual o token mais provável de vir a seguir?
Não há nenhuma etapa explícita de "ensinar" fatos. O modelo não lê uma enciclopédia e extrai conhecimento. Ele processa bilhões de exemplos do tipo "dado o contexto X, qual o token Y?" e ajusta os pesos para acertar cada vez mais. Se o texto de treino contém muitos parágrafos sobre a Revolução Francesa, o modelo aprenderá a associar "Revolução Francesa" a "1789" porque essa co-ocorrência reduz o erro de previsão. Mas ele não "sabe" o que é uma revolução: capturou um padrão estatístico que, com sorte, generaliza para perguntas novas.
Treinar um LLM não é ensinar fatos. É ajustar pesos para prever a próxima palavra, repetido bilhões de vezes, até que o erro de previsão seja o menor possível.
Do texto cru aos exemplos de previsão: tokenização e embedding na prática
Pegue a frase "o gato subiu no telhado". O primeiro passo é a tokenização: transformar essa sequência de caracteres numa sequência de tokens numéricos. A tokenização divide o texto em unidades que o modelo consegue processar, usando regras pré-definidas (como o BPE do GPT-2). Palavras curtas viram um token cada; palavras longas podem ser quebradas. A frase vira algo como ["o", " gato", " subiu", " no", " telhado"], cada um mapeado para um número inteiro. Esse mapeamento é fixo e forma o vocabulário do modelo.
Depois, esses números viram embeddings: vetores densos que representam o significado do token num espaço contínuo, onde similaridade semântica corresponde a proximidade geométrica. O embedding não é aprendido manualmente, ele é uma lookup table (uma matriz onde cada linha é o vetor de um token), e essa matriz também é um peso ajustado pelo backpropagation durante o treino, exatamente como qualquer outra camada do modelo. Se "gato" e "felino" aparecem em contextos parecidos, seus embeddings vão convergir para direções próximas no espaço.
Com a sequência tokenizada e convertida em embeddings, o modelo gera exemplos de treino da seguinte forma: para cada posição da frase, o contexto é tudo que veio antes, e o target é o token atual. Para a frase de exemplo, os pares são: "o" → "gato"; "o gato" → "subiu"; "o gato subiu" → "no"; "o gato subiu no" → "telhado". Cada exemplo é usado uma vez. A ordem importa: o modelo nunca vê o futuro, só o passado, e é assim que ele aprende causalidade linguística. Esse processo produz um número de exemplos igual ao número de tokens do corpus menos um.
Como o modelo transforma contexto em probabilidades de tokens
Dado o contexto convertido em embeddings, o modelo, uma pilha de camadas de self-attention e redes feedforward, processa a sequência e produz um vetor de logits para cada posição. Cada logit é um número real bruto associado a um token do vocabulário; quanto maior o logit, mais forte a evidência para aquele token. Mas logits não são probabilidades, porque podem ser negativos e não somam 1.
A transformação de logits em probabilidades é feita pela função softmax: ela eleva cada logit à exponencial e divide pela soma de todas as exponenciais, produzindo uma distribuição de probabilidade sobre o vocabulário inteiro. O softmax garante que valores mais altos virem probabilidades maiores, mas também torna explícita a competição entre tokens: se um token ganha, os outros perdem na mesma proporção.
Para o contexto "o gato subiu", o modelo deve atribuir alta probabilidade a tokens como "no", "em", "para" e baixa a tokens como "banana" ou "computador". A qualidade da previsão depende de quão bem os pesos foram ajustados até ali. A saída final é, portanto, uma distribuição que o modelo acredita ser a mais provável; o que falta é medir o quão longe ela está da distribuição real (que é um pico só no token correto).
Como a entropia cruzada mede o erro, token por token
A função que mede o erro entre a previsão e o real se chama entropia cruzada (cross-entropy). Para um único exemplo, o contexto "o gato subiu" e o target "no", ela vale , onde é a probabilidade que o modelo atribuiu ao token "no". Se o modelo está confiante e certo (), a perda é baixa, cerca de 0,1; se ele atribui probabilidade baixa (), a perda é alta, 6,9. O logaritmo natural (ln) é usado porque ele penaliza muito mais erros confiantes: a diferença entre e parece pequena na probabilidade, mas na loss a diferença é de 2,3 para 0,1.
A loss (função de perda) é simplesmente o nome que se dá a esse valor de erro. Uma loss alta significa que o modelo deu probabilidade baixa ao token correto; uma loss baixa significa que ele deu probabilidade alta. Reduzir a loss equivale a ajustar os pesos para que, da próxima vez, a distribuição de probabilidade produzida pelo modelo atribua mais peso ao token certo.
Para uma sequência inteira, a loss total é a soma das entropias cruzadas de cada posição, geralmente dividida pelo número de tokens (a média). O objetivo do treino é minimizar essa média sobre todos os exemplos. Reduzir a loss a zero exigiria que o modelo atribuísse probabilidade 1 ao token certo em toda posição, o que é impossível para linguagem natural (muitas sequências são genuinamente ambíguas). Por isso a loss nunca zera; ela converge para um valor chamado perplexidade (), que indica quantas alternativas o modelo considera, em média, para cada token. Uma perplexidade de 10 significa que, em média, o modelo considera cerca de 10 tokens como candidatos igualmente plausíveis em cada posição.
Backpropagation: como o erro viaja da saída até , e
A loss calculada é um escalar. Agora precisamos descobrir quais pesos ajustar para reduzi-la. O backpropagation (retropropagação) calcula, para cada peso do modelo, a derivada parcial da loss em relação àquele peso, ou seja, o gradiente local. O gradiente é um vetor que aponta na direção de maior aumento da loss; por isso, andar na direção oposta a ele (subtraindo uma fração do gradiente) é o que reduz a loss. Cada derivada parcial indica, em termos numéricos, o quanto uma pequena mudança naquele peso afetaria a loss. Se o gradiente de um peso é grande, significa que aquele peso tem forte influência no erro.
O nome "backpropagation" vem do fato de que o cálculo começa na saída (onde a loss é conhecida) e vai "para trás", camada por camada, aplicando a regra da cadeia do cálculo diferencial.
A regra da cadeia diz: se a loss depende da saída da camada, e a saída da camada depende do peso , então . O primeiro termo, , é o gradiente que vem da camada seguinte; o segundo, , é calculado localmente a partir das ativações armazenadas na passagem direta.
Vale a pena ver isso em ação para uma camada de atenção. Suponha que a saída da atenção é , onde , , . O gradiente é obtido assim: primeiro, o gradiente chega da camada seguinte. A regra da cadeia diz que . O termo envolve derivar a softmax e o produto com e , usando as ativações armazenadas (as matrizes e da passada direta). O termo é simplesmente a entrada da camada. O gradiente final é uma matriz que "empilha" a influência de cada posição do contexto sobre , tudo calculado em paralelo para um batch inteiro.
O mesmo raciocínio vale para e , e para cada uma das dezenas de camadas do modelo. O resultado do backpropagation é um vetor de gradientes de mesmo tamanho que o número de parâmetros do modelo, da ordem de bilhões de números. Esse vetor é a entrada do otimizador, que decide como aplicar a correção usando gradiente descendente.
O backpropagation é o algoritmo que permite que o erro de uma previsão errada se propague por bilhões de parâmetros, calculando exatamente quanto cada peso contribuiu para o erro. É esse cálculo que viabiliza o gradiente descendente, que ajusta cada peso na direção oposta ao seu gradiente, reduzindo a loss a cada passo.
Gradiente descendente, momentum e a adaptação do Adam
O gradiente descendente estocástico (SGD) é o algoritmo mais básico: para cada peso , a atualização é , onde (eta) é a taxa de aprendizado, um hiperparâmetro que controla o tamanho do passo. Subtrair o gradiente (que aponta para o aumento da loss) é o que garante que a loss diminua em cada iteração, desde que o passo seja pequeno o suficiente. Se é muito alto, o modelo pode oscilar e nunca convergir; se é muito baixo, o treino demora demais. Na prática, começa em torno de (0,0001) e é reduzido ao longo do treino com schedulers.
O SGD puro, porém, converge lentamente em paisagens com muitos platôs ou vales estreitos. Para acelerar, os otimizadores modernos adicionam momentum: uma fração do gradiente anterior é mantida, criando uma inércia que cancela oscilações em direções inconsistentes e acumula aceleração em direções consistentes. Pense numa bola descendo uma montanha: ela ganha velocidade nas descidas retas e desacelera nas mudanças bruscas de direção.
O Adam (e sua variante AdamW) vai além: ele adapta a taxa de aprendizado para cada parâmetro individualmente. Ele mantém duas médias móveis para cada peso: uma do gradiente (momento, que acelera em direções consistentes) e outra do quadrado do gradiente (que estima a variância e reduz a taxa de aprendizado em direções de alta oscilação). O resultado é que direções consistentes recebem passos maiores, e direções ruidosas recebem passos menores, tudo automaticamente. O AdamW é o otimizador padrão para LLMs, e ele também incorpora weight decay de forma desacoplada, penalizando pesos muito grandes para evitar overfitting.
Cada passo de gradiente descendente reduz a loss um pouco. Mas um único passo sobre um único exemplo não basta; é preciso processar muitos exemplos em lote e repetir muitas vezes.
Mini-batch SGD, época e o que significa treinar em escala
Em vez de atualizar os pesos para cada exemplo individual (instável e lento), o treino processa mini-batches: grupos de, digamos, 512 ou 1024 exemplos. O modelo calcula a loss média do batch, o gradiente médio via backpropagation, e então atualiza os pesos. Isso equilibra estabilidade e velocidade, e permite paralelização eficiente em GPUs, pois cada GPU processa um subconjunto do batch e os gradientes são sincronizados via AllReduce.
Uma época é uma passagem completa por todos os exemplos do dataset de treino. Para um dataset com 1 trilhão de tokens e batch de 512 exemplos, cada época tem cerca de 2 bilhões de passos. Na prática, um LLM grande treina por uma fração de época, os modelos da série GPT-3/4 treinaram por menos de uma época porque o dataset é tão grande que repetir o mesmo dado causaria overfitting, perdendo a capacidade de generalizar.
Treinar em escala significa distribuir o mini-batch entre centenas ou milhares de GPUs, cada uma calculando gradientes parciais, sincronizando-os e atualizando os pesos simultaneamente. É um problema de engenharia de sistemas tanto quanto de aprendizado de máquina. A comunicação entre GPUs é o principal gargalo de eficiência.
Overfitting, validação e por que parar na hora certa importa
Overfitting ocorre quando o modelo se ajusta demais ao dataset de treino e perde a capacidade de generalizar para textos novos. No caso de LLMs, overfitting é raro com datasets enormes (1T+ tokens), mas pode acontecer se o modelo for pequeno para o tamanho do dataset, ou se o dado for repetido muitas vezes. O sinal clássico é a loss de treino continuar caindo enquanto a loss de validação, calculada sobre um subconjunto retido do dataset (nunca visto pelo modelo durante o treino), começa a subir.
Para detectar overfitting, a cada certo número de passos (ou ao fim de cada época), o modelo é avaliado no conjunto de validação. O ponto ótimo de parada, early stopping, é quando a loss de validação atinge o mínimo antes de começar a subir. Na prática, LLMs são treinados por um número fixo de passos pré-determinado por simulações de custo, e a loss de validação é monitorada para verificar se o treino está no caminho certo.
Outra técnica de controle é o weight decay (decaimento de peso), que adiciona um termo à loss que penaliza pesos muito grandes, forçando o modelo a manter os pesos pequenos e evitando que ele decore ruídos. O AdamW, variante do Adam, incorpora weight decay de forma desacoplada.
Onde o treino termina e a especialização prática começa
Treinar um LLM do zero, o processo descrito neste post, é caro, demorado e acessível a poucas empresas no mundo. A maioria dos times que constroem agentes ou aplicações começa com um modelo pré-treinado, como o Llama ou o GPT, e o adapta para o seu domínio. É aí que entram as técnicas de fine-tuning, como o LoRA, que ajustam uma fração mínima dos parâmetros para injetar conhecimento específico sem pagar o custo de um treino completo.
Na Pumpkin, a gente entende que o treino é só o começo. O modelo pré-treinado, mesmo depois de fine-tuning, continua sendo um núcleo probabilístico que erra sem aviso. O harness, a camada de prompting estruturado com busca em conhecimento externo e validação determinística, é o que transforma esse núcleo num sistema confiável. É o harness que decide o que o modelo vê, que corrige as respostas quando elas saem do trilho e que garante que o agente opere dentro dos limites do negócio.
O treino ensina o modelo a prever o próximo token; o harness ensina o sistema a acertar a resposta inteira. Os dois trabalham juntos, e saber onde um termina e o outro começa é o que separa uma demo de um produto.
Como os LLMs são treinados do início ao fim?
O que é backpropagation no treinamento de LLMs?
Qual a diferença entre treino e fine-tuning de um LLM?
Como a loss é calculada durante o treinamento de um LLM?
O que significa uma época no treinamento de LLMs?
Como o gradiente descendente funciona no treino de modelos de linguagem?
O que é overfitting e como evitá-lo no treino de LLMs?
- Brown, T. B. et al. Language Models are Few-Shot Learners. NeurIPS, 2020. (GPT-3, a referência moderna de treino de LLM)
- Vaswani, A. et al. Attention Is All You Need. NeurIPS, 2017. (o transformer, arquitetura base dos LLMs)
- Kingma, D. P. & Ba, J. Adam: A Method for Stochastic Optimization. ICLR, 2015. (otimizador)
- Loshchilov, I. & Hutter, F. Decoupled Weight Decay Regularization (AdamW). ICLR, 2019. (AdamW)
- Sennrich, R., Haddow, B. & Birch, A. Neural Machine Translation of Rare Words with Subword Units (BPE). ACL, 2016. (tokenização BPE)
- Kaplan, J. et al. Scaling Laws for Neural Language Models. 2020. (leis de escala que guiam o tamanho de modelos e datasets)