Como um modelo treina com uma memória que não tem.

SRC·53 Source
Para aprender, ele precisa lembrar cada passo. Esse é o muro.

Para aprender, ele precisa lembrar cada passo. Esse é o muro.

Para melhorar, um modelo empurra sua entrada para frente por cada camada — e, para aprender com o erro, precisa guardar cada um desses resultados intermediários, prontos para a passagem de volta. A conta nunca foi o problema. A memória é. Num modelo fundo o bastante, segurar toda a passagem para frente de uma vez é justamente o que esgota o seu espaço.
Por que guardar tudo? Para rastrear a culpa de volta.

Por que guardar tudo? Para rastrear a culpa de volta.

Mstore==1La=O(L)M_{\text{store}} = \sum_{\ell=1}^{L} a_{\ell} = O(L)
Aprender faz a cada camada uma pergunta: quanto você somou ao erro? Responder exige a saída guardada daquela camada na ida — então o modelo guarda todas. Como um chef que deixa cada tigela de preparo sobre a bancada: para achar qual etapa azedou o molho, você deixa todas as tigelas à mostra, e a bancada lota antes de o prato ficar pronto. Um resultado guardado por camada significa que a conta de memória sobe no mesmo passo que a profundidade L.
Então é só não salvar? Aí o trabalho explode.

Então é só não salvar? Aí o trabalho explode.

Crecompute==1L=L(L+1)2=O(L2)C_{\text{recompute}} = \sum_{\ell=1}^{L} \ell = \frac{L(L+1)}{2} = O(L^{2})
Há uma saída óbvia: não guardar nada e, sempre que a passagem de volta precisar do valor de uma camada, recalculá-lo a partir da entrada. A memória some — mas o trabalho dispara. Como descer até o térreo toda vez: para chegar ao nono andar você recomeça lá de baixo, vez após vez. Refaça cada camada do zero e o esforço total cresce com o quadrado da profundidade.
A solução: guarde alguns marcos, refaça o resto.

A solução: guarde alguns marcos, refaça o resto.

M(k)=Lkwaypoints+kone segmentM(k) = \underbrace{\tfrac{L}{k}}_{\text{waypoints}} + \underbrace{k}_{\text{one segment}}
Nenhum extremo funciona, então fique no meio. Salve as ativações em apenas algumas camadas e jogue o resto fora; quando a passagem de volta precisar de um valor descartado, rode de novo só o trecho curto a partir do ponto salvo mais próximo. Como um trilheiro fincando uma bandeira a cada quilômetro: você não decora cada passo — para voltar, retorna à última bandeira e refaz aquele trecho curto. Marque um ponto a cada k camadas e você segura só L/k bandeiras mais os k passos do trecho que está refazendo.
Com que espaçamento? A raiz quadrada da profundidade.

Com que espaçamento? A raiz quadrada da profundidade.

dMdk=Lk2+1=0    k=L,M=2L=O(L)\frac{dM}{dk} = -\frac{L}{k^{2}} + 1 = 0 \;\Rightarrow\; k^{*} = \sqrt{L}, \quad M^{*} = 2\sqrt{L} = O(\sqrt{L})
Espace os marcos demais e cada recaminhada fica longa; junte-os demais e você não economizou memória. Os dois custos puxam em sentidos opostos, e o total é mínimo quando se equilibram. Como um time de revezamento distribuindo suas passagens de bastão: pernas longas demais e cada corredor se esgota, curtas demais e você contratou corredores à toa — o time é mais rápido quando cada perna tem o mesmo comprimento curto. O equilíbrio cai em uma bandeira a cada √L camadas — e a memória cai para cerca de √L.
O custo? Uma passagem a mais. Vale a pena.

O custo? Uma passagem a mais. Vale a pena.

CckptFfwd+Fbwd+Frecompute=F+2F+F=43CfullC_{\text{ckpt}} \approx F_{\text{fwd}} + F_{\text{bwd}} + F_{\text{recompute}} = F + 2F + F = \tfrac{4}{3}\,C_{\text{full}}
Nada é de graça: cada trecho descartado é recaminhado uma vez durante a passagem de volta, o que soma refazer toda a viagem de ida exatamente uma vez a mais. Como alugar uma van pequena e fazer duas viagens: você não tinha como pagar o caminhão grande, então percorre a rota duas vezes — um pouco mais de tempo, e tudo se muda do mesmo jeito. Um passo normal é uma ida e duas voltas; uma ida extra faz quatro partes onde havia três — cerca de um terço a mais de cômputo por um corte de memória quase à sua raiz quadrada.
Agora a memória é um botão, não um muro.

Agora a memória é um botão, não um muro.

Esse é o truque inteiro: a memória deixa de ser um muro e vira um botão que você pode girar. Gaste um pouco mais de tempo e você encaixa um modelo que jamais deveria caber — treine algo bem mais fundo do que seu hardware aguenta, só por aceitar reconstruir o que escolheu esquecer. Como um navio montado dentro de uma garrafa: o que não passa pelo gargalo chega lá assim mesmo, montado por um método paciente e engenhoso. O trabalho que você jogou fora nunca se perdeu — só era barato de refazer.
🌱 Uma memória que dá para reconstruir é mesmo uma memória?

🌱 Uma memória que dá para reconstruir é mesmo uma memória?

Ele escolheu esquecer — e então, quando precisou do pensamento de novo, simplesmente o reconstruiu. Nós raramente temos essa opção: nosso passado é guardado, não re-deduzido, e o que perdemos costuma estar perdido. Mas se uma coisa sempre pode recalcular o que esqueceu, esquecer chegou a ser uma perda? Talvez lembrar de tudo seja o hábito caro — e refazer o trabalho, em silêncio, seja o jeito mais barato de pensar.
toque →deslize ↑ para maisdeslize ↓ para sair