Mutt
Professional
- Messages
- 1,458
- Reaction score
- 1,074
- Points
- 113
What are we going to do? We will try to create a simple and completely small neural network, which we will teach to distinguish something. In this case, we will not go into history and mathematical jungle (such information is very easy to find) - instead, we will try to explain the problem (not the fact that it will be possible) to you and yourself with drawings and code.
Many of the terms in neural networks are biologically related, so let's start at the beginning.
The brain is a complex thing, but it can also be divided into several main parts and operations.
The causative agent can also be internal (for example, an image or an idea).
Now let's take a look at the basic and simplified parts of the brain.
The brain is generally like a wired network.
A neuron is the basic unit of calculus in the brain, it receives and processes chemical signals from other neurons, and, depending on a number of factors, either does nothing, or generates an electrical impulse, or an Action Potential, which then sends signals to neighboring connected neurons through synapses.
Dreams, memories, self-regulating movements, reflexes and in general everything that you think or do - everything happens thanks to this process: millions or even billions of neurons work at different levels and create connections that create various parallel subsystems and represent a biological neural network.
Of course, these are all simplifications and generalizations, but thanks to them we can describe a simple neural network.
And to describe it formalized using a graph:
Some clarification is required here. The circles are neurons, and the lines are the connections between them, and, in order not to complicate at this stage, the relationships represent the direct movement of information from left to right. The first neuron is currently active and highlighted in gray. We also assigned a number to it (1 if it works, 0 if not). The numbers between neurons show the weight of the connection.
The graphs above show the moment in time of the network, for a more accurate display, you need to divide it into time intervals:
To create your own neural network, you need to understand how weights affect neurons and how neurons are trained. Let's take a rabbit (test rabbit) as an example and put it under the conditions of a classic experiment.
When a safe stream of air is directed at them, rabbits, like humans, blink:
This behavior can be drawn with graphs.
As in the previous diagram, these graphs only show the moment when the rabbit feels the breath, and we thus code the breath as a boolean value. In addition, we calculate whether the second neuron is firing based on the weight value. If it is equal to 1, then the sensory neuron is triggered, we blink; if the weight is less than 1, we don't blink: the second neuron has a limit of 1.
Let's introduce one more element - a safe sound signal.
We can model rabbit interest like this.
The main difference is that the weight is now zero, so we didn't get a blinking rabbit, well, at least not yet. Now let's teach the rabbit to blink on command, mixing stimuli (sound signal and breath).
It is important that these events occur in different time periods, in graphs it will look like this.
Sound itself does nothing, but the airflow still makes the rabbit blink, and we show this through the weights times the stimuli (in red).
Learning complex behavior can be simplified as a gradual change in weight between linked neurons over time.
To train the rabbit, repeat the steps.
For the first three attempts, the circuits will look like this.
Please note that the weight for the sound stimulus grows after each repetition (highlighted in red), this value is now arbitrary - we chose 0.30, but the number can be anything, even negative. After the third repetition, you will not notice a change in the rabbit's behavior, but after the fourth repetition, something amazing will happen - the behavior will change.
We removed the exposure with air, but the rabbit still blinks when he hears the beep! Our last diagram can explain this behavior:
We trained the rabbit to respond to sound by blinking.
In a real experiment of this kind, it may take more than 60 repetitions to achieve a result.
Now we will leave the biological world of the brain and rabbits and try to adapt everything we have learned to create an artificial neural network. First, let's try to do a simple task.
Let's say we have a four-button machine that dispenses food when the right button is pressed (well, or energy if you're a robot). The task is to find out which button gives out the reward:
We can depict (schematically) what the button does when pressed like this:
It's better to solve this problem in its entirety, so let's look at all the possible results, including the correct one:
Click on the 3rd button to get your dinner.
To reproduce a neural network in code, we first need to make a model or graph with which we can map the network. Here is one graph that fits the task, and it also displays its biological counterpart well.
This neural network simply receives input - in this case, it will be the perception of which button was pressed. Next, the network replaces the input information with weights and draws an inference based on the addition of the layer. It sounds a bit confusing, but let's see how the button is represented in our model.
Note that all weights are 0, so the neural network, like a baby, is completely empty but completely interconnected.
Thus, we associate the external event with the input layer of the neural network and calculate the value at its output. It may or may not coincide with reality, but we will ignore this for now and begin to describe the task in a computer-understandable way. Let's start by entering the weights (we'll use JavaScript):
The next step is to create a function that collects the input values and weights and calculates the output value:
As expected, if we run this code, we get the same result as in our model or graph ...
evaluateNeuralNetwork (inputs, weights); // 0.00
Live example: Neural Net 001.
The next step in improving our neural network will be a way to test its own output or resulting values against a real situation, let's first encode this particular reality into a variable:
To detect inconsistencies (and how many), we'll add an error function:
With it, we can evaluate the performance of our neural network:
But more importantly, what about situations where reality is beneficial?
Now we know that our neural network model isn't working (and we know how much), great! This is great because we can now use the error function to control our learning. But all this will make sense if we redefine the error function as follows:
A subtle but important discrepancy that tacitly indicates that we will use previously obtained results for comparison with future actions (and for learning, as we will see later). It also exists in real life, full of repetitive patterns, so it can be an evolutionary strategy (well, most of the time).
Next, we'll add a new variable to our sample code:
Live example: Neural Net 002.
Let's summarize the intermediate result.
We started with a problem, made a simple model of it in the form of a biological neural network, and got a way to measure its performance in comparison with reality or the desired result. Now we need to find a way to correct the inconsistency - a process that can be viewed as learning for both computers and humans.
How to train a neural network?
The basis of training for both biological and artificial neural networks is repetition and learning algorithms, so we will work with them separately. Let's start with training algorithms.
In nature, learning algorithms are understood as changes in the physical or chemical characteristics of neurons after experiments:
A dramatic illustration of how two neurons change over time in the code and our "learning algorithm" model means that we will simply change something over time to make our life easier. Therefore, let's add a variable to indicate the degree of ease of life:
And what difference does that make?
This will change the weights (just like a rabbit!), Especially the weight of the output that we want to get:
How to code such an algorithm is your choice, for the sake of simplicity I add the learning factor to the weight, here it is as a function:
When used, this training function will simply add our training factor to the weight vector of the active neuron , before and after the training (or repeat) circle, the results will be like this:
Live example: Neural Net 003 .
Okay, now that we're heading in the right direction, the final piece of this puzzle will be the implementation of replays.
It's not that difficult, in nature we just do the same thing over and over, and in the code we just specify the number of repetitions:
And the implementation of the function of the number of repetitions into our training neural network will look like this:
Well, our final report:
Live example: Neural Net 004 .
Now we have a weight vector that will give only one result (chicken for dinner) if the input vector matches reality (pressing the third button).
So what is so cool we just did?
In this particular case, our neural network (after training) can recognize the input data and say, which will lead to the desired result (we will still need to program specific situations):
In addition, it is a scalable model, toy and tool for our training with you. We were able to learn something new about machine learning, neural networks and artificial intelligence.
Caution to users:
Notes and bibliography for further reading
I tried to avoid mathematics and strict terms, but if you're interested, we have constructed a perceptron, which is defined as a supervised learning algorithm (supervised learning ) double qualifiers - heavy stuff.
The biological structure of the brain is not an easy topic, partly because of inaccuracy, partly because of its complexity. Better to start with Neuroscience (Purves) and Cognitive Neuroscience (Gazzaniga). I've modified and adapted the bunny example from Gateway to Memory (Gluck), which is also a great guide to the world of graphs.
Another great resource, An Introduction to Neural Networks (Gurney), is perfect for all your AI needs.
Now in Python! Thanks to Ilya Andshmidt for providing the Python version:
Many of the terms in neural networks are biologically related, so let's start at the beginning.
The brain is a complex thing, but it can also be divided into several main parts and operations.
The causative agent can also be internal (for example, an image or an idea).
Now let's take a look at the basic and simplified parts of the brain.
The brain is generally like a wired network.
A neuron is the basic unit of calculus in the brain, it receives and processes chemical signals from other neurons, and, depending on a number of factors, either does nothing, or generates an electrical impulse, or an Action Potential, which then sends signals to neighboring connected neurons through synapses.
Dreams, memories, self-regulating movements, reflexes and in general everything that you think or do - everything happens thanks to this process: millions or even billions of neurons work at different levels and create connections that create various parallel subsystems and represent a biological neural network.
Of course, these are all simplifications and generalizations, but thanks to them we can describe a simple neural network.
And to describe it formalized using a graph:

Some clarification is required here. The circles are neurons, and the lines are the connections between them, and, in order not to complicate at this stage, the relationships represent the direct movement of information from left to right. The first neuron is currently active and highlighted in gray. We also assigned a number to it (1 if it works, 0 if not). The numbers between neurons show the weight of the connection.
The graphs above show the moment in time of the network, for a more accurate display, you need to divide it into time intervals:

To create your own neural network, you need to understand how weights affect neurons and how neurons are trained. Let's take a rabbit (test rabbit) as an example and put it under the conditions of a classic experiment.
When a safe stream of air is directed at them, rabbits, like humans, blink:

This behavior can be drawn with graphs.
As in the previous diagram, these graphs only show the moment when the rabbit feels the breath, and we thus code the breath as a boolean value. In addition, we calculate whether the second neuron is firing based on the weight value. If it is equal to 1, then the sensory neuron is triggered, we blink; if the weight is less than 1, we don't blink: the second neuron has a limit of 1.
Let's introduce one more element - a safe sound signal.
We can model rabbit interest like this.
The main difference is that the weight is now zero, so we didn't get a blinking rabbit, well, at least not yet. Now let's teach the rabbit to blink on command, mixing stimuli (sound signal and breath).
It is important that these events occur in different time periods, in graphs it will look like this.
Sound itself does nothing, but the airflow still makes the rabbit blink, and we show this through the weights times the stimuli (in red).
Learning complex behavior can be simplified as a gradual change in weight between linked neurons over time.
To train the rabbit, repeat the steps.
For the first three attempts, the circuits will look like this.
Please note that the weight for the sound stimulus grows after each repetition (highlighted in red), this value is now arbitrary - we chose 0.30, but the number can be anything, even negative. After the third repetition, you will not notice a change in the rabbit's behavior, but after the fourth repetition, something amazing will happen - the behavior will change.
We removed the exposure with air, but the rabbit still blinks when he hears the beep! Our last diagram can explain this behavior:
We trained the rabbit to respond to sound by blinking.

