Skip to main content

Vision, image and machine learning (partie AM)

4 mins

A. Classification de points 2D avec Pytorch #

Un réseau de neurones est un très bon ‘classifier’. Dans un exemple simple, nous voudrions reconnaitre la classe d’un point à partir de ses coordonnées 2D notées (x_1, x_2). Un point peut appartenir à 2 classes : classe 1 par exemple en bleu ou classe 2 par exemple en vert. Le réseau prend en entrée 2 valeurs (x_1, x_2) et sort 2 valeurs (suis-je_bleu?, suis-je_vert?). “suis-je_bleu?” sera représenté par un nombre réel entre 0 et 1 : proche de 0 indiquant que le point n’appartient pas à la classe, proche de 1 indiquant que le point appartient à la classe. Par exemple, une sortie [0.3, 0.7] sera tranché en “c’est un point de la classe 2”.

L’entrainement du réseau consistera à lui montrer toute une série de coordonnées de points avec les valeurs de classes associées. Le réseau va optimiser ses paramètres (poids) pour que le taux d’erreur devienne le plus petit possible.

Un neurone #

Un neurone artificiel (ou un perceptron) reçoit des valeurs d’entrées, il les multiplie une à une par un poids, puis en fait la somme. Cette somme est passée à une fonction d’activation. Par exemple une fonction d’activation très simple peut-être de comparer la somme à un seuil. Si elle est inférieure, la valeur de sortie sera 0, 1 sinon. L’objectif de l’apprentissage/optimisation est de retrouver les poids qui ferons correspondre au mieux la sortie à partir des entrées sur une base de connaissance disponible.

Image alt

Un réseau #

Le principe du réseau de neurones est d’assembler entre-eux des neurones, pour leur faire apprendre des tâches complexes. Les neurones vont être regroupés en couches, une couche réalisant une tâche donnant un niveau d’abstraction supplémentaire pour la couche suivante. Par exemple, pour reconnaître une lettre, la couche la plus basse va repérer des morceaux de courbes et la couche supérieure estime que certaines courbes ensembles forme un ‘A’ et non un ‘S’. L’utilisation de plusieurs couches (layer en anglais) est appelée apprentissage profond/Deep Learning.

Image alt

Voir une explication plus détaillé dans le cours ou éventuellement sur internet, la page Wikipedia par exemple.

Dans un 1er temps, allez jouer avec “Playground classifier” pour comprendre le principe de la classification de points avec un réseau de neurones profond.

Image alt

Dans un 2e temps vous allez écrire votre classifier de points avec PyTorch.

Les données #

Pour notre problème de reconnaitre la couleur d’un point, il faut des données d’apprentissage. Le code de départ est donné ici. Ce code génère des points (les données) procéduralement, donc autant que l’on veut. La classe bleu sont les points dont les coordonnées sont inférieures à cosinus, et la classe verte sont les points au dessus de cosinus. Dans un “vrai” problème, ces données ne peuvent se générer, il faut les trouver quelque part …

Image alt

L’apprentissage #

L’apprentissage se passe en différentes phases.

  • La définition du réseau.
  • La configuration de l’optimisation (optimizer), en général Stochastic Gradient Descent couplé à une fonction d’erreur.
  • La phase d’entrainement optimise les poids de chaque neurone à partir des données d’entrée couplées à leur sortie. La fonction d’erreur sert de mesure à faire descendre.
  • Une phase d’évaluation avec des données que le réseau n’a jamais vu pour mesurer la qualité de l’apprentissage.

Le code ci-dessous donne un réseau minimaliste. Vous devrez l’améliorer pour qu’il soit plus efficace.

      # voir le code de départ : https://github.com/ucacaxm/DeepLearning_Vision_SimpleExamples/blob/master/src/classifier/classifier_pointcloud_empty.py

        ########################################################################################"
        # Copier/coller juste avant main
        class Net(nn.Module):
           def __init__(self):
               super(Net, self).__init__()
               self.fc1 = nn.Linear(2, 64)
               self.fc2 = nn.Linear(64, 2)

           def forward(self, x):
              x = F.relu(self.fc1(x))
              x = self.fc2(x)
              return x



        ########################################################################################"
        ############# NETWORK definition/configuration => à copier/coller dans le main 
        net = Net()
        print(net)

        ############# SGD config: Stochastic Gradient Descent Config
        criterion = nn.CrossEntropyLoss()
        optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

        ############ TRAINNING
        for epoch in range(5):  # loop over the dataset multiple times
            running_loss = 0.0
            for i in range(1000):         # iterate on mini batches. mani-batch = a subset of the database
                inputs, labels = next_batch(128)
                inputs = torch.from_numpy(inputs)
                labels = torch.from_numpy(labels).long()
               
                # zero the parameter gradients
                optimizer.zero_grad()
        
                # forward + backward + optimize
                outputs = net(inputs)
                loss = criterion(outputs, torch.max(labels, 1)[1] )
                loss.backward()
                optimizer.step()

                # print statistics
                running_loss += loss.item()
                if i % 100 == 99:    # print every 2000 mini-batches
                    print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 100))
                    running_loss = 0.0      


        ############ EVALUATION         
        TODO
        
        ############ DRAWING POINT CLOUD WITH ERROR
        TODO

Regardez la page des tutos de PyTorch.

Le résultat #

Le résultat sera le taux de bonne reconnaissance de points, mesuré avec des points jamais observés pendant l’apprentissage. Par exemple après un apprentissage nous obtenons un taux de 96% de bonne classification, les points rouges sur l’image suivante sont les points mal classifiés.

Image alt

Pour rendre le problème un peu plus dur vous pouvez augmenter la plage de génération des points en changeant ceci :

    x = np.array( [ 2.0*3.141592*np.random.ranf(), 2.0*np.random.ranf()-1 ])
    devient
    x = np.array( [ 4.0*3.141592*np.random.ranf(), 2.0*np.random.ranf()-1 ])

Image alt