1

J'ai commencé avec un simple réseau de style de régression linéaire écrit en Tensorflow et basé en grande partie sur leur tutoriel MNIST pour les débutants. Il y a 7 variables d'entrée et 1 variable de sortie, toutes sur une échelle continue. Avec ce modèle, les sorties étaient en vol stationnaire autour de 1, ce qui était logique, car l'ensemble de sortie cible est largement dominé par des valeurs de 1. Ceci est un exemple de résultats générés par les données de test:L'addition de la couche cachée fait converger la sortie sur une valeur - Tensorflow

[ 0.95340264] 
[ 0.94097006] 
[ 0.96644485] 
[ 0.95954728] 
[ 0.93524933] 
[ 0.94564033] 
[ 0.94379318] 
[ 0.92746377] 
[ 0.94073343] 
[ 0.98421943] 

Cependant la précision Je ne suis jamais allé à environ 84%, j'ai donc décidé d'ajouter une couche cachée. Maintenant, la sortie a entièrement convergé sur une seule valeur, par exemple:

[ 0.96631247] 
[ 0.96631247] 
[ 0.96631247] 
[ 0.96631247] 
[ 0.96631247] 
[ 0.96631247] 
[ 0.96631247] 
[ 0.96631247] 
[ 0.96631247] 
[ 0.96631247] 

et la précision reste entre 82-84%. Lorsque l'on examine la valeur y obtenue, la valeur cible de y, et l'entropie croisée à partir d'une seule rangée de données sur la formation multiple passe lorsque la sortie cible est 1, la valeur de y obtenue se rapproche progressivement de 1:

[ 0.] 
[ 1.] 
0.843537 

[ 0.03999992] 
[ 1.] 
0.803543 

[ 0.07999983] 
[ 1.] 
0.763534 

[ 0.11999975] 
[ 1.] 
0.723541 

[ 0.15999967] 
[ 1.] 
0.683544 

, puis tourne autour de 1 après avoir atteint la cible:

[ 0.99136335] 
[ 1.] 
0.15912 

[ 1.00366712] 
[ 1.] 
0.16013 

[ 0.96366721] 
[ 1.] 
0.167638 

[ 0.97597092] 
[ 1.] 
0.163856 

[ 0.98827463] 
[ 1.] 
0.160069 

Cependant, lorsque la valeur y de la cible est de 0,5, il se comporte comme si la cible est 1, et approchant 0,5 dépassement alors:

[ 0.47648361] 
[ 0.5] 
0.378556 

[ 0.51296818] 
[ 0.5] 
0.350674 

[ 0.53279752] 
[ 0.5] 
0.340844 

[ 0.55262685] 
[ 0.5] 
0.331016 

[ 0.57245618] 
[ 0.5] 
0.321187 

tandis que l'entropie croisée continue à diminuer, comme il est d'atteindre effectivement l'objectif:

[ 0.94733644] 
[ 0.5] 
0.168714 

[ 0.96027154] 
[ 0.5] 
0.164533 

[ 0.97320664] 
[ 0.5] 
0.16035 

[ 0.98614174] 
[ 0.5] 
0.156166 

[ 0.99907684] 
[ 0.5] 
0.151983 

Impression sur les valeurs obtenues, la valeur cible, et la distance à la cible pour les données de test montre la même y obtenu quelle que soit la cible y:

5 
[ 0.98564607] 
[ 0.5] 
[ 0.48564607] 
6 
[ 0.98564607] 
[ 0.60000002] 
[ 0.38564605] 
7 
[ 0.98564607] 
[ 1.] 
[ 0.01435393] 
8 
[ 0.98564607] 
[ 1.] 
[ 0.01435393] 
9 
[ 0.98564607] 
[ 1.] 
[ 0.01435393] 

Le code est ci-dessous. a) Pourquoi, au cours de la partie formation, l'algorithme traite-t-il la valeur cible y comme si c'était toujours 1 et b) pourquoi produisait-il la même sortie pendant la partie test? Même s'il «pense» que la cible est toujours 1, il devrait y avoir au moins une certaine variation dans la sortie de test, comme on le voit dans la sortie de formation.

import argparse 
import dataset 
import numpy as np 
import os 
import sys 
import tensorflow as tf 

FLAGS = None 

