Jak dodać regularyzacje w TensorFlow?

95

W wielu dostępnych kodach sieci neuronowych zaimplementowanych przy użyciu TensorFlow zauważyłem, że warunki regularyzacyjne są często implementowane przez ręczne dodanie dodatkowego terminu do wartości straty.

Moje pytania to:

  1. Czy istnieje bardziej elegancki lub zalecany sposób regularyzacji niż robienie tego ręcznie?

  2. Uważam też, że get_variablema to argument regularizer. Jak należy tego używać? Zgodnie z moimi obserwacjami, jeśli przekażemy do niego regulator (np. tf.contrib.layers.l2_regularizerTensor reprezentujący człon regularyzowany zostanie obliczony i dodany do zbioru wykresów o nazwie tf.GraphKeys.REGULARIZATOIN_LOSSES. Czy ta kolekcja będzie automatycznie używana przez TensorFlow (np. Używana przez optymalizatory podczas uczenia)? czy oczekuje się, że sam powinienem korzystać z tej kolekcji?

Lifu Huang
źródło
1
żeby być bardzo wyraźnym, czy jest sposób, aby to zrobić S = tf.get_variable(name='S', regularizer=tf.contrib.layers.l2_regularizer )?
Pinocchio,
@Pinocchio, rozgryzłeś to?
Euler_Salter
2
@Euler_Salter Już nie pamiętam, przepraszam! Nie używam już tensora!
Pinokio

Odpowiedzi:

70

Jak powiesz w drugim punkcie, użycie regularizerargumentu jest zalecanym sposobem. Możesz go użyć get_variablelub ustawić raz w swoim variable_scopei uregulować wszystkie zmienne.

Straty są gromadzone na wykresie i musisz ręcznie dodać je do funkcji kosztu w ten sposób.

  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)

Mam nadzieję, że to pomoże!

Łukasz Kaiser
źródło
2
Dzięki stary. Myślałem, że TensorFlow miałby bardziej inteligentne sposoby obsługi warunków reg niż ręczne, wydaje się, że nie: P
Lifu Huang
14
BTW, dwie sugestie, popraw mnie, jeśli się mylę. (1), reg_constantwydaje mi się, że może nie być konieczne, ponieważ regulatory w TensorFlow mają argument scalew swoich konstruktorach, dzięki czemu wpływ warunków reg można kontrolować w bardziej precyzyjny sposób. I (2) użycie tf.add_nmoże być nieco lepsze niż sum, myślę, że użycie sumy może stworzyć wiele tensorów na wykresie do przechowywania pośrednich wyników.
Lifu Huang
1
żeby było to bardzo jasne, czy po umieszczeniu regulatora w zmiennej S = tf.get_variable(name='S', regularizer=tf.contrib.layers.l2_regularizer )mam kod, który zasugerowałeś? Jak w sum(tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES))?
Pinokio,
1
Czy można pokazać, jak sprawić, by zmienne wagi były częścią kolekcji, którą można odzyskać przez tf.get_collection (tf.GraphKeys.REGULARIZATION_LOSSES)?
Yu Shen,
3
Wygląda na to, że tf.reduce_sumnależy użyć zamiast sum?
ComputerScientist
46

Kilka aspektów istniejącej odpowiedzi nie było dla mnie od razu jasnych, więc oto przewodnik krok po kroku:

  1. Zdefiniuj regularyzator. Tutaj można ustawić stałą regularyzacji, np .:

    regularizer = tf.contrib.layers.l2_regularizer(scale=0.1)
    
  2. Utwórz zmienne poprzez:

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

    Równoważnie zmienne można tworzyć za pomocą zwykłego weights = tf.Variable(...)konstruktora, po którym następuje tf.add_to_collection(tf.GraphKeys.REGULARIZATION_LOSSES, weights).

  3. Zdefiniuj jakiś losstermin i dodaj termin regularyzacji:

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

    Uwaga: wygląda na to, że tf.contrib.layers.apply_regularizationjest zaimplementowany jako AddN, więc mniej więcej równoważny z sum(reg_variables).

bluenote10
źródło
10
Myślę, że stosujesz regularyzator dwukrotnie - zarówno w kroku, jak i w kroku 3. apply_regularizationnie powinno być konieczne, jeśli już określiłeś regulatora podczas tworzenia zmiennej.
interjay
2
@interjay, zrób przykład, wszystkie te odpowiedzi są bardzo niejasne! Dzieje się tak, ponieważ zawsze przynajmniej jedna osoba pisze pod spodem komentarz, mówiąc, że w powyższej odpowiedzi jest coś nie tak.
Euler_Salter
1
@interjay Jestem prawie pewien, że zrobienie obu było konieczne, kiedy ostatnio to testowałem. Nie jestem jednak pewien, czy to się zmieniło.
bluenote10
1
Nie, to nie ma sensu, ponieważ wtedy nie musiałbyś przekazywać tego samego regulatora do dwóch funkcji. Dokumentacja (i nazwa) jasno określa, że REGULARIZATION_LOSSESjest to całkowita strata zwrócona przez regulatory, więc zasadniczo dzwonisz regularizer(regularizer(weight)).
interjay
1
Myślę, że zamieszanie tutaj wynika z części „równoważnej”. Opisuje dwie różne metody i wybierasz jedną, nie jest to metoda, która wymaga dwukrotnego zastosowania regularyzacji.
gcp
28

Dam prostą, poprawną odpowiedź, ponieważ jej nie znalazłem. Potrzebujesz dwóch prostych kroków, resztę zajmuje magia tensorflow:

  1. Dodaj regulatory podczas tworzenia zmiennych lub warstw:

    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. Dodaj termin regularyzacji podczas definiowania straty:

    loss = ordinary_loss + tf.losses.get_regularization_loss()
    
alyaxey
źródło
Jeśli tworzę operację regulatora za pomocą regularizer = tf.contrib.layers.l2_regularizer (0,001), czy mogę przekazać to do inicjacji wielu warstw? czy też muszę utworzyć osobny regulator dla każdej warstwy, np. likeregularizer1 = tf.contrib.layers.l2_regularizer (0,001), regularyzator2 = ................. regularyzator3 = .... .. i tak dalej?
MiloMinderbinder
@Nitin Możesz użyć tego samego regulatora. Jest to po prostu funkcja Pythona, która jako argument stosuje utratę wagi.
alyaxey
1
To wygląda na najbardziej eleganckie rozwiązanie, ale czy to naprawdę działa? Czym się to różni od say reg_variables = tf.get_collection (tf.GraphKeys.REGULARIZATION_LOSSES) reg_term = tf.contrib.layers.apply_regularization (regulizer, reg_variables) loss + = reg_term
GeorgeOfTheRF
1
Chcę tylko wspomnieć, że tf.contrib.layers.fully_connected może zastąpić tf.layers.dense, a ponadto dodać więcej funkcji. Odnieś się do tych: to , to i to .
Osama Salah
16

Inna opcja zrobienia tego z contrib.learnbiblioteką jest następująca, oparta na samouczku Deep MNIST na stronie internetowej Tensorflow. Po pierwsze, zakładając, że zaimportowałeś odpowiednie biblioteki (takie jak import tensorflow.contrib.layers as layers), możesz zdefiniować sieć w oddzielnej metodzie:

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 

Następnie w głównej metodzie możesz użyć następującego fragmentu kodu:

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)

Aby to zadziałało, musisz postępować zgodnie z samouczkiem MNIST, z którym łączyłem się wcześniej i zaimportować odpowiednie biblioteki, ale nauczenie się TensorFlow jest przyjemnym ćwiczeniem i łatwo jest zobaczyć, jak regularyzacja wpływa na wynik. Jeśli zastosujesz regularyzację jako argument, zobaczysz:

- 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

Zwróć uwagę, że część regularyzacji zawiera trzy elementy w oparciu o dostępne elementy.

Przy regularyzacjach 0, 0,0001, 0,01 i 1,0, otrzymuję wartości dokładności testu wynoszące odpowiednio 0,9468, 0,9476, 0,9183 i 0,1135, pokazujące niebezpieczeństwa związane z wysokimi składnikami regularyzacyjnymi.

Informatyk
źródło
2
Naprawdę szczegółowy przykład.
stackoverflowuser2010
Downvoter, chcesz wyjaśnić? :)
ComputerScientist
5

Jeśli ktoś nadal szuka, chciałbym tylko dodać, że w tf.keras możesz dodać regulację wagi, przekazując je jako argumenty w swoich warstwach. Przykład dodania regularyzacji L2 pobranej hurtowo z witryny 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)
])

O ile wiem, nie ma potrzeby ręcznego dodawania strat regularyzacyjnych tą metodą.

Źródła: https://www.tensorflow.org/tutorials/keras/overfit_and_underfit#add_weight_regularization

MoltenMuffins
źródło
4

Przetestowałem tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)iz tf.losses.get_regularization_loss()jednym l2_regularizerna wykresie i stwierdziłem, że zwracają tę samą wartość. Obserwując ilość wartości, domyślam się, że reg_constant ma już sens dla wartości, ustawiając parametr tf.contrib.layers.l2_regularizer.

ocean
źródło
3

Jeśli masz CNN, możesz wykonać następujące czynności:

W swojej funkcji modelu:

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

W Twojej funkcji utraty:

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
źródło
1

Niektóre odpowiedzi wprawiają mnie w zakłopotanie, tutaj podaję dwie metody, aby to jasno wyrazić.

#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 

Następnie można go dodać do całkowitej straty

user3201329
źródło
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
źródło
1
Dziękujemy za ten fragment kodu, który może zapewnić ograniczoną, natychmiastową pomoc. Właściwe wyjaśnienie znacznie poprawiłoby jego długoterminową wartość, pokazując, dlaczego jest to dobre rozwiązanie problemu i uczyniłoby go bardziej użytecznym dla przyszłych czytelników z innymi, podobnymi pytaniami. Zmień swoją odpowiedź, dodając wyjaśnienie, w tym przyjęte założenia.
Maximilian Peters
1

tf.GraphKeys.REGULARIZATION_LOSSES nie zostaną dodane automatycznie, ale istnieje prosty sposób na ich dodanie:

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

tf.losses.get_regularization_loss()używa tf.add_ndo sumowania wpisów tf.GraphKeys.REGULARIZATION_LOSSESelementarnych. tf.GraphKeys.REGULARIZATION_LOSSESbędzie zazwyczaj listą skalarów obliczoną za pomocą funkcji regulatora. Pobiera wpisy z wywołań, tf.get_variablektóre mają regularizerokreślony parametr. Możesz również dodać do tej kolekcji ręcznie. Byłoby to przydatne podczas używania, tf.Variablea także podczas określania regulatorów aktywności lub innych niestandardowych regulatorów. Na przykład:

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

(W tym przykładzie prawdopodobnie bardziej efektywne byłoby uregulowanie x, ponieważ y naprawdę spłaszcza się dla dużego x).

Elias Hasle
źródło