L'intelligence du sémaphore

C'est quoi un sémaphore ?

chappe.jpeg

Calcul de Le sémaphore avec TensorFlow sur GPU au lieu du CPU avec TensorFlow

Images sorties de Blender

Images adaptées pour l'apprentissage

L'optimisation a montré que la meilleure solution est avec ce type d'image.

Relu Rectifier neural networks

def relu(x):
    """Rectified Linear Unit:
 
    In the context of artificial neural networks, the rectifier is an
    activation function defined as the positive part of its argument.
 
    Rectifie les négatifs à 0:
    -1 > 0
     1 > 1
     """
    return np.maximum(0, x)

Relu_prime

def relu_prime(z):
    """La fonction de Heaviside (également fonction échelon unité, fonction
    marche d'escalier) est la fonction indicatrice de R.
    Une fonction indicatrice, est une fonction définie sur un
    ensemble E qui explicite l’appartenance ou non à un sous-ensemble F de E
    de tout élément de E. 
    C'est donc la fonction H (discontinue en 0) prenant la valeur 1 pour tous
    les réels positifs et la valeur 0 pour les réels strictement négatifs.
    """
    return np.asarray(z > 0, dtype=np.float32)

Sigmoïd

Elle représente la fonction de répartition de la loi logistique. Elle est souvent utilisée dans les réseaux de neurones parce qu'elle est dérivable, ce qui est une contrainte pour l'algorithme de rétropropagation de Werbos. La forme de la dérivée de sa fonction inverse est extrêmement simple et facile à calculer, ce qui améliore les performances des algorithmes.

def sigmoid(x):
    """La fonction sigmoïde est une courbe en S."""
    return 1 / (1 + np.exp(-x))

Sigmoïd prime

def sigmoid_prime(z):
    """La dérivée de la fonction sigmoid."""
    return z * (1 - z)

Algorithme du gradient stochastique

L'algorithme du gradient stochastique est une méthode de descente de gradient (itérative) utilisée pour la minimisation d'une fonction objectif qui est écrite comme une somme de fonctions différentiables.

Diagonale de 1

numpy.eye(N, M=None, k=0, dtype=<class 'float'>, order='C')\\
Return a 2-D array with ones on the diagonal and zeros elsewhere.

Matrice ou la sortie est idéale: le 1 correspond à entée[i] = sortie[i], et entée[j],sortie[k] =0 si j différent de k

Initialisation de X. Glorot et He

X = Xavier = prénom

Un réseau de neurones Perceptron multicouches est un type de réseau dont l'information circule dans un unique sens, de la couche d'entrée vers la couche de sortie. Ont dit qu'il est un réseau “à propagation directe” (feedforward).

Notre réseau

Réseau de neurones:

Une colonne de 1600 en entrée, 2 nodes de 100, une sortie de 27 caractères.

Un réseau de neurones Convolutif est un type de réseau de neurones artificiels dans lequel le motif de connexion entre les neurones est inspiré par le cortex visuel des animaux. Actuellement, il est très utilisé pour l'analyse des images, des vidéos et du langage naturel.

Ce type de réseau est développé avec Yolo Darknet Préparation de mes propres images puis Yolo Darknet sans carte graphique et enfin Yolo Darknet sur un portable Optimus.

Du code expliqué avec beaucoup d'amour Enfin, là c'est de l'intelligence qu'on cherche, pas de l'amour.

La totalité du projet est à Semaphore sur Github, et Jeu du sémaphore dans le Blender Game Engine pour la création des images.

ia.py
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
 
import shutil
import numpy as np
import cv2
from pymultilame import MyTools
 
def sigmoid(x): return 1 / (1 + np.exp(-x))
def sigmoid_prime(z): return z * (1 - z)
def relu(x): return np.maximum(0, x)
def relu_prime(z): return np.asarray(z > 0, dtype=np.float32)
 
