IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
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

C++ Discussion :

Problème en régression linéaire


Sujet :

C++

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Mathématicien
    Inscrit en
    Juillet 2020
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Mathématicien

    Informations forums :
    Inscription : Juillet 2020
    Messages : 3
    Points : 7
    Points
    7
    Par défaut Problème en régression linéaire
    Bonjour !
    J'ai commencé à m'interesser au machine learning il y a quelques semaines avant de me mettre à en coder. Cependant, j'ai un petit problème : lorsque je donne des tailles de dataset trop grandes ou bien un trop gros nombre de répétitions lors d'un entrainement (en appelant la fonction gradient) le compilateur me renvoie la valeur "nan". J'ai cherché dans tous les recoins de mon code, recodé celui-ci en python mais en vain..
    Je fais donc appelle à vous pour m'aider à trouver une solution à mon problème.

    Voici le code :
    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
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
     
    #include <iostream>
    #include <vector>
    #include <stdlib.h>
     
    //dataset
    std::vector<double> inputs(100);
    std::vector<double> outputs(100);
     
     
     
    double a = 0;
    double b = 0;
    double alpha = 0.01;
     
    //fonction feedForward
    double feedForward(double x)
    {
        return a*x+b;
    }
     
    //Fonction coût
    double error(std::vector<double> _inputs, std::vector<double> _outputs)
    {
        double sum;
        double m = _inputs.size();
        for(size_t i = 0; i < m; i++)
        {
            sum += (feedForward(_inputs[i])-_outputs[i])*(feedForward(_inputs[i])-_outputs[i]);
        }
     
        return (1/(2*m))*sum;
    }
     
    //dérivée partielle de l'erreur par rapport à a
    double dja(std::vector<double> _inputs, std::vector<double> _outputs)
    {
        double sum;
        double m = _inputs.size();
        for(size_t i = 0; i < m; i++)
        {
            sum += inputs[i]*(a*inputs[i]+b-outputs[i]);
        }
        return (1/m)*sum;
    }
     
    //dérivée partielle de l'erreur par rapport à b
    double djb(std::vector<double> _inputs, std::vector<double> _outputs)
    {
        double sum;
        double m = _inputs.size();
        for(size_t i = 0; i < m; i++)
        {
            sum += (a*inputs[i]+b-outputs[i]);
        }
        return (1/m)*sum;
    }
     
    //algorithme de descente de gradient
    void gradient(std::vector<double> _inputs, std::vector<double> _outputs)
    {
        a = a - alpha*dja(_inputs, _outputs);
        b = b - alpha*djb(_inputs, _outputs);
    }
     
    int main()
    {
    	srand(time(0));
        //valeur aléatoire pour a et b
        a = rand()/(0.01*RAND_MAX);
    	b = rand()/(0.01*RAND_MAX);
     
        //remplissage du tableau
    	for(size_t i = 0; i < inputs.size(); i++)
    	{
    		inputs[i] = i;
    		outputs[i] = 3754.54*i+854;
    	}
     
        //affichage des résultats
        //appel de la fonction gradient
        for(size_t i = 0; i < 10000; i++)
        {
    		gradient(inputs, outputs);
            std::cout << "error : " << error(inputs, outputs) << std::endl;
    	    std::cout << "a : " <<  a << std::endl;
    	    std::cout << "b : " << b << std::endl;
            std::cout << std::endl;
        }
    }
    Voici la réponse du compilateur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
     
    error : -nan
    a : -nan
    b : -nan
    N'hésitez pas nom plus à me donner des astuces pour améliorer mon code !

  2. #2
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Salut,

    De manière générale, il faut savoir que la valeur nan représente une valeur qui "is not a number". Pour essayer de faire simple, nous pourrions dire que, sous la forme utilisée par l'application pour représenter ses nombres, la donnée utilisée ne permet pas de représenter un nombre.

    Pour éviter de te faire tout un cours sur un sujet que je ne maitrise pas, je te conseille de lire la page wikipedia relative à la norme IEEE 754, qui est la norme suivie par les types float, double et long double pour leur représentation des données

    Peut-être le fait de passer à l'utilisation de long double pourrait t'aider à retarder quelque peu l'apparition du problème, car il permettent la représentation de valeurs contenues dans un intervalle plus intéressant, mais ca ne te ferait sans doute au final que reculer pour mieux sauter.

    En outre, il faut bien se dire qu'il n'y a pas de miracle, et que, tout comme tu serais incapable de donner une valeur précise et correcte à 1/3 il y a des valeurs à virgule flottante qui traineront toujours "une certaine imprécision", quel que soit le type que l'on essaye d'utiliser pour les représenter

    Au delà d'un certain point, il faut accepter l'idée que, sans recourir à des bibliothèques spécifiquement conçues pour répondre à un problème donné, il devient plus ou moins impossible de travailler "correctement". Dans le cas présent, je te conseillerais volontiers de te tourner vers la bibliothèque mpfr, bien que je reconnaisse ne l'avoir jamais manipulée, ni de près, ni de loin :$

    Ceci étant dit, je vais quand même me permettre quelques remarques concernant ton code:
    1. L'utilisation de variables globales est une très très mauvaise idée.
    2. Au lieu d'utiliser srand et rand, qui posent de sérieux problèmes (entre autre du fait des limites de valeurs qu'elles imposent), je te conseillerais de t'intéresser aux fonctionnalités fournies (depuis C++11, ce qui fait quand même déjà 9 ans!!!) par le fichier d'en-tête <random>, dont les générateurs de nombres aléatoire est les uniform_XXX_distribution
    3. Les noms de fonction dja et djb sont, je n'en doute pas, parfaitement clairs dans ton esprit aujourd'hui. Il n'en sera sans doute pas de même quand tu devras relire ton code d'ici trois mois, six mois ou un an :$. Alors, penses à ceux qui doivent lire ton code alors qui n'étaient pas à coté de toi lorsque tu l'a écrit, et qui n'ont aucune idée de ce que tu voulais faire! essaye de choisir un nom qui désigne exactement l'usage que tu compte faire de tes fonctions (ainsi que de tes types de donnée et de tes données). Cela facilitera la vie de tout le monde
    4. Pour les fonctions, justement: tout ce qui est "plus gros qu'un type primitif"(comme le contenu d'une classe std::vector) mérite amplement d'être passé sous forme de référence à la fonction, ne serait-ce que pour éviter les copies inutiles. Si la fonction n'a pas pour objectif de modifier l'élément qu'elle reçoit en paramètre (sous forme de référence), il est préférable (et de très loin !) de passer ce paramètre sous forme de référence constante
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Mathématicien
    Inscrit en
    Juillet 2020
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Mathématicien

    Informations forums :
    Inscription : Juillet 2020
    Messages : 3
    Points : 7
    Points
    7
    Par défaut
    Merci beaucoup pour cette réponse très complète et compréhensible !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Régression linéaire, loi F, t, normale et Khi-2
    Par philben dans le forum Contribuez
    Réponses: 3
    Dernier message: 20/08/2020, 14h22
  2. Module qui permet de faire des régression linéaire ?
    Par Anti-T dans le forum Calcul scientifique
    Réponses: 3
    Dernier message: 04/09/2009, 13h28
  3. problème de régression linéaire
    Par piroman14 dans le forum Général Python
    Réponses: 5
    Dernier message: 17/04/2009, 13h07
  4. Réponses: 2
    Dernier message: 22/12/2006, 20h24
  5. [NaN] Calcul d'une régression linéaire
    Par GLDavid dans le forum Langage
    Réponses: 1
    Dernier message: 24/10/2006, 12h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo