ML Atlas

Machine learning do zero · Aula 3.3 · 16 de 33 aulas prontas · 12 min

Curvas de aprendizado: mais dados ou um modelo melhor?

Em resumo

As curvas de aprendizado mostram a nota no treino e na validação conforme os dados crescem. A forma delas diz se vale juntar dados ou trocar o modelo.

Aquecimento Duas perguntas de aulas anteriores. Um minuto, e a aula nunca fica bloqueada.
Da aula 3.2: Validação e validação cruzada Por que padronizar os atributos com todas as linhas antes da validação cruzada é um erro?

Ver a resposta

Resposta certa: Porque dados dos folds de validação vazam para o treino e inflam as notas

Toda etapa que aprende com os dados deve ser ajustada só nos folds de treino; caso contrário, os folds de validação deixam de ser inéditos.

Da aula 3.1: Overfitting: quando o modelo decora Quando o grau do polinômio aumenta, o que acontece com o erro de treino?

Ver a resposta

Resposta certa: Cai ou fica estável: uma curva mais flexível sempre consegue copiar uma mais simples

Um polinômio de grau maior contém todos os de grau menor como caso particular, então nunca se ajusta pior aos pontos de treino.

Na aula 3.1 o modelo era simples demais ou complexo demais, com a mesma quantidade de dados. Hoje você muda a quantidade de dados. É uma pergunta do dia a dia de quem pratica: o modelo funciona mais ou menos, então você junta mais exemplos ou troca o modelo? A resposta vem de uma curva de aprendizado: a nota no treino e na validação, desenhada para um conjunto de treino cada vez maior.

Preveja, depois confira Uma regressão logística aprende a reconhecer dígitos escritos à mão com 50 imagens. Nessas 50 imagens ela acerta 100%. Quanto ela acerta, mais ou menos, em dígitos novos da validação?
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: Cerca de 82%, ou seja, mais de dez pontos abaixo do treino

A validação dá 82,3% (média de 5 sorteios de 50 imagens), então a lacuna é de 17,7 pontos. Com todo o treino, 1438 imagens, a validação sobe para 95,8% e a lacuna cai para 2,2 pontos. Com poucos dados, 100% no treino é em grande parte memória.

Experimente

  • Com o modelo detalhado, mova o controle de 50 para 1438 imagens. Qual curva muda mais: a do treino ou a da validação?
  • Troque para o modelo de dígitos desfocados. Onde as curvas dele se encontram, e em que altura?
  • Compare o modelo detalhado com 100 imagens e o desfocado com 1438. Qual vence?

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

A ideia em poucas palavras

Uma curva de aprendizado são duas linhas: a acurácia nos dados de treino e na validação, conforme o número de exemplos de treino. Com algumas dezenas de imagens o modelo decora cada uma: o treino dá 100% e a validação 82,3%. Quanto mais dados, mais difícil decorar tudo, então o treino cai (para 98,0%) e a validação sobe (para 95,8%). A lacuna entre os dois cai de 17,7 para 2,2 pontos.

Da forma dessas linhas você lê a decisão:

  • Lacuna grande e validação ainda subindo (variância alta): o modelo conhece os dados de treino muito melhor que os novos. Mais dados vão ajudar, e a regularização também.
  • Lacuna pequena e as duas linhas baixas (viés alto): o modelo é simples demais. As curvas já se encontraram e mais dados quase não ajudam. Um modelo mais rico ou atributos melhores vão ajudar.

O modelo de dígitos desfocados vê cada dígito como uma imagem de 4 × 4, ou seja, 16 pixels em vez de 64. Com 1438 imagens ele tem 86,9% no treino e 85,0% na validação, uma lacuna de só 1,9 ponto. A validação normalmente não passa do treino, e o treino tem só 86,9%. O modelo detalhado já chega a 87,6% com apenas 100 imagens.

