Comportamento estranho com o otimizador Adam ao treinar por muito tempo

11

Estou tentando treinar um único perceptron (1000 unidades de entrada, 1 saída, sem camadas ocultas) em 64 pontos de dados gerados aleatoriamente. Estou usando o Pytorch usando o otimizador Adam:

import torch
from torch.autograd import Variable

torch.manual_seed(545345)
N, D_in, D_out = 64, 1000, 1

x = Variable(torch.randn(N, D_in))
y = Variable(torch.randn(N, D_out))

model = torch.nn.Linear(D_in, D_out)
loss_fn = torch.nn.MSELoss(size_average=False)

optimizer = torch.optim.Adam(model.parameters())
for t in xrange(5000):
  y_pred = model(x)
  loss = loss_fn(y_pred, y)

  print(t, loss.data[0])

  optimizer.zero_grad()
  loss.backward()
  optimizer.step()

Inicialmente, a perda diminui rapidamente, conforme o esperado:

(0, 91.74887084960938)
(1, 76.85824584960938)
(2, 63.434078216552734)
(3, 51.46927261352539)
(4, 40.942893981933594)
(5, 31.819372177124023)

Cerca de 300 iterações, o erro chega perto de zero:

(300, 2.1734419819452455e-12)
(301, 1.90354676465887e-12)
(302, 2.3347573874232808e-12)

Isso acontece por alguns milhares de iterações. No entanto, após o treinamento por muito tempo, o erro começa a aumentar novamente:

(4997, 0.002102422062307596)
(4998, 0.0020302983466535807)
(4999, 0.0017039275262504816)

Por que isso está acontecendo?

Bai Li
fonte
Eu não acho que o excesso de ajuste explique - a perda de treinamento está subindo, não a perda de validação. Por exemplo, isso não acontece ao usar o SGD, apenas com o Adam.
Bai Li
O modelo possui 1000 parâmetros e há apenas 1 ponto de dados; portanto, o modelo deve ajustar-se exatamente aos dados e a perda deve ser zero.
Bai Li
Oh, desculpe, você está certo. Existem 64 pontos de dados.
Bai Li
Existem 64 pontos de dados (ou seja, restrições) e 1000 parâmetros, portanto, é possível encontrar opções para os parâmetros para que o erro seja zero (e isso é fácil de ser feito analiticamente). Minha pergunta é por que Adam não encontra isso.
Bai Li

Respostas:

19

Essa pequena instabilidade no final da convergência é uma característica de Adam (e RMSProp) devido à forma como estima magnitudes médias de gradiente em etapas recentes e as divide por elas.

Uma coisa que Adam faz é manter uma média geométrica contínua dos gradientes e quadrados recentes dos gradientes. Os quadrados dos gradientes são usados ​​para dividir (outra média móvel) o gradiente atual para decidir a etapa atual. No entanto, quando o gradiente se tornar e permanecer muito próximo de zero, os quadrados do gradiente ficarão tão baixos que eles terão grandes erros de arredondamento ou serão efetivamente zero, o que pode gerar instabilidade (por exemplo, um gradiente estável a longo prazo em uma dimensão dá um passo relativamente pequeno de a devido a alterações em outros parâmetros), e o tamanho da etapa começa a pular, antes de se estabelecer novamente. 10 - 51010105

Na verdade, isso torna o Adam menos estável e pior para o seu problema do que a descida mais gradual do gradiente, supondo que você queira chegar tão perto de zero à perda zero quanto os cálculos permitirem o seu problema.

Na prática, em problemas de aprendizado profundo, você não chega tão perto da convergência (e para algumas técnicas de regularização, como paradas precoces, você não quer mesmo assim), portanto, geralmente não é uma preocupação prática sobre os tipos de problemas que Adam foi projetado para.

Você pode realmente ver isso ocorrendo no RMSProp em uma comparação de diferentes otimizadores (RMSProp é a linha preta - observe as últimas etapas assim que atinge o destino):

insira a descrição da imagem aqui

Você pode tornar o Adam mais estável e capaz de se aproximar da verdadeira convergência reduzindo a taxa de aprendizado. Por exemplo

optimizer = torch.optim.Adam(model.parameters(), lr=1e-5)

Levará mais tempo para otimizar. Usando lr=1e-5você precisa treinar para mais de 20.000 iterações antes de ver a instabilidade e a instabilidade é menos dramática, os valores ficam em torno de .107

Neil Slater
fonte
Esta é uma visualização espetacular, Neil. Quais são as dimensões reais? O que x e y representam? Os quadros são algumas épocas delta t ou n por quadro? Suponho que a estrela seja a melhor global em uma representação topográfica de disparidade (erro) em relação a dois parâmetros selecionados. Meu palpite está correto?
Douglas Daseeco 28/09
Não é minha visualização, você a encontrará em muitos lugares. As dimensões são unidades arbitrárias de parâmetros de entrada para uma função de teste e o gráfico mostra linhas de contorno para essa função (novamente em unidades arbitrárias, presumivelmente dimensionadas para que o NN funcione bem). Cada quadro é uma etapa de atualização de peso. Provavelmente é equivalente a uma atualização em mini-lote e, devido ao comportamento do SGD, espero que seja realmente resolvido exatamente usando o verdadeiro gradiente da função de teste - ou seja, não há conjunto de dados ou amostragem.
Neil Slater
1

O motivo é exatamente o mencionado na outra resposta, com uma ótima sugestão de usar uma taxa de aprendizado menor para evitar esse problema em torno de pequenos gradientes.

Eu posso pensar em algumas abordagens:

  1. Você pode recortar os gradientes com um limite superior / inferior, mas isso não garante a convergência e pode resultar em congelamento do treinamento, ficando preso em alguns mínimos locais e nunca sair dele.

  2. Treine com um tamanho de lote maior, mais épocas e com uma taxa de aprendizado decaída. Agora não tenho nenhuma prova prática de que aumentar o tamanho de um lote resulta em melhores gradientes, mas pelo que eu havia observado ao enfrentar problemas semelhantes aos seus, isso quase sempre ajudou.

Estou certo de que existem outros métodos (como taxa de aprendizado cíclico etc.) que tentam encontrar uma taxa de aprendizado ideal com base nas estatísticas.

Sanjay Krishna
fonte