I have been working toward implementing my own Neural Network library in C++ for fun.
I have managed to implement an XOR solving network based on widely available information. Now, I wanted to try a classification problem and use the cross-entropy as my loss function.
I have created a dataset of 729 records (all possible combinations of 3 numbers between 0 and 8):
Input Features | expected Output
--------------------------------
{0, 0, 0} | {0.0, 1.0}
{1, 0, 0} | {1.0, 0.0}
...
{8, 8, 7} | {0.0, 1.0}
{8, 8, 8} | {0.0, 1.0}
The output should be {0.0, 1.0}
when there is no 1
in the input, and {1.0, 0.0}
when there is a 1
in the input. (the inputs are normalised to the -1.0
to 1.0
range).
I was having a hard time getting my network to correctly accomplish this classification. Because I had the whole dataset, I tried training it on the complete dataset in an attempt to have it fit perfectly. I wanted to see it fit perfectly to provide me some assurance that my implementation was correct.
Numerous attempts failed:
# hidden | learning | results
units | rate | (accuracy)
--------------------------------
3 | 0.00001 | 72%
3 | 0.000001 | 60%
5 | 0.0001 | 80%
5 | 0.00001 | 75%
6 | 0.0001 | 79%
6 | 0.001 | 91%
10 | 0.001 | 72%
10 | 0.0001 | 91%
10 | 0.00001 | 71%
20 | 0.0001 | 91%
20 | 0.00001 | 74%
20 | 0.002 | 77%
These were all over 20k epochs, a momentum of 0.5, relu activation on all units, softmax and cross-entropy loss for the output. Some of these were unreliable too, meaning sometimes they would not learn at all, but starting with a new set of random weights worked.
You can see that it capped out at 91% accuracy. But, if I add a second hidden layer, so that my network looks like:
Input Layer | Hidden Layer 1 | Hidden Layer 2 | Output Layer
3 | 6 | 2 | 2
I instantly get 100% accuracy using 0.001
learning rate after only 1000 epochs.
Why does this additional hidden layer work? Is there a way to know when I should use additional layers?