Como definir a taxa de aprendizado adaptável para GradientDescentOptimizer?

104

Estou usando o TensorFlow para treinar uma rede neural. É assim que estou inicializando GradientDescentOptimizer:

init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)

mse        = tf.reduce_mean(tf.square(out - out_))
train_step = tf.train.GradientDescentOptimizer(0.3).minimize(mse)

O que acontece aqui é que não sei como definir uma regra de atualização para a taxa de aprendizado ou um valor de decaimento para isso.

Como posso usar uma taxa de aprendizagem adaptativa aqui?

Nome em Exibição
fonte
3
É um bom hábito inicializar todas as variáveis depois de especificar seu otimizador, porque alguns otimizadores como AdamOptimizer usam suas próprias variáveis ​​que também precisam ser inicializadas. Caso contrário, você pode obter um erro parecido com este:FailedPreconditionError (see above for traceback): Attempting to use uninitialized value beta2_power
JYun
Estou recebendo o erro mencionado acima, quando tento definir uma nova taxa de aprendizado no Tensorflow por tf.train.GradientDescentOptimizer(new_lr).minimize(loss). Parece que a definição de uma nova taxa de aprendizado requer a inicialização do modelo com as variáveis ​​já treinadas. Mas não consigo descobrir como fazer isso.
Siladittya

Respostas:

193

Em primeiro lugar, tf.train.GradientDescentOptimizeré projetado para usar uma taxa de aprendizado constante para todas as variáveis ​​em todas as etapas. O TensorFlow também fornece otimizadores adaptativos prontos para uso, incluindo o tf.train.AdagradOptimizere o tf.train.AdamOptimizer, e eles podem ser usados ​​como substitutos imediatos.

No entanto, se você deseja controlar a taxa de aprendizado com a descida gradiente de outra forma, você pode tirar vantagem do fato de que o learning_rateargumento para o tf.train.GradientDescentOptimizerconstrutor pode ser um Tensorobjeto. Isso permite que você calcule um valor diferente para a taxa de aprendizagem em cada etapa, por exemplo:

learning_rate = tf.placeholder(tf.float32, shape=[])
# ...
train_step = tf.train.GradientDescentOptimizer(
    learning_rate=learning_rate).minimize(mse)

sess = tf.Session()

# Feed different values for learning rate to each training step.
sess.run(train_step, feed_dict={learning_rate: 0.1})
sess.run(train_step, feed_dict={learning_rate: 0.1})
sess.run(train_step, feed_dict={learning_rate: 0.01})
sess.run(train_step, feed_dict={learning_rate: 0.01})

Como alternativa, você pode criar um escalar tf.Variableque mantenha a taxa de aprendizado e atribuí-lo a cada vez que quiser alterar a taxa de aprendizado.

senhor
fonte
Ótima resposta. A mesma técnica pode ser usada para recorte de gradiente? tf.clip_by_normnão aceita um tensor para a norma do clipe, então que tal fazer [(tf.minimum(gv[0], ct), gv[1]) for gv in optimizer.compute_gradients(cost, vars)], ondect = tf.placeholder('float32', shape=[])
richizy
Isso deve funcionar, sim. (Embora olhando para tf.clip_by_norm, a única coisa que o impede de aceitar um tensor como entrada é o constant_op.constant(1.0 / clip_norm). Substituir essa expressão por math_ops.inv(clip_norm)faria com que funcionasse com uma entrada de espaço reservado (ou qualquer outro tensor).)
mrry
@mrry Fiz o que você disse e de alguma forma a velocidade do treinamento é muito mais lenta. É esperado, por favor?
tnq177
89

Tensorflow fornece uma op para aplicar automaticamente um decaimento exponencial a um tensor taxa de aprendizagem: tf.train.exponential_decay. Para obter um exemplo em uso, consulte esta linha no exemplo do modelo convolucional MNIST . Em seguida, use a sugestão de @mrry acima para fornecer essa variável como o parâmetro learning_rate para o otimizador de sua escolha.

O principal trecho a ser examinado é:

# Optimizer: set up a variable that's incremented once per batch and
# controls the learning rate decay.
batch = tf.Variable(0)

learning_rate = tf.train.exponential_decay(
  0.01,                # Base learning rate.
  batch * BATCH_SIZE,  # Current index into the dataset.
  train_size,          # Decay step.
  0.95,                # Decay rate.
  staircase=True)
# Use simple momentum for the optimization.
optimizer = tf.train.MomentumOptimizer(learning_rate,
                                     0.9).minimize(loss,
                                                   global_step=batch)

Observe o global_step=batchparâmetro a minimizar. Isso diz ao otimizador para incrementar o parâmetro 'batch' para você toda vez que treinar.

dga
fonte
3
Normalmente, a variável que você chama batché chamada global_stepe existem várias funções de conveniência, uma para criá-la tf.train.create_global_step()(que simplesmente cria um inteiro tf.Variablee o adiciona à tf.GraphKeys.GLOBAL_STEPcoleção) e tf.train.get_global_step().
Lenar Hoyt
86

O algoritmo de gradiente descendente usa a taxa de aprendizado constante que você pode fornecer durante a inicialização . Você pode passar por várias taxas de aprendizagem da maneira mostrada por Mrry.

Mas em vez disso, você também pode usar otimizadores mais avançados, que têm uma taxa de convergência mais rápida e se adaptam à situação.