Jak to policzono
  • Dígitos: Optical Recognition of Handwritten Digits, UCI, licença CC BY 4.0. 1797 imagens de 8 × 8 pixels, 10 dígitos.
  • Uma divisão 80/20 estratificada, a mesma do widget do Atlas: 1438 imagens para aprender, 359 para validar. Para cada tamanho, a média de 5 sorteios de quais imagens vão para o aprendizado.
  • Modelo: regressão logística (softmax) com uma penalidade de 0,001 sobre pesos grandes. O modelo desfocado vê as médias de blocos de 2 × 2 pixels.

Por que funciona

No treino o modelo vê as respostas, então com poucos dados ele pode decorá-las. Cada exemplo novo torna mais difícil decorar e mais fácil achar uma regra que também funcione fora do treino. Por isso as linhas se aproximam: o treino desce e a validação sobe. Elas se encontram no nível que esse modelo consegue atingir.

Esse nível depende do modelo, não dos dados. Uma imagem desfocada perde os detalhes que distinguem, por exemplo, um 3 de um 8, e nenhuma quantidade de exemplos os traz de volta. No código abaixo o mesmo experimento roda em 50 divisões diferentes: com todos os dados o modelo desfocado tem 86,4% no treino e 85,1% na validação, e o detalhado 96,6% na validação. O modelo detalhado com 100 imagens vence o desfocado com 1437 imagens em 49 de 50 divisões.

Erro comum

Verdadeiro ou falso: “mais dados sempre ajudam”. Falso. Mais dados ajudam quando o modelo é poderoso demais para a quantidade de dados: aí a lacuna é grande e a validação continua subindo. Quando o modelo é simples demais, as curvas se encontram cedo e ficam planas. No lab o modelo desfocado tem 83,6% na validação com 400 imagens e 85,0% com um conjunto quase quatro vezes maior. O modelo detalhado tem 95,8% com os mesmos dados. Antes de pagar para juntar dados, desenhe uma curva de aprendizado: se a nota do treino já é baixa, os dados não vão ajudar.

Observação: desenhe as curvas na validação ou na validação cruzada, não no conjunto de teste. O teste fica para a avaliação final.

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. O treino dá 100%, a validação 82,3%, e a curva de validação ainda sobe. O que deve ajudar mais?
Ver a resposta

Resposta certa: Mais dados de treino, porque uma lacuna grande indica que o modelo decora

Lacuna grande e validação subindo significam variância alta. Com todo o treino o mesmo modelo chega a 95,8% na validação, e a lacuna cai para 2,2 pontos.

2. Com 1438 imagens o modelo desfocado tem 86,9% no treino e 85,0% na validação. O que fazer?
Ver a resposta

Resposta certa: Trocar por um modelo mais rico, porque as duas curvas se encontraram embaixo

É viés alto: a validação não vai pular acima do treino, e o treino tem só 86,9%. O modelo com os 64 pixels chega a 95,8% com os mesmos dados.

3. Por que a acurácia no treino cai quando os dados de treino crescem?
Ver a resposta

Resposta certa: Porque decorar cada exemplo fica mais difícil, então o modelo generaliza

Com 50 imagens o modelo acerta todas, com 1438 acerta 98,0%. Já a validação sobe de 82,3% para 95,8%.

Pontos-chave

  • Uma curva de aprendizado é a nota no treino e na validação para um conjunto de treino que cresce.
  • Lacuna grande e validação subindo: o modelo decora, mais dados vão ajudar.
  • Lacuna pequena com nota baixa: o modelo é simples demais; ajuda um modelo mais rico ou atributos melhores, não mais dados.
  • Desenhe a curva antes de pagar por dados; desenhe-a na validação e guarde o teste para o fim.

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

A matemática

Sejam A_tr(n) e A_val(n) a acurácia em n exemplos de treino e na validação. A curva de aprendizado são as duas funções de n. Em geral A_tr(n) cai, A_val(n) sobe, e as duas se aproximam do mesmo nível A*, a melhor acurácia que essa família de modelos alcança.

