Wie füge ich Regularisierungen in TensorFlow hinzu?

94

Ich habe in vielen verfügbaren neuronalen Netzwerkcodes, die mit TensorFlow implementiert wurden, festgestellt, dass Regularisierungsterme häufig durch manuelles Hinzufügen eines zusätzlichen Terms zum Verlustwert implementiert werden.

Meine Fragen sind:

  1. Gibt es eine elegantere oder empfohlene Art der Regularisierung als die manuelle?

  2. Ich finde auch, dass get_variabledas ein Argument hat regularizer. Wie soll es verwendet werden? Nach meiner Beobachtung wird, wenn wir einen Regularisierer an ihn übergeben (z. B. tf.contrib.layers.l2_regularizerein Tensor, der einen regulierten Term darstellt, berechnet und zu einer Diagrammsammlung mit dem Namen hinzugefügt tf.GraphKeys.REGULARIZATOIN_LOSSES. Wird diese Sammlung automatisch von TensorFlow verwendet (z. B. von Optimierern beim Training verwendet)? Wird erwartet, dass ich diese Sammlung selbst verwenden sollte?

Lifu Huang
quelle
1
Nur um super explizit zu sein, ist der Weg, es zu tun S = tf.get_variable(name='S', regularizer=tf.contrib.layers.l2_regularizer )?
Pinocchio
@ Pinocchio hast du es herausgefunden?
Euler_Salter
2
@Euler_Salter Ich erinnere mich nicht mehr, sorry! Tensor Flow nicht mehr verwenden!
Pinocchio

Antworten:

70

Wie Sie im zweiten Punkt sagen, wird die Verwendung des regularizerArguments empfohlen. Sie können es in verwenden get_variableoder einmal in Ihrem festlegen variable_scopeund alle Ihre Variablen regulieren lassen.

Die Verluste werden in der Grafik erfasst, und Sie müssen sie wie folgt manuell zu Ihrer Kostenfunktion hinzufügen.

  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)

Hoffentlich hilft das!

Lukasz Kaiser
quelle
2
Danke, Mann. Ich dachte, TensorFlow hätte einige intelligentere Möglichkeiten, mit Reg-Begriffen umzugehen, als sie manuell zu tun, scheint nicht: P
Lifu Huang
14
Übrigens, zwei Vorschläge, korrigieren Sie mich, wenn ich falsch liege. (1), denke ich, ist reg_constantmöglicherweise nicht notwendig, da Regularisierer in TensorFlow ein Argument scalein ihren Konstruktoren haben, damit die Auswirkung von reg-Begriffen feinkörniger gesteuert werden kann. Und (2) die Verwendung von tf.add_nkönnte etwas besser sein als sum, ich denke, die Verwendung von sum könnte viele Tensoren im Diagramm erzeugen, um Zwischenergebnisse zu speichern.
Lifu Huang
1
Also, um es super klar zu machen, nachdem ich den Regularizer auf die Variable gesetzt habe S = tf.get_variable(name='S', regularizer=tf.contrib.layers.l2_regularizer ), habe ich dann den Code, den Sie vorgeschlagen haben? Wie in sum(tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES))?
Pinocchio
1
Könnte zeigen, wie die Gewichtungsvariablen als Teil der Sammlung von tf.get_collection (tf.GraphKeys.REGULARIZATION_LOSSES) abgerufen werden können?
Yu Shen
3
Es scheint wie tf.reduce_sumsollte statt verwendet werden sum?
ComputerScientist
45

Einige Aspekte der vorhandenen Antwort waren mir nicht sofort klar, daher hier eine Schritt-für-Schritt-Anleitung:

  1. Definieren Sie einen Regularizer. Hier kann die Regularisierungskonstante eingestellt werden, z.

    regularizer = tf.contrib.layers.l2_regularizer(scale=0.1)
  2. Erstellen Sie Variablen über:

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

    Entsprechend können Variablen über den regulären weights = tf.Variable(...)Konstruktor erstellt werden, gefolgt von tf.add_to_collection(tf.GraphKeys.REGULARIZATION_LOSSES, weights).

  3. Definieren Sie einen lossBegriff und fügen Sie den Regularisierungsbegriff hinzu:

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

    Hinweis: Es sieht so aus tf.contrib.layers.apply_regularization, als wäre es als implementiert AddN, also mehr oder weniger äquivalent zu sum(reg_variables).

bluenote10
quelle
10
Ich denke, Sie wenden den Regularizer zweimal an - sowohl in Schritt als auch in Schritt 3. Dies apply_regularizationsollte nicht erforderlich sein, wenn Sie den Regularizer bereits beim Erstellen der Variablen angegeben haben.
Interjay
2
@interjay bitte mach ein Beispiel, all diese Antworten sind super unklar! Dies liegt daran, dass immer mindestens eine Person einen Kommentar darunter schreibt, der besagt, dass die obige Antwort etwas falsch macht.
Euler_Salter
1
@interjay Ich bin mir ziemlich sicher, dass beides notwendig war, als ich das letzte Mal getestet habe. Ich bin mir nicht sicher, ob sich dies geändert hat.
bluenote10
1
Nein, das macht keinen Sinn, denn dann müssten Sie nicht denselben Regularizer an zwei Funktionen übergeben. Die Dokumentation (und der Name) machen deutlich, dass REGULARIZATION_LOSSESes sich um den von den Regularisierern zurückgegebenen Gesamtverlust handelt, sodass Sie im Wesentlichen anrufen regularizer(regularizer(weight)).
Interjay
1
Ich denke, die Verwirrung hier rührt vom "äquivalenten" Teil her. Er beschreibt zwei verschiedene Methoden, und Sie wählen eine aus. Es handelt sich nicht um eine Methode, bei der die Regularisierung zweimal angewendet wird.
GCP
28

Ich werde eine einfache richtige Antwort geben, da ich keine gefunden habe. Sie benötigen zwei einfache Schritte, der Rest wird durch Tensorflow-Magie erledigt:

  1. Fügen Sie beim Erstellen von Variablen oder Ebenen Regularisierer hinzu:

    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. Fügen Sie den Regularisierungsbegriff hinzu, wenn Sie den Verlust definieren:

    loss = ordinary_loss + tf.losses.get_regularization_loss()
Alyaxey
quelle
Wenn ich einen Regularizer-Op mit dem Regularizer = tf.contrib.layers.l2_regularizer (0,001) erstelle, kann ich ihn dann an mehrere Ebeneninitiationen übergeben? oder muss ich für jede Ebene einen separaten Regularizer erstellen .. und so weiter?
MiloMinderbinder
@Nitin Sie können denselben Regularizer verwenden. Es ist nur eine Python-Funktion, die als Argument den Verlust auf Gewichte anwendet.
Alyaxey
1
Das sieht nach der elegantesten Lösung aus, aber funktioniert das wirklich? Wie unterscheidet sich von etwa reg_variables = tf.get_collection (tf.GraphKeys.REGULARIZATION_LOSSES) reg_term = tf.contrib.layers.apply_regularization (Regularisator, reg_variables) Verlust + = reg_term
GeorgeOfTheRF
1
Ich möchte nur erwähnen, dass tf.contrib.layers.fully_connected tf.layers.dense ersetzen und darüber hinaus weitere Funktionen hinzufügen kann. Beziehen Sie sich auf diese: dies , dies und das .
Osama Salah
16

Eine weitere Option, um dies mit der contrib.learnBibliothek zu tun, ist die folgende, basierend auf dem Deep MNIST-Tutorial auf der Tensorflow-Website. Angenommen, Sie haben die relevanten Bibliotheken (z. B. import tensorflow.contrib.layers as layers) importiert , können Sie zunächst ein Netzwerk in einer separaten Methode definieren:

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 

