fragen zu "simplenet" klasse



  • also, ich habe diese klasse gefunden und ich verstehe ein paar sachen nicht so ganz. zuerst das wichtigste:
    ich habe mir bisher alle funktionen bis auf die train-fkt. angeschaut. in der run-fkt. verstehe ich ein paar sachen nicht:

    ...
        for(int i=0; i<amountH; i++)                //get input of hidden layer
            for(int j=0; j<=amountI; j++)
                    inH[i]+=ihWeights[j][i]*outI[j];
    ...
    

    der unterste teil zeigt ein problem dass in der funktion öfters aufkommt. ich verstehe nich warum der programmierer in der zweidimensionallen matrix

    ihWeights[j][i] statt ihWeights[i][j]
    

    verwendet.
    und dürften nicht die laut definition die zu mult. arrays unterschiedlich lang sein?!
    oder wie darf ich mir dass:

    ihWeights[j][i]*outI[j]
    

    vorstellen?

    dann ist noch

    ..
        for(int i=0; i<amountH; i++)                //get output of hidden layer (sigmoide function)
            outH[i]=1/(1+exp(-inH[i]));
    ...
    

    ebenfalls in der run-fkt. zu finden. also ich weiß nicht so recht was eine sigmoide fkt. ist, was womöglich bedeutet dass ich den sinn hinter der schleife nicht erkenne 😞

    und wenn ich mir die run-fkt. noch genauer angucke dann sehe ich warum der progger im konstruktor unbedingt das array vergrößern wollte:

    hoWeights=new float*[amountH+1];
    

    nämlich deshalb:

    outI[amountI]=1;
    

    nur finde ich das sehr sinnlos, das netz funktioniert ebenfalls ohne die '1' am schluss des arrays 😕

    ich hoffe man kann einem anfänger bei diesen sicherlich trivialen problemen helfen 🙄

    hier die klasse: also alles bis run ist recht einfach zu verstehen! ich glaub der destr. ist nicht ganz richtig, aber das ist hier auch nicht sinn und zweck des thread.
    konstruktor stellt wie gewohnt speicher bereit.
    dazwischen ist nichts für euch interessantes(einschließlich "set_zero()")...

    #ifndef _SIMPLENET_H 
    #define _SIMPLENET_H
    
    class simpleNet{
    private:
    	float **ihWeights, **hoWeights;
    	float **ihWDelta, **hoWDelta;
    	float *inI, *inH, *inO;
    	float *outI, *outH, *outO;
    	float *errH, *errO, *prefO, *diffO;
    	int amountI, amountH, amountO;
    	float errTol, learnRate, absorp;
    	void setZero();
    public:
        simpleNet(int dimI, int dimH, int dimO);
        simpleNet(int dimI, int dimH, int dimO, float **ihW, float **hoW);
        ~simpleNet();
        float *getOutput();
        float *getODiff();
        void setErrTolerance(float tol);
        void setLearnRate(float rate);
        void setAbsorp(float abs);
        float *run(float *input);
        bool train(float *input, float *pOutput);
    };
    
    #endif
    
    #include <stdlib.h>
    #include <time.h>
    #include <math.h>
    #include "simpleNet.h"
    
    simpleNet::simpleNet(int dimI, int dimH, int dimO){
        srand(time(NULL));
        amountI=dimI; amountH=dimH; amountO=dimO;   //save dimensions of the net
        ihWeights=new float*[amountI+1];            //create weight matrices
        for(int i=0; i<=amountI; i++)
            ihWeights[i]=new float[amountH];
        hoWeights=new float*[amountH+1];
        for(int i=0; i<=amountH; i++)
            hoWeights[i]=new float[amountO];
        ihWDelta=new float*[amountI+1];            //create weight difference matrices
        for(int i=0; i<=amountI; i++)
            ihWDelta[i]=new float[amountH];
        hoWDelta=new float*[amountH+1];
        for(int i=0; i<=amountH; i++)
            hoWDelta[i]=new float[amountO];
        for(int i=0; i<=amountI; i++)               //fill with rand values (-0.3...0.3)
            for(int j=0; j<amountH; j++)
                    ihWeights[i][j]=(float)rand()/RAND_MAX*6/10-0.3;
        for(int i=0; i<=amountH; i++)
            for(int j=0; j<amountO; j++)
                    hoWeights[i][j]=(float)rand()/RAND_MAX*6/10-0.3;
        prefO=new float[amountO];                   //allocate mem for other matrices
        inI=new float[amountI];
        inH=new float[amountH];
        inO=new float[amountO];
        outI=new float[amountI+1];
        outH=new float[amountH+1];
        outO=new float[amountO];
        errH=new float[amountH+1];
        errO=new float[amountO];
        diffO=new float[amountO];
        learnRate=0.25;                             //setting default learning rate
        errTol=0.1;                                 //setting default error tolerance
        absorp=0.7;                                 //setting default absorption rate
    }
    
    simpleNet::simpleNet(int dimI, int dimH, int dimO, float **ihW, float **hoW){
        simpleNet(dimI,dimH,dimO);
        for(int i=0; i<=amountI; i++)               //create weight matrices with user-defined values
            for(int j=0; j<=amountH; j++)
                    ihWeights[i][j]=ihW[i][j];
        for(int i=0; i<=amountH; i++)
            for(int j=0; j<=amountO; j++)
                    hoWeights[i][j]=hoW[i][j];   
    }    
    
    simpleNet::~simpleNet(){                        //free allocated mem
        delete ihWeights; delete hoWeights; delete prefO; delete inI;
        delete inH; delete inO; delete outI; delete outH; delete outO;
        delete errH; delete errO; delete diffO; delete ihWDelta; delete hoWDelta;
    }
    
    void simpleNet::setZero(){
        for(int i=0; i<amountI; i++){
            inI[i]=0;
            outI[i]=0;
        }
        for(int i=0; i<amountH; i++){
            inH[i]=0;
            outH[i]=0;
            errH[i]=0;
        }
        for(int i=0; i<amountO; i++){
            inO[i]=0;
            outO[i]=0;
            errO[i]=0;
        }
    }
    
    float *simpleNet::getOutput(){
        return outO;
    }    
    
    float *simpleNet::getODiff(){
        return diffO;
    }
    
    void simpleNet::setErrTolerance(float tol){
        errTol=tol;
    }
    
    void simpleNet::setLearnRate(float rate){
        learnRate=rate;
    }
    
    void simpleNet::setAbsorp(float abs){
        absorp=abs;
    }
    
    float *simpleNet::run(float *input){            //complete run through the net
        setZero();                                  //set needed matrices to zero
        for(int i=0; i<amountI; i++)                //save input-vector
            inI[i]=input[i];
        for(int i=0; i<amountI; i++)                //special case here: inI=outI
            outI[i]=inI[i];
        outI[amountI]=1;                            //shift neuron = 1                        
        for(int i=0; i<amountH; i++)                //get input of hidden layer
            for(int j=0; j<=amountI; j++)
                    inH[i]+=ihWeights[j][i]*outI[j];
        for(int i=0; i<amountH; i++)                //get output of hidden layer (sigmoide function)
            outH[i]=1/(1+exp(-inH[i]));
        outH[amountH]=1;                             //shift neuron = 1
        for(int i=0; i<amountO; i++)                //get input of output layer
            for(int j=0; j<=amountH; j++)
                    inO[i]+=hoWeights[j][i]*outH[j];
        for(int i=0; i<amountO; i++)                 //get output of output layer (sigmoide function)    
            outO[i]=1/(1+exp(-inO[i]));
        return outO;
    }    
    
    bool simpleNet::train(float *input, float *pOutput){
        bool converge=true;
        for(int i=0; i<=amountI; i++)               //set delta matrices to 0 (start value)
            for(int j=0; j<amountH; j++)
                    ihWDelta[i][j]=0;
        for(int i=0; i<=amountH; i++)
            for(int j=0; j<amountO; j++)
                    hoWDelta[i][j]=0;
        run(input);                                 //run forward
        for(int i=0; i<amountO; i++)                //save preferred output
            prefO[i]=pOutput[i];
        for(int i=0; i<amountO; i++){               //compute output difference vector
            diffO[i]=prefO[i]-outO[i];
            if(fabs(diffO[i])>errTol) converge=false;//difference within limit?
        }
        for(int i=0; i<amountO; i++)                //compute error vector of output layer
            errO[i]=diffO[i]*outO[i]*(1-outO[i]);
        for(int i=0; i<=amountH; i++){               //compute error vector of hidden layer
            for(int j=0; j<amountO; j++)
                    errH[i]+=errO[j]*hoWeights[i][j];
            errH[i]*=outH[i]*(1-outH[i]);
        }
        for(int i=0; i<=amountI; i++)                //update input-hidden weight matrix
            for(int j=0; j<amountH; j++){
                    ihWDelta[i][j]=learnRate*errH[j]*outI[i]+ihWDelta[i][j]*absorp;
                    ihWeights[i][j]=ihWeights[i][j]+ihWDelta[i][j];
            }    
        for(int i=0; i<=amountH; i++)                //update hidden-output weight matrix
            for(int j=0; j<amountO; j++){
                    hoWDelta[i][j]=learnRate*errO[j]*outH[i]+hoWDelta[i][j]*absorp;
                    hoWeights[i][j]=hoWeights[i][j]+hoWDelta[i][j];
            }
        return converge;
    }
    


  • Hi,
    leider gerade nicht genug Zeit den ganzen Code durchzusehen...

    Eine sigmoide Funktion kannst du dir hier anschauen (Seite 5)
    http://ki.cs.tu-berlin.de/lehre/mmk03/ausarbeitungen/boenke.pdf

    Die Formel dafür steht oben im Code:
    f(x) = 1/(1+exp(-inH[x]));

    Google mal nach: (multi-Lagen / mehrschichtiges) Perzeptron, damit du verstehst, was dein Programm tut ..

    outI[amountI]=1;
    

    Wird outI[amountI] auch irgendwo gelesen/benutzt ?



  • leider gerade nicht genug Zeit den ganzen Code durchzusehen...

    um gottes willen, dass hätt ich auch nicht verlangt 🙂

    Wird outI[amountI] auch irgendwo gelesen/benutzt ?

    das amount* steht für die dimensionen des netzen. werden im konstruktor festgelegt. ich versteh nur nicht welchen zweck dann die 1 am ende des arrays erfüllt, die in der runfkt. eingeschoben wird.



  • das dumme ist, dass ich ein paar sachen noch nicht kenne(schulisch)->irgendwie fang ich an meine mathelehrerin zu hassen. wie zum beispiel unendliche geometrische reihen, wie sie im pdf-link standen 😞

    könnte mir vielleicht jemand erklären, der sich vielleicht damit noch auskennt, was die run-fkt. macht? es sind ja eigentlich nur zwei math. funktionen, zum einen die sigmoide, die 2 mal verwendet wird und zum anderen, die mit der 2d-matrix, die ebenfalls 2 mal verwendet wird.



  • Run Fkt (die for-Schleifen):

    • kopiere Input zu Eingabeschicht
    • da diese nichts berechnet gilt dort: Ausgabe == EIngabe, Zusätzlicher Wert (outI[amountI]) ist der sog. Bias, mit dem die Schwelle verschoben werden kann: die "Empfindlichkeit", der Wert ab dem Neurone in der Schicht "aktiv" werden (verschiebt den Arbeitsbereich, s.u.))
    • berechne Input der nächsten Schicht als gewichtete Summe (für jede mögliche Verbindung Neuron j der Eingabeschicht auf Neuron i des Hidden Layer gibt es ein Gewicht ihWeights[j][i]) - Jedes Gewicht gibt an, wie stark Neuron j von Neuron i beeinflusst wird (Dösiges Beispiel: Ausgabe von Neuron i beschreibe, wie hell eine best. Glühbirne brennt, das Gewicht ihWeights[j][i] gibt dann an, ob diese Birne vom Eingabesensor von Neuron j gut zu sehen ist ..., die Summe gibt an, wieviel Licht insgesamt auf den Sensor trifft)
    • Jedes Neuron des HL berechnet seine Aktivierung durch die sigmoide Fkt. Die (nicht lineare) sigm. Fkt beschreibt, dass das Neuron in gewissen Bereichen stärker auf Veränderungen seines "Sensors" reagiert als in anderen - es hat einen Arbeitsbereich (z.B.: bei sehr hellem Licht reagiert der Sensor stark, bei noch viel hellerem nicht (viel) stärker)
    • bilde gewichtete Summe ähnlich wie zuvor
    • Berechne Aktivierung ähnlich wie zuvor

    In der Train Fkt geht es dann darum, die Gewichte so zu verändern, daß ein best. erwünscher Zusammenhang zwischen Eingabe und Ausgabe zustande kommt.



  • DANKE! das hilft mir ungemnein 🙂
    nur ein problem ist noch:
    wenn man die sigmoide funktion betrchtet:
    hat die zufällig den grenzwert für lim(x -> sonstewas) = 1?
    f(x) = 1/(1+exp(-inH[x]));
    und ich weiß mit dem exp(); nichts anzufangen, der gibt mir bei exp(2) eine 7,3... aus, d.h. das wenn man exp(2) umformt in 2^c (wies im buch steht mit so einem verkrüppelten x), c eine konst. sein müsste, deren wert mir unbekannt ist :(. ich glaub das gehört ins mathe-forum, aber du scheinst das zu wissen.



  • hat die zufällig den grenzwert für lim(x -> sonstewas) = 1?

    genau.

    exp(x) sollte e hoch x heissen, e: die natürliche Zahl 2.71828....


Anmelden zum Antworten