Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Intelligence artificielle Discussion :

Réseau de neurones : propagation et rétropropagation


Sujet :

Intelligence artificielle

  1. #1
    Candidat au Club
    Réseau de neurones : propagation et rétropropagation
    Bonjour,

    Je souhaiterais une discussion et un retour de votre part. Ceci d'une part pour savoir si je me plante et d'autre part pour améliorer mon code...

    Présentation :

    Durant cette période de confinement j'ai décidé de me plonger dans le domaine des réseaux de neurones appliqués à la détection de chiffres à partir du tout début.
    J'ai donc codé en Java un Perceptron, un réseau de neurones (propagation et rétropropagation du gradient de l'erreur). J'ai implémenté les fonctions d'activation de type sigmoid, tanh et PreRELU (RELU pas réussi à le faire fonctionner : le réseau se bloque de suite...) et j'ai bien galéré pour appréhender les hyper paramètres.
    Bref, à ce jour ça marche ! J'utilise la base d'images MNIST et j'ai obtenu un score de 95,4%. J'aurais pu avoir plus mais j'ai arrêté le prog au bout de 8h...

    Je trouve l'apprentissage long : pour parcourir 30 000 images par exemple je mets 1mn ... sachant qu'un tiers du temps correspond à la propagation et le reste à la rétropropagation.
    Mon réseau à 784 entrées (28*28), une couche d'entrée de 784 neurones, une couche cachée de 100 neurones et une couche de sortie de 10 neurones
    Mon PC est un I7 4600U @2.10 Gz (4 core)

    Trouvez vous ce temps long, trop long ou raisonnable ?

    Mon deuxième point maintenant : la recherche d'amélioration du temps d'execution
    J'ai voulu essayer de profiter pleinement du processeur. Seulement utilisé qu'à 25% au max, j'ai décidé de commencer à optimiser la partie "propagation". J'ai donc lancé mes calculs par des Threads.
    Et là comble de l'histoire :
    • le temps d'execution est plus long,
    • le processeur est utilisé à 100%.


    Après avoir testé les threads simplement (temps catastrophiques) j'ai ensuite utilisé les services "Executor" qui permet de n’exécuter que 4 thread à la fois (1 par proc). Ce qui a très nettement amélioré les temps mais pas assez. J'arrive à des temps équivalent que lorsque j'ai des boucles de plus de 10000 itérations pour un Perceptron. Ce qui en pratique n'arrive jamais dans une couche de 800 neurones... J'ai l'impression que la mise en oeuvre du mecanisme des Threads est trop longue et fait perdre du temps d’exécution....

    D’où ma deuxième série de questions :

    • existe-t-il en java une autre manière de gérer des Thread (pour des petits calculs) ?
    • d'une manière plus globale, existe-t-il une manière de calculer une propagation (et une rétropropagtion) adaptée aux threads ?




    Merci pour vos retours d'expériences !

    Bien cordialement,
    Xavier

  2. #2
    Responsable Qt & Livres



    La plupart des codes utilisent justement des GPU, parce que les traitements à effectuer sont massivement parallèles : c'est un paradigme qui s'applique bien aux GPU. Sur CPU, les fils d'exécution sont assez lourds à gérer (ils nécessitent l'intervention du système d'exploitation), il vaut mieux les utiliser pour une série de tâches plus grosses (à la limite, avec un mécanisme producteur-consommateur). Tu pourrais aussi regarder du côté des fibres (parfois lightweight threads). En Java, ça semble correspondre au Project Loom (https://wiki.openjdk.java.net/display/loom/Main).
    Vous souhaitez participer aux rubriques Qt ou PyQt (tutoriels, FAQ, traductions), HPC ? Contactez-moi par MP.

    Créer des applications graphiques en Python avec PyQt5
    Créer des applications avec Qt 5.

    Pas de question d'ordre technique par MP !

  3. #3
    Candidat au Club
    Merci pour ce premier retour.

    Effectivement je ne connaissais pas les "lightweight threads" et plus particulièrement les "fibers" et "continuations" du projet Loom.

    Ce projet n'est pas un module en soit mais une intégration des "lightweight threads" dans java (openjdk). J'ai donc récupéré un bin du jdk15 comportant loom.

    J'ai donc fait des tests sous Windows 7. J'ai pris 2 boucles imbriquées.
    - la première faisant 20 000 itérations,
    - la deuxième, via Thread, qui lance x fois le calcul d'un neurone (somme pondérée des entrées * activation) - x étant la variable de tests.

    Sachant que les entrées du neurone ont 784 valeurs.

    Ce qui donne le graphique suivant :


    Pour les petits traitements je remarque bien que LOOM est bien plus optimisé que les Thread conventionnels. Mais dans mon cas de figure pour un réseau de neurones ayant une couche cachée de 100 neurones (x=100), le gain de temps par rapport au temps de calcul sans thread n'y est pas...

    Enfin, le projet LOOM est en incubation et il faut utiliser une version spéciale d'openjdk pour le moment. Ce qui est limitant.

    En conclusion, merci dans tous les cas car j'aurais pas découvert les fibers qui seront bientôt dans les JDK apparemment d'après ce que j'ai lu sur Internet.

    Et pour ma quête d'optimisation je vais commencer à réfléchir comment traduire une propagation que je fais actuellement de couche en couche en un autre mode (lequel ?) ...

    Xavier

  4. #4
    Responsable Qt & Livres

    Sinon, tu ne peux pas accéder à des bibliothèques externes comme cuDNN (si tu as un GPU NVIDIA) ou Intel DNNL (qui doit aussi bien fonctionner sur des CPU AMD) ? Elles sont d'ores et déjà optimisées pour ces traitements, à un niveau que Java aura du mal à atteindre (pas de vectorisation de l'exécution du code dans les JVM, autant que j'en sache). Peut-être à travers des bibliothèques comme ND4J / DL4J (https://github.com/eclipse/deeplearning4j), selon le niveau d'abstraction que tu souhaites ?
    Vous souhaitez participer aux rubriques Qt ou PyQt (tutoriels, FAQ, traductions), HPC ? Contactez-moi par MP.

    Créer des applications graphiques en Python avec PyQt5
    Créer des applications avec Qt 5.

    Pas de question d'ordre technique par MP !

  5. #5
    Candidat au Club
    Salut,

    Bien que je souhaite comprendre par moi même et ne pas utiliser de framework dédié pour le moment, j'ai quand même essayé DL4J ...

    Au moins pour avoir une idée de temps de calcul, vu que c'est le premier point de ma question.

    j'obtiens le comparatif suivant :



    Remarque : mon programme ne tourne pas en thread et utilise 25% max du processeur. En revanche DL4J semble utiliser les 4 Proc et fait des pointes de 80% du processeur.

    Donc je n'ai pas à rougir ... et je pense que DL4J est confronté au même problème de thread évoqué plus haut. Mais gardant tout point tout honneur, la bibliothèque DL4J est largement meilleure que ce je j'ai fait ...

    Ainsi en utilisant les exemples fournis pour un MLP avec des images MNIST, l'apprentissage se fait par sous lot (batchsize) répété autant de fois que voulu (epoch) sous DL4J.
    Alors que moi, pour arriver à 95%, je prends le lot des 60000 images que j'injecte puis je recommence pour faire augmenter le % de réussite de reconnaissance. Pour avoir un score intéressant, il me faut plusieurs heures (8 à 12h).

    Alors qu’apparemment avec le principe de batchsize et d'epoch, l'apprentissage (et le taux de réussite) est plus rapide à obtenir [si j'ai bien compris]
    Exemple avec DL4J avec une couche cachée de 500 neuronnes , batchsize 60 (pour une base de données de 60 000images) et epoch 10 :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
     
     
    o.d.e.f.m.MLPMnistSingleLayerExample - Build model....
    o.n.l.f.Nd4jBackend - Loaded [CpuBackend] backend
    o.n.n.NativeOpsHolder - Number of threads used for linear algebra: 2
    o.n.l.c.n.CpuNDArrayFactory - *********************************** CPU Feature Check Warning ***********************************
    o.n.l.c.n.CpuNDArrayFactory - Warning: Initializing ND4J with Generic x86 binary on a CPU with AVX/AVX2 support
    o.n.l.c.n.CpuNDArrayFactory - Using ND4J with AVX/AVX2 will improve performance. See deeplearning4j.org/cpu for more details
    o.n.l.c.n.CpuNDArrayFactory - Or set environment variable ND4J_IGNORE_AVX=true to suppress this warning
    o.n.l.c.n.CpuNDArrayFactory - *************************************************************************************************
    o.n.n.Nd4jBlas - Number of threads used for OpenMP BLAS: 2
    o.n.l.a.o.e.DefaultOpExecutioner - Backend used: [CPU]; OS: [Windows 7]
    o.n.l.a.o.e.DefaultOpExecutioner - Cores: [4]; Memory: [1,8GB];
    o.n.l.a.o.e.DefaultOpExecutioner - Blas vendor: [OPENBLAS]
    o.d.n.m.MultiLayerNetwork - Starting MultiLayerNetwork with WorkspaceModes set to [training: ENABLED; inference: ENABLED], cacheMode set to [NONE]
    o.d.e.f.m.MLPMnistSingleLayerExample - Train model....
    o.d.o.l.ScoreIterationListener - Score at iteration 0 is 2.3897819242940592
    o.d.o.l.ScoreIterationListener - Score at iteration 1000 is 0.23358663968755608
    o.d.o.l.ScoreIterationListener - Score at iteration 2000 is 0.1297209259153225
    o.d.o.l.ScoreIterationListener - Score at iteration 3000 is 0.13428583632245206
    o.d.o.l.ScoreIterationListener - Score at iteration 4000 is 0.30239178251113813
    o.d.o.l.ScoreIterationListener - Score at iteration 5000 is 0.1694713128288924
    o.d.o.l.ScoreIterationListener - Score at iteration 6000 is 0.07841451496571797
    o.d.o.l.ScoreIterationListener - Score at iteration 7000 is 0.16543589731281402
    o.d.o.l.ScoreIterationListener - Score at iteration 8000 is 0.07686042362550718
    o.d.o.l.ScoreIterationListener - Score at iteration 9000 is 0.10974577510467272
     --> Temps :86612
    o.d.e.f.m.MLPMnistSingleLayerExample - Evaluate model....
    o.d.e.f.m.MLPMnistSingleLayerExample - 
     
    ========================Evaluation Metrics========================
     # of classes:    10
     Accuracy:        0,9747
     Precision:       0,9747
     Recall:          0,9744
     F1 Score:        0,9745
    Precision, recall & F1: macro-averaged (equally weighted avg. of 10 classes)
     
     
    =========================Confusion Matrix=========================
        0    1    2    3    4    5    6    7    8    9
    ---------------------------------------------------
      971    0    1    1    0    2    1    2    2    0 | 0 = 0
        0 1122    3    1    0    1    4    0    4    0 | 1 = 1
        6    2 1001    1    2    0    4    7    9    0 | 2 = 2
        0    0    1  991    0    2    0    6    5    5 | 3 = 3
        3    0    2    1  950    0    3    3    2   18 | 4 = 4
        5    1    0    9    2  857    8    1    7    2 | 5 = 5
        5    3    0    1    4    4  938    0    3    0 | 6 = 6
        0    5   11    4    0    1    0  988    1   18 | 7 = 7
        4    0    1    4    3    4    5    2  948    3 | 8 = 8
        4    5    1    4    8    2    1    3    0  981 | 9 = 9
     
    Confusion matrix format: Actual (rowClass) predicted as (columnClass) N times


    Temps apprentissage : 86 s (lol avec mes 8 heures)

    Je vais pousser mon code dans cette voie pour voir si j'obtiens sensiblement les mêmes résultats ...

    Merci dourouc05 dans tous les cas pour tes pistes ... cela m'a bien aidé à avancer d'un point de vue global.

    Xavier