¿Cómo agregar regularizaciones en TensorFlow?

94

Encontré en muchos códigos de redes neuronales disponibles implementados con TensorFlow que los términos de regularización a menudo se implementan agregando manualmente un término adicional al valor de pérdida.

Mis preguntas son:

  1. ¿Existe una forma de regularización más elegante o recomendada que hacerlo manualmente?

  2. También encuentro que get_variabletiene un argumento regularizer. ¿Cómo debe usarse? Según mi observación, si le pasamos un regularizador (como tf.contrib.layers.l2_regularizer, por ejemplo , se calculará un tensor que representa un término regularizado y se agregará a una colección de gráficos denominada tf.GraphKeys.REGULARIZATOIN_LOSSES. ¿TensorFlow usará esa colección automáticamente (por ejemplo, los optimizadores durante el entrenamiento)? O ¿Se espera que use esa colección yo solo?

Lifu Huang
fuente
1
sólo para ser súper explícito, ¿es la forma de hacerlo S = tf.get_variable(name='S', regularizer=tf.contrib.layers.l2_regularizer )?
Pinocho
@Pinocho, ¿lo has descubierto?
Euler_Salter
2
@Euler_Salter Ya no recuerdo, ¡lo siento! ¡Ya no usas el flujo tensorial!
Pinocho

Respuestas:

70

Como dice en el segundo punto, usar el regularizerargumento es la forma recomendada. Puede usarlo get_variableo configurarlo una vez en suvariable_scope y regularizar todas sus variables.

Las pérdidas se recopilan en el gráfico y debe agregarlas manualmente a su función de costos de esta manera.

  reg_losses = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
  reg_constant = 0.01  # Choose an appropriate one.
  loss = my_normal_loss + reg_constant * sum(reg_losses)

¡Espero que ayude!

Lukasz Kaiser
fuente
2
Gracias hombre. Estaba pensando que TensorFlow tendría formas más inteligentes de manejar los términos de registro que hacerlo manualmente, parece que no: P
Lifu Huang
14
Por cierto, dos sugerencias, corrígeme si me equivoco. (1), creo que reg_constantpodría no ser necesario, ya que los regularizadores en TensorFlow tienen un argumento scaleen sus constructores para que el impacto de los términos reg se pueda controlar de una manera más detallada. Y (2) usar tf.add_npodría ser un poco mejor que sum, supongo que usar sum podría crear muchos tensores en el gráfico para almacenar el resultado intermedio.
Lifu Huang
1
así que para que quede muy claro, después de poner el regularizador en la variable S = tf.get_variable(name='S', regularizer=tf.contrib.layers.l2_regularizer ), ¿tengo el código que sugieres? ¿Como en sum(tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES))?
Pinocho
1
¿Podría mostrar cómo hacer que las variables de pesos sean parte de la colección recuperable por tf.get_collection (tf.GraphKeys.REGULARIZATION_LOSSES)?
Yu Shen
3
Parece que tf.reduce_sumdebería usarse en lugar de sum?
ComputerScientist
45

Algunos aspectos de la respuesta existente no me quedaron claros de inmediato, por lo que aquí hay una guía paso a paso:

  1. Defina un regularizador. Aquí es donde se puede establecer la constante de regularización, por ejemplo:

    regularizer = tf.contrib.layers.l2_regularizer(scale=0.1)
  2. Crea variables a través de:

        weights = tf.get_variable(
            name="weights",
            regularizer=regularizer,
            ...
        )

    De manera equivalente, las variables se pueden crear mediante el weights = tf.Variable(...)constructor regular , seguido de tf.add_to_collection(tf.GraphKeys.REGULARIZATION_LOSSES, weights).

  3. Defina algún losstérmino y agregue el término de regularización:

    reg_variables = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
    reg_term = tf.contrib.layers.apply_regularization(regularizer, reg_variables)
    loss += reg_term

    Nota: Parece que tf.contrib.layers.apply_regularizationse implementa como un AddN, por lo que es más o menos equivalente a sum(reg_variables).

bluenote10
fuente
10
Creo que está aplicando el regularizador dos veces, tanto en el paso como en el paso 3. apply_regularizationno debería ser necesario si ya especificó el regularizador al crear la variable.
interjay
2
@interjay, por favor, da un ejemplo, ¡todas estas respuestas son muy poco claras! Esto se debe a que siempre hay al menos una persona que escribe un comentario debajo y dice que la respuesta anterior tiene algún problema.
Euler_Salter
1
@interjay Estoy bastante seguro de que hacer ambas cosas era necesario la última vez que probé esto. Sin embargo, no estoy seguro de si esto ha cambiado.
bluenote10
1
No, eso no tiene sentido porque entonces no necesitaría pasar el mismo regularizador a dos funciones. La documentación (y el nombre) deja en claro que REGULARIZATION_LOSSESes la pérdida total devuelta por los regularizadores, por lo que básicamente está llamando regularizer(regularizer(weight)).
Interjay
1
Creo que la confusión aquí proviene de la parte "equivalente". Describe dos métodos diferentes y usted elige uno, no es un método que implique aplicar la regularización dos veces.
gcp
28

