A Simple Neural Network With A Single Neuron

Nishank Sharma
the ML blog
Published in
7 min readJul 6, 2017

Hello guys,

It’s Nishank here, and today we will learn, how to make a simple neural net and predict some numeric output using that. A neural network is a simple mathematical unit, which takes some input and predicts something on the basis of training it received earlier.

Show your support by subscribing to our newsletter!

A neural network is made up of many neurons which help in computation. A single neuron has something called a weight attached to it, also called synaptic weight. These weights changes in the direction of our prediction when we train our neural network.

So the focus of this post is, creating a neural network with a single neuron, training it for 10000 runs, predicting the output in every run, obtaining the error by comparing it with our expected output, adjusting weight based on the error and then finally try to predict the actual output.

The best part about this is, we will not be using any libraries for making our neural net (except numpy obviously). This would help us in understanding the basic structure of a neural network and how it actually works.

Without making it anymore overwhelming for you, let’s start with the code. We will start by installing the library required, in this case numpy .

Installing numpy

Then we will import the libraries required. We will need exp for exponential (you will discover why, later), array (for array obviously), random for generating random numbers and dot for doing the dot product (right the physics one!) all from numpy.

Importing Packages

Okay, so we will be using the following function for our program training and testing purposes as data.

Data

You must be wondering how the heck did he got that output? Don’t you worry, no rocket science here, I just copy-pasted the entire Input 2 row of the table!

Input 2 = Output

So we will be using this data set. Now, moving on, let’s declare the input and output variables for our program, which would both be arrays that represent this table.

The .T used in train_outputs is used to transform the array, thereby making it a vector so that it can be multiplied easily and so that we can . tally it easily with the table . Also, train_inputs is an array of arrays, which will be used in our model. Notice, that I have exactly replicated the table above in our input and output variables.

Our next step in generation of random synaptic weights for our neuron at the starting of training. These generated weights will be adjusted as our program progresses. We will do so by using random function.

Random Synaptic Weights

We have used seed() function here to keep the generated random weights the same, each time the program is executed, until it is closed.

Now here is a concept worth understanding. Well it’s more of an application than a concept. We need to generate random numbers for a neuron with 3 input connection and 1 output connection, so our function becomes random(3,1).

A Single Neuron

Also we need to generate random numbers in the range -1 to 1 (since our output is either 0 or 1). While using the random function for range a to b , the random function is defined as : (b — a) * random_sample() + a , so here a = -1 and b = 1 and the function becomes something like this, where synaptic_weights = 2 * random.random((3, 1)) — 1.

Next, we will create the main part of our neuron, i.e the function we will use to train it. Because a neuron without training is as good as a piece of log.

train() Function

Don’t be intimidated by this simple function (yeah simple!), let’s break it into small pieces. the train function contains 4 main blocks : the head, output predictor, error calculator and weight adjuster. It’s that simple!

The Head

The first part of train() function is the head. It accepts 3 arguments, namely train_inputs (the inputs for training), train_outputs (the outputs for training) and iterations (the number of time the loop will run to train the neuron, so that it’s weights could be adjusted.).

There is also a for loop which runs for the number of iterations provided. Here xrange is used to specify the number of time the loop should run. The remaining 3 parts of train() function are inside this loop.

Output Predictor

This part of train() is used to predict output for the given train_inputs using the current synaptic_weights. This is done by using getoutput() function, which can be defined as follows:

getoutput() Function

Here we will be using sigmoid value of inputs and synaptic_weights. For combining these, we have used dot() function to perform the dot product of inputs and synaptic_weights and sending them into a sigmoid() function.

A sigmoid function is a common function used in neural networks to predict the output. What it does, is it normalizes the value of the dot product between 0 and 1(exactly the thing with need!).

It looks something like this:

Sigmoid Function

Let’s put this concept into code:

sigmoid() Function

Error Calculator

The next part is calculating the error. It is simple step that subtracts the output we got in Output Predictor part from the actual expected output stored in the train_outputs variable.

Error

Weight Adjuster

The last and the most important part of train() function. Here synaptic_weights are adjusted using the error obtained in Error Calculator.

The sigmoid curve looks something like this -

Sigmoid Curve

Notice, that the line gets straighter and constant as we move towards the edges. That means the gradient increases and the surety of getting the right prediction increases. We will also use this concept of sigmoid gradient in our program to get more accurate values.

Sigmoid Gradient = output * (1-output)

Weight Adjuster

Here, first we have given our output from Output Predictor to sig_grad() function. What it does is, it calculates the Sigmoid Gradient of the output using the formula above so that we can move towards the edges of the sigmoid curve and get more accurate results.

Sigmoid Gradient

Next, we will multiply our error value to sigmoid gradient of output to modify our outputs accordingly and finally, we take the dot product of these and the transpose (.T) of train_inputs to get our adjustment.

The final step of each run and train() function is to update the synaptic_weights by adding adjustment to it. We declare the variable as global synaptic_weights to access the global variable called synaptic_weights (because in python, definition and declaration are together and it would give an error if we update synaptic_weights before declaring them, also they would be present in local scope).

The rest of the program is just passing the values into train() function and then printing the results.

Rest Of The Program

We just printed the Random Starting Synaptic Weights, and the called train() function by passing train_inputs , train_outputs and 10000 as our number of runs.

Next we printed the synaptic weights after training and the tested the neural net with a custom input of [1,1,0] , ideally we should get 1 as it is in the 2nd row and we just copied the 2nd row in the output (see the top of this post). Let’s see what happens!

Output

Observe that our output is [0.9999225] , which is very close to 1 , exactly the output we wanted. Also the synaptic weights have changed and look much more consistent. We trained our model 10000 times and it can predict output so closely, and this is just one neuron, imagine the power of neural nets with 1000s of neurons!

I hope you enjoyed reading this post and it was both informative and interesting and it improved your practical understanding of neural nets. You can get the entire code of this post by clicking the banner below. Don’t forget to subscribe!

--

--

Nishank Sharma
the ML blog

Hello, I’m Nishank. I design beautiful, usable and enjoyable interfaces.