def main(_): 
    num_fields = 7 
    batch_size = 100 
    rating_field = 7 
    outputs = 1 
    hidden_units = 7 

    train_data = dataset.Dataset("REPPED_RATING_TRAINING.txt", " ", num_fields, rating_field) 
    td_len = len(train_data.data) 
    test_data = dataset.Dataset("REPPED_RATING_TEST.txt", " ", num_fields, rating_field) 
    test_len = len(test_data.data) 
    test_input = test_data.data[:, :num_fields].reshape(test_len, num_fields) 
    test_target = test_data.fulldata[:, rating_field ].reshape(test_len, 1) 

    graph = tf.Graph() 
    with graph.as_default(): 
      x = tf.placeholder(tf.float32, [None, num_fields], name="x") 
      W1 = tf.Variable(tf.zeros([num_fields, hidden_units])) 
      b1 = tf.Variable(tf.zeros([hidden_units])) 
      W2 = tf.Variable(tf.zeros([hidden_units, outputs])) 
      b2 = tf.Variable(tf.zeros([outputs])) 
      H = tf.add(tf.matmul(x, W1), b1, name="H") 
      y = tf.add(tf.matmul(H, W2), b2, name="y") 
      y_ = tf.placeholder(tf.float32, [None, outputs]) 
      yd = tf.abs(y_ - y) 
      cross_entropy = tf.reduce_mean(yd) 
      train_step = tf.train.GradientDescentOptimizer(0.04).minimize(cross_entropy) 
      init = tf.global_variables_initializer() 
      saver = tf.train.Saver() 

    with tf.Session(graph=graph) as sess: 
      sess.run(init) 

      train_input, train_target = train_data.batch(td_len) 
      for _ in range(FLAGS.times): 
        ts, yo, yt, ce = sess.run([train_step, y, y_, cross_entropy], feed_dict={x: train_input, y_:train_target}) 
        #print obtained y, target y, and cross entropy from a given row over 10 training instances 
        print(yo[3]) 
        print(yt[3]) 
        print(ce) 
        print() 

      checkpoint_file = os.path.join(FLAGS.model_dir, 'saved-checkpoint') 
      print("\nWriting checkpoint file: " + checkpoint_file) 
      saver.save(sess, checkpoint_file) 

      test_input, test_target = test_data.batch(test_len) 
      ty, ty_, tce, tyd = sess.run(
        [y, y_, cross_entropy, yd], 
        feed_dict={x : test_input, y_: test_target}) 
      #print obtained y, target y, and distance to target for 10 random test rows 
      for ix in range(10): 
        print(ix) 
        print(ty[ix]) 
        print(ty_[ix]) 
        print(tyd[ix]) 

      print() 
      print('Ran times: ' + str(FLAGS.times)) 
      print('Acc: ' + str(1-tce)) 

if __name__ == '__main__': 
    parser = argparse.ArgumentParser() 
    parser.add_argument('--times', type=int, default=100, 
        help='Number of passes to train') 
    parser.add_argument('--model_dir', type=str, 
      default=os.path.join('.', 'tmp'), 
      help='Directory for storing model info') 
    FLAGS, unparsed = parser.parse_known_args() 
    tf.app.run(main=main, argv=[sys.argv[0]] + unparsed) 

Répondre

1

Il y a plusieurs problèmes dans votre code, et beaucoup d'entre eux pourraient faire en sorte le réseau de ne pas former correctement:

  • Vous initialisez les poids et les biais d'une valeur zéro. Il doit être initialisé avec une petite valeur aléatoire (uniforme ou normalement distribué).
  • Il n'y a aucune fonction d'activation dans votre réseau, ce qui le rend uniquement capable de modéliser uniquement les relations linéaires.
  • Le taux d'apprentissage est fixe, c'est un hyper-paramètre que vous devez régler. Vous devez également surveiller la valeur de la fonction de perte pendant l'entraînement, pour vous assurer qu'elle diminue et converge vers une petite valeur. Si ce n'est pas alors vous devriez pas regarder les sorties, car le réseau n'apprend rien.

De même, si vous ne normalisiez pas les entrées et les sorties, vous devriez également le faire.

+0

J'ai changé la fonction d'initialisation de poids en random_normal, en utilisant un stddev de 0.35.L'écart-type de la distribution est-il un autre hyperparamètre à régler, ou existe-t-il un stddev optimal générique? En outre, toute idée pourquoi initialiser des poids à zéro fonctionne dans certaines circonstances, mais pas d'autres? J'ai réessayé en utilisant random_normal pour les poids et la fonction relu d'activation pour les unités cachées. L'espace de sortie est maintenant clairement différencié, merci pour la réponse. – mudstick