1. #1
    Membre à l'essai
    Homme Profil pro
    Ingénieur généraliste
    Inscrit en
    septembre 2016
    Messages
    21
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur généraliste
    Secteur : Conseil

    Informations forums :
    Inscription : septembre 2016
    Messages : 21
    Points : 14
    Points
    14

    Par défaut Erreur d'mplémentation sur RDN simple

    Bonjour à tous,

    J'essaye depuis peu de monter un RDN simple, sans prétention, mais paramétrable afin de mieu comprendre le sujet et de développer par la même mes compétences en C. Si j'ai choisi ce langage, c'est parce-que je suis familier avec lui et que je ne suis pas fan des langages haut niveau et/ou interprétés. Mon but étant de comprendre, je fais le choix de ne pas utiliser de librairies "clik and play" qui existent sûrement un peu partout.

    J'ai donc procédé par étape : Neurone simple, couche, et réseau ; chacune étant représentée par une structure, une fonction d'initialisation et une fonction de calcul.

    Je fais fonctionner un neurone simple sans soucis, de même, j'arrive à initialiser une couche. Cependant, lors du calcul d'une couche, j'ai une belle erreur de segmentation.

    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
     
    void layer_compute(layer_t *lay, double *u_ent)
    {
    	for(int i = 0; i < lay->layer_nb_ker; i++)
    	{
    		kernel_compute(&(lay->layer_ker[i]), u_ent);
    		lay->layer_out[i]=lay->layer_ker[i].kor_out;
    	}	
     
    }
     
    double kernel_compute(kernel_t *kor, double *u_ent)
    {
    	kor->kor_int[0] = kor->kor_zint;
    	for(int i = 0; i < kor->kor_nb_int; i++)
    	{
    		kor->kor_int[i+1] = u_ent[i];
     
    		kor->kor_sum += (kor->kor_int[i+1] * kor->kor_win[i+1]);
    	}
    	kor->kor_sum += (kor->kor_int[0] * kor->kor_win[0]);
     
     
    	kor->kor_out = heaviside(kor->kor_sum);
     
    	return kor->kor_out;
     
    }
    J'ai supprimé le code "superflu", et, pour aider à la compréhension, les structures ci-dessous :

    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
     
    typedef struct layer layer_t;
    typedef struct kernel kernel_t;
     
    struct layer {
    	int layer_nb_int;		// size of layer input vector
    	int layer_nb_ker;		// size of kernel vector
    	short int layer_func;	// layer function
     
    	double *layer_int;		// layer input vector
    	double *layer_out;		// layer output vector
    	double *layer_win;		// layer input weights
     
    	kernel_t *layer_ker;	// kernel vector
    };
     
    struct kernel {
    	short int kor_func;
    	int kor_nb_int;		// size of kernel input vector
    	double kor_zint;	// the 0 input value (default = -1)
     
    	double *kor_int;	// kernel input vector
    	double *kor_win;	// kernel input weights vector
    	double kor_sum;		// main kernel function result (sum)
    	double kor_out;		// kernel final computing result
    };
    Le code me retourne donc bien une valeur pour le premier neurone, mais après, c'est "erreur de segmentation".

    Les initialisations sont réalisée avec des tableaux dynamiques, cependant, lorsque je by-pass le layer et que je fais le calcul sur un simple neurone (initialisation et calcul), tout se déroule bien...
    J'ai essayé de reprendre plusieurs fois mon code, mais je me retrouve toujours face à cette situation : dès que j'essaie de passer l'objet d'un objet, ça foire....

    Quelqu'un saurait m'indiquer mon erreur ? Merci d'avance !!

  2. #2
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    5 893
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2006
    Messages : 5 893
    Points : 16 268
    Points
    16 268
    Billets dans le blog
    1

    Par défaut

    Citation Envoyé par BioKore Voir le message
    Quelqu'un saurait m'indiquer mon erreur ?
    Bonjour

    Il faudrait qu'on voit comment ont été alloués tes tableaux parce que c'est certainement là que ça cafouille. Toutefois je suis dubitatif sur ce passage for (int i = 0; i < kor->kor_nb_int; i++) kor->kor_int[i+1] = u_ent[i]. C'est ce "+1" qui m'embête parce que si kor_nb_int est bien corrélé à kor_int alors tu dépasses ton tableau.
    Exemple (selon ma compréhension): kor_int est alloué à 5, donc ses indices vont de 0 à 4. De son côté kor_nb_int vaut 5 (puisque d'après ce que je comprends, le nb de int correspond à la taille allouée).
    Quand i va de 0 à 4 et que tu tapes dans kor_int[i+1] alors tu tapes dans des indices allant de 1 à 5 or l'indice "kor_int[5]" est interdit !!!

    PS: tu n'es pas obligé de donner un nom à ta structure quand 1) elle n'est pas référencée dans sa définition (comme dans les listes) et 2) tu lui donnes un nom de type. Ce qui est tout à fait le cas ici.
    Exemple

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    typedef struct {
    	short int kor_func;
    	int kor_nb_int;		// size of kernel input vector
    	double kor_zint;	// the 0 input value (default = -1)
     
    	double *kor_int;	// kernel input vector
    	double *kor_win;	// kernel input weights vector
    	double kor_sum;		// main kernel function result (sum)
    	double kor_out;		// kernel final computing result
    } kernel_t;
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

  3. #3
    Membre à l'essai
    Homme Profil pro
    Ingénieur généraliste
    Inscrit en
    septembre 2016
    Messages
    21
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur généraliste
    Secteur : Conseil

    Informations forums :
    Inscription : septembre 2016
    Messages : 21
    Points : 14
    Points
    14

    Par défaut

    Bonjour, et merci pour ce retour. Comme pour hier, c'et un problème d'initialisation en fait, effectivement. Je n'ai plus le soucis de débordement de mémoire, mais les poids de chaque neurone, initialisés via le layer se comportent bizarrement. Je pense que j'essaie de faire un truc très simple mais via un chemin très compliqué.... Bref.

    En ce qui concerne le kor_int[i+1], c'est normal. En fait, ce dernier est initialisé à taille_entrée +1 afin de pouvoir paramétrer l'entrée supplémentaire nécessaire (-1).
    Ainsi, si *u_ent = {1, 2, 4, 5, 8}, alors kor->kor_int = {-1, 1, 2, 4, 5, 8}. C'est normal et prévu. Cependant, j'ai décidé de simplifier encore donc cette partie est devenue :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
     
    kor->kor_sum = kor->kor_zint * kor->kor_win[0];
    	for(int i = 0; i < kor->kor_nb_int; i++)
    	{
    		kor->kor_sum += u_ent[i] * kor->kor_win[i+1];
    	}
    Ce qui fonctionne correctement.

    Maintenant, mon soucis lors de l'initialisation est le suivant :


    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
     
     
    void une_fonction ( layer_t *lay, double *tab)
    {
    	for(int i = 0; i < 5; i++)
    	{
    		autre_fonction(&(lay->kern[i]), tab);
    		printf("value : %f\n", lay->kern[i].var);	// ok, ici lay->kern[i].var = 0.8;
    	}
    }
     
    void autre_fonction (kernel_t *kor, double *tab)
    {
    	kor->var = 0.8;
    }
     
     
    layer_t *ulay = malloc(sizeof(layer_t));
    if(ulay == NULL)
    	exit(EXIT_FAILURE);
     
    une_fonction(ulay, unTab);
     
    printf("value : %f\n", ulay->kern[i].var);		// ici ça donne une valeur différente de 0.8
     
    // pourtant, 
     
    kernel_t *ukor = malloc(sizeof(kernel_t));
    if(ukor == NULL)
    	exit(EXIT_FAILURE);
     
    autre_fonction(ukor, unTab);
    printf("value : %f\n", ukor->var);		// ceci retourne bien 0.8

    Donc là, j'ai beau cherché, je ne vois pas d'où vient l'erreur. Le seul truc que je peut voir, c'est le fameux ulay->kern[i].var, mais ça me surprendrais car cela fonctionne bien dans la boucle, mais plus quand on sort de la fonction...

  4. #4
    Membre expert
    Inscrit en
    mars 2005
    Messages
    1 072
    Détails du profil
    Informations forums :
    Inscription : mars 2005
    Messages : 1 072
    Points : 3 145
    Points
    3 145

    Par défaut

    Quelle est la dernière définition du type layer_t ? Comment est déclaré le membre kern particulièrement ?

    Parce qu'allouer la mémoire pour la structure parente, c'est bien, mais si kern n'est pas un tableau de taille fixe, il faut l'allouer séparément..

  5. #5
    Membre à l'essai
    Homme Profil pro
    Ingénieur généraliste
    Inscrit en
    septembre 2016
    Messages
    21
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur généraliste
    Secteur : Conseil

    Informations forums :
    Inscription : septembre 2016
    Messages : 21
    Points : 14
    Points
    14

    Par défaut

    Eh, oui, c'est bien ce que je pensais.... En fait, je fais un "layer_t *lay = malloc(sizeof(layer_t))", mais en fait, dans la structure "layer_t", j'ai un "kernel_t *kor = malloc(sizeof(kernel_t) * nb_ker)", donc la taille de mon objet n'est alors pas suffisante...


    La solution serai-t elle de faire : "layer_t *lay = malloc(sizeof(layer_t) + sizeof(kernel_t)*nb_ker)" ?
    Je ne vois pas comment je pourrais l'allouer séparément sachant qu'il doit faire partie de layer_t

    Je vais essayer d'implémenter ça ce soir pour tester...


    Edit : Tous les tableaux présents dans mes structures sont dynamiques, je vais essayer de faire ça pour tous ces tableaux mais il doit exister une autre solution non ?

    Merci d'avance !

  6. #6
    Membre expert
    Inscrit en
    mars 2005
    Messages
    1 072
    Détails du profil
    Informations forums :
    Inscription : mars 2005
    Messages : 1 072
    Points : 3 145
    Points
    3 145

    Par défaut

    Citation Envoyé par BioKore Voir le message
    La solution serai-t elle de faire : "layer_t *lay = malloc(sizeof(layer_t) + sizeof(kernel_t)*nb_ker)" ?
    Ça c'est l'allocation conjointe d'une structure et d'un tableau déclaré comme un flexible array member, une particularité du C99 que je doute que tu emploies.

    Si, comme c'est le plus probable, tu as déclaré ton membre comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    typedef struct {
        // ...
     
        kernel_t *kern;
    } layer_t;
    ...alors kern est un simple pointeur et ce sur quoi il pointe est décorrélé de la zone mémoire qui héberge l'instance de ta structure. Si tu veux qu'il pointe sur une zone de mémoire valide, il faut lui en donner une et donc réaliser une allocation supplémentaire.


    Avant de te lancer dans un tel projet complexe, peut-être devrais-tu consolider les bases à travers des exercices plus simple de manipulation de zones mémoire et de références ?

  7. #7
    Membre à l'essai
    Homme Profil pro
    Ingénieur généraliste
    Inscrit en
    septembre 2016
    Messages
    21
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur généraliste
    Secteur : Conseil

    Informations forums :
    Inscription : septembre 2016
    Messages : 21
    Points : 14
    Points
    14

    Par défaut

    Merci pour ce retour ; c'est effectivement des termes (et très certainement des logiques associées) qui me sont inconnues... Moi qui pensais que ce n'était qu'une idée farfelue sortie de ma tête.

    Je vais suivre ton conseil et essayer de trouver des cours un peu plus poussés sur les pointeurs que ceux que j'ai parcouru jusqu'à maintenant...

    Cependant, pour en revenir au problème posé, en réalité, il faudrait que je déclare séparément un tableau (dynamique car c'est là le but de ma manœuvre), et que je fasse pointer le fameux "layer_t kor" vers la première adresse du tableau alloué ailleurs c'est bien ça ? Je pense que c'est effectivement faisable, même si ça me fait ajouter une fonction supplémentaire. C'est bien ça que tu entendais par "réaliser une allocation supplémentaire" ?

    On sort du coup un peu du contexte de ce post, mais, une autre solution à laquelle j'ai pensé est de passer sur du C++ ; j'en ai quelques notions aussi vagues que celles que j'ai en C, mais je me dis que dans un cas comme celui-ci, la POO peut peut-être simplifié la chose, d'une certaine manière (mais je me trompe peut-être). Et qu'en serait-il du basic niveau performances (mémoire / CPU) pour ce type de projet (a qualité d'algorithme et d'implémentation équivalente) ?


    Moi qui pensais être capable de réaliser un projet d'apparence "simple" (quand on dessine un réseau de 3 neurones sur 2 couches) en C, je suis servi. Mais je ne vais pas lâcher l'affaire pour autant ; c'est comme ça que je vais évoluer dans ce langage

    Merci pour votre aide et vos conseils !



    EDIT : Problème réglé ! En fait, l'erreur venait du seul bout de code non diffusé : un (pour simplifier) layer_t *p = calloc(x, sizeof(double)); Dans les faits c'était moins flagrant que présenté comme ça mais l'erreur était bien de ce type. Bon.... Bien que je sois content de moi, je doute en avoir fini avec mes soucis (reste la structure "réseau" à implémenter et le code à rendre plus lisible) ; mais j'ai tout de même la possibilité de tester mon fameux réseau à 3 neurones tant souhaité !!!

    Merci à vous tous pour vous être décarcassés sur un problème de lecture de ma part ! Promis, je redoublerais d'attention sur ce type d'erreurs à l'avenir.

  8. #8
    Membre expert
    Inscrit en
    mars 2005
    Messages
    1 072
    Détails du profil
    Informations forums :
    Inscription : mars 2005
    Messages : 1 072
    Points : 3 145
    Points
    3 145

    Par défaut

    Citation Envoyé par BioKore Voir le message
    Cependant, pour en revenir au problème posé, en réalité, il faudrait que je déclare séparément un tableau (dynamique car c'est là le but de ma manœuvre), et que je fasse pointer le fameux "layer_t kor" vers la première adresse du tableau alloué ailleurs c'est bien ça ? Je pense que c'est effectivement faisable, même si ça me fait ajouter une fonction supplémentaire. C'est bien ça que tu entendais par "réaliser une allocation supplémentaire" ?
    C'est ça, en effet. On peut dire qu'il faut généralement autant d'appels à malloc qu'il y a de pointeurs à initialiser. Cela en supposant bien évidemment que ces pointeurs « possèdent » leur zone mémoire (on parle d'ownership : notion également utilisée en C++, Rust..) et ne sont pas que des références « faibles », i.e. : pointent sur de la mémoire gérée par un autre module du programme.

    Tu peux regrouper ça au sein d'une fonction dédiée :

    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
    layer_t *layer_alloc(size_t kerncount, /* ... */) {
        layer_t *l = malloc(sizeof *l);
        if (l) {
            /* layer initialization... */
     
            l->kern = malloc(kerncount * sizeof *l->kern);
            if (l->kern) {
                for (size_t i = 0; i < kerncount; ++i) {
                    /* kernel initialization... */
                }
            }
            else {
                free(l);
                l = NULL;
            }
        }
     
        return l;
    }

    Citation Envoyé par BioKore Voir le message
    On sort du coup un peu du contexte de ce post, mais, une autre solution à laquelle j'ai pensé est de passer sur du C++ ; j'en ai quelques notions aussi vagues que celles que j'ai en C, mais je me dis que dans un cas comme celui-ci, la POO peut peut-être simplifié la chose, d'une certaine manière (mais je me trompe peut-être). Et qu'en serait-il du basic niveau performances (mémoire / CPU) pour ce type de projet (a qualité d'algorithme et d'implémentation équivalente) ?
    J'ai envie de te dire : peu importe le langage, ce n'est pas ce qui te limite. Ton expérience de programmeur, c'est cela qu'il faut nourrir.

    Pour d'autres raisons que le C, le C++ est un langage très complexe et incroyablement difficile à appréhender (on te racontera probablement le contraire sur le forum dédié..). Le C++, c'est un peu l'expérience ratée qui articule péniblement « k..kill m..meee » dans le labo du savant fou. Si tu t'y intéresses parce que tu penses que ce sera plus facile qu'en C, je ne te le conseille pas. Code plutôt ton truc en Python ou, si tu veux vraiment être hardcore, en Rust (et au moins tu seras à la page).

    Le Basic, je ne connais pas.

  9. #9
    Membre à l'essai
    Homme Profil pro
    Ingénieur généraliste
    Inscrit en
    septembre 2016
    Messages
    21
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur généraliste
    Secteur : Conseil

    Informations forums :
    Inscription : septembre 2016
    Messages : 21
    Points : 14
    Points
    14

    Par défaut

    Merci pour ce retour.

    Le code que tu propose ne ressemble pas tout à fait au mien (qui, j'en suis sure, contient encore pas mal d'inepties), mais j'imagine qu'il conduit au même résultat. Cette dernière me parait pas trop mal d'ailleurs, bien qu'un peu trapue à lire (quoi que .... quand je regarde ce que j'ai fait....).

    En suite, je suis d'accord avec toi, le C++ peut certainement être plus complexe que le C ; mais il a l'avantage de la POO qui offre certaines simplicités / sécurités que l'on ne retrouve pas en C, ce qui peut le rendre plus séduisant que le C pour les codeurs du dimanche (comme moi). Mais, j'ai entendu dire je ne sais plus trop où que le C++ avait tendance à être plus gourmand en ressources que le C (évidemment, ce constat ne s'applique sûrement que pour les programmeurs "experts" à la recherche de de quelques ridicules millièmes de secondes et bits de mémoire sur des fonctionnalités complexes).

    Bref, je me suis dis que, quitte à apprendre un langage "puissant", de bas niveau et bien portable, le C était un bon langage.

    En tout cas, merci encore ; mon projet étant loin d'être terminé, tu seras la bienvenu sur mes très probables prochains posts !

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

Discussions similaires

  1. erreur de syntaxe sur une requête très simple
    Par Anandamine dans le forum PHP & MySQL
    Réponses: 9
    Dernier message: 01/06/2012, 10h45
  2. [e4] Erreurs sur une simple appli RCP
    Par pingoui dans le forum Eclipse Platform
    Réponses: 4
    Dernier message: 26/07/2011, 23h48
  3. Erreur de compilation sur un interpreteur de commandes simples.
    Par Tibapbedoum dans le forum Autres éditeurs
    Réponses: 0
    Dernier message: 24/11/2008, 19h07
  4. Erreur sur un simple Select
    Par defluc dans le forum SQL
    Réponses: 4
    Dernier message: 25/03/2007, 21h10
  5. Erreur ORA-01036 sur un XMLGRAM
    Par sch dans le forum XMLRAD
    Réponses: 5
    Dernier message: 07/09/2004, 15h56

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