web-dev-qa-db-fra.com

Le biais dans la couche convolutionnelle fait-il vraiment une différence dans la précision du test?

Je comprends que les biais sont nécessaires dans les petits réseaux, pour déplacer la fonction d'activation. Mais dans le cas d'un réseau profond qui a plusieurs couches de CNN, de regroupement, d'abandon et d'autres activations non linéaires, le biais fait-il vraiment une différence? Le filtre convolutionnel apprend les fonctionnalités locales et pour une étant donné le canal de sortie conv, la même polarisation est utilisée.

Ce n'est pas une dupe de ce lien . Le lien ci-dessus explique uniquement le rôle du biais dans les petits réseaux de neurones et n'essaie pas d'expliquer le rôle du biais dans les réseaux profonds contenant plusieurs couches CNN, les abandons, la mise en commun et les fonctions d'activation non linéaires.

J'ai effectué une expérience simple et les résultats ont indiqué que la suppression du biais de la couche conv ne faisait aucune différence dans la précision du test final. Il y a deux modèles formés et le test- la précision est presque la même (légèrement meilleure dans une sans biais.)

  • model_with_bias,
  • model_without_bias (biais non ajouté dans la couche conv)

Sont-ils utilisés uniquement pour des raisons historiques?

Si l'utilisation du biais n'apporte aucun gain de précision, ne devrions-nous pas les omettre? Moins de paramètres à apprendre.

Je serais reconnaissant si quelqu'un qui a des connaissances plus approfondies que moi pouvait expliquer la signification (le cas échéant) de ces biais dans les réseaux profonds.

Voici le code complet et le résultat de l'expérience expérience biais-VS-no_bias

batch_size = 16
patch_size = 5
depth = 16
num_hidden = 64

graph = tf.Graph()

with graph.as_default():

  # Input data.
  tf_train_dataset = tf.placeholder(
    tf.float32, shape=(batch_size, image_size, image_size, num_channels))
  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)

  # Variables.
  layer1_weights = tf.Variable(tf.truncated_normal(
      [patch_size, patch_size, num_channels, depth], stddev=0.1))
  layer1_biases = tf.Variable(tf.zeros([depth]))
  layer2_weights = tf.Variable(tf.truncated_normal(
      [patch_size, patch_size, depth, depth], stddev=0.1))
  layer2_biases = tf.Variable(tf.constant(1.0, shape=[depth]))
  layer3_weights = tf.Variable(tf.truncated_normal(
      [image_size // 4 * image_size // 4 * depth, num_hidden], stddev=0.1))
  layer3_biases = tf.Variable(tf.constant(1.0, shape=[num_hidden]))
  layer4_weights = tf.Variable(tf.truncated_normal(
      [num_hidden, num_labels], stddev=0.1))
  layer4_biases = tf.Variable(tf.constant(1.0, shape=[num_labels]))

  # define a Model with bias .
  def model_with_bias(data):
    conv = tf.nn.conv2d(data, layer1_weights, [1, 2, 2, 1], padding='SAME')
    hidden = tf.nn.relu(conv + layer1_biases)
    conv = tf.nn.conv2d(hidden, layer2_weights, [1, 2, 2, 1], padding='SAME')
    hidden = tf.nn.relu(conv + layer2_biases)
    shape = hidden.get_shape().as_list()
    reshape = tf.reshape(hidden, [shape[0], shape[1] * shape[2] * shape[3]])
    hidden = tf.nn.relu(tf.matmul(reshape, layer3_weights) + layer3_biases)
    return tf.matmul(hidden, layer4_weights) + layer4_biases

  # define a Model without bias added in the convolutional layer.
  def model_without_bias(data):
    conv = tf.nn.conv2d(data, layer1_weights, [1, 2, 2, 1], padding='SAME')
    hidden = tf.nn.relu(conv ) # layer1_ bias is not added 
    conv = tf.nn.conv2d(hidden, layer2_weights, [1, 2, 2, 1], padding='SAME')
    hidden = tf.nn.relu(conv) # + layer2_biases)
    shape = hidden.get_shape().as_list()
    reshape = tf.reshape(hidden, [shape[0], shape[1] * shape[2] * shape[3]])
    # bias are added only in Fully connected layer(layer 3 and layer 4)
    hidden = tf.nn.relu(tf.matmul(reshape, layer3_weights) + layer3_biases)
    return tf.matmul(hidden, layer4_weights) + layer4_biases

  # Training computation.
  logits_with_bias = model_with_bias(tf_train_dataset)
  loss_with_bias = tf.reduce_mean(
    tf.nn.softmax_cross_entropy_with_logits(labels=tf_train_labels, logits=logits_with_bias))

  logits_without_bias = model_without_bias(tf_train_dataset)
  loss_without_bias = tf.reduce_mean(
    tf.nn.softmax_cross_entropy_with_logits(labels=tf_train_labels, logits=logits_without_bias))

  # Optimizer.
  optimizer_with_bias = tf.train.GradientDescentOptimizer(0.05).minimize(loss_with_bias)
  optimizer_without_bias = tf.train.GradientDescentOptimizer(0.05).minimize(loss_without_bias)

  # Predictions for the training, validation, and test data.
  train_prediction_with_bias = tf.nn.softmax(logits_with_bias)
  valid_prediction_with_bias = tf.nn.softmax(model_with_bias(tf_valid_dataset))
  test_prediction_with_bias = tf.nn.softmax(model_with_bias(tf_test_dataset))

  # Predictions for without
  train_prediction_without_bias = tf.nn.softmax(logits_without_bias)
  valid_prediction_without_bias = tf.nn.softmax(model_without_bias(tf_valid_dataset))
  test_prediction_without_bias = tf.nn.softmax(model_without_bias(tf_test_dataset))

num_steps = 1001

with tf.Session(graph=graph) as session:
  tf.global_variables_initializer().run()
  print('Initialized')
  for step in range(num_steps):
    offset = (step * batch_size) % (train_labels.shape[0] - batch_size)
    batch_data = train_dataset[offset:(offset + batch_size), :, :, :]
    batch_labels = train_labels[offset:(offset + batch_size), :]
    feed_dict = {tf_train_dataset : batch_data, tf_train_labels : batch_labels}
    session.run(optimizer_with_bias, feed_dict=feed_dict)
    session.run(optimizer_without_bias, feed_dict = feed_dict)
  print('Test accuracy(with bias): %.1f%%' % accuracy(test_prediction_with_bias.eval(), test_labels))
  print('Test accuracy(without bias): %.1f%%' % accuracy(test_prediction_without_bias.eval(), test_labels))

Sortie:

Initialisé

Précision du test (avec biais): 90,5%

Précision du test (sans biais): 90,6%

9
Aparajuli

Les biais sont ajustés aux côtés des poids en apprenant des algorithmes tels que la descente de gradient. les biais diffèrent des poids, c'est qu'ils sont indépendants de la sortie des couches précédentes . Conceptuellement, le biais est provoqué par l'entrée d'un neurone avec une activation fixe de 1, et est donc mis à jour en soustrayant uniquement le produit de la valeur delta et du taux d'apprentissage.

Dans un grand modèle, la suppression des entrées de biais fait très peu de différence car chaque nœud peut créer un nœud de biais à partir de l'activation moyenne de toutes ses entrées, ce qui, selon la loi des grands nombres, sera à peu près normal. À la première couche, la possibilité que cela se produise dépend de votre distribution d'entrée. Pour MNIST par exemple, l'activation moyenne de l'entrée est à peu près constante. Sur un petit réseau, vous avez bien sûr besoin d'une entrée de polarisation, mais sur un grand réseau, sa suppression ne fait presque aucune différence .

Bien que dans un grand réseau cela ne fasse aucune différence, cela dépend toujours de l'architecture du réseau. Par exemple dans LSTM:

La plupart des applications de LSTM initialisent simplement les LSTM avec de petits poids aléatoires, ce qui fonctionne bien sur de nombreux problèmes. Mais cette initialisation définit effectivement la porte d'oubli à 0,5. Cela introduit un gradient de fuite avec un facteur de 0,5 par pas de temps, ce qui peut poser des problèmes lorsque les dépendances à long terme sont particulièrement graves. Ce problème est résolu en initialisant simplement la polarisation des portes d'oubli à une grande valeur telle que 1 ou 2. Ce faisant, la porte d'oubli sera initialisée à une valeur qui est proche de 1, permettant un écoulement de gradient.

Voir également:

5
Amir