Implémentation d'un réseau de neurones à rétropropagation

Modèle de régression

Objectif

Appprendre la relation linéaire \(y = 2x\).

Architecture

Réseau neuronal à une couche cachée avec un seul neurone.

Fonction de coût

Erreur quadratique moyenne :

\[MSE = \frac{1}{2}(\hat{y} - y)^2\] ### Algorithme

Descente de gradient standard, minimisant l'erreur sur l'ensemble des données à chaque époque.

Propagation avant

\[ \begin{align*} \alpha &= v \cdot x \\ b &= \sigma(\alpha) \\ \beta &= w \cdot b \\ \hat{y} &= \beta \\ E &= \frac{1}{2}(\hat{y} - y)^2 \end{align*} \] ### Rétropropagation

Mise à jour des paramètres :

\[ \begin{align*} \Delta w &= -\eta \cdot (\hat{y} - y) \cdot b \\ \Delta v &= -\eta \cdot (\hat{y} - y) \cdot w \cdot \sigma'(\alpha) \cdot x \\ \sigma'(\alpha) &= \sigma(\alpha) \cdot (1 - \sigma(\alpha)) \end{align*} \] ### Implémentation en C++

#include <iostream>
#include <cmath>

class Reseau {
private:
    double tauxApprentissage;
    double poidsV = 0.5, poidsW = 0.5;
    
    double activation(double x) {
        return 1.0 / (1.0 + exp(-x));
    }

public:
    Reseau(double eta) : tauxApprentissage(eta) {}

    double prediction(double entree) {
        double signalCache = poidsV * entree;
        double activationCachee = activation(signalCache);
        return poidsW * activationCachee;
    }

    void miseAJour(double entree, double prediction, double etiquette) {
        double signalCache = poidsV * entree;
        double derivee = activation(signalCache) * (1 - activation(signalCache));
        double delta = prediction - etiquette;
        
        poidsW -= tauxApprentissage * delta * activation(signalCache);
        poidsV -= tauxApprentissage * delta * poidsW * derivee * entree;
    }
};

int main() {
    Reseau modele(0.01);
    std::cout << "Prédiction initiale (x=3): " << modele.prediction(3) << std::endl;
    
    for (int epoch = 0; epoch < 500; epoch++) {
        double erreur = 0.0;
        for (int i = 0; i < 10; i++) {
            double pred = modele.prediction(i);
            double cible = 2 * i;
            erreur += 0.5 * pow(pred - cible, 2);
            modele.miseAJour(i, pred, cible);
        }
        std::cout << "Époque " << epoch << ": Erreur = " << erreur/10 << std::endl;
    }
    std::cout << "Prédiction finale (x=3): " << modele.prediction(3) << std::endl;
    return 0;
}

Implémentation PyTorch

import torch
import torch.nn as nn

class ModeleSimple(nn.Module):
    def __init__(self):
        super(ModeleSimple, self).__init__()
        self.couche = nn.Linear(1, 1)
        self.activation = nn.Sigmoid()
        
    def forward(self, x):
        return self.activation(self.couche(x))

entrees = torch.tensor([[i] for i in range(10)], dtype=torch.float32)
cibles = torch.tensor([[2*i] for i in range(10)], dtype=torch.float32)

modele = ModeleSimple()
optimiseur = torch.optim.SGD(modele.parameters(), lr=0.01)
fonction_perte = nn.MSELoss()

for epoch in range(500):
    optimiseur.zero_grad()
    predictions = modele(entrees)
    perte = fonction_perte(predictions, cibles)
    perte.backward()
    optimiseur.step()

Modèle de classification

Architecture

Réseau à deux entrées et deux neurones de sortie pour classification binaire.

Fonction de coût

Entropie croisée :

\[ H(y, \hat{y}) = -\sum_{i=1}^{2} y_i \log(\hat{y}_i) \] ### Propagation avant

\[ \begin{align*} a_j &= \sum_{i} w_{ij} x_i \\ b_j &= \sigma(a_j) \\ \hat{y}_k &= \frac{e^{b_k}}{\sum_{m} e^{b_m}} \end{align*} \] ### Rétropropagation

Dérivées des poids :

\[ \frac{\partial H}{\partial w_{ij}} = (\hat{y}_j - y_j) \cdot \sigma'(a_j) \cdot x_i \] ### Implémentation Python

import numpy as np

class Classifieur:
    def __init__(self):
        self.poids = np.array([[0.5, 0.5], [0.5, 0.5]])
        self.taux = 0.5
        
    def sigmoide(self, z):
        return 1 / (1 + np.exp(-z))
    
    def propagation(self, x):
        a = self.poids.T.dot(x)
        b = self.sigmoide(a)
        exp_b = np.exp(b)
        return exp_b / np.sum(exp_b)
    
    def entrainement(self, x, y):
        a = self.poids.T.dot(x)
        b = self.sigmoide(a)
        exp_b = np.exp(b)
        predictions = exp_b / np.sum(exp_b)
        
        gradient = np.outer(x, (predictions - y) * b * (1 - b))
        self.poids -= self.taux * gradient

Étiquettes: Rétropropagation Perceptron Multicouche descente de gradient Régression Linéaire Classification Binaire

Publié le 10 juillet à 01h56