In einer Hauptmethode können Sie dann das folgende Codefragment verwenden:

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)

Damit dies funktioniert, müssen Sie dem zuvor verlinkten MNIST-Tutorial folgen und die relevanten Bibliotheken importieren. Es ist jedoch eine gute Übung, TensorFlow zu lernen, und es ist leicht zu erkennen, wie sich die Regularisierung auf die Ausgabe auswirkt. Wenn Sie eine Regularisierung als Argument anwenden, sehen Sie Folgendes:

- 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

Beachten Sie, dass der Regularisierungsteil drei Elemente enthält, basierend auf den verfügbaren Elementen.

Mit Regularisierungen von 0, 0,0001, 0,01 und 1,0 erhalte ich Testgenauigkeitswerte von 0,9468, 0,9476, 0,9183 bzw. 0,1135, was die Gefahren hoher Regularisierungsterme zeigt.

Informatiker
quelle
2
Wirklich detailliertes Beispiel.
stackoverflowuser2010
5

Wenn noch jemand sucht, möchte ich nur hinzufügen, dass Sie in tf.keras eine Gewichtsregulierung hinzufügen können, indem Sie sie als Argumente in Ihren Ebenen übergeben. Ein Beispiel für das Hinzufügen einer L2-Regularisierung, die im Großhandel von der Tensorflow Keras Tutorials-Website übernommen wurde:

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

Soweit ich weiß, müssen die Regularisierungsverluste bei dieser Methode nicht manuell addiert werden.

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

Geschmolzene Muffins
quelle
4

Ich habe getestet tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)und tf.losses.get_regularization_loss()mit einem l2_regularizerin der Grafik festgestellt, dass sie den gleichen Wert zurückgeben. Wenn Sie die Menge des Werts beobachten, hat reg_constant den Wert bereits durch Setzen des Parameters von sinnvoll tf.contrib.layers.l2_regularizer.

Ozean
quelle
3

Wenn Sie CNN haben, können Sie Folgendes tun:

In Ihrer Modellfunktion:

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

In Ihrer Verlustfunktion:

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
quelle
1

Einige Antworten machen mich verwirrter. Hier gebe ich zwei Methoden, um es klar zu machen.

#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 

Dann kann es zum Gesamtverlust addiert werden

user3201329
quelle
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
quelle
1
Vielen Dank für dieses Code-Snippet, das möglicherweise nur begrenzte und sofortige Hilfe bietet. Eine richtige Erklärung würde ihren langfristigen Wert erheblich verbessern, indem sie zeigt, warum dies eine gute Lösung für das Problem ist, und es für zukünftige Leser mit anderen, ähnlichen Fragen nützlicher machen. Bitte bearbeiten Sie Ihre Antwort, um eine Erklärung hinzuzufügen, einschließlich der von Ihnen getroffenen Annahmen.
Maximilian Peters
1

tf.GraphKeys.REGULARIZATION_LOSSES wird nicht automatisch hinzugefügt, aber es gibt eine einfache Möglichkeit, sie hinzuzufügen:

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

tf.losses.get_regularization_loss()wird verwendet, tf.add_num die Einträge von tf.GraphKeys.REGULARIZATION_LOSSESelementweise zu summieren . tf.GraphKeys.REGULARIZATION_LOSSESIn der Regel handelt es sich um eine Liste von Skalaren, die mithilfe von Regularisierungsfunktionen berechnet werden. Es werden Einträge von Aufrufen abgerufen tf.get_variable, für die der regularizerParameter angegeben wurde. Sie können diese Sammlung auch manuell hinzufügen. Dies ist nützlich, wenn Sie tf.VariableAktivitäts-Regularisierer oder andere benutzerdefinierte Regularisierer verwenden und auch angeben. Zum Beispiel:

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

(In diesem Beispiel wäre es vermutlich effektiver, x zu regulieren, da y für großes x wirklich abflacht.)

Elias Hasle
quelle