Comment ajouter des régularisations dans TensorFlow?

94

J'ai trouvé dans de nombreux codes de réseau neuronal disponibles mis en œuvre à l'aide de TensorFlow que les termes de régularisation sont souvent mis en œuvre 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 également que cela get_variablea un argument regularizer. Comment doit-il être utilisé? Selon mon observation, si nous lui passons un régulariseur (par exemple 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ée par les optimiseurs lors de l'entraînement)? Ou Dois-je utiliser cette collection par moi-même?

Lifu Huang
la source
1
juste pour être super explicite, est-ce la manière de le faire S = tf.get_variable(name='S', regularizer=tf.contrib.layers.l2_regularizer )?
Pinocchio
@Pinocchio l'avez-vous compris?
Euler_Salter
2
@Euler_Salter Je ne me souviens plus, désolé! N'utilisez plus de flux tenseur!
Pinocchio

Réponses:

70

Comme vous le dites dans le deuxième point, l'utilisation de l' regularizerargument est la méthode recommandée. Vous pouvez l'utiliser get_variableou le définir une fois dans votre variable_scopeet faire régulariser toutes vos variables.

Les pertes sont collecté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 cela pourra aider!

Lukasz Kaiser
la source
2
Merci mec. Je pensais que TensorFlow aurait des moyens plus intelligents de gérer les termes reg que de les faire manuellement, ne semble pas: P
Lifu Huang
14
BTW, deux suggestions, corrigez-moi si je me trompe. (1), je suppose que reg_constantce n'est peut-être pas nécessaire, car les régularisateurs de TensorFlow ont un argument scaledans leurs constructeurs afin que l'impact des termes reg puisse être contrôlé d'une manière plus fine. Et (2) l'utilisation tf.add_npourrait être légèrement meilleure que sum, je suppose que l'utilisation de la somme pourrait créer de nombreux tenseurs dans le graphique pour stocker le résultat intermédiaire.
Lifu Huang
1
donc juste pour que ce soit super clair, après avoir mis le régulariseur à la variable S = tf.get_variable(name='S', regularizer=tf.contrib.layers.l2_regularizer ), puis-je le code que vous avez suggéré? Comme dans sum(tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES))?
Pinocchio
1
Pourrait montrer comment rendre les variables de pondération pour faire partie de la collection récupérables par tf.get_collection (tf.GraphKeys.REGULARIZATION_LOSSES)?
Yu Shen
3
Il semble que tf.reduce_sumdevrait être utilisé à la place de sum?
ComputerScientist
45

Quelques aspects de la réponse existante n'étaient pas immédiatement clairs pour moi, voici donc un guide étape par étape:

  1. Définissez 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éez des variables via:

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

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

  3. Définissez un lossterme 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 qu'il tf.contrib.layers.apply_regularizationsoit implémenté comme un AddN, donc plus ou moins équivalent à sum(reg_variables).

bluenote10
la source
10
Je pense que vous appliquez le régulariseur deux fois - à la fois à l'étape et à l'étape 3. apply_regularizationne devrait pas être nécessaire si vous avez déjà spécifié le régulariseur lors de la création de la variable.
entre le
2
@interjay s'il vous plaît faites un exemple, toutes ces réponses ne sont pas claires! C'est parce qu'il y a toujours au moins une personne qui écrit un commentaire en dessous en disant que la réponse ci-dessus a quelque chose qui ne va pas.
Euler_Salter
1
@interjay Je suis presque sûr que faire les deux était nécessaire la dernière fois que j'ai testé cela. Je ne sais pas si cela a changé.
bluenote10
1
Non, cela n'a aucun sens car alors vous n'auriez pas besoin de passer le même régulariseur à deux fonctions. La documentation (et le nom) indique clairement que REGULARIZATION_LOSSESc'est la perte totale retournée par les régularisateurs, donc vous appelez essentiellement regularizer(regularizer(weight)).
entre
1
Je pense que la confusion vient ici de la partie «équivalente». Il décrit deux méthodes différentes et vous en choisissez une, ce n'est pas une méthode qui consiste à appliquer deux fois la régularisation.
gcp
28

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

  1. Ajoutez des régularisateurs lors de la création de variables ou de couches:

    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 lors de la définition de la perte:

    loss = ordinary_loss + tf.losses.get_regularization_loss()
alyaxey
la source
Si je crée une opération de régularisation par regularizer = tf.contrib.layers.l2_regularizer (0.001), puis-je la transmettre à des initiations à plusieurs couches? ou dois-je créer un régulariseur séparé pour chaque couche likeregularizer1 = tf.contrib.layers.l2_regularizer (0.001), regularizer2 = ................. regularizer3 = .... .. etc?
MiloMinderbinder
@Nitin Vous pouvez utiliser le même régulariseur. C'est juste une fonction python qui applique la perte aux poids comme argument.
alyaxey
1
Cela ressemble à la solution la plus élégante mais cela fonctionne-t-il vraiment? En quoi est-ce différent de dire reg_variables = tf.get_collection (tf.GraphKeys.REGULARIZATION_LOSSES) reg_term = tf.contrib.layers.apply_regularization (regularizer, reg_variables) loss + = reg_term
GeorgeOfTheRF
1
Je veux juste mentionner que tf.contrib.layers.fully_connected peut remplacer tf.layers.dense et, en outre, ajouter plus de fonctionnalités. Reportez-vous à ceux-ci: ceci , ceci et ceci .
Osama Salah
16

Une autre option pour le faire avec la contrib.learnbibliothèque est la suivante, basée sur le didacticiel Deep MNIST sur le site Web Tensorflow. Tout d'abord, en supposant que vous avez importé les bibliothèques pertinentes (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 lié précédemment et importer les bibliothèques pertinentes, mais c'est un bon exercice 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 de précision de test de 0,9468, 0,9476, 0,9183 et 0,1135, respectivement, montrant les dangers des termes de régularisation élevés.

Informaticien
la source
2
Exemple vraiment détaillé.
stackoverflowuser2010
5

Si quelqu'un cherche toujours, je voudrais juste ajouter que dans tf.keras, vous pouvez ajouter une régularisation de poids en les passant comme arguments dans vos couches. 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)
])

Il n'est pas nécessaire d'ajouter manuellement les pertes de régularisation avec cette méthode pour autant que je sache.

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

Muffins fondus
la source
4

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

océan
la source
3

Si vous avez CNN, vous pouvez faire ce qui suit:

Dans votre fonction 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)
tsveti_iko
la source
1

Certaines réponses me rendent plus confus. Ici, je donne deux méthodes pour le faire clairement.

#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

utilisateur3201329
la source
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
la source
1
Merci pour cet extrait de code, qui pourrait fournir une aide limitée et immédiate. Une explication appropriée améliorerait considérablement sa valeur à long terme en montrant pourquoi c'est une bonne solution au problème et la rendrait plus utile aux futurs lecteurs avec d'autres questions similaires. Veuillez modifier votre réponse pour ajouter des explications, y compris les hypothèses que vous avez formulées.
Maximilian Peters
1

tf.GraphKeys.REGULARIZATION_LOSSES ne seront pas ajoutés 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_npour additionner les entrées de l' tf.GraphKeys.REGULARIZATION_LOSSESélément par élément. tf.GraphKeys.REGULARIZATION_LOSSESsera généralement une liste de scalaires, calculés à l'aide des fonctions de régularisation. Il obtient les entrées des appels à tf.get_variablequi ont le regularizerparamètre spécifié. Vous pouvez également ajouter manuellement à cette collection. Cela serait utile lors de l'utilisation tf.Variableet également lors de la spécification des régulariseurs d'activité ou d'autres régulariseurs 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 probablement plus efficace de régulariser x, car y s'aplatit vraiment pour un x grand.)

Elias Hasle
la source