Как добавить регуляции в TensorFlow?
Я обнаружил во многих доступных нейронных сетевых кодах, реализованных с использованием TensorFlow, что условия регуляризации часто реализуются вручную, добавив дополнительный термин к значению потерь.
Мои вопросы:
-
Есть ли более элегантный или рекомендуемый способ регуляризации, чем делать это вручную?
-
Я также обнаружил, что get_variable
имеет аргумент regularizer
. Как его использовать? Согласно моему наблюдению, если мы передадим ему регуляризатор (например, tf.contrib.layers.l2_regularizer
, тензор, представляющий упорядоченный член, будет вычислен и добавлен в коллекцию графа с именем tf.GraphKeys.REGULARIZATOIN_LOSSES
. Будет ли эта коллекция автоматически использоваться TensorFlow (например, используется оптимизаторы при обучении)? Или ожидается, что я должен сам использовать эту коллекцию?
Ответы
Ответ 1
Как вы говорите во второй точке, рекомендуется использовать аргумент 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
Несколько аспектов существующего ответа не были сразу понятны мне, поэтому здесь приводится пошаговое руководство:
-
Определите регуляризатор. Здесь константа регуляризации может быть задана, например:
regularizer = tf.contrib.layers.l2_regularizer(scale=0.1)
-
Создание переменных через:
weights = tf.get_variable(
name="weights",
regularizer=regularizer,
...
)
Эквивалентно, переменные могут быть созданы с помощью обычного конструктора weights = tf.Variable(...)
, за которым следует tf.add_to_collection(tf.GraphKeys.REGULARIZATION_LOSSES, weights)
.
-
Определите некоторый член 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)
.
Ответ 3
Я дам простой правильный ответ, так как не нашел его. Вам понадобятся два простых шага, остальное - магия тензорного потока:
-
Добавьте регуляризаторы при создании переменных или слоев:
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))
-
Добавьте термин регуляризации при определении потери:
loss = ordinary_loss + tf.losses.get_regularization_loss()
Ответ 4
Другой вариант сделать это с библиотекой contrib.learn
заключается в следующем, на основе Deep MNIST tutorial на веб-сайте 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 соответственно, что указывает на опасность высоких констант регуляризации.
Ответ 5
Я тестировал tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
и tf.losses.get_regularization_loss()
с одним l2_regularizer
в графе и обнаружил, что они возвращают одно и то же значение. Наблюдая за количеством значений, я полагаю, что reg_constant уже имеет смысл в значении, установив параметр tf.contrib.layers.l2_regularizer
.
Ответ 6
Некоторые ответы меня больше смущают. Я даю два метода, чтобы сделать это ясно.
#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
Затем его можно добавить в общую потерю
Ответ 7
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
Ответ 8
Если у вас есть 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)