TensorFlow - регуляризация с потерями L2, как применить ко всем весам, а не только к последнему?

Я играю с ИНС, которая является частью курса Udacity DeepLearning.

У меня есть задание, которое включает в себя обобщение сети с одним скрытым слоем ReLU с использованием потерь L2. Интересно, как правильно ввести это, чтобы штрафовали ВСЕ веса, а не только веса выходного слоя.

Код для сети без обобщения находится внизу сообщения (код для фактического запуска обучения выходит за рамки вопроса).

Очевидный способ введения L2 - заменить расчет потерь чем-то вроде этого (если бета 0,01):

loss = tf.reduce_mean( tf.nn.softmax_cross_entropy_with_logits(out_layer, tf_train_labels) + 0.01*tf.nn.l2_loss(out_weights))

Но в этом случае он будет учитывать значения весов выходного слоя. Я не уверен, как правильно наказывать веса, которые входят в скрытый слой ReLU. Нужно ли это вообще или введение штрафов на выходном слое как-то также будет контролировать скрытые веса?

#some importing
from __future__ import print_function
import numpy as np
import tensorflow as tf
from six.moves import cPickle as pickle
from six.moves import range

#loading data
pickle_file = '/home/maxkhk/Documents/Udacity/DeepLearningCourse/SourceCode/tensorflow/examples/udacity/notMNIST.pickle'

with open(pickle_file, 'rb') as f:
  save = pickle.load(f)
  train_dataset = save['train_dataset']
  train_labels = save['train_labels']
  valid_dataset = save['valid_dataset']
  valid_labels = save['valid_labels']
  test_dataset = save['test_dataset']
  test_labels = save['test_labels']
  del save  # hint to help gc free up memory
  print('Training set', train_dataset.shape, train_labels.shape)
  print('Validation set', valid_dataset.shape, valid_labels.shape)
  print('Test set', test_dataset.shape, test_labels.shape)


#prepare data to have right format for tensorflow
#i.e. data is flat matrix, labels are onehot

image_size = 28
num_labels = 10

def reformat(dataset, labels):
  dataset = dataset.reshape((-1, image_size * image_size)).astype(np.float32)
  # Map 0 to [1.0, 0.0, 0.0 ...], 1 to [0.0, 1.0, 0.0 ...]
  labels = (np.arange(num_labels) == labels[:,None]).astype(np.float32)
  return dataset, labels
train_dataset, train_labels = reformat(train_dataset, train_labels)
valid_dataset, valid_labels = reformat(valid_dataset, valid_labels)
test_dataset, test_labels = reformat(test_dataset, test_labels)
print('Training set', train_dataset.shape, train_labels.shape)
print('Validation set', valid_dataset.shape, valid_labels.shape)
print('Test set', test_dataset.shape, test_labels.shape)


#now is the interesting part - we are building a network with
#one hidden ReLU layer and out usual output linear layer

#we are going to use SGD so here is our size of batch
batch_size = 128

#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
  loss = tf.reduce_mean( tf.nn.softmax_cross_entropy_with_logits(out_layer, tf_train_labels))

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

person Maksim Khaitovich    schedule 09.07.2016    source источник
comment
Альтернативой сбору всех весовых переменных вручную является добавление их в коллекцию, обычно tf.GraphKeys.REGULARIZATION_LOSSES. Примеры решений см. В этом вопросе.   -  person bluenote10    schedule 10.04.2017


Ответы (3)


hidden_weights, hidden_biases, out_weights и out_biases - все параметры модели, которую вы создаете. Вы можете добавить L2-регуляризацию ко ВСЕМ этим параметрам следующим образом:

loss = (tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(
    logits=out_layer, labels=tf_train_labels)) +
    0.01*tf.nn.l2_loss(hidden_weights) +
    0.01*tf.nn.l2_loss(hidden_biases) +
    0.01*tf.nn.l2_loss(out_weights) +
    0.01*tf.nn.l2_loss(out_biases))

С примечанием @Keight Johnson, чтобы не регулировать предвзятость:

loss = (tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(
    logits=out_layer, labels=tf_train_labels)) +
    0.01*tf.nn.l2_loss(hidden_weights) +
    0.01*tf.nn.l2_loss(out_weights) +
person keveman    schedule 10.07.2016
comment
Привет, почему мы должны добавлять l2-регуляризацию к смещениям, я думаю, нет необходимости добавлять l2-регуляризацию к смещению. - person GoingMyWay; 30.11.2016
comment
Вы не должны упорядочивать смещения, только веса. - person Keith Johnson; 13.12.2016
comment
@AlexanderYau: вы правы: ... По этим причинам мы обычно не включаем условия предвзятости при регуляризации (см. здесь) - person johndodo; 16.12.2016
comment
почему вы используете reduce_mean? Разве результат l2_loss не должен быть скаляром? - person Swair; 31.07.2017
comment
почему вы не делите по количеству образцов ?? - person SpaceMonkey; 06.06.2018
comment
@Keith Johnson: Вы можете объяснить? - person mrgloom; 14.09.2019

Более короткий и масштабируемый способ сделать это:

vars   = tf.trainable_variables() 
lossL2 = tf.add_n([ tf.nn.l2_loss(v) for v in vars ]) * 0.001

Это в основном сумма l2_loss всех ваших обучаемых переменных. Вы также можете создать словарь, в котором вы укажете только те переменные, которые хотите добавить к своей стоимости, и использовать вторую строку выше. Затем вы можете добавить lossL2 к вашему значению кросс-энтропии softmax, чтобы рассчитать ваши общие потери.

Изменить. Как упоминал Петр Дабковски, приведенный выше код также упорядочит предубеждения. Этого можно избежать, добавив оператор if во второй строке;

lossL2 = tf.add_n([ tf.nn.l2_loss(v) for v in vars
                    if 'bias' not in v.name ]) * 0.001

Это можно использовать для исключения других переменных.

person PhABC    schedule 19.07.2016
comment
Обратите внимание, что для понимания списка, отбирающего смещения, это зависит от фактического / имени / переменной tf, поэтому, если вы не назвали это чем-то с смещением в нем, пример не выберет его. - person stolsvik; 03.06.2017
comment
Абсолютно! Вот почему я указал, что это можно использовать для исключения других переменных. Однако хорошо отметить это, спасибо. - person PhABC; 04.06.2017

Фактически, мы обычно не упорядочиваем условия систематической ошибки (перехват). Итак, я выбираю:

loss = (tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(
    logits=out_layer, labels=tf_train_labels)) +
    0.01*tf.nn.l2_loss(hidden_weights) +
    0.01*tf.nn.l2_loss(out_weights))

Наказывая член перехвата, поскольку перехват добавляется к значениям y, это приведет к изменению значений y, добавляя константу c к перехватам. Наличие этого или отсутствие не повлияет на результаты, но потребует некоторых вычислений.

person Yousof Erfani    schedule 07.04.2017