Causas comuns de nans durante o treinamento

86

Percebi que uma ocorrência frequente durante o treinamento está NANsendo introduzida.

Freqüentemente, parece ser introduzido por pesos em camadas de produto interno / totalmente conectadas ou de convolução explodindo.

Isso está ocorrendo porque o cálculo do gradiente está explodindo? Ou é por causa da inicialização do peso (em caso afirmativo, por que a inicialização do peso tem esse efeito)? Ou provavelmente é causado pela natureza dos dados de entrada?

A questão abrangente aqui é simplesmente: Qual é o motivo mais comum para os NANs ocorrerem durante o treinamento? E em segundo lugar, quais são alguns métodos para combater isso (e por que funcionam)?

Aidan Gomez
fonte
Você está chamando funções específicas do MATLAB? É todo o seu próprio código?
Matthew Gunn
2
@MatthewGunn Não acho que esta questão seja específica do matlab, mas sim cafferelacionada.
Shai

Respostas:

137

Boa pergunta.
Eu me deparei com esse fenômeno várias vezes. Aqui estão minhas observações:


Gradiente explodir

Motivo: grandes gradientes desviam o processo de aprendizagem do caminho.

O que você deve esperar: Olhando o log de tempo de execução, você deve olhar os valores de perda por iteração. Você notará que a perda começa a crescer significativamente de iteração para iteração, eventualmente a perda será muito grande para ser representada por uma variável de ponto flutuante e se tornará nan.

O que você pode fazer: Diminua o base_lr(no solver.prototxt) em uma ordem de magnitude (pelo menos). Se você tiver várias camadas de perda, deve inspecionar o log para ver qual camada é responsável pela explosão do gradiente e diminuir loss_weight(em train_val.prototxt) para essa camada específica, em vez da geral base_lr.


Política de taxa de aprendizagem e parâmetros ruins

Motivo: o caffe falha ao calcular uma taxa de aprendizado válida e obtém 'inf'ou 'nan', em vez disso, essa taxa inválida multiplica todas as atualizações e, portanto, invalidando todos os parâmetros.

O que você deve esperar: olhando para o log do tempo de execução, você deve ver que a própria taxa de aprendizagem se torna 'nan', por exemplo:

... sgd_solver.cpp:106] Iteration 0, lr = -nan

O que você pode fazer: corrigir todos os parâmetros que afetam a taxa de aprendizagem em seu 'solver.prototxt'arquivo.
Por exemplo, se você usar lr_policy: "poly"e esquecer de definir o max_iterparâmetro, você acabará com lr = nan...
Para obter mais informações sobre a taxa de aprendizado no caffe, consulte este tópico .


Função de perda defeituosa

Motivo: às vezes, os cálculos da perda nas camadas de perda fazem com que nans apareça. Por exemplo, InfogainLosscamada de alimentação com valores não normalizados , usando camada de perda personalizada com bugs, etc.

O que você deve esperar: ao examinar o log de tempo de execução, você provavelmente não notará nada de incomum: a perda está diminuindo gradualmente e, de repente, um a nanaparece.

O que você pode fazer: veja se consegue reproduzir o erro, adicione impressão à camada de perda e depure o erro.

Por exemplo: Uma vez eu usei uma perda que normalizou a penalidade pela frequência de ocorrência do rótulo em um lote. Acontece que, se um dos rótulos de treinamento não aparecesse no lote - a perda calculada produzia nans. Nesse caso, trabalhar com lotes grandes o suficiente (no que diz respeito ao número de etiquetas do conjunto) foi o suficiente para evitar esse erro.


Entrada defeituosa

Motivo: você tem uma contribuição nannisso!

O que você deve esperar: assim que o processo de aprendizagem "atinge" essa entrada - a saída falha nan. Olhando para o log de tempo de execução, você provavelmente não notará nada incomum: a perda está diminuindo gradualmente e, de repente, um a nanaparece.

O que você pode fazer: reconstruir seus conjuntos de dados de entrada (lmdb / leveldn / hdf5 ...) certifique-se de não ter arquivos de imagem ruins em seu conjunto de treinamento / validação. Para depuração, você pode construir uma rede simples que lê a camada de entrada, tem uma perda simulada em cima dela e percorre todas as entradas: se uma delas estiver com defeito, essa rede falsa também deve produzir nan.


passo maior que o tamanho do kernel na "Pooling"camada

Por alguma razão, escolher stride> kernel_sizepara agrupar pode resultar em nans. Por exemplo:

layer {
  name: "faulty_pooling"
  type: "Pooling"
  bottom: "x"
  top: "y"
  pooling_param {
    pool: AVE
    stride: 5
    kernel: 3
  }
}

resultados com nans em y.


Instabilidades em "BatchNorm"

