RNN (Reccurent Neural Network) est également implémenté dans TensorFlow, et bien qu'il y ait un tutoriel, l'exemple lui-même est un peu compliqué traitant du modèle de langage, et j'ai senti que c'était difficile à comprendre pour les débutants.
Cette fois, j'essaierai l'implémentation RNN dans TensorFlow, en prenant comme exemple le problème du traitement d'un modèle plus simple qui n'est pas un modèle de langage.
Étant donné que la version de TensorFlow a été mise à niveau et qu'il y a une partie qui ne fonctionne pas, ici (TensorFlow RNN related import or Basic LSTMCell related error (v 0.11r ~) / items / dd24f176023b65e78f84)) Essayez-le.
Le modèle RNN simple et sa méthode de mise en œuvre sont très utiles dans le blog note de Peter, donc si c'est votre première fois, veuillez d'abord le lire. Je le recommande. Si vous citez le chiffre RNN du site ci-dessus,
Ça ressemble à ça.
En d'autres termes, après avoir multiplié les données de l'unité de couche d'entrée x par le poids W_x, la sortie de l'unité s qui entre dans l'unité de couche cachée s est récurrente, et le résultat de l'application du poids W_rec est l'unité s à l'étape suivante. entrer. Compte tenu de l'état développé à droite de la figure ci-dessus, l'état de la valeur initiale s_0 de l'unité de couche cachée change l'état en multipliant le poids W_rec au fur et à mesure que l'étape progresse. A ce moment, x est entré à chaque étape, et l'état de s_n dans l'étape finale est sorti vers l'unité de couche de sortie y.
C'est un flux comme celui-ci.
Le modèle RNN de note de Peter est un modèle de réseau qui renvoie la valeur totale lorsque la valeur numérique de X_k = 0. ou 1. est entrée. ..
Par exemple
X = [0. 1. 1. 0. 1. 0. 0. 1. 0. 0.]
Est la valeur totale de cette liste.
Y = 2.
Est un modèle qui produit correctement. C'est un modèle qui donne un résultat immédiatement si vous l'ajoutez simplement, mais cette fois nous le trouverons en l'entraînant avec RNN.
LSTM
Cependant, le didacticiel RNN de TensorFlow utilise une méthode appelée LSTM (Long-Short Term Memory) au lieu d'un simple RNN. Comme le montre la figure ci-dessus, dans un RNN normal, la taille du NN devient de plus en plus grande proportionnellement au nombre d'étapes. Par conséquent, il existe un problème en ce que la quantité de calcul et de mémoire requise pour appliquer la méthode de propagation de retour d'erreur augmente, l'erreur propagée explose et le calcul devient instable.
D'autre part, dans LSTM, en utilisant l'unité LSTM au lieu de la simple couche cachée, il est possible de déterminer dans quelle mesure la valeur de base (valeur de cellule de mémoire) de l'unité est conservée la fois suivante et dans quelle mesure elle affecte l'étape suivante. Vous pouvez l'ajuster.
Une unité LSTM est comme indiqué dans la figure ci-dessus.
h ^ {l − 1} _t
et sortie de la lth couche cachée au temps t − 1h_ {t − 1 } ^ l
.
--Porte de modulation d'entrée: a pour rôle d'ajuster la valeur ajoutée à la cellule mémoire.
--Oublier la porte ・ ・ ・ Il a pour rôle d'ajuster la durée de conservation de la valeur de la cellule mémoire à la prochaine fois.
--Porte de sortie: il a pour rôle d'ajuster dans quelle mesure la valeur de la cellule mémoire affecte la couche suivante.Il est composé des éléments ci-dessus.
Pour une explication détaillée de LSTM, voir l'article de blog de Christopher Olah (http://colah.github.io/posts/2015-08-Understanding-LSTMs/. 08-Understanding-LSTMs /)), qui est une excellente expérience d'apprentissage.
À l'origine, dans l'exemple ci-dessus, il n'est pas nécessaire de faire ressortir le LSTM car toutes les entrées passées fonctionnent de manière égale sur le pas en cours. Cependant, cette fois, je vais essayer l'exemple total ci-dessus en utilisant BasicLSTMCell qui est implémenté par défaut dans TensoreFlow. J'ai mis le code dans https://github.com/yukiB/rnntest.
Tout d'abord, la création de données
def create_data(num_of_samples, sequence_len):
X = np.zeros((num_of_samples, sequence_len))
for row_idx in range(nb_of_samples):
X[row_idx,:] = np.around(np.random.rand(sequence_len)).astype(int)
# Create the targets for each sequence
t = np.sum(X, axis=1)
return X, t
C'est fait par.
La conception de la couche LSTM est
def inference(input_ph, istate_ph):
with tf.name_scope("inference") as scope:
weight1_var = tf.Variable(tf.truncated_normal([num_of_input_nodes, num_of_hidden_nodes], stddev=0.1), name="weight1")
weight2_var = tf.Variable(tf.truncated_normal([num_of_hidden_nodes, num_of_output_nodes], stddev=0.1), name="weight2")
bias1_var = tf.Variable(tf.truncated_normal([num_of_hidden_nodes], stddev=0.1), name="bias1")
bias2_var = tf.Variable(tf.truncated_normal([num_of_output_nodes], stddev=0.1), name="bias2")
in1 = tf.transpose(input_ph, [1, 0, 2])
in2 = tf.reshape(in1, [-1, num_of_input_nodes])
in3 = tf.matmul(in2, weight1_var) + bias1_var
in4 = tf.split(0, length_of_sequences, in3)
cell = rnn_cell.BasicLSTMCell(num_of_hidden_nodes, forget_bias=forget_bias)
rnn_output, states_op = rnn.rnn(cell, in4, initial_state=istate_ph)
output_op = tf.matmul(rnn_output[-1], weight2_var) + bias2_var
return output_op
Cela se fera à.
in3 = tf.matmul(in2, weight1_var) + bias1_var
Donne la formule de mise à jour de cellule dans l'unité LSTM. Aussi
output_op = tf.matmul(rnn_output[-1], weight2_var) + bias2_var
La sortie obtenue à partir de la dernière couche LSTM de toutes les étapes est pondérée et polarisée pour obtenir la sortie finale.
En ce qui concerne le calcul des coûts, puisque la valeur de sortie est une valeur continue cette fois, nous avons utilisé MSE (erreur quadratique moyenne) et l'avons conçu de manière à ce que les données unitaires soient passées telles quelles sans passer la fonction d'activation.
def loss(output_op, supervisor_ph):
with tf.name_scope("loss") as scope:
square_error = tf.reduce_mean(tf.square(output_op - supervisor_ph))
loss_op = square_error
tf.scalar_summary("loss", loss_op)
return loss_op
Pour évaluer l'exactitude, nous avons fait une combinaison de 100 listes et des réponses correctes, et avons calculé le rapport de celles avec une différence entre le résultat de la prédiction et la bonne réponse inférieure à 0,05.
def calc_accuracy(output_op, prints=False):
inputs, ts = make_prediction(num_of_prediction_epochs)
pred_dict = {
input_ph: inputs,
supervisor_ph: ts,
istate_ph: np.zeros((num_of_prediction_epochs, num_of_hidden_nodes * 2)),
}
output= sess.run([output_op], feed_dict=pred_dict)
def print_result (p, q):
print("output: %f, correct: %d" % (p , q))
if prints:
[print_result(p, q) for p, q in zip(output[0], ts)]
opt = abs(output - ts)[0]
total = sum([1 if x[0] < 0.05 else 0 for x in opt])
print("accuracy %f" % (total/float(len(ts))))
return output
À ce stade, spécifiez l'optimiseur et démarrez le calcul.
def training(loss_op):
with tf.name_scope("training") as scope:
training_op = optimizer.minimize(loss_op)
return training_op
random.seed(0)
np.random.seed(0)
tf.set_random_seed(0)
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
X, t = create_data(num_of_sample, length_of_sequences)
with tf.Graph().as_default():
input_ph = tf.placeholder(tf.float32, [None, length_of_sequences, num_of_input_nodes], name="input")
supervisor_ph = tf.placeholder(tf.float32, [None, num_of_output_nodes], name="supervisor")
istate_ph = tf.placeholder(tf.float32, [None, num_of_hidden_nodes * 2], name="istate")
output_op, states_op, datas_op = inference(input_ph, istate_ph)
loss_op = loss(output_op, supervisor_ph)
training_op = training(loss_op)
summary_op = tf.merge_all_summaries()
init = tf.initialize_all_variables()
with tf.Session() as sess:
saver = tf.train.Saver()
summary_writer = tf.train.SummaryWriter("/tmp/tensorflow_log", graph=sess.graph)
sess.run(init)
for epoch in range(num_of_training_epochs):
inputs, supervisors = get_batch(size_of_mini_batch, X, t)
train_dict = {
input_ph: inputs,
supervisor_ph: supervisors,
istate_ph: np.zeros((size_of_mini_batch, num_of_hidden_nodes * 2)),
}
sess.run(training_op, feed_dict=train_dict)
if (epoch ) % 100 == 0:
summary_str, train_loss = sess.run([summary_op, loss_op], feed_dict=train_dict)
print("train#%d, train loss: %e" % (epoch, train_loss))
summary_writer.add_summary(summary_str, epoch)
if (epoch ) % 500 == 0:
calc_accuracy(output_op)
Le code dans https://github.com/yukiB/rnntest produit le résultat final comme suit.
[0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0]
output: 6.010024, correct: 6
[1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0]
output: 5.986825, correct: 6
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
output: 0.223431, correct: 0
[0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0]
output: 3.002296, correct: 3
...
accuracy 0.980000
Dans l'environnement à portée de main, la précision était d'environ 98% à la suite de l'apprentissage de 5000 fois par lots de 100 pièces. Apparemment, il apprend correctement.
Aussi, quand j'ai vérifié la convergence de la fonction de coût avec TensorBoard
C'est devenu comme ci-dessus.
Cette fois, j'ai essayé de voir l'implémentation RNN de TensorFLow à travers un modèle de sommation simple. Si vous modifiez l'optimiseur ou le nombre de couches cachées, le degré de convergence changera considérablement, il est donc intéressant de l'essayer.
Recommended Posts