ML Atlas

Machine learning do zero · Aula 3.6 · 19 de 33 aulas prontas · 12 min

Parada antecipada

Em resumo

Uma rede treinada por tempo demais decora rótulos errados. Com 20% de rótulos aleatórios, 100 épocas sem parar baixam a acurácia de teste de 86,1% para 76,3%.

Aquecimento Duas perguntas de aulas anteriores. Um minuto, e a aula nunca fica bloqueada.
Da aula 3.5: Ajustar hiperparâmetros sem trapacear Como avaliar com justiça um modelo cujos hiperparâmetros você escolheu por validação cruzada?

Ver a resposta

Resposta certa: Conferi-lo em um teste reservado ou com validação cruzada aninhada em volta do ajuste

O teste reservado e a validação cruzada aninhada não participaram da escolha. No código a validação cruzada comum dá 94,0% e a aninhada 91,9%.

Da aula 3.4: Regularização: ridge e lasso Em que a penalidade ridge difere da penalidade lasso?

Ver a resposta

Resposta certa: O ridge puxa todos os pesos para zero e o lasso deixa alguns exatamente em zero

O ridge penaliza os quadrados dos pesos e não zera nenhum; o lasso penaliza os valores absolutos e zera os pesos um a um. No lab o ridge com α = 398 tem 10 pesos diferentes de zero, o lasso com α = 15,8 só 3.

Uma rede neural aprende em épocas: uma época é uma passada por todos os exemplos de treino. Depois de cada época a perda de treino costuma cair. A pergunta da aula 3.1 volta de outra forma: quantas épocas são demais? A parada antecipada responde com o conjunto de validação: o treino para quando a perda de validação deixa de cair, e o modelo volta à melhor época.

Preveja, depois confira Uma rede neural pequena aprende a reconhecer dígitos manuscritos com 299 imagens. Em 20% delas o rótulo é um dígito aleatório em vez do verdadeiro. A menor perda de validação vem na época 28. Mesmo assim você treina 100 épocas em vez de parar na melhor. O que acontece com a acurácia no teste?
Qual é o seu grau de certeza?

Experimento interativo

Este experimento interativo funciona em um navegador com JavaScript ativado. O texto ao redor descreve o que ele mostra.

Ver a resposta

Resposta certa: Cai de 86,1% para 76,3%, porque a rede decora também os rótulos errados

Os pesos da época 28 têm 86,1% nas 997 imagens de teste; depois de 100 épocas, 76,3%: 9,7 pontos a menos. Enquanto isso a perda de validação sobe de 0,48 para 0,84, e dos 51 rótulos errados a rede acaba repetindo todos.

Experimente

  • O lab abre com rótulos limpos. Mude para os rótulos aleatórios e deixe a paciência em 5. Em que época o treino para, quais pesos ficam e essa é a melhor época de todo o percurso?
  • Aumente a paciência para 10. O que muda na época mantida e na acurácia de teste?
  • Volte aos rótulos limpos. Quanto custa agora treinar até o fim?

Depois de conferir no lab, vamos dar nome ao que você vê.

A ideia em palavras simples

No começo do treino a rede aprende o que muitas imagens têm em comum: a forma de um zero, de um oito, de um sete. As perdas de treino e de validação caem juntas. Depois a rede começa a ajustar exemplos isolados, inclusive os de rótulo errado. A perda de treino continua caindo e a de validação começa a subir. É o sobreajuste da aula 3.1, só que ao longo das épocas em vez do número de parâmetros.

A parada antecipada vigia a perda de validação. Ela guarda a época com a menor perda e conta as épocas sem melhora. Quando elas chegam ao valor da paciência, o treino para e a rede volta aos pesos da melhor época. No lab, com paciência 10, o treino para na época 38 e ficam os pesos da época 28: 86,1% no teste em vez de 76,3% depois de 100 épocas.

Paciência de menos também atrapalha. A curva de validação oscila de uma época para outra. Com paciência 5 o treino para já na época 23 e fica com os pesos da época 18 (85,0% no teste), embora a melhor fosse a época 28.

