So following the example at the end of the chapter here, I generated a neural network for digit recognition which is (surprisingly) accurate. It's a 784->100->10
feedforward network with one input layer, one hidden layer, and one output layer.
So for an example, here is an input image (reshaped to be a 28x28
image):
After running through the first layer, which has a sigmoid activation function:
first_layer_output = sigmoid(np.dot(weights[0],input_image)+biases[0])
I get the following result (reduced to 100 pixels, shown as a 10x10
image):
Then, I generate the final output with:
last_layer_output = sigmoid(np.dot(weights[1],first_layer_output)+biases[1])
Which has the following output:
Basically it makes the correct guess. How can I interpret visually what is happening to the input image? Is there a way to visually represent what each neuron is "looking for"? I've used the Tensorflow Playground, and the layers make intuitive sense. For example, something simple like this image, I can see how the first two neurons of the hidden layer are basically just the positive and negative averages of the first two input neurons:
In a similar attempt, I thought about seeing how the weights to a given neuron were altering my image so I did an element-by-element multiplication of the pixels by the weights for the most positively weighed neuron in my output layer (weights[1][3]
has the weights for the output layer corresponding to the number 3):
pos_n = weights[1][3].argsort()[-1]
e_by_e = np.multiply(input_image.reshape((28,28)),weights[0][pos_n].reshape((28,28)))
plt.imshow(e_by_e)
Is the correct way to interpret the image is that this neuron is weighing positively the pixels in red (red is high according to that colormap) and conversely decreasing the weights of pixels in blue? So you can imagine the top of the '3' is negatively weighted, while the "arch" along the top half of the '3' is positively weighted?
Here's the pos_n
neuron alone:
Edit: Per @Lagerbaer 's suggestion below, I trained a simpler network. This network is a feedforward 784->1->2
network with one input, one hidden, and one output layer to distinguish only between 0s and 1s in the MNIST dataset. It's >99% accurate and here is an image of the weights:
weights[0][pos_n]
instead of already multiplying it with the input. That way, you would see which parts of the input image that particular neuron "scans" for. $\endgroup$pos_n
neuron above -- thanks $\endgroup$