Daré una respuesta simple y correcta ya que no encontré ninguna. Necesita dos pasos simples, el resto se realiza mediante tensorflow magic:

  1. Agregue regularizadores al crear variables o capas:

    tf.layers.dense(x, kernel_regularizer=tf.contrib.layers.l2_regularizer(0.001))
    # or
    tf.get_variable('a', regularizer=tf.contrib.layers.l2_regularizer(0.001))
  2. Agregue el término de regularización al definir la pérdida:

    loss = ordinary_loss + tf.losses.get_regularization_loss()
alyaxey
fuente
Si estoy creando una operación de regularizador mediante regularizer = tf.contrib.layers.l2_regularizer (0.001), ¿puedo pasarla a iniciaciones de múltiples capas? o necesito crear un regularizador separado para cada capa comoregularizer1 = tf.contrib.layers.l2_regularizer (0.001), regularizer2 = ................. regularizer3 = .... .. ¿y así?
MiloMinderbinder
@Nitin Puede utilizar el mismo regularizador. Es solo una función de Python que aplica la pérdida a los pesos como argumento.
alyaxey
1
Esta parece la solución más elegante, pero ¿realmente funciona? ¿En qué se diferencia esto de, digamos, reg_variables = tf.get_collection (tf.GraphKeys.REGULARIZATION_LOSSES) reg_term = tf.contrib.layers.apply_regularization (regularizer, reg_variables) loss + = reg_term
GeorgeOfTheRF
1
Solo quiero mencionar que tf.contrib.layers.fully_connected puede reemplazar a tf.layers.dense y, además, agregar más funcionalidades. Consulte estos: esto , esto y esto .
Osama Salah
16

Otra opción para hacer esto con la contrib.learnbiblioteca es la siguiente, basada en el tutorial Deep MNIST en el sitio web de Tensorflow. Primero, asumiendo que ha importado las bibliotecas relevantes (como import tensorflow.contrib.layers as layers), puede definir una red en un método separado:

def easier_network(x, reg):
    """ A network based on tf.contrib.learn, with input `x`. """
    with tf.variable_scope('EasyNet'):
        out = layers.flatten(x)
        out = layers.fully_connected(out, 
                num_outputs=200,
                weights_initializer = layers.xavier_initializer(uniform=True),
                weights_regularizer = layers.l2_regularizer(scale=reg),
                activation_fn = tf.nn.tanh)
        out = layers.fully_connected(out, 
                num_outputs=200,
                weights_initializer = layers.xavier_initializer(uniform=True),
                weights_regularizer = layers.l2_regularizer(scale=reg),
                activation_fn = tf.nn.tanh)
        out = layers.fully_connected(out, 
                num_outputs=10, # Because there are ten digits!
                weights_initializer = layers.xavier_initializer(uniform=True),
                weights_regularizer = layers.l2_regularizer(scale=reg),
                activation_fn = None)
        return out 

Luego, en un método principal, puede usar el siguiente fragmento de código:

def main(_):
    mnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True)
    x = tf.placeholder(tf.float32, [None, 784])
    y_ = tf.placeholder(tf.float32, [None, 10])

    # Make a network with regularization
    y_conv = easier_network(x, FLAGS.regu)
    weights = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, 'EasyNet') 
    print("")
    for w in weights:
        shp = w.get_shape().as_list()
        print("- {} shape:{} size:{}".format(w.name, shp, np.prod(shp)))
    print("")
    reg_ws = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES, 'EasyNet')
    for w in reg_ws:
        shp = w.get_shape().as_list()
        print("- {} shape:{} size:{}".format(w.name, shp, np.prod(shp)))
    print("")

    # Make the loss function `loss_fn` with regularization.
    cross_entropy = tf.reduce_mean(
        tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y_conv))
    loss_fn = cross_entropy + tf.reduce_sum(reg_ws)
    train_step = tf.train.AdamOptimizer(1e-4).minimize(loss_fn)

Para que esto funcione, debe seguir el tutorial de MNIST que vinculé anteriormente e importar las bibliotecas relevantes, pero es un buen ejercicio para aprender TensorFlow y es fácil ver cómo la regularización afecta la salida. Si aplica una regularización como argumento, puede ver lo siguiente:

- EasyNet/fully_connected/weights:0 shape:[784, 200] size:156800
- EasyNet/fully_connected/biases:0 shape:[200] size:200
- EasyNet/fully_connected_1/weights:0 shape:[200, 200] size:40000
- EasyNet/fully_connected_1/biases:0 shape:[200] size:200
- EasyNet/fully_connected_2/weights:0 shape:[200, 10] size:2000
- EasyNet/fully_connected_2/biases:0 shape:[10] size:10

- EasyNet/fully_connected/kernel/Regularizer/l2_regularizer:0 shape:[] size:1.0
- EasyNet/fully_connected_1/kernel/Regularizer/l2_regularizer:0 shape:[] size:1.0
- EasyNet/fully_connected_2/kernel/Regularizer/l2_regularizer:0 shape:[] size:1.0

Tenga en cuenta que la parte de regularización le ofrece tres elementos, según los elementos disponibles.

Con regularizaciones de 0, 0.0001, 0.01 y 1.0, obtengo valores de precisión de prueba de 0.9468, 0.9476, 0.9183 y 0.1135, respectivamente, que muestran los peligros de los términos de alta regularización.

Científico de la computación
fuente
2
Ejemplo realmente detallado.
stackoverflowuser2010
5

Si alguien todavía está buscando, me gustaría agregar que en tf.keras puede agregar regularización de peso pasándolos como argumentos en sus capas. Un ejemplo de cómo agregar regularización L2 tomado al por mayor del sitio de tutoriales de Tensorflow Keras:

model = keras.models.Sequential([
    keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001),
                       activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001),
                       activation=tf.nn.relu),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])

Hasta donde yo sé, no hay necesidad de agregar manualmente las pérdidas de regularización con este método.

Referencia: https://www.tensorflow.org/tutorials/keras/overfit_and_underfit#add_weight_regularization

MoltenMuffins
fuente
4

Probé tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)y tf.losses.get_regularization_loss()con uno l2_regularizeren el gráfico, y descubrí que devuelven el mismo valor. Al observar la cantidad del valor, supongo que reg_constant ya tiene sentido en el valor al establecer el parámetro de tf.contrib.layers.l2_regularizer.

Oceano
fuente
3

Si tiene CNN, puede hacer lo siguiente:

En la función de su modelo:

conv = tf.layers.conv2d(inputs=input_layer,
                        filters=32,
                        kernel_size=[3, 3],
                        kernel_initializer='xavier',
                        kernel_regularizer=tf.contrib.layers.l2_regularizer(1e-5),
                        padding="same",
                        activation=None) 
...

En su función de pérdida:

onehot_labels = tf.one_hot(indices=tf.cast(labels, tf.int32), depth=num_classes)
loss = tf.losses.softmax_cross_entropy(onehot_labels=onehot_labels, logits=logits)
regularization_losses = tf.losses.get_regularization_losses()
loss = tf.add_n([loss] + regularization_losses)
tsveti_iko
fuente
1

Algunas respuestas me confunden más, aquí les doy dos métodos para que quede claro.

#1.adding all regs by hand
var1 = tf.get_variable(name='v1',shape=[1],dtype=tf.float32)
var2 = tf.Variable(name='v2',initial_value=1.0,dtype=tf.float32)
regularizer = tf.contrib.layers.l1_regularizer(0.1)
reg_term = tf.contrib.layers.apply_regularization(regularizer,[var1,var2])
#here reg_term is a scalar

#2.auto added and read,but using get_variable
with tf.variable_scope('x',
        regularizer=tf.contrib.layers.l2_regularizer(0.1)):
    var1 = tf.get_variable(name='v1',shape=[1],dtype=tf.float32)
    var2 = tf.get_variable(name='v2',shape=[1],dtype=tf.float32)
reg_losses = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
#here reg_losses is a list,should be summed 

Luego, se puede agregar a la pérdida total

user3201329
fuente
1
cross_entropy = tf.losses.softmax_cross_entropy(
  logits=logits, onehot_labels=labels)

l2_loss = weight_decay * tf.add_n(
     [tf.nn.l2_loss(tf.cast(v, tf.float32)) for v in tf.trainable_variables()])

loss = cross_entropy + l2_loss
Alex-zhai
fuente
1
Gracias por este fragmento de código, que puede proporcionar ayuda inmediata y limitada. Una explicación adecuada mejoraría enormemente su valor a largo plazo al mostrar por qué es una buena solución al problema y lo haría más útil para futuros lectores con otras preguntas similares. Edite su respuesta para agregar alguna explicación, incluidas las suposiciones que hizo.
Maximilian Peters
1

tf.GraphKeys.REGULARIZATION_LOSSES no se agregarán automáticamente, pero hay una forma sencilla de agregarlos:

reg_loss = tf.losses.get_regularization_loss()
total_loss = loss + reg_loss

tf.losses.get_regularization_loss()utiliza tf.add_npara sumar las entradas de tf.GraphKeys.REGULARIZATION_LOSSESelemento. tf.GraphKeys.REGULARIZATION_LOSSESNormalmente será una lista de escalares, calculada mediante funciones de regularizador. Obtiene entradas de llamadas a tf.get_variableque tienen el regularizerparámetro especificado. También puede agregar a esa colección manualmente. Eso sería útil al usar tf.Variabley también al especificar regularizadores de actividad u otros regularizadores personalizados. Por ejemplo:

#This will add an activity regularizer on y to the regloss collection
regularizer = tf.contrib.layers.l2_regularizer(0.1)
y = tf.nn.sigmoid(x)
act_reg = regularizer(y)
tf.add_to_collection(tf.GraphKeys.REGULARIZATION_LOSSES, act_reg)

(En este ejemplo, presumiblemente sería más efectivo regularizar x, ya que y realmente se aplana para x grande).

Elias Hasle
fuente