Jak to policzono
  • Dígitos: Optical Recognition of Handwritten Digits, UCI, licença CC BY 4.0. 1797 imagens de 8×8 pixels.
  • Divisão estratificada: 299 imagens para aprender, 501 para validação, 997 para o teste. Na versão com ruído cada rótulo de treino é trocado, com probabilidade de 20%, por um dígito aleatório: mudaram 51 rótulos (um dígito aleatório às vezes acerta o verdadeiro).
  • Rede 64 → 32 → 10, ReLU, entropia cruzada, SGD com momento 0,9, passo 0,05, lotes de 32 imagens, 100 épocas. Perda de validação calculada depois de cada época.
  • A validação e o teste têm os rótulos verdadeiros. O ruído está só nos dados de treino.

Por que funciona

Um exemplo com rótulo errado é difícil para a rede: a imagem parece um três, mas o rótulo diz "sete". Para baixar a perda num exemplo assim, a rede precisa aprender uma regra que só serve para ele. Ela costuma fazer isso tarde, quando já domina os padrões fáceis e comuns. No lab a rede repete 10 dos 51 rótulos errados na época 28, e todos os 51 depois de 100 épocas. Nos próprios dados de treino ela tem então 99,7% de acurácia: concorda até com os rótulos que são falsos.

Regras ajustadas a rótulos errados estragam as respostas em imagens novas. O conjunto de validação tem os rótulos verdadeiros, então a perda dele sobe justamente quando a rede começa a aprender o ruído. Por isso é ela, e não a perda de treino, que diz quando parar.

Não é acaso de uma única execução. No código abaixo o mesmo experimento roda no scikit-learn em outras 10 divisões e sorteios de ruído: a melhor época cai entre 13 e 23, e treinar até 100 épocas baixa a acurácia de teste em todas as 10 execuções, em média de 87,2% para 76,4%. A melhor época do lab (28) fica fora dessa faixa porque também depende dos pesos iniciais e da ordem dos lotes: a mesma rede do lab com outras 9 sementes aleatórias se sai melhor entre as épocas 12 e 25, e treinar até 100 épocas baixa a acurácia de teste todas as vezes.

Erro comum

Verdadeiro ou falso: "treinar por mais tempo sempre dá um modelo melhor". Falso. Treinar por mais tempo sempre se ajusta melhor aos dados de treino, mas não aos novos. Com rótulos aleatórios, 100 épocas dão 99,7% de acurácia no treino e 76,3% no teste, enquanto parar na época 28 dá 86,1% no teste.

Uma observação no sentido contrário: com rótulos limpos, treinar até o fim quase não estraga nada. A menor perda de validação vem na época 30 (93,9% no teste), e depois de 100 épocas a acurácia é 94,5%. A parada antecipada nem sempre salva acurácia, mas sempre economiza tempo e protege de dados piores do que você imagina.

Quiz

Três perguntas para você se testar. Escolha uma resposta ou abra a resposta embaixo de cada pergunta. No teclado: as setas escolhem, Enter ou Espaço confirma.

1. Em que a parada antecipada se baseia para decidir quando parar o treino?
Ver a resposta

Resposta certa: Na perda de validação: o treino para quando ela deixa de cair

A perda de treino cai quase até o fim, mesmo quando a rede aprende ruído. A perda de validação, calculada em dados fora do treino, sobe quando o modelo começa a sobreajustar.

2. Com 20% de rótulos aleatórios, a rede tem 99,7% no treino e 76,3% no teste depois de 100 épocas. O que isso significa?
Ver a resposta

Resposta certa: A rede decorou também os rótulos errados, e isso estraga as respostas dela em dados novos

Acurácia alta no treino com ruído nos rótulos quer dizer que a rede ajustou o ruído também. Os pesos da época 28 têm 86,1% no teste.

3. Paciência 5 para o treino na época 23 e mantém a época 18, embora a menor perda esteja na época 28. Por quê?
Ver a resposta

Resposta certa: Porque a curva de validação oscila, e paciência de menos confunde uma oscilação com o mínimo

A perda de validação não cai de forma regular: algumas épocas piores seguidas podem ser acaso. Com paciência 10 o treino chega à época 28.

Pontos-chave

  • Uma época é uma passada pelos dados de treino; a perda de treino quase sempre cai, a de validação não.
  • A parada antecipada interrompe o treino quando a perda de validação não melhora por algumas épocas (a paciência) e volta aos melhores pesos.
  • Treinar demais com rótulos errados ensina o ruído à rede: o teste cai de 86,1% para 76,3%.
  • Paciência de menos para o treino numa oscilação casual da curva.

Mais a fundo: fórmula, código, prática

A matemática

Perda de validação depois da época e: L_val(e) = −(1/m) · Σᵢ log p_e(yᵢ | xᵢ) em m imagens de validação (entropia cruzada).

A regra com paciência P: e = argmin_{e ≤ t} L_val(e); o treino para na primeira época t com t − e ≥ P e devolve os pesos w(e). Se essa época não chegar, devolve w(e) de todo o percurso.

A parada antecipada age de forma parecida com a penalidade da aula 3.4. Com descida do gradiente e passo pequeno, os pesos começam perto de zero e se afastam dele a cada época. Menos épocas significam pesos menores: para um modelo linear com perda quadrática, parar depois de t passos tem mais ou menos o mesmo efeito que ridge com α da ordem de 1 / (passo · t).

No código (Python)

O mesmo experimento no scikit-learn: 10 divisões e sorteios de ruído diferentes, uma rede 64 → 32 → 10 treinada época a época, guardando os pesos da época com a menor perda de validação.

import copy
import numpy as np
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier
from sklearn.metrics import log_loss

X, y = load_digits(return_X_y=True)
X = X / 16
def run(seed):  # 300 dígitos para aprender, 500 para validação, os outros 997 para o teste
    used, te = train_test_split(np.arange(len(y)), train_size=800, stratify=y, random_state=seed)
    tr, va = train_test_split(used, test_size=500, stratify=y[used], random_state=seed)
    rng = np.random.default_rng(seed)
    noisy = y[tr].copy()
    flip = rng.random(len(tr)) < 0.2  # 20% dos rótulos de treino trocados por um dígito aleatório
    noisy[flip] = rng.integers(0, 10, flip.sum())
    net = MLPClassifier(hidden_layer_sizes=(32,), solver="sgd", learning_rate_init=0.05, momentum=0.9, batch_size=32, alpha=0, random_state=seed)
    best, best_loss = None, np.inf
    for epoch in range(1, 101):
        net.partial_fit(X[tr], noisy, classes=np.arange(10))
        loss = log_loss(y[va], net.predict_proba(X[va]), labels=np.arange(10))
        if loss < best_loss:
            best, best_loss, best_epoch = copy.deepcopy(net), loss, epoch  # a parada antecipada guarda os pesos da melhor época
    return best_epoch, best.score(X[te], y[te]), net.score(X[te], y[te])
r = np.array([run(s) for s in range(10)])
print(f"10 splits and noise draws: lowest validation loss at epoch {r[:, 0].min():.0f} to {r[:, 0].max():.0f}; test at that epoch {r[:, 1].mean():.1%}, after 100 epochs {r[:, 2].mean():.1%}; lower after 100 in {(r[:, 2] < r[:, 1]).sum()} of 10")

Saída

10 splits and noise draws: lowest validation loss at epoch 13 to 23; test at that epoch 87.2%, after 100 epochs 76.4%; lower after 100 in 10 of 10

As divisões, os pesos iniciais e o ruído são diferentes dos do lab, então os números também. O quadro é o mesmo: a melhor época vem cedo (entre 13 e 23), e treinar até 100 épocas baixa a acurácia de teste em todas as 10 execuções, em média de 87,2% para 76,4%.

Para quem pratica
  • No Keras: EarlyStopping(monitor="val_loss", patience=10, restore_best_weights=True). Sem restore_best_weights=True ficam os pesos da última época, não os da melhor.
  • No PyTorch você mesmo escreve o laço: depois de cada época calcule a perda de validação e guarde uma cópia dos pesos sempre que ela for a menor.
  • No scikit-learn: MLPClassifier(early_stopping=True, n_iter_no_change=...) separa uma parte dos dados de treino para validação; ele vigia a acurácia de validação, não a perda. No gradient boosting a mesma ideia se chama n_iter_no_change ou early_stopping_rounds.
  • O número de épocas escolhido na validação também é um hiperparâmetro: o resultado de validação na melhor época é um pouco inflado (aula 3.5), então faça a avaliação final em um teste reservado.

Vá mais fundo no Atlas

Verbetes da enciclopédia sobre as ideias desta aula: