web-dev-qa-db-fra.com

Comment ajouter des régularisations dans TensorFlow?

J'ai constaté dans de nombreux codes de réseau neuronal disponibles implémentés à l'aide de TensorFlow que les termes de régularisation sont souvent implémentés en ajoutant manuellement un terme supplémentaire à la valeur de perte.

Mes questions sont:

  1. Existe-t-il un moyen de régularisation plus élégant ou recommandé que de le faire manuellement?

  2. Je trouve aussi que get_variable a un argument regularizer. Comment devrait-il être utilisé? Selon mon observation, si nous lui passons un régularisateur (tel que tf.contrib.layers.l2_regularizer, un tenseur représentant un terme régularisé sera calculé et ajouté à une collection de graphes nommée tf.GraphKeys.REGULARIZATOIN_LOSSES. Cette collection sera-t-elle automatiquement utilisée par TensorFlow? (par exemple, utilisé par les optimiseurs lors de la formation)? Ou est-il prévu que je devrais utiliser cette collection par moi-même?

87
Lifu Huang

Comme vous le dites dans le deuxième point, l'utilisation de l'argument regularizer est la méthode recommandée. Vous pouvez l'utiliser dans get_variable, ou le définir une fois dans votre variable_scope et régulariser toutes vos variables.

Les pertes sont rassemblées dans le graphique et vous devez les ajouter manuellement à votre fonction de coût comme ceci.

  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)

J'espère que ça t'as aidé!

66
Lukasz Kaiser

Quelques aspects de la réponse existante ne m'ont pas été immédiatement compris. Voici donc un guide pas à pas:

  1. Définir un régularisateur. C’est ici que la constante de régularisation peut être définie, par exemple:

    regularizer = tf.contrib.layers.l2_regularizer(scale=0.1)
    
  2. Créer des variables via:

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

    De manière équivalente, les variables peuvent être créées via le constructeur régulier weights = tf.Variable(...), suivi de tf.add_to_collection(tf.GraphKeys.REGULARIZATION_LOSSES, weights).

  3. Définissez un terme loss et ajoutez le terme de régularisation:

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

    Remarque: Il semble que tf.contrib.layers.apply_regularization soit implémenté en tant que AddN, donc plus ou moins équivalent à sum(reg_variables).

41
bluenote10

Je vais vous donner une réponse simple et correcte car je n'en ai pas trouvé. Vous avez besoin de deux étapes simples, le reste est fait par la magie du tensorflow:

  1. Ajoutez des régulariseurs lors de la création de variables ou de calques:

    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. Ajoutez le terme de régularisation lorsque vous définissez une perte:

    loss = ordinary_loss + tf.losses.get_regularization_loss()
    
24
alyaxey

Une autre option pour ce faire avec la bibliothèque contrib.learn est la suivante, basée sur le didacticiel MNIST approfondi sur le site Web de Tensorflow. Tout d'abord, en supposant que vous ayez importé les bibliothèques appropriées (telles que import tensorflow.contrib.layers as layers), vous pouvez définir un réseau dans une méthode distincte:

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 

Ensuite, dans une méthode principale, vous pouvez utiliser l'extrait de code suivant:

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)

Pour que cela fonctionne, vous devez suivre le didacticiel MNIST auquel j'ai déjà fait référence et importer les bibliothèques appropriées, mais c'est un exercice agréable pour apprendre TensorFlow et il est facile de voir comment la régularisation affecte la sortie. Si vous appliquez une régularisation en tant qu'argument, vous pouvez voir ce qui suit:

- 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

Notez que la partie régularisation vous donne trois éléments, en fonction des éléments disponibles.

Avec des régularisations de 0, 0,0001, 0,01 et 1,0, j'obtiens des valeurs d'exactitude de test de 0,9468, 0,9476, 0,9183 et 0,11155, montrant les dangers de conditions de régularisation élevées.

17

J'ai testé tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES) et tf.losses.get_regularization_loss() avec un l2_regularizer dans le graphique et j'ai constaté qu'ils retournaient la même valeur. En observant la quantité de la valeur, je suppose que reg_constant a déjà un sens pour la valeur en définissant le paramètre de tf.contrib.layers.l2_regularizer.

4
ocean

Si quelqu'un cherche toujours, j'aimerais juste ajouter que dans tf.keras, vous pouvez ajouter une régularisation du poids en les passant comme arguments dans vos calques. Voici un exemple d’ajout de régularisation L2 pris en gros à partir du site Tensorflow Keras Tutorials:

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

Autant que je sache, il n'est pas nécessaire d'ajouter manuellement les pertes de régularisation avec cette méthode.

Référence: https://www.tensorflow.org/tutorials/keras/overfit_and_underfit#add_weight_regularization

3
MoltenMuffins

Si vous avez CNN, vous pouvez procéder comme suit:

Dans votre fonction de modèle:

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

Dans votre fonction de perte:

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)
3
tsveti_iko

Certaines réponses me rendent plus confus. Je donne deux méthodes pour le rendre clair.

#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 

Ensuite, il peut être ajouté à la perte totale

1
user3201329
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
1
Alex-zhai

tf.GraphKeys.REGULARIZATION_LOSSES ne sera pas ajouté automatiquement, mais il existe un moyen simple de les ajouter:

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

tf.losses.get_regularization_loss() utilise tf.add_n pour additionner les entrées de tf.GraphKeys.REGULARIZATION_LOSSES élément. tf.GraphKeys.REGULARIZATION_LOSSES sera généralement une liste de scalaires, calculée à l'aide des fonctions de régulariseur. Il obtient les entrées des appels à tf.get_variable pour lesquels le paramètre regularizer est spécifié. Vous pouvez également ajouter manuellement à cette collection. Cela serait utile lors de l’utilisation de tf.Variable ainsi que lors de la spécification de régulateurs d’activité ou d’autres régulateurs personnalisés. Par exemple:

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

(Dans cet exemple, il serait vraisemblablement plus efficace de régulariser x, car y s'aplatit vraiment pour les gros x.)

0
Elias Hasle