1

J'ai écrit ma première implémentation TensorFlow d'un RNN qui prend en entrée des séquences aléatoires qui augmentent ou diminuent. Les étiquettes d'apprentissage sont un entier unique correspondant à chaque séquence, 1 étant une séquence croissante et 0 décroissant. Comme mon modèle s'entraîne, il se penche rapidement vers la classification de chaque séquence comme étant décroissante et je n'arrive pas à comprendre pourquoi. Voici mon code:Pourquoi mon RNN apprend-il à classer toutes les entrées comme étant seulement une des deux classifications possibles?

from __future__ import print_function 
import tensorflow as tf 
from tensorflow.contrib import rnn 
import random 

sequenceLength = 5  # Input Dimension 
maxNum = 1000   # Must be >= than (sequenceLength - 1) 
outputDim = 1 
hiddenDim = 16 
learningRate = 0.1 
trainingIterations = 10000 
batchSize = 10 
displayStep = 1000 

def generateData(): 
    data = [] 
    labels = [] 
    for _ in range(batchSize): 
     type = (1 if random.random() < 0.5 else 0) 
     temp = [] 
     if type == 1: 
      labels.append([1]) 
      temp.append(random.randint(0, maxNum - sequenceLength + 1)) 
      for i in range(1, sequenceLength): 
       temp.append(random.randint(temp[i - 1] + 1, maxNum - sequenceLength + i + 1)) 
      data.append(temp) 
     if type == 0: 
      labels.append([0]) 
      temp.append(random.randint(0 + sequenceLength - 1, maxNum)) 
      for i in range(1, sequenceLength): 
       temp.append(random.randint(0 + sequenceLength - i - 1, temp[i - 1] - 1)) 
      data.append(temp) 
    return data, labels 

x = tf.placeholder(tf.float32, [batchSize, sequenceLength], name="input") 
y = tf.placeholder(tf.float32, [batchSize, outputDim], name="label") 

W = tf.Variable(tf.random_normal([hiddenDim, outputDim])) 
b = tf.Variable(tf.random_normal([outputDim])) 

cell = rnn.BasicRNNCell(hiddenDim) 
outputs, states = tf.nn.static_rnn(cell, [x], dtype=tf.float32) 
prediction = tf.sigmoid(tf.matmul(outputs[0], W + b)) 

loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=prediction, labels=y)) 
optimiser = tf.train.AdamOptimizer(learning_rate=learningRate).minimize(loss) 

correctPrediction = tf.equal(tf.round(prediction), y) 
accuracy = tf.reduce_mean(tf.cast(correctPrediction, tf.float32)) 

with tf.Session() as session: 
    session.run(tf.global_variables_initializer()) 
    for i in range(trainingIterations): 
     batchX, batchY = generateData() 
     dict = {x: batchX, y : batchY} 
     session.run(optimiser, feed_dict=dict) 
     if i % displayStep == 0: 
      print("Predictions:\t" + str(session.run(tf.transpose(tf.round(prediction)), dict))) 
      print("Labels:\t\t" + str(session.run(tf.transpose(y), dict)) + "\n") 
     #  batchAccuracy = session.run(accuracy, feed_dict=dict) 
     #  batchLoss = session.run(loss, feed_dict=dict) 
     #  print("Iteration: " + str(i) + "\nAccuracy: " + str(batchAccuracy) + "\nLoss: " + str(batchLoss) + "\n") 

Comme je l'ai dit, ceci est ma première mise en œuvre en utilisant tensorflow, bien que je suis bien conscient de la façon dont fonctionne un RNN, je suis encore tout à fait perdu avec l'abstraction de haut niveau que nous interagir avec TensorFLow. Ce sont mes calculs de prediction, loss, correctPrediction et accuracy dont je ne suis pas sûr. Est-ce que la façon dont j'utilise la fonction sigmoïde est double? Une fois pour produire une probabilité pour ma prédiction, et encore pour calculer l'entropie croisée entre ma prédiction (comme la probabilité) et l'étiquette.

