TensorFlow — введение в сеть как регуляризации L2, так и отсева. Есть ли в этом смысл?

В настоящее время я играю с ANN, которая является частью курса Udactity DeepLearning.

Я успешно построил и обучил сеть и ввел регуляризацию L2 для всех весов и смещений. Прямо сейчас я пробую отсев для скрытого слоя, чтобы улучшить обобщение. Интересно, есть ли смысл одновременно вводить регуляризацию L2 в скрытый слой и отбрасывать на том же слое? Если да, то как это сделать правильно?

Во время выпадения мы буквально отключаем половину активаций скрытого слоя и удваиваем количество выводимых остальных нейронов. При использовании L2 мы вычисляем норму L2 для всех скрытых весов. Но я не уверен, как вычислить L2, если мы используем отсев. Мы отключаем некоторые активации, не должны ли мы удалить веса, которые сейчас «не используются» из расчета L2? Любые ссылки по этому вопросу будут полезны, я не нашел никакой информации.

На всякий случай, если вам интересно, мой код для ANN с регуляризацией L2 приведен ниже:

#for NeuralNetwork model code is below
#We will use SGD for training to save our time. Code is from Assignment 2
#beta is the new parameter - controls level of regularization. Default is 0.01
#but feel free to play with it
#notice, we introduce L2 for both biases and weights of all layers

beta = 0.01

#building tensorflow graph
graph = tf.Graph()
with graph.as_default():
      # Input data. For the training data, we use a placeholder that will be fed
  # at run time with a training minibatch.
  tf_train_dataset = tf.placeholder(tf.float32,
                                    shape=(batch_size, image_size * image_size))
  tf_train_labels = tf.placeholder(tf.float32, shape=(batch_size, num_labels))
  tf_valid_dataset = tf.constant(valid_dataset)
  tf_test_dataset = tf.constant(test_dataset)

  #now let's build our new hidden layer
  #that's how many hidden neurons we want
  num_hidden_neurons = 1024
  #its weights
  hidden_weights = tf.Variable(
    tf.truncated_normal([image_size * image_size, num_hidden_neurons]))
  hidden_biases = tf.Variable(tf.zeros([num_hidden_neurons]))

  #now the layer itself. It multiplies data by weights, adds biases
  #and takes ReLU over result
  hidden_layer = tf.nn.relu(tf.matmul(tf_train_dataset, hidden_weights) + hidden_biases)

  #time to go for output linear layer
  #out weights connect hidden neurons to output labels
  #biases are added to output labels  
  out_weights = tf.Variable(
    tf.truncated_normal([num_hidden_neurons, num_labels]))  

  out_biases = tf.Variable(tf.zeros([num_labels]))  

  #compute output  
  out_layer = tf.matmul(hidden_layer,out_weights) + out_biases
  #our real output is a softmax of prior result
  #and we also compute its cross-entropy to get our loss
  #Notice - we introduce our L2 here
  loss = (tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(
    out_layer, tf_train_labels) +
    beta*tf.nn.l2_loss(hidden_weights) +
    beta*tf.nn.l2_loss(hidden_biases) +
    beta*tf.nn.l2_loss(out_weights) +
    beta*tf.nn.l2_loss(out_biases)))

  #now we just minimize this loss to actually train the network
  optimizer = tf.train.GradientDescentOptimizer(0.5).minimize(loss)

  #nice, now let's calculate the predictions on each dataset for evaluating the
  #performance so far
  # Predictions for the training, validation, and test data.
  train_prediction = tf.nn.softmax(out_layer)
  valid_relu = tf.nn.relu(  tf.matmul(tf_valid_dataset, hidden_weights) + hidden_biases)
  valid_prediction = tf.nn.softmax( tf.matmul(valid_relu, out_weights) + out_biases) 

  test_relu = tf.nn.relu( tf.matmul( tf_test_dataset, hidden_weights) + hidden_biases)
  test_prediction = tf.nn.softmax(tf.matmul(test_relu, out_weights) + out_biases)



#now is the actual training on the ANN we built
#we will run it for some number of steps and evaluate the progress after 
#every 500 steps

#number of steps we will train our ANN
num_steps = 3001

#actual training
with tf.Session(graph=graph) as session:
  tf.initialize_all_variables().run()
  print("Initialized")
  for step in range(num_steps):
    # Pick an offset within the training data, which has been randomized.
    # Note: we could use better randomization across epochs.
    offset = (step * batch_size) % (train_labels.shape[0] - batch_size)
    # Generate a minibatch.
    batch_data = train_dataset[offset:(offset + batch_size), :]
    batch_labels = train_labels[offset:(offset + batch_size), :]
    # Prepare a dictionary telling the session where to feed the minibatch.
    # The key of the dictionary is the placeholder node of the graph to be fed,
    # and the value is the numpy array to feed to it.
    feed_dict = {tf_train_dataset : batch_data, tf_train_labels : batch_labels}
    _, l, predictions = session.run(
      [optimizer, loss, train_prediction], feed_dict=feed_dict)
    if (step % 500 == 0):
      print("Minibatch loss at step %d: %f" % (step, l))
      print("Minibatch accuracy: %.1f%%" % accuracy(predictions, batch_labels))
      print("Validation accuracy: %.1f%%" % accuracy(
        valid_prediction.eval(), valid_labels))
      print("Test accuracy: %.1f%%" % accuracy(test_prediction.eval(), test_labels))

person Maksim Khaitovich    schedule 10.07.2016    source источник
comment
Почему вы упорядочиваете предубеждения?   -  person Tamim Addari    schedule 20.08.2016


Ответы (3)


Хорошо, после некоторых дополнительных усилий мне удалось решить эту проблему и внедрить в свою сеть как L2, так и отсев, код ниже. Я получил небольшое улучшение по сравнению с той же сетью без отсева (с L2 на месте). Я до сих пор не уверен, стоит ли вводить их оба, L2 и отсев, но, по крайней мере, это работает и немного улучшает результаты.

#ANN with introduced dropout
#This time we still use the L2 but restrict training dataset
#to be extremely small

#get just first 500 of examples, so that our ANN can memorize whole dataset
train_dataset_2 = train_dataset[:500, :]
train_labels_2 = train_labels[:500]

#batch size for SGD and beta parameter for L2 loss
batch_size = 128
beta = 0.001

#that's how many hidden neurons we want
num_hidden_neurons = 1024

#building tensorflow graph
graph = tf.Graph()
with graph.as_default():
  # Input data. For the training data, we use a placeholder that will be fed
  # at run time with a training minibatch.
  tf_train_dataset = tf.placeholder(tf.float32,
                                    shape=(batch_size, image_size * image_size))
  tf_train_labels = tf.placeholder(tf.float32, shape=(batch_size, num_labels))
  tf_valid_dataset = tf.constant(valid_dataset)
  tf_test_dataset = tf.constant(test_dataset)

  #now let's build our new hidden layer
  #its weights
  hidden_weights = tf.Variable(
    tf.truncated_normal([image_size * image_size, num_hidden_neurons]))
  hidden_biases = tf.Variable(tf.zeros([num_hidden_neurons]))

  #now the layer itself. It multiplies data by weights, adds biases
  #and takes ReLU over result
  hidden_layer = tf.nn.relu(tf.matmul(tf_train_dataset, hidden_weights) + hidden_biases)

  #add dropout on hidden layer
  #we pick up the probabylity of switching off the activation
  #and perform the switch off of the activations
  keep_prob = tf.placeholder("float")
  hidden_layer_drop = tf.nn.dropout(hidden_layer, keep_prob)  

  #time to go for output linear layer
  #out weights connect hidden neurons to output labels
  #biases are added to output labels  
  out_weights = tf.Variable(
    tf.truncated_normal([num_hidden_neurons, num_labels]))  

  out_biases = tf.Variable(tf.zeros([num_labels]))  

  #compute output
  #notice that upon training we use the switched off activations
  #i.e. the variaction of hidden_layer with the dropout active
  out_layer = tf.matmul(hidden_layer_drop,out_weights) + out_biases
  #our real output is a softmax of prior result
  #and we also compute its cross-entropy to get our loss
  #Notice - we introduce our L2 here
  loss = (tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(
    out_layer, tf_train_labels) +
    beta*tf.nn.l2_loss(hidden_weights) +
    beta*tf.nn.l2_loss(hidden_biases) +
    beta*tf.nn.l2_loss(out_weights) +
    beta*tf.nn.l2_loss(out_biases)))

  #now we just minimize this loss to actually train the network
  optimizer = tf.train.GradientDescentOptimizer(0.5).minimize(loss)

  #nice, now let's calculate the predictions on each dataset for evaluating the
  #performance so far
  # Predictions for the training, validation, and test data.
  train_prediction = tf.nn.softmax(out_layer)
  valid_relu = tf.nn.relu(  tf.matmul(tf_valid_dataset, hidden_weights) + hidden_biases)
  valid_prediction = tf.nn.softmax( tf.matmul(valid_relu, out_weights) + out_biases) 

  test_relu = tf.nn.relu( tf.matmul( tf_test_dataset, hidden_weights) + hidden_biases)
  test_prediction = tf.nn.softmax(tf.matmul(test_relu, out_weights) + out_biases)



#now is the actual training on the ANN we built
#we will run it for some number of steps and evaluate the progress after 
#every 500 steps

#number of steps we will train our ANN
num_steps = 3001

#actual training
with tf.Session(graph=graph) as session:
  tf.initialize_all_variables().run()
  print("Initialized")
  for step in range(num_steps):
    # Pick an offset within the training data, which has been randomized.
    # Note: we could use better randomization across epochs.
    offset = (step * batch_size) % (train_labels_2.shape[0] - batch_size)
    # Generate a minibatch.
    batch_data = train_dataset_2[offset:(offset + batch_size), :]
    batch_labels = train_labels_2[offset:(offset + batch_size), :]
    # Prepare a dictionary telling the session where to feed the minibatch.
    # The key of the dictionary is the placeholder node of the graph to be fed,
    # and the value is the numpy array to feed to it.
    feed_dict = {tf_train_dataset : batch_data, tf_train_labels : batch_labels, keep_prob : 0.5}
    _, l, predictions = session.run(
      [optimizer, loss, train_prediction], feed_dict=feed_dict)
    if (step % 500 == 0):
      print("Minibatch loss at step %d: %f" % (step, l))
      print("Minibatch accuracy: %.1f%%" % accuracy(predictions, batch_labels))
      print("Validation accuracy: %.1f%%" % accuracy(
        valid_prediction.eval(), valid_labels))
      print("Test accuracy: %.1f%%" % accuracy(test_prediction.eval(), test_labels))