In a real experiment of this kind, it may take more than 60 repetitions to achieve a result.
Now we will leave the biological world of the brain and rabbits and try to adapt everything we have learned to create an artificial neural network. First, let's try to do a simple task.
Let's say we have a four-button machine that dispenses food when the right button is pressed (well, or energy if you're a robot). The task is to find out which button gives out the reward:

We can depict (schematically) what the button does when pressed like this:

It's better to solve this problem in its entirety, so let's look at all the possible results, including the correct one:

Click on the 3rd button to get your dinner.
To reproduce a neural network in code, we first need to make a model or graph with which we can map the network. Here is one graph that fits the task, and it also displays its biological counterpart well.
This neural network simply receives input - in this case, it will be the perception of which button was pressed. Next, the network replaces the input information with weights and draws an inference based on the addition of the layer. It sounds a bit confusing, but let's see how the button is represented in our model.
Note that all weights are 0, so the neural network, like a baby, is completely empty but completely interconnected.
Thus, we associate the external event with the input layer of the neural network and calculate the value at its output. It may or may not coincide with reality, but we will ignore this for now and begin to describe the task in a computer-understandable way. Let's start by entering the weights (we'll use JavaScript):
Code:
var inputs = [0,1,0,0];
var weights = [0,0,0,0];
// For convenience, these vectors can be called
The next step is to create a function that collects the input values and weights and calculates the output value:
Code:
function evaluateNeuralNetwork (inputVector, weightVector) {
var result = 0;
inputVector.forEach (function (inputValue, weightIndex) {
layerValue = inputValue * weightVector [weightIndex];
result + = layerValue;
});
return (result.toFixed (2));
}
// May seem complex, but all it does is match the weight / input pairs and add the result
evaluateNeuralNetwork (inputs, weights); // 0.00
Live example: Neural Net 001.
The next step in improving our neural network will be a way to test its own output or resulting values against a real situation, let's first encode this particular reality into a variable:

