TensorFlow MLP не обучает XOR
Я построил MLP с библиотекой Google TensorFlow. Сеть работает, но как-то отказывается учиться правильно. Он всегда сходится к выходному значению почти 1,0, независимо от того, какой на самом деле вход.
Полный код можно посмотреть здесь.
Есть идеи?
Вход и выход (размер партии 4) выглядит следующим образом:
input_data = [[0., 0.], [0., 1.], [1., 0.], [1., 1.]] # XOR input
output_data = [[0.], [1.], [1.], [0.]] # XOR output
n_input = tf.placeholder(tf.float32, shape=[None, 2], name="n_input")
n_output = tf.placeholder(tf.float32, shape=[None, 1], name="n_output")
Конфигурация скрытого слоя:
# hidden layer's bias neuron
b_hidden = tf.Variable(0.1, name="hidden_bias")
# hidden layer's weight matrix initialized with a uniform distribution
W_hidden = tf.Variable(tf.random_uniform([2, hidden_nodes], -1.0, 1.0), name="hidden_weights")
# calc hidden layer's activation
hidden = tf.sigmoid(tf.matmul(n_input, W_hidden) + b_hidden)
Конфигурация выходного слоя:
W_output = tf.Variable(tf.random_uniform([hidden_nodes, 1], -1.0, 1.0), name="output_weights") # output layer's weight matrix
output = tf.sigmoid(tf.matmul(hidden, W_output)) # calc output layer's activation
Мои методы обучения выглядят так:
loss = tf.reduce_mean(cross_entropy) # mean the cross_entropy
optimizer = tf.train.GradientDescentOptimizer(0.01) # take a gradient descent for optimizing
train = optimizer.minimize(loss) # let the optimizer train
Я попробовал обе установки для перекрестной энтропии:
cross_entropy = -tf.reduce_sum(n_output * tf.log(output))
а также
cross_entropy = tf.nn.sigmoid_cross_entropy_with_logits(n_output, output)
где n_output
исходный вывод, как описано в output_data
а также output
прогнозируемое / рассчитанное значение моей сети.
Обучение внутри цикла for (для n эпох) выглядит так:
cvalues = sess.run([train, loss, W_hidden, b_hidden, W_output],
feed_dict={n_input: input_data, n_output: output_data})
Я сохраняю результат для значений для отладки loss
, W_hidden
...
Независимо от того, что я пробовал, когда я тестирую свою сеть, пытаясь проверить вывод, она всегда выдает что-то вроде этого:
(...)
step: 2000
loss: 0.0137040186673
b_hidden: 1.3272010088
W_hidden: [[ 0.23195425 0.53248233 -0.21644847 -0.54775208 0.52298909]
[ 0.73933059 0.51440752 -0.08397482 -0.62724304 -0.53347367]]
W_output: [[ 1.65939867]
[ 0.78912479]
[ 1.4831928 ]
[ 1.28612828]
[ 1.12486529]]
(--- finished with 2000 epochs ---)
(Test input for validation:)
input: [0.0, 0.0] | output: [[ 0.99339396]]
input: [0.0, 1.0] | output: [[ 0.99289012]]
input: [1.0, 0.0] | output: [[ 0.99346077]]
input: [1.0, 1.0] | output: [[ 0.99261558]]
Таким образом, он не учится должным образом, но всегда приближается к 1,0, независимо от того, какой вход подается.
2 ответа
Тем временем с помощью коллеги я смог исправить свое решение и хотел опубликовать его для полноты. Мое решение работает с кросс-энтропией и без изменения данных обучения. Кроме того, он имеет желаемую форму ввода (1, 2), а выходной сигнал является скалярным.
Это использует AdamOptimizer
что уменьшает ошибку гораздо быстрее, чем GradientDescentOptimizer
, См. Этот пост для получения дополнительной информации (& questions^^) об оптимизаторе.
Фактически, моя сеть дает достаточно хорошие результаты всего за 400-800 шагов обучения.
После 2000 шагов обучения результат почти "идеален":
step: 2000
loss: 0.00103311243281
input: [0.0, 0.0] | output: [[ 0.00019799]]
input: [0.0, 1.0] | output: [[ 0.99979786]]
input: [1.0, 0.0] | output: [[ 0.99996307]]
input: [1.0, 1.0] | output: [[ 0.00033751]]
import tensorflow as tf
#####################
# preparation stuff #
#####################
# define input and output data
input_data = [[0., 0.], [0., 1.], [1., 0.], [1., 1.]] # XOR input
output_data = [[0.], [1.], [1.], [0.]] # XOR output
# create a placeholder for the input
# None indicates a variable batch size for the input
# one input's dimension is [1, 2] and output's [1, 1]
n_input = tf.placeholder(tf.float32, shape=[None, 2], name="n_input")
n_output = tf.placeholder(tf.float32, shape=[None, 1], name="n_output")
# number of neurons in the hidden layer
hidden_nodes = 5
################
# hidden layer #
################
# hidden layer's bias neuron
b_hidden = tf.Variable(tf.random_normal([hidden_nodes]), name="hidden_bias")
# hidden layer's weight matrix initialized with a uniform distribution
W_hidden = tf.Variable(tf.random_normal([2, hidden_nodes]), name="hidden_weights")
# calc hidden layer's activation
hidden = tf.sigmoid(tf.matmul(n_input, W_hidden) + b_hidden)
################
# output layer #
################
W_output = tf.Variable(tf.random_normal([hidden_nodes, 1]), name="output_weights") # output layer's weight matrix
output = tf.sigmoid(tf.matmul(hidden, W_output)) # calc output layer's activation
############
# learning #
############
cross_entropy = -(n_output * tf.log(output) + (1 - n_output) * tf.log(1 - output))
# cross_entropy = tf.square(n_output - output) # simpler, but also works
loss = tf.reduce_mean(cross_entropy) # mean the cross_entropy
optimizer = tf.train.AdamOptimizer(0.01) # take a gradient descent for optimizing with a "stepsize" of 0.1
train = optimizer.minimize(loss) # let the optimizer train
####################
# initialize graph #
####################
init = tf.initialize_all_variables()
sess = tf.Session() # create the session and therefore the graph
sess.run(init) # initialize all variables
#####################
# train the network #
#####################
for epoch in xrange(0, 2001):
# run the training operation
cvalues = sess.run([train, loss, W_hidden, b_hidden, W_output],
feed_dict={n_input: input_data, n_output: output_data})
# print some debug stuff
if epoch % 200 == 0:
print("")
print("step: {:>3}".format(epoch))
print("loss: {}".format(cvalues[1]))
# print("b_hidden: {}".format(cvalues[3]))
# print("W_hidden: {}".format(cvalues[2]))
# print("W_output: {}".format(cvalues[4]))
print("")
print("input: {} | output: {}".format(input_data[0], sess.run(output, feed_dict={n_input: [input_data[0]]})))
print("input: {} | output: {}".format(input_data[1], sess.run(output, feed_dict={n_input: [input_data[1]]})))
print("input: {} | output: {}".format(input_data[2], sess.run(output, feed_dict={n_input: [input_data[2]]})))
print("input: {} | output: {}".format(input_data[3], sess.run(output, feed_dict={n_input: [input_data[3]]})))
Я не могу комментировать, потому что у меня недостаточно репутации, но у меня есть несколько вопросов на этот вопрос. Функция $L_2$ loss имеет смысл, потому что в основном это функция MSE, но почему не работает перекрестная энтропия? Конечно, работает для других NN libs. Во-вторых, почему в мире перевод вашего входного пространства из $[0,1] -> [-1,1]$ окажет какое-либо влияние, особенно после того, как вы добавили векторы смещения.
РЕДАКТИРОВАТЬ Это решение, использующее кросс-энтропию и горячую компиляцию из нескольких источников. EDIT^2 изменил код для использования кросс-энтропии без какого-либо дополнительного кодирования или какого-либо странного смещения целевого значения.
import math
import tensorflow as tf
import numpy as np
HIDDEN_NODES = 10
x = tf.placeholder(tf.float32, [None, 2])
W_hidden = tf.Variable(tf.truncated_normal([2, HIDDEN_NODES]))
b_hidden = tf.Variable(tf.zeros([HIDDEN_NODES]))
hidden = tf.nn.relu(tf.matmul(x, W_hidden) + b_hidden)
W_logits = tf.Variable(tf.truncated_normal([HIDDEN_NODES, 1]))
b_logits = tf.Variable(tf.zeros([1]))
logits = tf.add(tf.matmul(hidden, W_logits),b_logits)
y = tf.nn.sigmoid(logits)
y_input = tf.placeholder(tf.float32, [None, 1])
loss = -(y_input * tf.log(y) + (1 - y_input) * tf.log(1 - y))
train_op = tf.train.GradientDescentOptimizer(0.01).minimize(loss)
init_op = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init_op)
xTrain = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
yTrain = np.array([[0], [1], [1], [0]])
for i in xrange(2000):
_, loss_val,logitsval = sess.run([train_op, loss,logits], feed_dict={x: xTrain, y_input: yTrain})
if i % 10 == 0:
print "Step:", i, "Current loss:", loss_val,"logits",logitsval
print "---------"
print sess.run(y,feed_dict={x: xTrain})