Ich versuche, ein wiederkehrendes neuronales Netzwerk mit Tensorflow (r0.10, Python 3.5) auf ein Spielzeug Klassifizierung Problem zu trainieren, aber ich bekomme verwirrende Ergebnisse.Warum Tensorflow RNN nicht Spielzeug Daten lernen
Ich möchte eine Folge von Nullen und Einsen in eine RNN einspeisen und die Zielklasse für ein gegebenes Element der Folge als die Zahl haben, die durch die aktuellen und vorherigen Werte der Sequenz repräsentiert wird, die als binär behandelt werden Nummer. Zum Beispiel:
input sequence: [0, 0, 1, 0, 1, 1]
binary digits : [-, [0,0], [0,1], [1,0], [0,1], [1,1]]
target class : [-, 0, 1, 2, 1, 3]
Es scheint so etwas ist ein RNN sollte recht leicht erlernen kann, sondern mein Modell ist nur in der Lage Klassen zu unterscheiden [0,2] von [1,3]. Mit anderen Worten, es ist in der Lage, die Klassen zu unterscheiden, deren laufende Ziffer 0 ist von denen, deren aktuelle Ziffer 1 ist. Dies führt zu der Annahme, dass das RNN-Modell nicht korrekt lernt, den vorherigen Wert der Sequenz zu betrachten .
Es gibt verschiedene Tutorials und Beispiele ([1], [2], [3]), die zeigen, wie Recurrent Neural Networks (RNNs) in tensorflow zu bauen und zu verwenden, aber nach ihnen das Studium habe ich noch nicht mein Problem sehen (Es hilft nicht, dass alle Beispiele Text als Quelldaten verwenden).
Ich gebe meine Daten zu tf.nn.rnn()
als eine Liste der Länge T
, deren Elemente sind [batch_size x input_size]
Sequenzen. Da meine Sequenz eindimensional ist, ist input_size
gleich eins, also glaube ich, dass ich eine Liste von Sequenzen der Länge batch_size
eingabe (die documentation ist mir unklar, welche Dimension als Zeitdimension behandelt wird). Ist dieses Verständnis korrekt? Wenn das der Fall ist, dann verstehe ich nicht, warum das RNN-Modell nicht richtig lernt.
Es ist schwer, einen kleinen Satz von Code zu erhalten, die durch meine volle RNN laufen kann, dann ist dies das Beste, was ich tun konnte (es meist aus the PTB model here angepasst ist und the char-rnn model here):
import tensorflow as tf
import numpy as np
input_size = 1
batch_size = 50
T = 2
lstm_size = 5
lstm_layers = 2
num_classes = 4
learning_rate = 0.1
lstm = tf.nn.rnn_cell.BasicLSTMCell(lstm_size, state_is_tuple=True)
lstm = tf.nn.rnn_cell.MultiRNNCell([lstm] * lstm_layers, state_is_tuple=True)
x = tf.placeholder(tf.float32, [T, batch_size, input_size])
y = tf.placeholder(tf.int32, [T * batch_size * input_size])
init_state = lstm.zero_state(batch_size, tf.float32)
inputs = [tf.squeeze(input_, [0]) for input_ in tf.split(0,T,x)]
outputs, final_state = tf.nn.rnn(lstm, inputs, initial_state=init_state)
w = tf.Variable(tf.truncated_normal([lstm_size, num_classes]), name='softmax_w')
b = tf.Variable(tf.truncated_normal([num_classes]), name='softmax_b')
output = tf.concat(0, outputs)
logits = tf.matmul(output, w) + b
probs = tf.nn.softmax(logits)
cost = tf.reduce_mean(tf.nn.seq2seq.sequence_loss_by_example(
[logits], [y], [tf.ones_like(y, dtype=tf.float32)]
))
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
tvars = tf.trainable_variables()
grads, _ = tf.clip_by_global_norm(tf.gradients(cost, tvars),
10.0)
train_op = optimizer.apply_gradients(zip(grads, tvars))
init = tf.initialize_all_variables()
with tf.Session() as sess:
sess.run(init)
curr_state = sess.run(init_state)
for i in range(3000):
# Create toy data where the true class is the value represented
# by the current and previous value treated as binary, i.e.
train_x = np.random.randint(0,2,(T * batch_size * input_size))
train_y = train_x + np.concatenate(([0], (train_x[:-1] * 2)))
# Reshape into T x batch_size x input_size
train_x = np.reshape(train_x, (T, batch_size, input_size))
feed_dict = {
x: train_x, y: train_y
}
for j, (c, h) in enumerate(init_state):
feed_dict[c] = curr_state[j].c
feed_dict[h] = curr_state[j].h
fetch_dict = {
'cost': cost, 'final_state': final_state, 'train_op': train_op
}
# Evaluate the graph
fetches = sess.run(fetch_dict, feed_dict=feed_dict)
curr_state = fetches['final_state']
if i % 300 == 0:
print('step {}, train cost: {}'.format(i, fetches['cost']))
# Test
test_x = np.array([[0],[0],[1],[0],[1],[1]]*(T*batch_size*input_size))
test_x = test_x[:(T*batch_size*input_size),:]
probs_out = sess.run(probs, feed_dict={
x: np.reshape(test_x, [T, batch_size, input_size]),
init_state: curr_state
})
# Get the softmax outputs for the points in the sequence
# that have [0, 0], [0, 1], [1, 0], [1, 1] as their
# last two values.
for i in [1, 2, 3, 5]:
print('{}: [{:.4f} {:.4f} {:.4f} {:.4f}]'.format(
[1, 2, 3, 5].index(i), *list(probs_out[i,:]))
)
Die hier Endausgabe ist
0: [0.4899 0.0007 0.5080 0.0014]
1: [0.0003 0.5155 0.0009 0.4833]
2: [0.5078 0.0011 0.4889 0.0021]
3: [0.0003 0.5052 0.0009 0.4936]
was zeigt, dass es nur lernt, [0,2] von [1,3] zu unterscheiden. Warum lernt dieses Modell nicht, den vorherigen Wert in der Sequenz zu verwenden?