person Maksim Khaitovich    schedule 10.07.2016
comment
В оригинальной статье об отсеве конкретно упоминается такая конфигурация, так что вы, вероятно, в хорошей форме, пытаясь это сделать. Хотя я мог бы отметить, что не считаю нормальным включать регуляризацию L2 в смещения, только в веса. jmlr.org/papers/volume15/srivastava14a.old/source/ stats.stackexchange.com/questions/153605/ - person David Parks; 31.08.2016
comment
@DavidParks Похоже, нам также нужно включить L2 в предвзятость. Пожалуйста, взгляните на пример Tensorflow MNIST здесь: github.com/tensorflow/tensorflow/blob/master/tensorflow/models/ Поиск по вызовам функции «l2_loss». - person Petr Shypila; 02.09.2016
comment
Возьмем это в качестве примера: у нас есть один признак x и его значения y, и мы выполняем линейную подгонку к данным, y=mx+b. Если все точки данных сгруппированы вокруг y = 1000 с небольшой дисперсией, нам понадобится большое смещение, чтобы сдвинуть линию до 1000. Это не проблема для корректировки, это просто то, где лежат данные. Проблема в том, что мы перевешиваем функцию. Предвзятость — это всего лишь смещение. С учетом сказанного я недавно построил гистограмму весов и смещений для задач классификации и регрессии, и ни в одном случае я не видел больших смещений. Поэтому я сомневаюсь, что это вызывает заметную проблему. - person David Parks; 14.11.2016
comment
@PetrShypila Приведенный пример кажется неправильным. Насколько я понимаю, нет смысла применять регуляризацию к смещению. Смещение не приведет к переоснащению вашей модели, поэтому оно не должно наказываться. Вот еще один курс по регуляризации: youtube.com/watch?v=ef2OPmANLaM (кстати, я получить точность 93% за 3000 шагов без регуляризации смещения) - person Julien; 26.11.2016
comment
@Julien хорошо, эти примеры, предоставленные Tensorflow, развиваются. Честно говоря, я не эксперт в Tensorflow и ML, так что эти ребята тоже могут ошибаться. - person Petr Shypila; 26.11.2016
comment
Вот ссылка на упорядочивание смещения, которое я хотел: deeplearningbook.org/contents/regularization.html, просто выполните поиск по смещению, и вы найдете там абзац, касающийся нерегуляризации единицы смещения. - person David Parks; 07.12.2016
comment
да. Предвзятость не должна быть систематизирована. Я удалил это из вашего кода в своей собственной реализации, и он работал немного лучше. - person marc; 10.12.2016
comment
Он отлично работает, как вы его написали, но в результате reduce_mean получается скаляр, как и l2_loss, однако вы сначала добавляете скаляр к тензору, а затем reduce_mean. Это не обязательно, и я ожидаю, что это будет медленнее. Сделайте это вместо этого: loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits( out_layer, tf_train_labels)) + beta*tf.nn.l2_loss(hidden_weights) + ... - person Bastiaan; 28.06.2017
comment
Я никогда не видел, чтобы beta умножалось в функции потерь. Это распространено? Должен ли это быть настраиваемым параметром? - person O.rka; 24.07.2017

Нет недостатка в использовании нескольких регуляризаций. На самом деле есть статья Dropout: A Simple Way to Prevent Neural Networks из Overfitting, где авторы проверили, насколько это помогает. Очевидно, что для разных наборов данных у вас будут разные результаты, но для вашего MNIST:

введите описание изображения здесь

вы можете видеть, что Dropout + Max-norm дает самую низкую ошибку. Кроме того, у вас есть большая ошибка в коде.

Вы используете l2_loss для весов и смещений:

beta*tf.nn.l2_loss(hidden_weights) +
beta*tf.nn.l2_loss(hidden_biases) +
beta*tf.nn.l2_loss(out_weights) +
beta*tf.nn.l2_loss(out_biases)))

Вы не должны наказывать высокие предубеждения. Поэтому удалите l2_loss из-за предубеждений.

person Salvador Dali    schedule 28.05.2017

На самом деле, в исходной статье помимо отсева используется регуляризация по максимальной норме, а не L2: «Нейронная сеть была оптимизирована при ограничении ||w||2 ≤ c. Это ограничение было наложено во время оптимизации путем проецирования w на поверхность шара радиуса c всякий раз, когда w выходит из него. Это также называется регуляризацией по максимальной норме, поскольку подразумевает, что максимальное значение, которое может принимать норма любого веса, равно c" (http://jmlr.org/papers/volume15/srivastava14a/srivastava14a.pdf)

Хорошее обсуждение этого метода регуляризации можно найти здесь: https://plus.google.com/+IanGoodfellow/posts/QUaCJfvDpni

person Yoel Zeldes    schedule 15.12.2016