¿Cómo establecer la tasa de aprendizaje adaptativo para GradientDescentOptimizer?

104

Estoy usando TensorFlow para entrenar una red neuronal. Así es como estoy 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)

El problema aquí es que no sé cómo establecer una regla de actualización para la tasa de aprendizaje o un valor de caída para eso.

¿Cómo puedo usar una tasa de aprendizaje adaptativo aquí?

nombre para mostrar
fuente
3
Es un buen hábito inicializar todas las variables después de especificar su optimizador porque algunos optimizadores como AdamOptimizer usan sus propias variables que también deben inicializarse. De lo contrario, puede obtener un error similar a este:FailedPreconditionError (see above for traceback): Attempting to use uninitialized value beta2_power
JYun
Recibo este error mencionado anteriormente, cuando intento establecer una nueva tasa de aprendizaje en Tensorflow por tf.train.GradientDescentOptimizer(new_lr).minimize(loss). Parece que establecer una nueva tasa de aprendizaje requiere inicializar el modelo con las variables ya entrenadas. Pero no puedo averiguar cómo hacer eso.
Siladittya

Respuestas:

193

En primer lugar, tf.train.GradientDescentOptimizerestá diseñado para utilizar una tasa de aprendizaje constante para todas las variables en todos los pasos. TensorFlow también proporciona optimizadores adaptativos listos para usar, incluidos el tf.train.AdagradOptimizery el tf.train.AdamOptimizer, y estos se pueden usar como reemplazos directos.

Sin embargo, si desea controlar la tasa de aprendizaje con un descenso de gradiente de otro modo vainilla, puede aprovechar el hecho de que el learning_rateargumento para el tf.train.GradientDescentOptimizerconstructor puede ser un Tensorobjeto. Esto le permite calcular un valor diferente para la tasa de aprendizaje en cada paso, por ejemplo:

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})

Alternativamente, puede crear un escalar tf.Variableque contenga la tasa de aprendizaje y asignarlo cada vez que desee cambiar la tasa de aprendizaje.

señor
fuente
Gran respuesta. ¿Se puede utilizar la misma técnica para el recorte de degradado? tf.clip_by_normno acepta un tensor para la norma del clip, entonces, ¿qué tal si [(tf.minimum(gv[0], ct), gv[1]) for gv in optimizer.compute_gradients(cost, vars)], dóndect = tf.placeholder('float32', shape=[])
Richizy
Eso debería funcionar, sí. (Aunque mirando tf.clip_by_norm, lo único que impide que acepte un tensor como entrada es la constant_op.constant(1.0 / clip_norm)sustitución de esa expresión con. math_ops.inv(clip_norm)Sería hacer que funcione con un marcador de posición (o cualquier otro tensor) de entrada.)
mrry
@mrry Hice lo que dijiste y de alguna manera la velocidad de entrenamiento es mucho más lenta. ¿Se espera por favor?
tnq177
89

Tensorflow proporciona un artículo para aplicar automáticamente un decaimiento exponencial a un tensor velocidad de aprendizaje: tf.train.exponential_decay. Para ver un ejemplo en uso, consulte esta línea en el ejemplo del modelo convolucional MNIST . Luego, use la sugerencia de @ mrry anterior para proporcionar esta variable como el parámetro learning_rate a su optimizador de elección.

El extracto clave para mirar es:

# 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)

Tenga en cuenta el global_step=batchparámetro para minimizar. Eso le dice al optimizador que incremente de manera útil el parámetro 'lote' cada vez que entrena.

dga
fuente
3
Por lo general, se llama a la variable que batchllama global_stepy hay varias funciones de conveniencia, una para crearla tf.train.create_global_step()(que simplemente crea un número entero tf.Variabley lo agrega a la tf.GraphKeys.GLOBAL_STEPcolección) y tf.train.get_global_step().
Lenar Hoyt
86

El algoritmo de descenso de gradiente utiliza la tasa de aprendizaje constante que puede proporcionar durante la inicialización . Puede aprobar varias tasas de aprendizaje de la manera que muestra Mrry.

Pero en lugar de eso, también puede usar optimizadores más avanzados que tienen una tasa de convergencia más rápida y se adaptan a la situación.