Foi relatado que, em algumas configurações, a "BatchNorm"camada pode gerar nans devido a instabilidades numéricas.
Este problema foi levantado em bvlc / caffe e PR # 5136 está tentando corrigi-lo.


Recentemente, tornou-se ciente de debug_infobandeira: Ajuste debug_info: trueem 'solver.prototxt'vai fazer print caffe para registrar mais informações de depuração (incluindo magnitudes de gradiente e valores de ativação) durante o treino: Esta informação pode ajudar na identificação blowups gradiente e outros problemas no processo de formação .

Shai
fonte
Obrigado, como interpretar esses números? Quais são esses números? pastebin.com/DLYgXK5v por que há apenas um número por saída de camada !? como devem ser esses números para que alguém saiba que há um problema ou não há !?
Rika
@Hossein é exatamente disso que trata este post .
Shai
Obrigado por esta resposta. Estou recebendo perda NAN para um aplicativo de segmentação de imagem treinado com perda DICE (mesmo depois de adicionar uma pequena constante de epsilon / suavidade). Meu conjunto de dados contém algumas imagens cuja verdade fundamental correspondente não contém nenhum rótulo de primeiro plano e quando removi essas imagens do treinamento, a perda foi estabilizada. Eu não tenho certeza por que isso?
samra irshad
@samrairshad, você já tentou aumentar o epsilon na perda de DICE?
Shai de
Sim eu fiz. Abri a postagem no estouro de pilha e colei a evolução da perda de algumas épocas. Aqui está a referência: stackoverflow.com/questions/62259112/…
samra irshad
5

No meu caso, a causa não foi definir o viés nas camadas de convolução / deconvolução.

Solução: adicione o seguinte aos parâmetros da camada de convolução.

bias_filler {tipo: valor "constante": 0}

Izady
fonte
como ficaria isso em matconvnet? Tenho algo como 'biases'.init_bias * ones (1,4, single)
h612
4

Esta resposta não é sobre uma causa para nans, mas sim propõe uma maneira de ajudar a depurá-lo. Você pode ter esta camada python:

class checkFiniteLayer(caffe.Layer):
  def setup(self, bottom, top):
    self.prefix = self.param_str
  def reshape(self, bottom, top):
    pass
  def forward(self, bottom, top):
    for i in xrange(len(bottom)):
      isbad = np.sum(1-np.isfinite(bottom[i].data[...]))
      if isbad>0:
        raise Exception("checkFiniteLayer: %s forward pass bottom %d has %.2f%% non-finite elements" %
                        (self.prefix,i,100*float(isbad)/bottom[i].count))
  def backward(self, top, propagate_down, bottom):
    for i in xrange(len(top)):
      if not propagate_down[i]:
        continue
      isf = np.sum(1-np.isfinite(top[i].diff[...]))
        if isf>0:
          raise Exception("checkFiniteLayer: %s backward pass top %d has %.2f%% non-finite elements" %
                          (self.prefix,i,100*float(isf)/top[i].count))

Adicionar esta camada em train_val.prototxtcertos pontos que você suspeita pode causar problemas:

layer {
  type: "Python"
  name: "check_loss"
  bottom: "fc2"
  top: "fc2"  # "in-place" layer
  python_param {
    module: "/path/to/python/file/check_finite_layer.py" # must be in $PYTHONPATH
    layer: "checkFiniteLayer"
    param_str: "prefix-check_loss" # string for printouts
  }
}
Shai
fonte
1

learning_rate é alto e deve ser diminuído A precisão no código RNN era nan, com selecione o valor baixo para a taxa de aprendizado que corrige

Mohammad Rasoul tanhatalab
fonte
-1

Eu estava tentando construir um autoencoder esparso e tinha várias camadas nele para induzir a esparsidade. Enquanto corria minha rede, encontrei os NaNs. Ao remover algumas das camadas (no meu caso, eu realmente tive que remover 1), descobri que os NaNs desapareceram. Então, eu acho que muita dispersão pode levar a NaNs também (alguns cálculos 0/0 podem ter sido invocados !?)

LKB
fonte
Você pode ser um pouco mais específico? você pode fornecer detalhes sobre a configuração que tinha se nana configuração fixa? que tipo de camadas? quais parâmetros?
Shai
1
@shai eu usei várias camadas InnerProduct (lr_mult 1, decay_mult 1, lr_mult 2, decay_mult 0, xavier, std: 0,01) camadas, cada uma seguida por ReLU (exceto a última). Eu estava trabalhando com MNIST e, se bem me lembro, a arquitetura era 784 -> 1000 -> 500 -> 250 -> 100 -> 30 (e uma fase de decodificador simétrico); remover a camada 30 junto com seu ReLU fez os NaNs desaparecerem.
LKB de