2016-07-25 2 views
3

Я пытаюсь реализовать простую полностью подключенную нейронную сеть с прямой связью в TensorFlow (версия Python 3). Сеть имеет 2 входа и 1 выход, и я пытаюсь подготовить его для вывода XOR двух входов. Мой код выглядит следующим образом:TensorFlow: 2-слойная прямая нейронная сеть

import numpy as np 
import tensorflow as tf 

sess = tf.InteractiveSession() 

inputs = tf.placeholder(tf.float32, shape = [None, 2]) 
desired_outputs = tf.placeholder(tf.float32, shape = [None, 1]) 

weights_1 = tf.Variable(tf.zeros([2, 3])) 
biases_1 = tf.Variable(tf.zeros([1, 3])) 
layer_1_outputs = tf.nn.sigmoid(tf.matmul(inputs, weights_1) + biases_1) 

weights_2 = tf.Variable(tf.zeros([3, 1])) 
biases_2 = tf.Variable(tf.zeros([1, 1])) 
layer_2_outputs = tf.nn.sigmoid(tf.matmul(layer_1_outputs, weights_2) + biases_2) 

error_function = -tf.reduce_sum(desired_outputs * tf.log(layer_2_outputs)) 
train_step = tf.train.GradientDescentOptimizer(0.05).minimize(error_function) 

sess.run(tf.initialize_all_variables()) 

training_inputs = [[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]] 
training_outputs = [[0.0], [1.0], [1.0], [0.0]] 

for i in range(10000): 
    train_step.run(feed_dict = {inputs: np.array(training_inputs), desired_outputs: np.array(training_outputs)}) 

print(sess.run(layer_2_outputs, feed_dict = {inputs: np.array([[0.0, 0.0]])})) 
print(sess.run(layer_2_outputs, feed_dict = {inputs: np.array([[0.0, 1.0]])})) 
print(sess.run(layer_2_outputs, feed_dict = {inputs: np.array([[1.0, 0.0]])})) 
print(sess.run(layer_2_outputs, feed_dict = {inputs: np.array([[1.0, 1.0]])})) 

Это кажется достаточно простым, но операторы печати в конце показывают, что нейронная сеть далеко не желаемых результатов, независимо от количества учебных итераций или скорости обучения. Может ли кто-нибудь увидеть, что я делаю неправильно?

спасибо.

EDIT: Я также попытался следующую альтернативную функцию ошибки:

error_function = 0.5 * tf.reduce_sum(tf.sub(layer_2_outputs, desired_outputs) * tf.sub(layer_2_outputs, desired_outputs)) 

Эта функция ошибки представляет собой сумму квадратов ошибок. Он ВСЕГДА приводит к тому, что сеть выводит значение ровно 0,5 - еще одно указание на ошибку где-то в моем коде.

EDIT 2: Я обнаружил, что мой код отлично работает для AND и OR, но не для XOR. Я сейчас очень озадачен.

ответ

8

В коде есть несколько проблем. В следующем я собираюсь прокомментировать каждую строку, чтобы привести вас к решению.

Примечание: XOR не является линейно разделяемым. Вам нужно больше 1 скрытого слоя.

N.B: Линии, начинающиеся с # [!], являются линиями, в которых вы ошибались.

import numpy as np 
import tensorflow as tf 

sess = tf.InteractiveSession() 

# a batch of inputs of 2 value each 
inputs = tf.placeholder(tf.float32, shape=[None, 2]) 

# a batch of output of 1 value each 
desired_outputs = tf.placeholder(tf.float32, shape=[None, 1]) 

# [!] define the number of hidden units in the first layer 
HIDDEN_UNITS = 4 

# connect 2 inputs to 3 hidden units 
# [!] Initialize weights with random numbers, to make the network learn 
weights_1 = tf.Variable(tf.truncated_normal([2, HIDDEN_UNITS])) 

# [!] The biases are single values per hidden unit 
biases_1 = tf.Variable(tf.zeros([HIDDEN_UNITS])) 

# connect 2 inputs to every hidden unit. Add bias 
layer_1_outputs = tf.nn.sigmoid(tf.matmul(inputs, weights_1) + biases_1) 

# [!] The XOR problem is that the function is not linearly separable 
# [!] A MLP (Multi layer perceptron) can learn to separe non linearly separable points (you can 
# think that it will learn hypercurves, not only hyperplanes) 
# [!] Lets' add a new layer and change the layer 2 to output more than 1 value 