EDIT

Je viens de remarquer que, dans de très rares occasions, sans modifier le code, le RNN apprend rapidement à classer les séquences correctement.

+0

Pour toute question portant spécifiquement sur le processus de conception et de la formation des modèles d'apprentissage de la machine, envisager de demander plutôt sur [Science Data SE] (https: //datascience.stackexchange.com) ou [Cross Validated] (https://stats.stackexchange.com). –

Répondre

2

Votre taux d'apprentissage est trop élevé. Je réduit le taux d'apprentissage à

learningRate = 0.01 

En outre, vous n'avez pas besoin d'appliquer sigmoïde ici

prediction = tf.sigmoid(tf.matmul(outputs[0], W + b)) 

que votre perte intègre déjà le sigmoïde:

loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=prediction, labels=y)) 

J'ai modifié votre code avec les changements ci-dessus (ainsi que des changements supplémentaires dans la section d'impression, pour ajuster le format), et obtenu la sortie suivante (vous pouvez voir que les prédictions deviennent parfaites à partir de la deuxième segment d'impression):

Predictions: [[ 0. 1. 0. 0. 0. 0. 0. 1. 0. 1.]] 
Labels:  [[ 1. 0. 1. 1. 1. 0. 1. 0. 0. 0.]] 

Iteration: 0 
Accuracy: 0.2 
Loss: 3.27201 

Predictions: [[ 0. 1. 0. 0. 1. 1. 0. 0. 0. 0.]] 
Labels:  [[ 0. 1. 0. 0. 1. 1. 0. 0. 0. 0.]] 

Iteration: 1000 
Accuracy: 1.0 
Loss: 0.000647951 

Predictions: [[ 0. 1. 1. 1. 1. 1. 0. 1. 0. 1.]] 
Labels:  [[ 0. 1. 1. 1. 1. 1. 0. 1. 0. 1.]] 

Iteration: 2000 
Accuracy: 1.0 
Loss: 0.000801496 

Predictions: [[ 1. 0. 1. 1. 0. 0. 1. 0. 1. 0.]] 
Labels:  [[ 1. 0. 1. 1. 0. 0. 1. 0. 1. 0.]] 

Iteration: 3000 
Accuracy: 1.0 
Loss: 0.000515367 

Predictions: [[ 1. 1. 1. 1. 1. 1. 1. 0. 0. 0.]] 
Labels:  [[ 1. 1. 1. 1. 1. 1. 1. 0. 0. 0.]] 

Iteration: 4000 
Accuracy: 1.0 
Loss: 0.000312456 

Predictions: [[ 0. 0. 0. 0. 1. 0. 0. 1. 0. 0.]] 
Labels:  [[ 0. 0. 0. 0. 1. 0. 0. 1. 0. 0.]] 

Iteration: 5000 
Accuracy: 1.0 
Loss: 5.86302e-05 

Predictions: [[ 1. 0. 1. 0. 0. 0. 0. 0. 0. 1.]] 
Labels:  [[ 1. 0. 1. 0. 0. 0. 0. 0. 0. 1.]] 

Iteration: 6000 
Accuracy: 1.0 
Loss: 5.79187e-05 

Predictions: [[ 1. 0. 0. 1. 1. 0. 1. 0. 0. 1.]] 
Labels:  [[ 1. 0. 0. 1. 1. 0. 1. 0. 0. 1.]] 

Iteration: 7000 
Accuracy: 1.0 
Loss: 0.000136576 

Predictions: [[ 1. 0. 1. 1. 0. 0. 1. 1. 0. 1.]] 
Labels:  [[ 1. 0. 1. 1. 0. 0. 1. 1. 0. 1.]] 

Iteration: 8000 
Accuracy: 1.0 
Loss: 4.11543e-05 

Predictions: [[ 0. 1. 0. 0. 0. 0. 0. 1. 0. 0.]] 
Labels:  [[ 0. 1. 0. 0. 0. 0. 0. 1. 0. 0.]] 

Iteration: 9000 
Accuracy: 1.0 
Loss: 7.28511e-06 

Voici le code modifié:

from __future__ import print_function 
import tensorflow as tf 
from tensorflow.contrib import rnn 
import random 

sequenceLength = 5  # Input Dimension 
maxNum = 1000   # Must be >= than (sequenceLength - 1) 
outputDim = 1 
hiddenDim = 16 
learningRate = 0.01 
trainingIterations = 10000 
batchSize = 10 
displayStep = 1000 

def generateData(): 
    data = [] 
    labels = [] 
    for _ in range(batchSize): 
     type = (1 if random.random() < 0.5 else 0) 
     temp = [] 
     if type == 1: 
      labels.append([1]) 
      temp.append(random.randint(0, maxNum - sequenceLength + 1)) 
      for i in range(1, sequenceLength): 
       temp.append(random.randint(temp[i - 1] + 1, maxNum - sequenceLength + i + 1)) 
      data.append(temp) 
     if type == 0: 
      labels.append([0]) 
      temp.append(random.randint(0 + sequenceLength - 1, maxNum)) 
      for i in range(1, sequenceLength): 
       temp.append(random.randint(0 + sequenceLength - i - 1, temp[i - 1] - 1)) 
      data.append(temp) 
    return data, labels 

x = tf.placeholder(tf.float32, [batchSize, sequenceLength], name="input") 
y = tf.placeholder(tf.float32, [batchSize, outputDim], name="label") 

W = tf.Variable(tf.random_normal([hiddenDim, outputDim])) 
b = tf.Variable(tf.random_normal([outputDim])) 

cell = rnn.BasicRNNCell(hiddenDim) 
outputs, states = tf.nn.static_rnn(cell, [x], dtype=tf.float32) 
prediction = tf.matmul(outputs[0], W + b) 

loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=prediction, labels=y)) 
optimiser = tf.train.AdamOptimizer(learning_rate=learningRate).minimize(loss) 

