Sådan bygger du et trelags neuralt netværk fra bunden

I dette indlæg, vil jeg gå gennem de nødvendige skridt for at opbygge en tre lags neuralt netværk. Jeg gennemgår et problem og forklarer dig processen sammen med de vigtigste begreber undervejs.

Problemet at løse

En landmand i Italien havde et problem med sin mærkningsmaskine: den blandede etiketterne på tre vinsorter. Nu har han 178 flasker tilbage, og ingen ved, hvilken sort der lavede dem! For at hjælpe denne stakkels mand vil vi opbygge en klassifikator, der genkender vinen baseret på 13 attributter for vinen.

Det faktum, at vores data er mærket (med en af ​​de tre cultivars etiketter) gør dette til et overvåget læringsproblem . I det væsentlige er det, vi ønsker at gøre, at bruge vores inputdata (de 178 uklassificerede vinflasker), sætte det gennem vores neurale netværk og derefter få det rigtige mærke til hver vinkultur som output.

Vi træner vores algoritme til at blive bedre og bedre til at forudsige (y-hat), hvilken flaske der hører til hvilken etiket.

Nu er det tid til at begynde at opbygge det neurale netværk!

Nærme sig

At opbygge et neuralt netværk er næsten som at opbygge en meget kompliceret funktion eller sammensætte en meget vanskelig opskrift. I begyndelsen kan de ingredienser eller trin, du bliver nødt til at tage, virke overvældende. Men hvis du nedbryder alt sammen og gør det trin for trin, har du det godt.

Kort sagt:

  • Inputlaget (x) består af 178 neuroner.
  • A1, det første lag, består af 8 neuroner.
  • A2, det andet lag, består af 5 neuroner.
  • A3, det tredje og outputlag, består af 3 neuroner.

Trin 1: den sædvanlige forberedelse

Importer alle nødvendige biblioteker (NumPy, skicit-learning, pandaer) og datasættet, og definer x og y.

#importing all the libraries and dataset
import pandas as pdimport numpy as np
df = pd.read_csv('../input/W1data.csv')df.head()
# Package imports
# Matplotlib import matplotlibimport matplotlib.pyplot as plt
# SciKitLearn is a machine learning utilities libraryimport sklearn
# The sklearn dataset module helps generating datasets
import sklearn.datasetsimport sklearn.linear_modelfrom sklearn.preprocessing import OneHotEncoderfrom sklearn.metrics import accuracy_score

Trin 2: initialisering

Før vi kan bruge vores vægte, skal vi initialisere dem. Da vi endnu ikke har værdier til vægtene, bruger vi tilfældige værdier mellem 0 og 1.

I Python random.seedgenererer funktionen "tilfældige tal". Tilfældige tal er dog ikke rigtig tilfældige. De genererede tal er pseudorandom , hvilket betyder, at tallene genereres af en kompliceret formel, der får det til at se tilfældigt ud. For at generere tal tager formlen den tidligere genererede værdi som input. Hvis der ikke genereres nogen tidligere værdi, tager det ofte tiden som en første værdi.

Derfor frø vi generatoren - for at sikre, at vi altid får de samme tilfældige tal . Vi giver en fast værdi, som talgeneratoren kan starte med, hvilket i dette tilfælde er nul.

np.random.seed(0)

Trin 3: fremad formering

Der er omtrent to dele af træning af et neuralt netværk. For det første formerer du dig frem gennem NN. Det vil sige, at du “tager skridt” fremad og sammenligner disse resultater med de reelle værdier for at få forskellen mellem dit output og hvad det skal være. Du ser dybest set, hvordan NN klarer sig, og finder fejlene.

Når vi har initialiseret vægtene med et pseudo-tilfældigt tal, tager vi et lineært skridt fremad. Vi beregner dette ved at tage vores input A0 gange prikproduktet af tilfældige initialiserede vægte plus en bias . Vi startede med en bias på 0. Dette er repræsenteret som:

Nu tager vi vores z1 (vores lineære trin) og sender den gennem vores første aktiveringsfunktion . Aktiveringsfunktioner er meget vigtige i neurale netværk. I det væsentlige konverterer de et indgangssignal til et udgangssignal - det er derfor, de også kaldes Overføringsfunktioner. De introducerer ikke-lineære egenskaber til vores funktioner ved at konvertere den lineære input til en ikke-lineær output, hvilket gør det muligt at repræsentere mere komplekse funktioner.

Der er forskellige slags aktiveringsfunktioner (forklaret i dybden i denne artikel). Til denne model valgte vi at bruge tanh- aktiveringsfunktionen til vores to skjulte lag - A1 og A2 - som giver os en outputværdi mellem -1 og 1.

Da dette er et klassificeringsproblem i flere klasser (vi har 3 outputetiketter ), bruger vi softmax- funktionen til outputlaget - A3 - fordi dette beregner sandsynlighederne for klasserne ved at spytte en værdi mellem 0 og 1.

Ved at føre z1 gennem aktiveringsfunktionen har vi oprettet vores første skjulte lag - A1 - som kan bruges som input til beregning af det næste lineære trin, z2.

I Python ser denne proces sådan ud:

# This is the forward propagation functiondef forward_prop(model,a0): # Load parameters from model W1, b1, W2, b2, W3, b3 = model['W1'], model['b1'], model['W2'], model['b2'], model['W3'],model['b3'] # Do the first Linear step z1 = a0.dot(W1) + b1 # Put it through the first activation function a1 = np.tanh(z1) # Second linear step z2 = a1.dot(W2) + b2 # Put through second activation function a2 = np.tanh(z2) #Third linear step z3 = a2.dot(W3) + b3 #For the Third linear activation function we use the softmax function a3 = softmax(z3) #Store all results in these values cache = {'a0':a0,'z1':z1,'a1':a1,'z2':z2,'a2':a2,'a3':a3,'z3':z3} return cache

I sidste ende gemmes alle vores værdier i cachen.

Trin 4: bagud formering

Når vi spredes videre gennem vores NN, udbreder vi vores fejlgradient for at opdatere vores vægtparametre. Vi kender vores fejl og vil minimere den så meget som muligt.

We do this by taking the derivative of the error function, with respect to the weights (W) of our NN, using gradient descent.

Lets visualize this process with an analogy.

Imagine you went out for a walk in the mountains during the afternoon. But now its an hour later and you are a bit hungry, so it’s time to go home. The only problem is that it is dark and there are many trees, so you can’t see either your home or where you are. Oh, and you forgot your phone at home.

But then you remember your house is in a valley, the lowest point in the whole area. So if you just walk down the mountain step by step until you don’t feel any slope, in theory you should arrive at your home.

So there you go, step by step carefully going down. Now think of the mountain as the loss function, and you are the algorithm, trying to find your home (i.e. the lowest point). Every time you take a step downwards, we update your location coordinates (the algorithm updates the parameters).

The loss function is represented by the mountain. To get to a low loss, the algorithm follows the slope — that is the derivative — of the loss function.

When we walk down the mountain, we are updating our location coordinates. The algorithm updates the parameters of the neural network. By getting closer to the minimum point, we are approaching our goal of minimizing our error.

In reality, gradient descent looks more like this:

We always start with calculating the slope of the loss function with respect to z, the slope of the linear step we take.

Notation is as follows: dv is the derivative of the loss function, with respect to a variable v.

Next we calculate the slope of the loss function with respect to our weights and biases. Because this is a 3 layer NN, we will iterate this process for z3,2,1 + W3,2,1 and b3,2,1. Propagating backwards from the output to the input layer.

This is how this process looks in Python:

