Як додати регуляризації в TensorFlow?


94

У багатьох доступних кодах нейронної мережі, реалізованих за допомогою TensorFlow, я виявив, що умови регуляризації часто реалізуються вручну, додаючи додатковий термін до вартості втрат.

Мої запитання:

  1. Чи є більш елегантний або рекомендований спосіб регуляризації, ніж робити це вручну?

  2. Я також вважаю, що get_variableтут є аргумент regularizer. Як його використовувати? Згідно з моїм спостереженням, якщо ми передамо йому регуляризатор (наприклад tf.contrib.layers.l2_regularizer, тензор, що представляє регуляризований термін, буде обчислений і доданий до набору графіків з іменем tf.GraphKeys.REGULARIZATOIN_LOSSES. Чи буде ця колекція автоматично використовуватися TensorFlow (наприклад, використовуватися оптимізаторами під час навчання)? Або чи очікується, що я повинен використовувати цю колекцію самостійно?


1
просто щоб бути супер явним, це спосіб це зробити S = tf.get_variable(name='S', regularizer=tf.contrib.layers.l2_regularizer )?
Буратіно

@Pinocchio ти це зрозумів?
Euler_Salter

2
@Euler_Salter Я вже не пам’ятаю, вибачте! Більше не використовуючи тензорний потік!
Буратіно

Відповіді:


70

Як ви говорите у другому пункті, використання regularizerаргументу є рекомендованим способом. Ви можете використовувати його get_variableабо встановити один раз у своєму, variable_scopeі всі ваші змінні будуть упорядковані.

Втрати збираються на графіку, і вам потрібно вручну додати їх до вашої функції витрат, як це.

  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)

Сподіваюся, що це допомагає!


2
Дякую людино. Я думав, що TensorFlow матиме кілька розумніших способів обробки регіональних термінів, ніж вручну, здається, ні: P
Lifu Huang

14
До речі, дві пропозиції, виправте мене, якщо я помиляюся. (1), я думаю, це reg_constantможе бути не потрібно, оскільки scaleрегулятори в TensorFlow мають аргумент у своїх конструкторах, щоб вплив reg-термінів можна було контролювати більш детально. І (2) використання tf.add_nможе бути трохи кращим, ніж sum, я думаю, використання суми може створити багато тензорів у графіку для зберігання проміжного результату.
Ліфу Хуан

1
так що, щоб це було надзвичайно чітко, після того, як я поставив регулятор до змінної S = tf.get_variable(name='S', regularizer=tf.contrib.layers.l2_regularizer ), то чи робити мені код, який ви запропонували? Як у sum(tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES))?
Буратіно

1
Чи може показати, як зробити змінні ваги частиною колекції, яку можна отримати за допомогою tf.get_collection (tf.GraphKeys.REGULARIZATION_LOSSES)?
Ю Шень

3
Здається, tf.reduce_sumслід використовувати замість sum?
ComputerScientist

45

Декілька аспектів існуючої відповіді були мені не одразу зрозумілі, тож ось покроковий посібник:

  1. Визначте регулятор. Тут можна встановити константу регуляризації, наприклад:

    regularizer = tf.contrib.layers.l2_regularizer(scale=0.1)
  2. Створюйте змінні за допомогою:

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

    Еквівалентно, змінні можна створювати за допомогою регулярного weights = tf.Variable(...)конструктора, за яким слід tf.add_to_collection(tf.GraphKeys.REGULARIZATION_LOSSES, weights).

  3. Визначте деякий lossтермін і додайте термін регуляризації:

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

    Примітка: Схоже tf.contrib.layers.apply_regularization, реалізовано як AddN, тому більш-менш еквівалентно sum(reg_variables).


10
Я думаю, ви застосовуєте регулятор двічі - і в кроці, і в кроці 3. apply_regularizationне потрібно, якщо ви вже вказали регулятор при створенні змінної.
інтержой

2
@interjay, будь ласка, наведіть приклад, усі ці відповіді надзвичайно незрозумілі! Це пов’язано з тим, що завжди є принаймні одна людина, яка пише коментар нижче, кажучи, що у наведеній вище відповіді щось не так.
Euler_Salter

1
@interjay Я майже впевнений, що робити обоє потрібно було востаннє, коли я це тестував. Я не впевнений, що це змінилося.
bluenote10,

1
Ні, це не має сенсу, тому що тоді вам не потрібно буде передавати один і той же регулятор на дві функції. З документації (та назви) чітко видно, що REGULARIZATION_LOSSESце загальна втрата, яку повертають регулятори, тож ви по суті телефонуєте regularizer(regularizer(weight)).
інтермедія

1
Я думаю, що плутанина тут походить від "рівноцінно" частини. Він описує два різні методи, і ви вибираєте один, це не один метод, який передбачає застосування регуляризації двічі.
GCP

28

Я дам просту правильну відповідь, оскільки я її не знайшов. Вам потрібні два простих кроки, решта виконується за допомогою магії tensorflow:

  1. Додайте регулятори під час створення змінних або шарів:

    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. Додайте термін регуляризації при визначенні збитків:

    loss = ordinary_loss + tf.losses.get_regularization_loss()

Якщо я створюю регуляризатор op за допомогою regularizer = tf.contrib.layers.l2_regularizer (0,001), чи можу я передати його на кілька ініціацій шару? або мені потрібно створити окремий регулятор для кожного шару, наприклад, регулятор1 = tf.contrib.layers.l2_regularizer (0,001), регулятор2 = ................. регуляризатор3 = .... .. і так далі?
MiloMinderbinder

@Nitin Ви можете використовувати той самий регулятор. Це просто функція python, яка застосовує втрати до ваг як свій аргумент.
alyaxey

1
Це виглядає як найелегантніше рішення, але чи справді це працює? Чим це відрізняється від say reg_variables = tf.get_collection (tf.GraphKeys.REGULARIZATION_LOSSES) reg_term = tf.contrib.layers.apply_regularization (регулятор, reg_variables) втрата + = reg_term
GeorgeOfTheRF

1
Я просто хочу зазначити, що tf.contrib.layers.fully_connected може замінити tf.layers.dense і, крім того, додати більше функціональних можливостей. Зверніться до них: це , це і це .
Усама Салах

16

Інший варіант зробити це з contrib.learnбібліотекою полягає в наступному, заснованому на підручнику Deep MNIST на веб-сайті Tensorflow. По-перше, припускаючи, що ви імпортували відповідні бібліотеки (такі як import tensorflow.contrib.layers as layers), ви можете визначити мережу окремим методом:

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 

Тоді в основному методі ви можете використовувати такий фрагмент коду:

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)

Щоб це працювало, вам потрібно дотримуватися підручника MNIST, до якого я посилався раніше, та імпортувати відповідні бібліотеки, але це приємна вправа для вивчення TensorFlow, і легко зрозуміти, як регуляризація впливає на результат. Якщо ви застосуєте регуляризацію як аргумент, ви можете побачити наступне:

- 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

Зверніть увагу, що частина регуляризації дає вам три елементи, виходячи з наявних елементів.

З регуляризаціями 0, 0,0001, 0,01 та 1,0, я отримую значення точності випробувань 0,9468, 0,9476, 0,9183 та 0,1135 відповідно, показуючи небезпеку високих умов регуляризації.


2
Дійсно детальний приклад.
stackoverflowuser2010,

5

Якщо хтось все ще шукає, я просто хотів би додати, що в tf.keras ви можете додати регуляризацію ваги, передаючи їх як аргументи у свої шари. Приклад додавання регуляризації L2, взятий оптом із веб-сайту 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)
])

Наскільки мені відомо, немає необхідності додавати втрати від регуляризації вручну за допомогою цього методу.

Посилання: https://www.tensorflow.org/tutorials/keras/overfit_and_underfit#add_weight_regularization


4

Я протестував tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)і tf.losses.get_regularization_loss()з одним l2_regularizerна графіку, і виявив, що вони повертають однакове значення. Спостерігаючи за величиною значення, я вважаю, що reg_constant вже мав сенс щодо значення, встановивши параметр tf.contrib.layers.l2_regularizer.


3

Якщо у вас CNN, ви можете зробити наступне:

У функції вашої моделі:

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

У функції втрат:

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

Деякі відповіді роблять мене більш розгубленим. Тут я даю два методи, щоб це чітко пояснити.

#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 

Тоді це може бути додано до загальної втрати


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
Дякуємо за цей фрагмент коду, який може надати обмежену негайну допомогу. Правильне пояснення значно покращило б його довгострокове значення, показавши, чому це хороше рішення проблеми, і зробило б його більш корисним для майбутніх читачів з іншими подібними питаннями. Будь ласка, відредагуйте свою відповідь, щоб додати пояснення, включаючи припущення, які ви зробили.
Максиміліан Пітерс

1

tf.GraphKeys.REGULARIZATION_LOSSES не додаватимуться автоматично, але є простий спосіб додати їх:

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

tf.losses.get_regularization_loss()використовує tf.add_nдля підсумовування елементів по tf.GraphKeys.REGULARIZATION_LOSSESелементам. tf.GraphKeys.REGULARIZATION_LOSSESзазвичай являє собою список скалярів, обчислений за допомогою функцій регулятора. Він отримує записи із викликів, для tf.get_variableяких regularizerвказаний параметр. Ви також можете додати до цієї колекції вручну. Це було б корисно при використанні, tf.Variableа також при зазначенні регуляторів діяльності або інших спеціальних регуляторів. Наприклад:

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

(У цьому прикладі, мабуть, було б ефективніше регулювати x, оскільки y справді вирівнюється для великого x.)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.