Reputation: 123
Following code was written to learn the XOR function, but about half of the time the network does not learn and the loss after each epoch stays the same.
train_f = [[0, 0], [0, 1], [1, 0], [1, 1]]
train_c = [[0], [1], [1], [0]]
test_f = train_f
test_c = train_c
import tensorflow as tf
import tflearn
X = [[0., 0.], [0., 1.], [1., 0.], [1., 1.]]
Y_xor = [[0.], [1.], [1.], [0.]]
# Graph definition
with tf.Graph().as_default():
# Building a network with 2 optimizers
net = tflearn.input_data(shape=[None, 2])
# Nand operator definition
net = tflearn.fully_connected(net, 2, activation='relu')
net = tflearn.fully_connected(net, 2, activation='relu')
net = tflearn.fully_connected(net, 1, activation='sigmoid')
regressor = tflearn.regression(net, optimizer='adam', learning_rate=0.005, loss="mean_square",)
# Training
m = tflearn.DNN(regressor)
m.fit(X, Y_xor, n_epoch=256, snapshot_epoch=False)
# Testing
print("Testing XOR operator")
print("0 xor 0:", m.predict([[0., 0.]]))
print("0 xor 1:", m.predict([[0., 1.]]))
print("1 xor 0:", m.predict([[1., 0.]]))
print("1 xor 1:", m.predict([[1., 1.]]))
Sometimes I get correct results like this:
Testing XOR operator
0 xor 0: [[0.1487255096435547]]
0 xor 1: [[0.9297153949737549]]
1 xor 0: [[0.9354135394096375]]
1 xor 1: [[0.1487255096435547]]
But often this:
Testing XOR operator
0 xor 0: [[0.4999997615814209]]
0 xor 1: [[0.5000002384185791]]
1 xor 0: [[0.4999997615814209]]
1 xor 1: [[0.5000001788139343]]
My 2x2x1 network should be able to perform XOR, and there is even some evidence that suggests that this network should always converge http://www.ncbi.nlm.nih.gov/pubmed/12662805
I have also tried to change the relu layers to sigmoid, to perform 2048 iterations, and to make a 4x4x1 and 6x6x1 networks, but the same problem still occurs sometimes.
Could there be something wrong with how the weights are initialized? How do I use tflearn to have a neural net learn the xor function?
Upvotes: 11
Views: 1986
Reputation: 1624
I've decided to add another answer: I've done some more research and have some substantially different advice to provide.
After skimming this paper, it dawned on me that the reason why you're not seeing convergence might have to do with the initial weights. The paper specifically references some work by Hirose et al (Hirose, Yamashita, and Hijiya 1991) that found that initialization with a limited range of weights results in a very low probability of convergence. The "sweet spot" seemed to be a range between 0.5 and 1 on average to reliably converge.
It turns out that tflearn will default to using truncated normal initialization with a stddev of 0.02. So the weights have a very limited range. I've found that I can get reasonably reliable results using random uniform initialization of -1.0 to 1.0.
Also, incidentally it turns out that you've added a 3rd layer. XOR requires only one hidden layer, so you can remove the second one. Here's the code that works for me:
import tensorflow as tf
import tflearn
X = [[0., 0.], [0., 1.], [1., 0.], [1., 1.]]
Y_xor = [[0.], [1.], [1.], [0.]]
# Graph definition
with tf.Graph().as_default():
tnorm = tflearn.initializations.uniform(minval=-1.0, maxval=1.0)
net = tflearn.input_data(shape=[None, 2])
net = tflearn.fully_connected(net, 2, activation='sigmoid', weights_init=tnorm)
net = tflearn.fully_connected(net, 1, activation='sigmoid', weights_init=tnorm)
regressor = tflearn.regression(net, optimizer='sgd', learning_rate=2., loss='mean_square')
# Training
m = tflearn.DNN(regressor)
m.fit(X, Y_xor, n_epoch=10000, snapshot_epoch=False)
# Testing
print("Testing XOR operator")
print("0 xor 0:", m.predict([[0., 0.]]))
print("0 xor 1:", m.predict([[0., 1.]]))
print("1 xor 0:", m.predict([[1., 0.]]))
print("1 xor 1:", m.predict([[1., 1.]]))
Note that I am using mean square error. To my surprise, it seems to work best for this problem. Cross-entropy seems to cause the optimizer to languish in relatively flat regions of the problem space. I would have expected the opposite; maybe someone better versed in the mathematics will be able to better explain that.
Upvotes: 9
Reputation: 3738
I've got analog problem, when I was looking for the minimal neuron network architecture required to learn XOR which should be a (2,2,1) network. In fact, maths shows that the (2,2,1) network can solve the XOR problem, but maths doesn't show that the (2,2,1) network is easy to train. That said, I've got easily good results with (2,3,1) or (2,4,1) network architectures. Furthermore weights initialization with random number between 0.5 and 1.0 helps to converge.
The problem seems to be related to the existence of many local minima. Look at this 1998 paper, «Learning XOR: exploring the space of a classic problem» by Richard Bland. Maybe you could try different random initialization of the weights or change your loss function.
It works fine with Keras or TensorFlow using loss function 'mean_squared_error', sigmoid activation and Adam optimizer.
Upvotes: 0
Reputation: 1624
In addition to @Ishamael's advice, consider using a different loss function. Mean squared error is not generally a good choice for sigmoid activations because the gradient can shrink too small to be useful for learning due to saturation.
Upvotes: 3
Reputation: 12795
The network with relu
s (as it is written in the code snippet) is expected to often fail to train. The reason for that is that if the input to relu is less than zero, the output is zero, and therefore the gradient going back is also zero.
Since you have two layers, each having only two relu units, with random initialization each of these two layers has 25% of having all its neurons returning zero, and therefore having zero gradient going back => neural network will not learn at all. In such a network the output of the last layer (before the final sigmoid) will be zero, sigmoid of which is 0.5 -- exactly what you observe on the attempts on which your network didn't converge.
Since each layer has 25% chance of doing this damage, the entire network has a total chance of around 45% (1 - (1 - 0.25)^2
) of failing to train from the get go. There's also a non-zero chance that the network is not in such a state at the beginning, but happens to bring itself to such a state during training, further increasing the chance of divergence.
With four neurons the chance will be significantly lower, but still not zero.
Now, the only thing I cannot answer is why your network doesn't converge when you replace relu
with sigmoid
-- such a network should be always able to learn "xor". My only hypothesis is that you replaced only one relu
with sigmoid
, not both of them.
Can you replace both relu
s with sigmoid
s and confirm you still observe divergence?
Upvotes: 10