Aqui está uma breve explicação com base no meu entendimento:

  • momentum ajuda SGD a navegar ao longo das direções relevantes e suaviza as oscilações no irrelevante. Ele simplesmente adiciona uma fração da direção da etapa anterior a uma etapa atual. Isso atinge a amplificação da velocidade na direção correta e suaviza a oscilação em direções erradas. Esta fração está geralmente no intervalo (0, 1). Também faz sentido usar momentum adaptativo. No início do aprendizado, um grande impulso apenas atrapalhará seu progresso, então faz sentido usar algo como 0,01 e, uma vez que todos os gradientes altos tenham desaparecido, você pode usar um impulso maior. Há um problema com o momentum: quando estamos muito próximos da meta, nosso momentum na maioria dos casos é muito alto e ele não sabe que deve desacelerar. Isso pode fazer com que ele perca ou oscile em torno dos mínimos
  • O gradiente acelerado de nesterov supera esse problema começando a desacelerar cedo. No momento, primeiro calculamos o gradiente e, em seguida, damos um salto nessa direção amplificado por qualquer momento anterior. NAG faz a mesma coisa, mas em outra ordem: primeiro, damos um grande salto com base em nossas informações armazenadas e, em seguida, calculamos o gradiente e fazemos uma pequena correção. Essa mudança aparentemente irrelevante oferece acelerações práticas significativas.
  • AdaGrad ou gradiente adaptativo permite que a taxa de aprendizagem se adapte com base em parâmetros. Ele executa atualizações maiores para parâmetros não frequentes e atualizações menores para parâmetros frequentes. Por isso, é adequado para dados esparsos (PNL ou reconhecimento de imagem). Outra vantagem é que basicamente elimina a necessidade de ajustar a taxa de aprendizagem. Cada parâmetro possui sua própria taxa de aprendizado e devido às peculiaridades do algoritmo, a taxa de aprendizado é monotonicamente decrescente. Isso causa o maior problema: em algum ponto do tempo, a taxa de aprendizagem é tão pequena que o sistema para de aprender
  • AdaDelta resolve o problema de diminuir monotonicamente a taxa de aprendizagem em AdaGrad. Em AdaGrad, a taxa de aprendizagem foi calculada aproximadamente como um dividido pela soma das raízes quadradas. Em cada estágio, você adiciona outra raiz quadrada à soma, o que faz com que o denominador diminua constantemente. Em AdaDelta, em vez de somar todas as raízes quadradas anteriores, ele usa uma janela deslizante que permite que a soma diminua. RMSprop é muito semelhante ao AdaDelta
  • Adam ou momentum adaptativo é um algoritmo semelhante ao AdaDelta. Mas, além de armazenar taxas de aprendizagem para cada um dos parâmetros, ele também armazena mudanças de momentum para cada um deles separadamente

    A poucos visualizações : insira a descrição da imagem aqui insira a descrição da imagem aqui

Salvador Dalí
fonte
2
Para comparação de diferentes otimizadores no TensorFlow, dê uma olhada no seguinte notebook ipython : github.com/vsmolyakov/experiments_with_python/blob/master/chp03/… for
Vadim Smolyakov
Otimizadores mais avançados não devem ser usados
Dima Lituiev
@DimaLituiev você pode usar dois otimizadores ao mesmo tempo? Se não, então você está usando o otimizador1 em vez do otimizador2.
Salvador Dali
1
não é isso que estou dizendo e essa não era a questão aqui. Você sugere o uso de otimizadores avançados em vez de taxa de aprendizagem adaptativa. Estou dizendo que você prefere usar otimizadores avançados além da taxa de aprendizagem adaptativa
Dima Lituiev
7

Dos documentos oficiais do tensorflow

global_step = tf.Variable(0, trainable=False)
starter_learning_rate = 0.1
learning_rate = tf.train.exponential_decay(starter_learning_rate, global_step,
                                       100000, 0.96, staircase=True)

# Passing global_step to minimize() will increment it at each step.
learning_step = (
tf.train.GradientDescentOptimizer(learning_rate)
.minimize(...my loss..., global_step=global_step))
Prakash Vanapalli
fonte
0

Se você deseja definir taxas de aprendizagem específicas para intervalos de épocas como 0 < a < b < c < .... Em seguida, você pode definir sua taxa de aprendizado como um tensor condicional, condicional à etapa global, e alimentar isso normalmente para o otimizador.

Você poderia conseguir isso com um monte de tf.condinstruções aninhadas , mas é mais fácil construir o tensor recursivamente:

def make_learning_rate_tensor(reduction_steps, learning_rates, global_step):
    assert len(reduction_steps) + 1 == len(learning_rates)
    if len(reduction_steps) == 1:
        return tf.cond(
            global_step < reduction_steps[0],
            lambda: learning_rates[0],
            lambda: learning_rates[1]
        )
    else:
        return tf.cond(
            global_step < reduction_steps[0],
            lambda: learning_rates[0],
            lambda: make_learning_rate_tensor(
                reduction_steps[1:],
                learning_rates[1:],
                global_step,)
            )

Então, para usá-lo, você precisa saber quantas etapas de treinamento existem em uma única época, para que possamos usar a etapa global para alternar no momento certo e, finalmente, definir as épocas e as taxas de aprendizagem desejadas. Então, se eu quiser as taxas de aprendizado [0.1, 0.01, 0.001, 0.0001]durante os intervalos de época de [0, 19], [20, 59], [60, 99], [100, \infty]respectivamente, eu faria:

global_step = tf.train.get_or_create_global_step()
learning_rates = [0.1, 0.01, 0.001, 0.0001]
steps_per_epoch = 225
epochs_to_switch_at = [20, 60, 100]
epochs_to_switch_at = [x*steps_per_epoch for x in epochs_to_switch_at ]
learning_rate = make_learning_rate_tensor(epochs_to_switch_at , learning_rates, global_step)
Ben
fonte