A lacuna A_tr(n) − A_val(n) mede a variância: o quanto a nota depende de quais exemplos foram usados no aprendizado. A distância 1 − A é o viés desta família de modelos junto com um ruído que nenhum modelo remove (dígitos ilegíveis até para uma pessoa): nenhum dado a remove. Mais dados diminuem a lacuna; só uma troca de modelo eleva A.

A regressão logística do lab minimiza L = perda média + (λ / 2) · ‖W‖² com λ = 0,001. No scikit-learn a mesma penalidade é C = 1 / (λ · n) = 1000 / n.

No código (Python)

O mesmo experimento no scikit-learn em 50 divisões diferentes: um modelo com 64 pixels e outro com o dígito desfocado em 16 pixels, com um número crescente de imagens de treino.

import numpy as np
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression

X, y = load_digits(return_X_y=True)
X = X / 16  # 8 × 8 = 64 pixels de 0 a 1, como no lab
X16 = X.reshape(-1, 4, 2, 4, 2).mean(axis=(2, 4)).reshape(len(X), -1)  # o mesmo dígito desfocado em 4 × 4 = 16 pixels
def run(Z, n, seed):
    Xtr, Xva, ytr, yva = train_test_split(Z, y, test_size=0.2, stratify=y, random_state=seed)
    i = np.random.default_rng(seed).permutation(len(ytr))[:n]  # as primeiras n imagens de treino depois de embaralhar
    m = LogisticRegression(C=1000 / n, max_iter=5000).fit(Xtr[i], ytr[i])  # C = 1000 / n é a penalidade 0,001 do lab
    return m.score(Xtr[i], ytr[i]), m.score(Xva, yva)
for name, Z in (("64 pixels", X), ("16 pixels", X16)):
    for n in (50, 100, 400, 800, 1437):
        tr, va = np.mean([run(Z, n, s) for s in range(50)], axis=0)  # média de 50 divisões diferentes
        print(f"{name}, {n} images: training {tr:.1%}, validation {va:.1%}, gap {(tr - va) * 100:.1f} points")
wins = sum(run(X, 100, s)[1] > run(X16, 1437, s)[1] for s in range(50))
print(f"64 pixels from 100 images beat 16 pixels from 1437 images in {wins} of 50 splits")

Saída

64 pixels, 50 images: training 100.0%, validation 81.2%, gap 18.8 points
64 pixels, 100 images: training 100.0%, validation 89.5%, gap 10.5 points
64 pixels, 400 images: training 99.7%, validation 94.9%, gap 4.8 points
64 pixels, 800 images: training 99.0%, validation 96.0%, gap 2.9 points
64 pixels, 1437 images: training 98.2%, validation 96.6%, gap 1.6 points
16 pixels, 50 images: training 98.5%, validation 72.6%, gap 25.9 points
16 pixels, 100 images: training 94.1%, validation 79.8%, gap 14.4 points
16 pixels, 400 images: training 87.7%, validation 83.8%, gap 3.8 points
16 pixels, 800 images: training 86.9%, validation 84.6%, gap 2.3 points
16 pixels, 1437 images: training 86.4%, validation 85.1%, gap 1.3 points
64 pixels from 100 images beat 16 pixels from 1437 images in 49 of 50 splits

O lab mostra uma divisão e 5 sorteios, o código 50 divisões, então os números diferem um pouco: com 50 imagens a validação dá 82,3% no lab e 81,2% em média. A forma das curvas e a conclusão são as mesmas.

Para quem pratica
  • No scikit-learn as curvas vêm de learning_curve (com validação cruzada) e LearningCurveDisplay. Em classificação use StratifiedKFold, para que cada tamanho tenha todas as classes.
  • Desenhe o número de exemplos em escala logarítmica: assim se vê melhor o ganho de cada vez que os dados dobram.
  • Uma curva de validação (validation_curve) é outra coisa: a nota conforme um ajuste do modelo, como a força da regularização, com os dados fixos.
  • Antes de juntar dados, estime o que uma duplicação vai trazer: se a última trouxe uma fração de ponto, a próxima trará ainda menos.

Vá mais fundo no Atlas

Verbetes da enciclopédia sobre as ideias desta aula: