Как добавить регуляризации в 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 будет несколько более разумных способов обработки терминов reg, чем при их использовании вручную, похоже, нет: P
Лифу Хуанг
14
Кстати, два предложения, поправьте меня, если я ошибаюсь. (1), я думаю, это reg_constantможет быть необязательно, поскольку регуляризаторы в TensorFlow имеют аргумент scaleв своих конструкторах, так что влияние условий 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нет необходимости, если вы уже указали регуляризатор при создании переменной.
Interjay
2
@interjay, пожалуйста, приведите пример, все эти ответы очень непонятны! Это потому, что всегда есть по крайней мере один человек, который пишет под комментарием, что в приведенном выше ответе что-то не так.
Euler_Salter
1
@interjay Я почти уверен, что делать и то и другое было необходимо в последний раз, когда я это тестировал. Я не уверен, что это изменилось.
bluenote10
1
Нет, в этом нет смысла, потому что тогда вам не нужно передавать один и тот же регуляризатор двум функциям. Документация (и название) ясно дает понять, что REGULARIZATION_LOSSESэто полная потеря, возвращаемая регуляризаторами, поэтому вы, по сути, звоните regularizer(regularizer(weight)).
Interjay
1
Я думаю, что путаница здесь проистекает из части «эквивалентности». Он описывает два разных метода, и вы выбираете один, это не тот метод, который требует двойного применения регуляризации.
gcp
28

Я дам простой правильный ответ, так как не нашел. Вам нужно два простых шага, остальное сделает магия тензорного потока:

  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()
алексей
источник
Если я создаю операцию регуляризатора с помощью Regularizer = tf.contrib.layers.l2_regularizer (0.001), могу ли я передать его инициациям нескольких уровней? или мне нужно создать отдельный регуляризатор для каждого слоя, например, regularizer1 = tf.contrib.layers.l2_regularizer (0.001), regularizer2 = ................. регуляризатор3 = .... .. и так далее?
MiloMinderbinder
@Nitin Вы можете использовать тот же регуляризатор. Это просто функция Python, которая применяет потерю к весам в качестве аргумента.
alyaxey 07
1
Это кажется наиболее элегантным решением, но действительно ли это работает? Чем это отличается от, скажем, reg_variables = tf.get_collection (tf.GraphKeys.REGULARIZATION_LOSSES) reg_term = tf.contrib.layers.apply_regularization (регуляризатор, reg_variables) loss + = 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)
tsveti_iko
источник
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 

Затем его можно добавить в общую потерю

user3201329
источник
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.)

Элиас Хасл
источник