Aquí hay una breve explicación basada en mi entendimiento:

  • El impulso ayuda a SGD a navegar en las direcciones relevantes y suaviza las oscilaciones en las irrelevantes. Simplemente agrega una fracción de la dirección del paso anterior a un paso actual. Esto logra la amplificación de la velocidad en la dirección correcta y suaviza la oscilación en direcciones incorrectas. Esta fracción suele estar en el rango (0, 1). También tiene sentido utilizar el impulso adaptativo. Al comienzo del aprendizaje, un gran impulso solo obstaculizará su progreso, por lo que tiene sentido usar algo como 0.01 y una vez que desaparezcan todos los gradientes altos, puede usar un impulso mayor. Hay un problema con el impulso: cuando estamos muy cerca de la meta, nuestro impulso en la mayoría de los casos es muy alto y no sabe que debería ralentizarse. Esto puede hacer que se pierda u oscile alrededor de los mínimos.
  • El gradiente acelerado de nesterov supera este problema al comenzar a desacelerar temprano. En el impulso, primero calculamos el gradiente y luego damos un salto en esa dirección amplificado por el impulso que teníamos anteriormente. NAG hace lo mismo pero en otro orden: primero damos un gran salto en función de nuestra información almacenada, luego calculamos el gradiente y hacemos una pequeña corrección. Este cambio aparentemente irrelevante proporciona importantes aceleraciones prácticas.
  • AdaGrad o gradiente adaptativo permite que la tasa de aprendizaje se adapte según los parámetros. Realiza actualizaciones más grandes para los parámetros poco frecuentes y actualizaciones más pequeñas para los frecuentes. Debido a esto, es muy adecuado para datos dispersos (NLP o reconocimiento de imágenes). Otra ventaja es que básicamente elimina la necesidad de ajustar la tasa de aprendizaje. Cada parámetro tiene su propia tasa de aprendizaje y, debido a las peculiaridades del algoritmo, la tasa de aprendizaje disminuye monótonamente. Esto causa el mayor problema: en algún momento, la tasa de aprendizaje es tan pequeña que el sistema deja de aprender.
  • AdaDelta resuelve el problema de la disminución monótona de la tasa de aprendizaje en AdaGrad. En AdaGrad, la tasa de aprendizaje se calculó aproximadamente como uno dividido por la suma de raíces cuadradas. En cada etapa, agrega otra raíz cuadrada a la suma, lo que hace que el denominador disminuya constantemente. En AdaDelta, en lugar de sumar todas las raíces cuadradas pasadas, utiliza una ventana deslizante que permite que la suma disminuya. RMSprop es muy similar a AdaDelta
  • Adam o el impulso adaptativo es un algoritmo similar a AdaDelta. Pero además de almacenar tasas de aprendizaje para cada uno de los parámetros, también almacena los cambios de impulso para cada uno de ellos por separado.

    A pocos visualizaciones : ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

Salvador Dalí
fuente
2
Para comparar diferentes optimizadores en TensorFlow, eche un vistazo al siguiente cuaderno de ipython : github.com/vsmolyakov/experiments_with_python/blob/master/chp03/… para
Vadim Smolyakov
Los optimizadores más avanzados no deben tomarse "en su lugar", pero además, consulte stats.stackexchange.com/questions/200063/…
Dima Lituiev
@DimaLituiev ¿puedes usar dos optimizadores al mismo tiempo? Si no es así, estás usando optimizer1 en lugar de optimizer2.
Salvador Dali
1
eso no es lo que estoy diciendo, y no era la pregunta aquí. Sugieres usar optimizadores avanzados en lugar de la tasa de aprendizaje adaptativo. Estoy diciendo que prefiere usar optimizadores avanzados además de la tasa de aprendizaje adaptativo
Dima Lituiev
7

De los documentos oficiales de 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
fuente
0

Si desea establecer tasas de aprendizaje específicas para intervalos de épocas como 0 < a < b < c < .... Luego, puede definir su tasa de aprendizaje como un tensor condicional, condicional en el paso global, y alimentar esto de forma normal al optimizador.

Puede lograr esto con un montón de tf.conddeclaraciones anidadas , pero es más fácil construir el tensor de forma recursiva:

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,)
            )

Luego, para usarlo, debe saber cuántos pasos de entrenamiento hay en una sola época, de modo que podamos usar el paso global para cambiar en el momento adecuado y, finalmente, definir las épocas y las tasas de aprendizaje que desee. Entonces, si quiero las tasas de aprendizaje [0.1, 0.01, 0.001, 0.0001]durante los intervalos de época de [0, 19], [20, 59], [60, 99], [100, \infty]respectivamente, haría:

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
fuente