# This is the backward propagation functiondef backward_prop(model,cache,y):
# Load parameters from model W1, b1, W2, b2, W3, b3 = model['W1'], model['b1'], model['W2'], model['b2'],model['W3'],model['b3'] # Load forward propagation results a0,a1, a2,a3 = cache['a0'],cache['a1'],cache['a2'],cache['a3'] # Get number of samples m = y.shape[0] # Calculate loss derivative with respect to output dz3 = loss_derivative(y=y,y_hat=a3)
# Calculate loss derivative with respect to second layer weights dW3 = 1/m*(a2.T).dot(dz3) #dW2 = 1/m*(a1.T).dot(dz2) # Calculate loss derivative with respect to second layer bias db3 = 1/m*np.sum(dz3, axis=0) # Calculate loss derivative with respect to first layer dz2 = np.multiply(dz3.dot(W3.T) ,tanh_derivative(a2)) # Calculate loss derivative with respect to first layer weights dW2 = 1/m*np.dot(a1.T, dz2) # Calculate loss derivative with respect to first layer bias db2 = 1/m*np.sum(dz2, axis=0) dz1 = np.multiply(dz2.dot(W2.T),tanh_derivative(a1)) dW1 = 1/m*np.dot(a0.T,dz1) db1 = 1/m*np.sum(dz1,axis=0) # Store gradients grads = {'dW3':dW3, 'db3':db3, 'dW2':dW2,'db2':db2,'dW1':dW1,'db1':db1} return grads

Step 5: the training phase

In order to reach the optimal weights and biases that will give us the desired output (the three wine cultivars), we will have to train our neural network.

I think this is very intuitive. For almost anything in life, you have to train and practice many times before you are good at it. Likewise, a neural network will have to undergo many epochs or iterations to give us an accurate prediction.

When you are learning anything, lets say you are reading a book, you have a certain pace. This pace should not be too slow, as reading the book will take ages. But it should not be too fast, either, since you might miss a very valuable lesson in the book.

In the same way, you have to specify a “learning rate” for the model. The learning rate is the multiplier to update the parameters. It determines how rapidly they can change. If the learning rate is low, training will take longer. However, if the learning rate is too high, we might miss a minimum. The learning rate is expressed as:

  • := means that this is a definition, not an equation or proven statement.
  • ais the learning rate called alpha
  • dL(w) is the derivative of the total loss with respect to our weight w
  • da is the derivative of alpha

We chose a learning rate of 0.07 after some experimenting.

# This is what we return at the endmodel = initialise_parameters(nn_input_dim=13, nn_hdim= 5, nn_output_dim= 3)model = train(model,X,y,learning_rate=0.07,epochs=4500,print_loss=True)plt.plot(losses)

Finally, there is our graph. You can plot your accuracy and/or loss to get a nice graph of your prediction accuracy. After 4,500 epochs, our algorithm has an accuracy of 99.4382022472 %.

Brief summary

We start by feeding data into the neural network and perform several matrix operations on this input data, layer by layer. For each of our three layers, we take the dot product of the input by the weights and add a bias. Next, we pass this output through an activation function of choice.

The output of this activation function is then used as an input for the following layer to follow the same procedure. This process is iterated three times since we have three layers. Our final output is y-hat, which is the prediction on which wine belongs to which cultivar. This is the end of the forward propagation process.

We then calculate the difference between our prediction (y-hat) and the expected output (y) and use this error value during backpropagation.

During backpropagation, we take our error — the difference between our prediction y-hat and y — and we mathematically push it back through the NN in the other direction. We are learning from our mistakes.

By taking the derivative of the functions we used during the first process, we try to discover what value we should give the weights in order to achieve the best possible prediction. Essentially we want to know what the relationship is between the value of our weight and the error that we get out as the result.

And after many epochs or iterations, the NN has learned to give us more accurate predictions by adapting its parameters to our dataset.

Dette indlæg blev inspireret af uge 1-udfordringen fra Bletchley Machine Learning Bootcamp, der startede den 7. februar. I de kommende ni uger er jeg en af ​​50 studerende, der vil gennemgå det grundlæggende i Machine Learning. Hver uge diskuterer vi et andet emne og skal indsende en udfordring, som kræver, at du virkelig forstår materialerne.

Hvis du har spørgsmål eller forslag, eller så lad mig det vide!

Eller hvis du vil tjekke hele koden, kan du finde den her på Kaggle.

Anbefalede videoer for at få en dybere forståelse på neurale netværk:

  • 3Blue1Browns serie om neurale netværk
  • Siraj Ravals serie om Deep Learning