Path: blob/master/site/pt-br/tutorials/keras/overfit_and_underfit.ipynb
25118 views
Copyright 2018 The TensorFlow Authors.
Overfitting e underfitting
Como sempre, o código deste exemplo usará a API tf.keras
. Se quiser saber mais sobre ela, confira o guia do Keras do TensorFlow.
Nos dois exemplos anteriores, classificação de textos e previsão de eficiência de combustível, a exatidão dos modelos para os dados de validação atinge o pico após fazer o treinamento com um determinado número de épocas. Depois, ela fica estagnada ou começa a cair.
Em outras palavras, ocorre um overfitting do modelo para os dados de treinamento. Aprender a lidar com o overfitting é importante. Embora geralmente seja possível atingir uma alta exatidão para o conjunto de treinamento, o que você realmente vai querer é desenvolver modelos que fazem boas generalizações para um conjunto de teste (ou dados nunca vistos).
O oposto de overfitting é underfitting, que ocorre quando ainda há espaço para melhorias com os dados de treinamento. Há vários motivos para isso correr: se o modelo não for poderoso o bastante, se estiver regularizado demais ou se simplesmente não tiver sido treinado o bastante. Isso significa que a rede não aprendeu padrões relevantes para os dados de treinamento.
Porém, se você treinar demais, o modelo começará a fazer overfitting e aprender padrões dos dados de treinamento que não fazem generalizações para os dados de teste. É preciso atingir um ponto de equilíbrio. Entender como escolher o número de épocas adequado para o treinamento (mostrado abaixo) é uma habilidade muito útil.
Para evitar o overfitting, a melhor solução é utilizar dados de treinamento mais completos. O dataset deve abranger o intervalo completo de entradas que o modelo deverá tratar. Dados adicionais serão úteis somente se contiverem casos novos e interessantes.
Um modelo treinado com dados mais completos vai fazer generalizações naturalmente melhores. Quando isso não é mais possível, a melhor solução é usar outras técnicas, como regularização, que colocam restrições na quantidade e no tipo de informações que o modelo pode armazenar. Se uma rede puder memorizar somente uma pequena quantidade de padrões, o processo de otimização forçará que ela se concentre nos padrões mais presentes, o que dará uma maior chance de fazer generalizações melhores.
Neste notebook, você verá diversas técnicas comuns de regularização e as utilizará para melhorar um modelo de classificação.
Configuração
Antes de começar, importe os pacotes necessários:
Dataset Higgs
O objetivo deste tutorial não é falar sobre física de partículas, então não se preocupe com os detalhes do dataset, que contém 11 milhões de exemplos, cada um com 28 características, além de um rótulo de classe binária.
A classe tf.data.experimental.CsvDataset
pode ser usada para ler registros CSV diretamente de um arquivo gzip, sem nenhum passo intermediário de descompactação.
A classe que lê o CSV retorna uma lista de escalares para cada registro. A seguinte função reencapsula essa lista de escalares em um par (feature_vector, label).
O TensorFlow é mais eficiente ao operar grandes lotes de dados.
Portanto, em vez de reencapsular cada linha individualmente, crie um novo tf.data.Dataset
que receba lotes de 10 mil exemplos, aplique a função pack_row
a cada lote e depois divida os lotes em registros individuais:
Avalie alguns registros desse novo packed_ds
.
As características não estão perfeitamente normalizadas, mas isso será suficiente para este tutorial.
Para manter este tutorial relativamente curto, use somente os primeiros mil exemplos para validação e os 10 mil seguintes para treinamento:
Os métodos Dataset.skip
e Dataset.take
facilitam esse processo.
Além disso, use o método Dataset.cache
para garantir que o loader não precise ler novamente os dados do arquivo em cada época:
Esses datasets retornam exemplos individuais. Use o método Dataset.batch
para criar lotes de tamanho adequado para o treinamento. Antes de fazer a divisão em lotes, lembre-se de usar Dataset.shuffle
e Dataset.repeat
no conjunto de treinamento.
Demonstração do overfitting
A forma mais simples de evitar o overfitting é começar com um modelo pequeno: um modelo com uma pequena quantidade de parâmetros que podem ser aprendidos (determinada pelo número de camadas e pelo número de unidades por camada). No aprendizado profundo, a quantidade de parâmetros que podem ser aprendidos em um modelo costuma ser chamada de "capacidade" do modelo.
Intuitivamente, um modelo com mais parâmetros terá mais "capacidade de memorização" e, portanto, conseguirá aprender mais facilmente um mapeamento perfeito tipo dicionário entre as amostras de treinamento e seus alvos, um mapeamento sem qualquer poder de generalização, mas isso seria inútil ao fazer previsões para dados nunca vistos.
Nunca se esqueça de que os modelos de aprendizado profundo costumam ser bons em se adequarem aos dados de treinamento, mas o verdadeiro desafio é a generalização, não a adequação.
Por outro lado, se a rede tiver recursos de memorização limitados, não conseguirá aprender o mapeamento tão facilmente. Para minimizar a perda, ela terá que aprender as representações compactadas, que têm maior poder de previsão. Ao mesmo tempo, se o seu modelo for pequeno demais, terá dificuldades de se adequar aos dados de treinamento. Há um equilíbrio entre "capacidade demais" e "capacidade insuficiente".
Infelizmente, não existe uma fórmula mágica para determinar a arquitetura ou tamanho certo do modelo (quanto ao número de camadas ou ao tamanho certo de cada camada). Você precisará fazer testes, usando uma série de diferentes arquiteturas.
Para encontrar o tamanho adequado para o modelo, é melhor começar com poucas camadas e parâmetros, depois aumentar o tamanho das camadas ou adicionar novas camadas até observar ganhos decrescentes quanto à perda de validação.
Comece com um modelo simples, usando somente camadas densamente conectadas (tf.keras.layers.Dense
) como linha de base, depois crie modelos maiores e compare-os.
Procedimento de treinamento
Diversos modelos são treinados de forma melhor se você reduzir gradualmente a taxa de aprendizado durante o treinamento. Use tf.keras.optimizers.schedules
para reduzir a taxa de aprendizado ao longo do tempo:
O código acima define um tf.keras.optimizers.schedules.InverseTimeDecay
para diminuir a taxa de aprendizado hiperbolicamente para metade da taxa base ao chegar a 1.000 épocas, um terço ao chegar a 2.000 épocas e assim por diante.
Cada modelo neste tutorial usará a mesma configuração de treinamento. Portanto, configure tudo de uma maneira reutilizável, começando pela lista de callbacks.
Neste tutorial, o treinamento é feito com várias épocas curtas. Para reduzir o ruído de criação de logs, use tfdocs.EpochDots
, que simplesmente registra um .
para cada época e um conjunto completo de métricas a cada 100 épocas.
Em seguida, inclua tf.keras.callbacks.EarlyStopping
para evitar tempos de treinamento longos e desnecessários. É importante notar que esse callback monitora val_binary_crossentropy
, não val_loss
. Essa diferença será importante mais adiante.
Use callbacks.TensorBoard
para gerar logs do TensorBoard referentes ao treinamento.
De maneira similar, cada modelo usará as mesmas configurações de Model.compile
de Model.fit
:
Modelo minúsculo
Comece treinando um modelo:
Agora, verifique como o modelo se saiu:
Modelo pequeno
Para verificar se você consegue superar o desempenho do modelo pequeno, treine modelos maiores progressivamente.
Experimente usar duas camadas ocultas, com 16 unidades cada:
Modelo médio
Agora, experimente usar três camadas ocultas, com 64 unidades cada:
E treine o modelo usando os mesmos dados:
Modelo grande
Para fins demonstrativos, você pode criar um modelo maior ainda e verificar com que velocidade ele sofre overfitting. Em seguida, adicione a esse comparativo uma rede que tenha muito mais capacidade, bem maior do que seria necessário para o problema em questão:
Novamente, treine o modelo usando os mesmos dados:
Plotar as perdas de treinamento e validação
As linhas sólidas mostram a perda de treinamento, enquanto as linhas tracejadas mostram a perda de validação (lembre-se de que uma perda de validação menor indica um modelo melhor).
Embora criar um modelo maior ofereça uma potência maior, se essa potência não for restringida de alguma forma, é fácil ocorrer overfitting para o conjunto de treinamento.
Tipicamente, neste exemplo, somente o modelo "Tiny"
(minúsculo) consegue evitar totalmente o overfitting, e cada modelo maior sofre overfitting mais rapidamente. Isso fica tão grave para o modelo "large"
(grande) que você precisa mudar o gráfico para uma escala logarítmica para entender o que está acontecendo.
Isso fica aparente ao plotar e comparar as métricas de validação com as métricas de treinamento.
É normal que haja uma pequena diferença.
Se as duas métricas estiverem caminhando na mesma direção, está tudo certo.
Se a métrica de validação começar a ficar estagnada enquanto a de treinamento continuar melhorando, provavelmente o overfitting está perto de ocorrer.
Se a métrica de validação estiver caminhando na direção errada, o modelo está claramente sofrendo overfitting.
Observação: todas as execuções de treinamento acima usaram callbacks.EarlyStopping
para encerrar o treinamento quando estava claro que o modelo não estava progredindo.
Ver no TensorBoard
Todos esses modelos criaram logs do TensorBoard durante o treinamento.
Abra um visualizador integrado do TensorBoard dentro de um notebook (lamentamos, mas não é possível exibir em tensorflow.org):
Você pode ver os resultados de uma execução anterior deste notebook em TensorBoard.dev.
Estratégias para evitar o overfitting
Antes de ler o conteúdo desta seção, copie os logs de treinamento do modelo "Tiny"
(minúsculo) acima para usá-lo como linha de base de comparação.
Acrescentar regularização de pesos
Talvez você já conheça o princípio da Navalha de Occam: dadas duas explicações para alguma coisa, a explicação com maior probabilidade de ser a correta é a "mais simples", aquela que faz o menor número de suposições. Isso também se aplica aos modelos aprendidos por redes neurais: para determinados dados de treinamento e uma arquitetura de rede, há diversos conjuntos de valores de peso (diversos modelos) que podem explicar os dados, e os modelos mais simples têm menor probabilidade de sofrerem overfitting do que os mais complexos.
Um "modelo simples" neste contexto é um modelo em que a distribuição de valores de parâmetros tem menos entropia (ou um modelo com menos parâmetros, conforme demonstrado na seção acima). Portanto, uma forma comum de mitigar o overfitting é colocar restrições na complexidade de uma rede, forçando que seus pesos tenham somente valores pequenos, o que deixa a distribuição dos valores de pesos mais "regular". Isso é chamado de "regularização de pesos" e é feito acrescentando-se um custo associado a ter pesos maiores à função de perda da rede. Há dois tipos de custo:
Regularização L1, em que o custo acrescentado é proporcional ao valor absoluto dos coeficientes de pesos (ou seja, o que é chamado de "norma L1" dos pesos).
Regularização L2, em que o custo acrescentado é proporcional ao quadrado do valor dos coeficientes de pesos (ou seja, o que é chamado de "norma L2" quadrada dos pesos). A regularização L2 também é chamada de decaimento de pesos no contexto de redes neurais. Não se confunda com os diferentes nomes: o decaimento de pesos é matematicamente o mesmo que a regularização L2.
A regularização L1 tende os pesos a exatamente zero, o que incentiva um modelo esparso. A regularização L2 penaliza os parâmetros de pesos sem torná-los esparsos, já que a penalidade vai a zero para pesos pequenos, um motivo pelo qual a regularização L2 é mais comum.
Em tf.keras
, a regularização de pesos é acrescentada passando-se instâncias do regularizador de pesos às camadas como argumentos de palavras-chave. Acrescente a regularização de pesos L2:
l2(0.001)
significa que cada coeficiente na matriz de pesos da camada acrescentará 0.001 * weight_coefficient_value**2
à perda total da rede.
É por isso que estamos monitorando binary_crossentropy
diretamente, pois esse componente de regularização não está presente.
Portanto, aquele mesmo modelo "Large"
(grande) com penalidade de regularização L2
tem desempenho muito melhor:
Conforme demonstrado no diagrama acima, agora o modelo com regularização "L2"
é muito mais competitivo em relação ao modelo "Tiny"
(minúsculo). Esse modelo "L2"
também é muito mais resistente ao overfitting do que o modelo "Large"
(grande) no qual foi baseado, apesar de ter a mesma quantidade de parâmetros.
Mais informações
É preciso notar dois aspectos importantes sobre esse tipo de regularização:
Se você estiver escrevendo seu próprio loop de treinamento, precisa perguntar ao modelo suas perdas de regularização.
Essa implementação funciona adicionando-se as penalidades de pesos à perda do modelo e depois aplicando-se um procedimento de otimização padrão em seguida.
Existe uma segunda estratégia, que executa o otimizador somente na perda bruta e então, ao aplicar o passo calculado, o otimizador também aplica um decaimento de pesos. Esse "decaimento de pesos desacoplado" é usado em otimizadores como tf.keras.optimizers.Ftrl
e tfa.optimizers.AdamW
.
Acrecentar dropout
O dropout é uma das técnicas de regularização mais eficazes e mais usadas para redes neurais, desenvolvida por Hinton e seus estudantes da Universidade de Toronto.
Veja uma explicação intuitiva para o dropout: como nós individuais da rede não podem depender da saída de outros, cada nós precisa gerar características que sejam úteis por si só.
O dropout, quando aplicado a uma camada, consiste da "eliminação" (ou seja, definição como zero) aleatória de uma quantidade de características de saída da camada durante o treinamento. Por exemplo, normalmente uma camada retornaria um vetor [0.2, 0.5, 1.3, 0.8, 1.1]
para uma determinada amostra de entrada durante o treinamento. Após a aplicação do dropout, esse mesmo vetor terá algumas entradas iguais a zero distribuídas aleatoriamente (por exemplo, [0, 0.5, 1.3, 0, 1.1]
).
A "taxa de dropout" é a fração das características que estão sendo definidas como zero. Geralmente, fica entre 0,2 e 0,5. No momento do teste, nenhuma unidade sofre dropout e, em vez disso, os valores de saída da camada são reduzidos por um fator igual à taxa de dropout para balancear o fato de que mais unidades estão ativas do que no momento de treinamento.
No Keras, você pode acrescentar dropout a uma rede pela camada tf.keras.layers.Dropout
, que é aplicada à saída da camada logo antes dela.
Acrescente duas camadas de dropout à sua rede para verificar o desempenho delas em reduzir o overfitting:
Com esse gráfico, fica claro que essas duas estratégias de regularização melhoram o comportamento do modelo "Large"
(grande), mas ele ainda não supera a linha de base "Tiny"
(minúsculo).
Agora experimente os dois juntos e veja se fica melhor.
Combinar L2 + dropout
Este modelo com a regularização "Combined"
(combinada) é nitidamente o melhor até agora.
Ver no TensorBoard
Esses modelos também são registrados nos logs do TensorBoard.
Para abrir uma visualização integrada, execute o seguinte em uma célula de código (lamentamos, mas não é possível exibir em tensorflow.org):
Você pode ver os resultados de uma execução anterior deste notebook em TensorBoard.dev.
Conclusões
Recapitulando, veja abaixo as formas mais comuns de evitar o overfitting em redes neurais:
Obter mais dados de treinamento.
Reduzir a capacidade da rede.
Acrescentar regularização de pesos.
Acrecentar dropout.
Confira duas estratégias importantes não discutidas neste guia:
Normalização de lotes (
tf.keras.layers.BatchNormalization
)
Lembre-se de que cada método pode ajudar individualmente, mas combiná-los pode ser ainda mais eficaz.