# connect first hidden units to 2 hidden units in the second hidden layer 
weights_2 = tf.Variable(tf.truncated_normal([HIDDEN_UNITS, 2])) 
# [!] The same of above 
biases_2 = tf.Variable(tf.zeros([2])) 

# connect the hidden units to the second hidden layer 
layer_2_outputs = tf.nn.sigmoid(
    tf.matmul(layer_1_outputs, weights_2) + biases_2) 

# [!] create the new layer 
weights_3 = tf.Variable(tf.truncated_normal([2, 1])) 
biases_3 = tf.Variable(tf.zeros([1])) 

logits = tf.nn.sigmoid(tf.matmul(layer_2_outputs, weights_3) + biases_3) 

# [!] The error function chosen is good for a multiclass classification taks, not for a XOR. 
error_function = 0.5 * tf.reduce_sum(tf.sub(logits, desired_outputs) * tf.sub(logits, desired_outputs)) 

train_step = tf.train.GradientDescentOptimizer(0.05).minimize(error_function) 

sess.run(tf.initialize_all_variables()) 

training_inputs = [[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]] 

training_outputs = [[0.0], [1.0], [1.0], [0.0]] 

for i in range(20000): 
    _, loss = sess.run([train_step, error_function], 
         feed_dict={inputs: np.array(training_inputs), 
            desired_outputs: np.array(training_outputs)}) 
    print(loss) 

print(sess.run(logits, feed_dict={inputs: np.array([[0.0, 0.0]])})) 
print(sess.run(logits, feed_dict={inputs: np.array([[0.0, 1.0]])})) 
print(sess.run(logits, feed_dict={inputs: np.array([[1.0, 0.0]])})) 
print(sess.run(logits, feed_dict={inputs: np.array([[1.0, 1.0]])})) 

Я увеличил число итераций поезда, чтобы убедиться, что сеть будет сходиться, независимо от того, что случайные значения инициализации.

Выход после 20000 поезда итерации:

[[ 0.01759939]] 
[[ 0.97418505]] 
[[ 0.97734243]] 
[[ 0.0310041]] 

Это выглядит довольно хорошо.

+0

Большое спасибо за подробный ответ. Я понимаю изменения, которые вы внесли. Тем не менее, я пытаюсь выполнить операцию XOR, а не операцию OR. Таким образом, на моих целевых выходах не было ошибок. целевые выходы - [[0.0], [1.0], [1.0], [0.0]]. Используя ваш код, я все еще не могу заставить нейронную сеть выполнять XOR. Можете ли вы предложить какую-либо помощь в этом отношении? – CircuitScholar

+0

Я обновил свой ответ. – nessuno

+0

Спасибо. Я действительно смог достичь цели только с двумя слоями. Ваша идея инициализации весов для ненулевых значений - это то, что заставило мой код работать. – CircuitScholar

1

Ваша реализация выглядит правильно. Вот несколько вещей, которые вы можете попробовать:

  • Изменение tf.nn.sigmoid других нелинейные функции активации
  • Используйте меньшую скорость обучения (1e-3 до 1e-5)
  • Используйте больше слоев
  • Следуйте за XOR neural network architecture
+0

Я пробовал ваши предложения; нет успеха. Я хотел бы добавить, что после обучения все входы приводят к очень сходным результатам (т.е. 00, 01, 10 и 11 все приводят к выводу нейронной сети ~ 0.77). Поскольку это простая полностью подключенная сеть, в этом случае большее количество слоев не даст каких-либо дополнительных возможностей или точности, поэтому я бы хотел этого избежать. Я также реализовал эту точную нейронную сеть в MATLAB раньше, и это сработало, поэтому я уверен, что я просто ошибся в своем коде где-то. – CircuitScholar

+0

В 'error_function' напрямую не умножаются желаемые выходы, а вместо этого вычитаются значения. Также попробуйте преобразовать его в евклидову потерю.В качестве альтернативы вы можете создать это как классификацию вместо проблемы регрессии. – ahaque

+0

Я попробовал более обычную функцию ошибки (см. Мое редактирование исходного сообщения), в котором была использована разница между целью и выходом вместо кросс-энтропии. Тем не менее, я все еще испытываю неправильное поведение. – CircuitScholar