class SemaphoreIA:
    def __init__(self, root, learningrate, failed=0):
        self.root = root
        self.learningrate = learningrate
        self.failed = failed
        self.tools = MyTools()
 
        # Dossier des ratés
        if self.failed:
            # Suppression du dossier failed et recréation pour le vider
            try:
                shutil.rmtree(self.root + 'failed')
            except:
                print('Pas de dossier failed')
            self.tools.create_directory(self.root + 'failed')
 
        # Réseau de neurones: colonne 1600 en entrée, 2 nodes de 100, sortie de 27 caractères
        self.layers = [1600, 100, 100, 27]
        # Fonction d'activation: imite l'activation d'un neuronne
        self.activations = [relu, relu, sigmoid]
 
        fichier = np.load(self.root + 'semaphore.npz')
        self.x_train, self.y_train = fichier['x_train'], fichier['y_train']
        self.x_train = 1 - self.x_train
        self.x_test, self.y_test = self.x_train[50000:,:], self.y_train[50000:]
        self.x_train, self.y_train = self.x_train[:50000,:], self.y_train[:50000]
 
        # Affichage des images pour distraire
        cv2.namedWindow('img')
 
    def training(self):
        """Apprentissage avec 60 000 images. Poids enregistré dans weights.npy"""
        print("Training...")
 
        # Matrice diagonale de 1
        diagonale = np.eye(27, 27)
 
        # globals() Return a dictionary representing the current global symbol table.
        self.activations_prime = [globals()[fonction.__name__ + '_prime'] for fonction in self.activations]
 
        node_dict = {}
 
        # Liste des poids
        # Initialisation des poids des nodes, pour ne pas à être à 0
        # Construit 3 matrices (100x1600, 100x100, 27x100)
        # /np.sqrt() résultat expérimental de l'initialisation d'un gars qui s'appelle Xavier Glorot et d'un autre qui s'appelle He !
        weight_list = [np.random.randn(self.layers[k+1], self.layers[k]) / \
                       np.sqrt(self.layers[k]) for k in range(len(self.layers)-1)]
 
        # vecteur_ligne = image en ligne à la 1ère itération
        # nombre_lettre = nombre correspondant à la lettre de l'image
        # i pour itération, vecteur_colonne = x_train de i, nombre_lettre = y_train de i
        for i, (vecteur_ligne, nombre_lettre) in enumerate(zip(self.x_train, self.y_train)):
 
            # Affichage pour distraire les mangalore
            if i % 10000 == 0:
                print(i, nombre_lettre)
                img = vecteur_ligne.reshape(40,40) * 255
                img = cv2.resize(img, (600, 600), interpolation=cv2.INTER_AREA)
                cv2.imshow("img", img)
                cv2.waitKey(1)
 
            # la ligne devient colonne
            vecteur_colonne = np.array(vecteur_ligne, ndmin=2).T
 
            # Forward propagation
            node_dict[0] = vecteur_colonne
            for k in range(len(self.layers)-1):
                # weight_list[k] (100x1600, 100x100 27x100) vecteur_colonne (1600,)
                # z de format 100 x 1
                z = np.dot(weight_list[k], vecteur_colonne)
 
                # self.activations = non linéaire sinon sortie fonction linéaire de l'entrée
                # imite le seuil d'activation électrique du neurone
                vecteur_colonne = self.activations[k](z)
 
                node_dict[k+1] = vecteur_colonne
 
            # Retro propagation, delta_a = écart entre la sortie réelle et attendue
            delta_a = vecteur_colonne - diagonale[:,[nombre_lettre]]
            # Parcours des nodes en sens inverse pour corriger proportionnellement
            # les poids en fonction de l'erreur par rapport à la valeur souhaitée
            # Descente du Gradient stochastique
            for k in range(len(self.layers)-2, -1, -1):
                delta_z = delta_a * self.activations_prime[k](node_dict[k+1])
                delta_w = np.dot(delta_z, node_dict[k].T)
                delta_a = np.dot(weight_list[k].T, delta_z)
                # Pour converger vers le minimum d'erreur
                weight_list[k] -= self.learningrate * delta_w
 
        # Dans un fichier
        np.save(self.root + 'weights.npy', weight_list)
        print('weights.npy enregistré')
        cv2.destroyAllWindows()
 
    def testing(self):
        """Teste avec 10 000 images, retourne le ratio de bon résultats"""
        print("Testing...")
 
        weight_list = np.load(self.root + 'weights.npy')
 
        # Nombre de bonnes reconnaissance
        success = 0
 
        # Dict avec le nombre d'erreurs par lettre
        failed_dict = {}
 
        for vecteur_ligne, nombre_lettre in zip(self.x_test, self.y_test):
            # image en ligne au 1er passage pour les failed
            img = vecteur_ligne.copy()
 
            for k in range(len(self.layers)-1):
                vecteur_ligne = self.activations[k](np.dot(weight_list[k],
                                                      vecteur_ligne))
 
            reconnu = np.argmax(vecteur_ligne)
            if reconnu == nombre_lettre:
                success += 1
            else:
                if self.failed:
                    self.write_failed(img, nombre_lettre, reconnu, success)
                if nombre_lettre in failed_dict:
                    failed_dict[nombre_lettre] += 1
                else:
                    if self.failed:
                        self.tools.create_directory(self.root + 'failed' + '/bad_' + str(nombre_lettre))
                        failed_dict[nombre_lettre] = 1
 
        if self.failed:
            sorted_by_value = sorted(failed_dict.items(), key=lambda kv: kv[1], reverse=True)
            print(sorted_by_value)
 
        resp = 100.0 * success / len(self.x_test)
        return resp
 
    def write_failed(self, img, nombre_lettre, reconnu, S):
        """Les images avec erreur de reconnaisance sont copiées dans
        /semaphore/failed/bad_11/11_6_9067.png
        11 est la lettre k, donc dans le dossier il ny a que la lettre k
        et le 2ème nombre est la lettre reconnue fausse
        """
        name = str(nombre_lettre) + '_' + str(reconnu) + '_'  + str(S) + '.png'
        fichier = self.root + 'failed' + '/bad_' + str(nombre_lettre) + '/' + name
        img = img.reshape(40,40) * 255
        cv2.imwrite(fichier, img)
 
 
if __name__ == "__main__":
    print(MyTools().get_absolute_path(__file__))
    root = MyTools().get_absolute_path(__file__)[:-28]
    print("Current directory:", root)
 
    for i in range(5):
        learningrate = 0.022
        failed = 0
        sia = SemaphoreIA(root, learningrate, failed)
        sia.training()
        resp = sia.testing()
        print("Learningrate: {} Résultat {}".format(learningrate, round(resp, 1)))
  • l_intelligence_du_semaphore.txt
  • Dernière modification: 2019/10/10 15:27
  • par serge