Python >> Tutoriel Python >  >> Python

Classification binaire à l'aide de réseaux de neurones

Cet article vous aidera à comprendre la classification binaire à l'aide de réseaux de neurones. (Utiliser uniquement Python sans bibliothèque intégrée à partir de rien)

Réseau de neurones

Définition :Un système informatique modélisé sur le cerveau et le système nerveux humain est connu sous le nom de Neural Network.
Lisez cet article intéressant sur Wikipedia – Neural Network

Classification binaire

La classification binaire consiste à classer les éléments d'un ensemble donné en deux groupes sur la base d'une règle de classification . Par exemple, classer des images d'humains à celles d'animaux.
C'est une sorte d'apprentissage supervisé où il n'y a que deux étiquettes. Bien que la classification binaire puisse sembler très basique, elle a de nombreuses applications dans l'industrie.

  • Détection de spam
  • Détection des transactions frauduleuses par carte de crédit
  • Diagnostic médical (ex :si un patient a un cancer ou non)

Régression logistique

La régression logistique est utilisée dans le cas d'une variable dépendante catégorielle (cible). Il s'agit d'une sorte d'algorithme de classification et non d'un algorithme de régression.
La fonction logistique est écrite comme l'inverse de la fonction logit, également connue sous le nom de fonction sigmoïde.
Mathématiquement,                                 Φ(z) =1/( 1+exp(-z))
où,                                                  z =w.x + b
Score Z

def z_score(w,x,b):
        return np.dot(w,x)+b

Pondérations et biais

Les paramètres w et b lors du calcul du score z sont respectivement le poids et le biais. Par exemple, notre tâche consiste à frapper un six dans un match de cricket. Ici, notre sortie devient "la balle traverse la limite sans toucher le sol" et l'entrée devient "frapper la balle avec la batte". Le ballon franchit la clôture dépendra de la « force » et du « timing » pour jouer le coup. Accepter? Cette « force » est en fait le « poids » et le « timing » est en fait le terme de « biais » dans le score z. Lisez un fil de discussion intéressant sur stackexchange à propos des pondérations et des biais.

Initialisation des pondérations et des biais
Voyons comment initialiser les poids et les biais en Python. Nous devons garder à l'esprit que lorsque les poids sont initialisés à zéro, le réseau de neurones a tendance à rester bloqué dans les minima locaux (et ne pourrait pas atteindre les minima globaux). Nous essayons donc d'initialiser les poids avec des valeurs aléatoires.

def init_params(n_x,n_h):

        ''' It is supposed that you have imported numpy as np
        We want to create a weight matrix of size 
        n_h X n_x with random values.
        And a Bias matrix of size n_h X 1 and initialize it
        randomly.'''
        w=np.random.rand(n_h,n_x)*np.sqrt(1/n_x) # Xavier Initialization.
        b=np.random.randn(n_h,1)
        return w,b

Fonctions d'activation

Définition :La fonction d'activation d'un nœud définit la sortie de ce nœud compte tenu d'une entrée ou d'un ensemble d'entrées. Cette sortie est ensuite utilisée comme entrée pour le nœud suivant et ainsi de suite jusqu'à ce qu'une solution souhaitée à la solution d'origine soit trouvée. La fonction sigmoïde ci-dessus est une sorte de fonction d'activation. Il existe de nombreux types de fonctions d'activation. Par exemple :sigmoïde, tanh, relu, softmax, softplus, etc. Nous pouvons définir les fonctions ReLU comme suit :  Φ(z) =max(z,0). Il existe différents types de fonctions ReLU, l'une d'entre elles étant la plus utilisée est Leaky ReLU. Nous définissons la fonction Leaky ReLU comme Φ(z) =max(z, e*z + c), où e et c sont de très petites constantes.
Calcul des activations

def activation(z,fn = 'linear'):
        act_fn ={'linear':z,
                 'relu':np.maximum(z,0),
                 'tanh':np.tanh(z),
                 'sigmoid':1/(1+np.exp(-z)),
                 'softmax':np.exp(z)/np.sum(np.exp(z))}
        return act_fn[fn]

Propagation vers l'avant

L'entrée X est l'information initiale dont nous disposons et nous avons atteint la solution d'origine. Le calcul séquentiel de z et les fonctions d'activation où le résultat précédent sert d'entrée pour la couche suivante. Ce processus essaie essentiellement de transporter et de traiter les informations initiales et de conclure un résultat.
Mise en œuvre de la propagation vers l'avant

def forward_prop(x, parameters):
        L = len(parameters)//2
        z_scores = {}
        activations = {'a0':x}
        for i in range(1,L+1):
            z_scores['z'+str(i)] = z_score(parameters['w'+str(i)],activations['a'+str(i-1)],parameters['b'+str(i)])
            z = z_scores['z'+str(i)]
            activations['a'+str(i)] = activation(z,fn=self.args[i-1][1])
        
        return z_scores, activations

Fonctions de coût et de perte
Définition de Wikipédia :A La fonction de perte ou la fonction de coût est une fonction qui mappe un événement ou les valeurs d'une ou plusieurs variables sur un nombre réel représentant intuitivement un certain « coût » associé à l'événement. Un problème d'optimisation cherche à minimiser une fonction de perte. Il existe de nombreux types de fonctions de perte utilisées dans les réseaux de neurones artificiels. Par exemple :erreur quadratique moyenne (MSE), erreur absolue moyenne (MAE), perte d'entropie croisée, etc.
Nous discuterons de la perte d'entropie croisée pour la tâche que nous avons sélectionnée, c'est-à-dire la classification binaire.
Nous peut définir la perte d'entropie croisée comme, L(y,a) =– y log(a) – (1-y) log(1 – a) .
et fonction de coût comme J(y,a) =(-1/m) * ∑ L(y,a) , où m =nombre d'échantillons.
Mise en œuvre de la fonction de coût

def compute_cost(y,y_hat):
        m = y.shape[0]
        epsilon = 0.0000001
        cost = (-1/m)*(np.dot(y, np.log(y_hat.T+epsilon)) + np.dot(1-y, np.log(1-y_hat.T+epsilon)))
        return np.squeeze(cost)

Propagation en arrière

Dans la rétropropagation, nous essayons essentiellement de trouver les gradients de la fonction de perte par rapport à différents paramètres. Ces gradients aident les paramètres à atteindre pas à pas les valeurs souhaitées. Dans un langage facile, essayez de le comprendre comme si vous deviez trouver la racine carrée de 50 en utilisant le calcul différentiel. Vous savez que la réponse se situe quelque part autour de 7 (car √49 vaut 7). Vous allez donc prendre une très petite valeur dx et l'ajouter à 7, puis calculer le carré de (7 + dx). Vous vous rapprocherez de plus en plus de √50 après chaque pas en augmentant la valeur dx. Et vous atteindrez √50 avec une certaine précision. Dans la rétropropagation, nous utilisons une approche similaire pour atteindre la valeur souhaitée. Je vous suggère de regarder la vidéo YouTube de 3Blue1Brown sur la rétropropagation.
Implémentation de la rétropropagation

def backprop(y, parameters, z_scores, activations):
        gradients = {}
        L = len(parameters//2)
        m = y.shape[0]
        for i in range(L,0,-1):
            if i==L:
                # Derivative of loss function wrt. z
                # when activation function is sigmoid.
                gradients['dz'+str(i)]=activations['a'+str(i)]-y
            else:
                # when activation function is ReLU
                gradients['dz'+str(i)] = np.multiply(np.dot(parameters['w'+str(i+1)].T, gradients['dz'+str(i+1)]), 1*(z_scores['z'+str(i)]>=0))
            dz = gradients['dz'+str(i)]
            gradients['dw'+str(i)] = (1/m)*np.matmul(dz,activations['a'+str(i-1)].T)
            gradients['db'+str(i)] = (1/m)*np.sum(dz,axis=1,keepdims=True)
        return gradients

Mettre à jour les pondérations et les biais
Après avoir calculé les gradients, nous devons mettre à jour les paramètres, puis à nouveau propager vers l'avant pour voir la perte. Nous répétons sans cesse le processus
Propagation vers l'avant —> Calculer le coût —> Propagation vers l'arrière —> Mettre à jour les paramètres —> Encore une fois la propagation vers l'avant, et ainsi de suite .
Le seul hyperparamètre utilisé pour mettre à jour les paramètres est le taux d'apprentissage (η) (pour cette implémentation simple). Les hyperparamètres sont les valeurs qui ne peuvent pas être formées et doivent être sélectionnées intelligemment. Après chaque itération,

w := w - η * (dJ/dw)
b := b - η * (dJ/db)

 

def update_params(parameters, gradients, learning_rate):
        eta = learning_rate
        for i in range(1,len(parameters)//2+1):
            parameters['w'+str(i)]-=eta*gradients['dw'+str(i)]
            parameters['b'+str(i)]-=eta*gradients['db'+str(i)]
        return parameters

Entraîner le modèle

Entraîner le modèle signifie simplement répéter plusieurs fois les étapes ci-dessus jusqu'à ce que la perte soit réduite à une certaine valeur. Sélectionnez le nombre d'itérations avec soin. En plus d'une bonne précision, nous avons également besoin de moins de temps de calcul.
Algorithme :

Initialize Parameters
for i = 1 to i = n:
     forward propagate
     calculate cost
     backward propagate ( i.e find gradients )
     update parameters
return parameters

Prédire les nouvelles données

Vous avez maintenant des données pour la prédiction et la seule chose dont nous avons besoin, ce sont les paramètres corrects. Après cela, nous n'avons rien à faire, il suffit de mettre les données dans le modèle formé et d'obtenir la sortie. L'implémentation Python de la fonction est illustrée ci-dessous.

def predict(x_test,params):
        z_scores, activations = forward_prop(x_test,params)
        y_pred = 1*(activations['a'+str(len(params)//2)]>0.5)
        return np.squeeze(y_pred)

C'est tout ce que vous devez faire pour créer un réseau de neurones.
Puisque j'ai expliqué toutes les étapes nécessaires et comment implémenter un code python pour eux, même si vous avez besoin d'aide, visitez mon référentiel GitHub pour voir l'implémentation réelle de Neural Network.
Vous aimerez peut-être lire mes autres articles –

  • Préparez votre propre ensemble de données pour la classification d'images à l'aide de Python
  • Présentation de Tensorflow

J'espère que vous êtes clair avec les concepts et si vous avez besoin d'aide à tout moment, n'hésitez pas à commenter.