To detect inconsistencies (and how many), we'll add an error function:
Code:
Error = Reality - Neural Net Output
With it, we can evaluate the performance of our neural network:
But more importantly, what about situations where reality is beneficial?
Now we know that our neural network model isn't working (and we know how much), great! This is great because we can now use the error function to control our learning. But all this will make sense if we redefine the error function as follows:
Code:
Error = <b> Desired Output </b> - Neural Net Output
A subtle but important discrepancy that tacitly indicates that we will use previously obtained results for comparison with future actions (and for learning, as we will see later). It also exists in real life, full of repetitive patterns, so it can be an evolutionary strategy (well, most of the time).
Next, we'll add a new variable to our sample code:
Code:
var input = [0,0,1,0];
var weights = [0,0,0,0];
var desiredResult = 1;
And a new function:
function evaluateNeuralNetError (desired, actual) {
return (desired - actual);
}
// After evaluating both the Network and the Error we would get:
// "Neural Net output: 0.00 Error: 1"
Let's summarize the intermediate result.
We started with a problem, made a simple model of it in the form of a biological neural network, and got a way to measure its performance in comparison with reality or the desired result. Now we need to find a way to correct the inconsistency - a process that can be viewed as learning for both computers and humans.
How to train a neural network?
The basis of training for both biological and artificial neural networks is repetition and learning algorithms, so we will work with them separately. Let's start with training algorithms.
In nature, learning algorithms are understood as changes in the physical or chemical characteristics of neurons after experiments:
A dramatic illustration of how two neurons change over time in the code and our "learning algorithm" model means that we will simply change something over time to make our life easier. Therefore, let's add a variable to indicate the degree of ease of life:
Code:
var learningRate = 0.20;
// The larger the value, the faster the learning process will be :)
And what difference does that make?
This will change the weights (just like a rabbit!), Especially the weight of the output that we want to get:
How to code such an algorithm is your choice, for the sake of simplicity I add the learning factor to the weight, here it is as a function:
Code:
function learn (inputVector, weightVector) {
weightVector.forEach (function (weight, index, weights) {
if (inputVector [index]> 0) {
weights [index] = weight + learningRate;
}
});
}
When used, this training function will simply add our training factor to the weight vector of the active neuron , before and after the training (or repeat) circle, the results will be like this:
Code:
// Original weight vector: [0,0,0,0]
// Neural Net output: 0.00 Error: 1
learn (input, weights);
// New Weight vector: [0,0.20,0,0]
// Neural Net output: 0.20 Error: 0.8
// If it's not obvious, the output of the neural network is close to 1 (output of a chicken) - what we are wanted, so we can conclude that we are moving in the right direction
Okay, now that we're heading in the right direction, the final piece of this puzzle will be the implementation of replays.
It's not that difficult, in nature we just do the same thing over and over, and in the code we just specify the number of repetitions:
Code:
var trials = 6;
And the implementation of the function of the number of repetitions into our training neural network will look like this:
Code:
function train (trials) {
for (i = 0; i <trials; i ++) {
neuralNetResult = evaluateNeuralNetwork (input, weights);
learn (input, weights);
}
}
Well, our final report:
Code:
Neural Net output: 0.00 Error: 1.00 Weight Vector: [0,0,0,0]
Neural Net output: 0.20 Error: 0.80 Weight Vector: [0,0,0.2,0]
Neural Net output: 0.40 Error: 0.60 Weight Vector: [0,0,0.4,0]
Neural Net output: 0.60 Error: 0.40 Weight Vector: [0,0,0.6,0]
Neural Net output: 0.80 Error: 0.20 Weight Vector: [0,0,0.8,0]
Neural Net output: 1.00 Error: 0.00 Weight Vector: [0,0,1,0]
// Chicken Dinner!
Now we have a weight vector that will give only one result (chicken for dinner) if the input vector matches reality (pressing the third button).
So what is so cool we just did?
In this particular case, our neural network (after training) can recognize the input data and say, which will lead to the desired result (we will still need to program specific situations):
In addition, it is a scalable model, toy and tool for our training with you. We were able to learn something new about machine learning, neural networks and artificial intelligence.
Caution to users:
- The mechanism for storing the studied weights is not provided, so this neural network will forget everything it knows. When updating or rerunning the code, at least six successful retries are needed for the network to fully learn if you think that a person or a machine will press buttons in a random order. This will take some time.
- Biological networks for learning important things have a learning rate of 1, so only one successful repetition will be needed.
- There is a learning algorithm that closely resembles biological neurons, with a catchy name: the widroff-hoff rule , or the widroff-hoff learning.
- Neuron thresholds (1 in our example) and overfitting effects (with a large number of repetitions, the result will be greater than 1) are not taken into account, but they are very important in nature and are responsible for large and complex blocks of behavioral responses. So are negative weights.
Notes and bibliography for further reading
I tried to avoid mathematics and strict terms, but if you're interested, we have constructed a perceptron, which is defined as a supervised learning algorithm (supervised learning ) double qualifiers - heavy stuff.
The biological structure of the brain is not an easy topic, partly because of inaccuracy, partly because of its complexity. Better to start with Neuroscience (Purves) and Cognitive Neuroscience (Gazzaniga). I've modified and adapted the bunny example from Gateway to Memory (Gluck), which is also a great guide to the world of graphs.
Another great resource, An Introduction to Neural Networks (Gurney), is perfect for all your AI needs.
Now in Python! Thanks to Ilya Andshmidt for providing the Python version:
Code:
inputs = [0, 1, 0, 0]
weights = [0, 0, 0, 0]
desired_result = 1
learning_rate = 0.2
trials = 6
def evaluate_neural_network (input_array, weight_array):
result = 0
for i in range (len (input_array)):
layer_value = input_array [i] * weight_array [i]
result + = layer_value
print ("evaluate_neural_network:" + str (result))
print ("weights:" + str (weights))
return result
def evaluate_error (desired, actual):
error = desired - actual
print ("evaluate_error:" + str (error))
return error
def learn (input_array, weight_array):
print ("learning ...")
for i in range (len (input_array)):
if input_array [i]> 0:
weight_array [i] + = learning_rate
def train (trials):
for i in range (trials):
neural_net_result = evaluate_neural_network (inputs, weights)
learn (inputs, weights)
train (trials)
Now on GO! Thanks to Kieran Mahir for this version.
package main
import (
"fmt"
"math"
)
func main () {
fmt.Println ("Creating inputs and weights ...")
inputs: = [] float64 {0.00, 0.00, 1.00, 0.00}
weights: = [] float64 {0.00, 0.00, 0.00, 0.00}
desired: = 1.00
learningRate: = 0.20
trials: = 6
train (trials, inputs, weights, desired, learningRate)
}
func train (trials int, inputs [] float64, weights [] float64, desired float64, learningRate float64) {
for i: = 1; i <trials; i ++ {
weights = learn (inputs, weights, learningRate)
output: = evaluate (inputs, weights)
errorResult: = evaluateError (desired, output)
fmt.Print ("Output:")
fmt.Print (math.Round (output * 100) / 100)
fmt.Print ("\ nError:")
fmt.Print (math.Round (errorResult * 100) / 100)
fmt.Print ("\ n \ n")
}
}
func learn (inputVector [] float64, weightVector [] float64, learningRate float64) [] float64 {
for index, inputValue: = range inputVector {
if inputValue> 0.00 {
weightVector [index] = weightVector [index] + learningRate
}
}
return weightVector
}
func evaluate (inputVector [] float64, weightVector [] float64) float64 {
result: = 0.00
for index, inputValue: = range inputVector {
layerValue: = inputValue * weightVector [index]
result = result + layerValue
}
return result
}
func evaluateError (desired float64, actual float64) float64 {
return desired - actual
}