Come aggiungere le regolarizzazioni in TensorFlow?


94

Ho riscontrato in molti codici di reti neurali disponibili implementati utilizzando TensorFlow che i termini di regolarizzazione vengono spesso implementati aggiungendo manualmente un termine aggiuntivo al valore di perdita.

Le mie domande sono:

  1. Esiste un modo di regolarizzazione più elegante o consigliato rispetto a farlo manualmente?

  2. Trovo anche che get_variableabbia un argomento regularizer. Come dovrebbe essere utilizzato? Secondo la mia osservazione, se gli passiamo un regolarizzatore (ad esempio tf.contrib.layers.l2_regularizer, un tensore che rappresenta un termine regolarizzato verrà calcolato e aggiunto a una raccolta di grafici denominata tf.GraphKeys.REGULARIZATOIN_LOSSES. Tale raccolta verrà utilizzata automaticamente da TensorFlow (ad esempio utilizzata dagli ottimizzatori durante l'addestramento)? Oppure è previsto che io utilizzi quella raccolta da solo?


1
solo per essere super esplicito, è il modo per farlo S = tf.get_variable(name='S', regularizer=tf.contrib.layers.l2_regularizer )?
Pinocchio

@Pinocchio hai capito?
Euler_Salter

2
@Euler_Salter non ricordo più, scusa! Non usare più il flusso tensore!
Pinocchio

Risposte:


70

Come dici nel secondo punto, l'uso regularizerdell'argomento è il modo consigliato. Puoi usarlo get_variableo impostarlo una volta nel tuo variable_scopee regolarizzare tutte le tue variabili.

Le perdite vengono raccolte nel grafico e devi aggiungerle manualmente alla funzione di costo in questo modo.

  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)

Spero che aiuti!


2
Grazie uomo. Stavo pensando che TensorFlow avrebbe avuto alcuni modi più intelligenti di gestire i termini reg rispetto a quelli manuali, sembra di no: P
Lifu Huang

14
A proposito, due suggerimenti, correggimi se sbaglio. (1), immagino che reg_constantpotrebbe non essere necessario, poiché i regolarizzatori in TensorFlow hanno un argomento scalenei loro costruttori in modo che l'impatto dei termini reg possa essere controllato in modo più dettagliato. E (2) l'uso tf.add_npotrebbe essere leggermente migliore di sum, immagino che l'uso della somma potrebbe creare molti tensori nel grafico per memorizzare il risultato intermedio.
Lifu Huang

1
quindi solo per renderlo molto chiaro, dopo aver messo il regolarizzatore nella variabile S = tf.get_variable(name='S', regularizer=tf.contrib.layers.l2_regularizer ), allora ho il codice che hai suggerito? Come in sum(tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES))?
Pinocchio

1
Potrebbe mostrare come rendere le variabili dei pesi parte della raccolta recuperabile da tf.get_collection (tf.GraphKeys.REGULARIZATION_LOSSES)?
Yu Shen,

3
Sembra che tf.reduce_sumdovrebbe essere usato al posto di sum?
ComputerScientist

45

Alcuni aspetti della risposta esistente non mi sono stati immediatamente chiari, quindi ecco una guida passo passo:

  1. Definisci un regolarizzatore. Qui è dove è possibile impostare la costante di regolarizzazione, ad esempio:

    regularizer = tf.contrib.layers.l2_regularizer(scale=0.1)
  2. Crea variabili tramite:

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

    In modo equivalente, le variabili possono essere create tramite il normale weights = tf.Variable(...)costruttore, seguito da tf.add_to_collection(tf.GraphKeys.REGULARIZATION_LOSSES, weights).

  3. Definisci un losstermine e aggiungi il termine di regolarizzazione:

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

    Nota: sembra che tf.contrib.layers.apply_regularizationsia implementato come un AddN, quindi più o meno equivalente a sum(reg_variables).


10
Penso che tu stia applicando il regolarizzatore due volte, sia nel passaggio che nel passaggio 3. apply_regularizationnon dovrebbe essere necessario se hai già specificato il regolarizzatore durante la creazione della variabile.
Interjay

2
@interjay per favore fai un esempio, tutte queste risposte sono super poco chiare! Questo perché c'è sempre almeno una persona che scrive un commento sotto dicendo che la risposta sopra ha qualcosa che non va.
Euler_Salter

1
@interjay Sono abbastanza sicuro che fare entrambe le cose fosse necessario l'ultima volta che l'ho provato. Tuttavia, non sono sicuro che sia cambiato.
bluenote10

1
No, non ha senso perché in tal caso non sarebbe necessario passare lo stesso regolarizzatore a due funzioni. La documentazione (e il nome) chiarisce che REGULARIZATION_LOSSESè la perdita totale restituita dai regolarizzatori, quindi essenzialmente stai chiamando regularizer(regularizer(weight)).
Interjay

1
Penso che la confusione qui derivi dalla parte "equivalentemente". Descrive due metodi diversi e tu ne scegli uno, non è un metodo che coinvolge due volte la regolarizzazione.
gcp

28

Fornirò una semplice risposta corretta poiché non ne ho trovata una. Hai bisogno di due semplici passaggi, il resto è fatto dalla magia di tensorflow:

  1. Aggiungi regolarizzatori durante la creazione di variabili o livelli:

    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. Aggiungere il termine di regolarizzazione quando si definisce la perdita:

    loss = ordinary_loss + tf.losses.get_regularization_loss()

Se sto creando un'operazione di regolarizzazione da regularizer = tf.contrib.layers.l2_regularizer (0.001) posso passarla a più iniziazioni di livello? oppure devo creare un regolarizzatore separato per ogni livello likeregularizer1 = tf.contrib.layers.l2_regularizer (0.001), regularizer2 = ................. regularizer3 = .... .. e così via?
MiloMinderbinder

@ Nitin Puoi usare lo stesso regolarizzatore. È solo una funzione Python che applica la perdita ai pesi come argomento.
alyaxey

1
Questa sembra la soluzione più elegante ma funziona davvero? In cosa differisce da say reg_variables = tf.get_collection (tf.GraphKeys.REGULARIZATION_LOSSES) reg_term = tf.contrib.layers.apply_regularization (regularizer, reg_variables) loss + = reg_term
GeorgeOfTheRF

1
Voglio solo menzionare che tf.contrib.layers.fully_connected può sostituire tf.layers.dense e, inoltre, aggiungere più funzionalità. Fare riferimento a questi: questo , questo e questo .
Osama Salah

16

Un'altra opzione per farlo con la contrib.learnlibreria è la seguente, basata sul tutorial Deep MNIST sul sito Web di Tensorflow. Innanzitutto, supponendo che tu abbia importato le librerie pertinenti (come import tensorflow.contrib.layers as layers), puoi definire una rete in un metodo separato:

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 

Quindi, in un metodo principale, puoi utilizzare il seguente frammento di codice:

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)

Per farlo funzionare è necessario seguire il tutorial MNIST a cui ho collegato in precedenza e importare le librerie pertinenti, ma è un bel esercizio per imparare TensorFlow ed è facile vedere come la regolarizzazione influisce sull'output. Se applichi una regolarizzazione come argomento, puoi vedere quanto segue:

- 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

Nota che la parte di regolarizzazione ti dà tre elementi, in base agli elementi disponibili.

Con le regolarizzazioni di 0, 0,0001, 0,01 e 1,0, ottengo valori di accuratezza del test rispettivamente di 0,9468, 0,9476, 0,9183 e 0,1135, che mostrano i pericoli dei termini di regolarizzazione elevati.


2
Esempio davvero dettagliato.
stackoverflowuser2010

5

Se qualcuno sta ancora cercando, vorrei solo aggiungere che in tf.keras puoi aggiungere la regolarizzazione del peso passandoli come argomenti nei tuoi livelli. Un esempio di aggiunta della regolarizzazione L2 preso all'ingrosso dal sito 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)
])

Non è necessario aggiungere manualmente le perdite di regolarizzazione con questo metodo per quanto ne so.

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


4

Ho provato tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)e tf.losses.get_regularization_loss()con uno l2_regularizernel grafico e ho scoperto che restituiscono lo stesso valore. Osservando la quantità del valore, immagino che reg_constant abbia già avuto senso sul valore impostando il parametro di tf.contrib.layers.l2_regularizer.


3

Se hai la CNN puoi fare quanto segue:

Nella funzione del tuo modello:

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

Nella tua funzione di perdita:

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)

1

Alcune risposte mi rendono più confuso.Qui do due metodi per renderlo chiaro.

#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 

Quindi, può essere aggiunto alla perdita totale


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

1
Grazie per questo snippet di codice, che potrebbe fornire un aiuto limitato e immediato. Una spiegazione adeguata migliorerebbe notevolmente il suo valore a lungo termine mostrando perché questa è una buona soluzione al problema e la renderebbe più utile ai futuri lettori con altre domande simili. Modifica la tua risposta per aggiungere qualche spiegazione, comprese le ipotesi che hai fatto.
Maximilian Peters

1

tf.GraphKeys.REGULARIZATION_LOSSES non verranno aggiunti automaticamente, ma c'è un modo semplice per aggiungerli:

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

tf.losses.get_regularization_loss()usa tf.add_nper sommare le voci di tf.GraphKeys.REGULARIZATION_LOSSESelemento-saggio. tf.GraphKeys.REGULARIZATION_LOSSESsarà tipicamente un elenco di scalari, calcolato utilizzando le funzioni di regolarizzazione. Ottiene le voci dalle chiamate a tf.get_variableche hanno il regularizerparametro specificato. Puoi anche aggiungere a quella raccolta manualmente. Ciò sarebbe utile quando si utilizza tf.Variablee anche quando si specificano regolarizzatori di attività o altri regolarizzatori personalizzati. Per esempio:

#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 questo esempio sarebbe presumibilmente più efficace regolarizzare x, poiché y si appiattisce davvero per x grande.)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.