correctPrediction = tf.equal(tf.round(tf.sigmoid(prediction)), y) 
accuracy = tf.reduce_mean(tf.cast(correctPrediction, tf.float32)) 

with tf.Session() as session: 
    session.run(tf.global_variables_initializer()) 
    for i in range(trainingIterations): 
     batchX, batchY = generateData() 
     dict = {x: batchX, y : batchY} 
     session.run(optimiser, feed_dict=dict) 
     if i % displayStep == 0: 
      print("Predictions:\t" + str(session.run(tf.transpose(tf.round(tf.sigmoid(prediction))), dict))) 
      print("Labels:\t\t" + str(session.run(tf.transpose(y), dict)) + "\n") 
      batchAccuracy = session.run(accuracy, feed_dict=dict) 
      batchLoss = session.run(loss, feed_dict=dict) 
      print("Iteration: " + str(i) + "\nAccuracy: " + str(batchAccuracy) + "\nLoss: " + str(batchLoss) + "\n") 
+0

Très bien, j'avais seulement envisagé d'augmenter le taux d'apprentissage pour que le modèle "oublie" qu'il avait appris à classer chaque séquence comme décroissante. Cependant, mon calcul de «perte» est toujours incorrect. Si vous décommentez les trois dernières lignes, vous verrez que 'précision 'est calculé parfaitement, mais' perte 'converge toujours vers' 0.5'. Je présume que cela doit se faire avec les prédictions étant '0' ou '1', mais cela n'a pas de sens pourquoi cela convergerait vers '0.5', même quand il prédireait correctement 100% des seqeunces. – KOB

+0

Si la précision pour un lot est '1,0', alors la prédiction (arrondie) pour chaque séquence de ce lot était correcte, et donc la moyenne de toutes les pertes devrait être inférieure à' 0.5', et vraisemblablement se déplacer vers '0.0 'Comme le modèle apprend de mieux en mieux? – KOB

+0

@KOB voir ma réponse mise à jour. –