verbesserungsvorschläge für endlich fertig gestellte klasse



  • so was haltet ihr davon?, abgesehen von der ausgabe 😞

    #ifndef MATRIX_KLASSE
    #define MATRIX_KLASSE
    
    #include <iostream>
    #include <cstdlib>
    
    template <class T>
    class matrix
    {
        private:
            T **matrix_zweidim;
    
            unsigned int zeilen_array;
            unsigned int spalten_array;
    
            unsigned int index_z;
            unsigned int index_s;
    
        public:
            matrix(unsigned int z, unsigned int s);  //zwei dimemsionen
            ~matrix();
    
            T *get_matrix();
    
            void ausgabe_array();
            void push_pos(T *feld, unsigned int zeilen_array, unsigned int spalten_array, int pos_z, int pos_s); //für zweidim matrix
    };
    
    //##############################################################################
    
    template <class T>
    inline matrix<T>::matrix(unsigned int zeilen, unsigned int spalten) 
    : index_z(0), index_s(0), zeilen_array(zeilen), spalten_array(spalten)
    {
        matrix_zweidim = new T*[zeilen];
        for(int i=0; i < zeilen; i++)
            matrix_zweidim[i] = new T[spalten];
    }
    
    template <class T>
    matrix<T>::~matrix()
    {
        for(int i=0; i < zeilen_array; i++)
            delete [] matrix_zweidim[i];
        delete [] matrix_zweidim;
    }
    
    template <class T>
    T *matrix<T>::get_matrix()
    {
        return matrix_zweidim;                      
    }
    
    template <class T>
    void matrix<T>::push_pos(T *feld, unsigned int feld_zeilen, unsigned int feld_spalten, int position_zeile, int position_spalte)
    {
        for(unsigned int i = position_zeile, j = 0; i < (feld_zeilen + position_zeile); i++, j++)
            for(unsigned int k = position_zeile, l = 0; k < (feld_spalten + position_spalte); k++, l++)
                matrix_zweidim[i][k] = feld[j][l];
    
        if( (feld_zeilen + position_zeile) > index_z)
            index_z = (feld_zeilen + position_zeile);
        if( (feld_spalten + position_spalte) > index_s)
            index_s = (feld_spalten + position_spalte);       
    }
    #endif
    
    #ifndef ARRAY_KLASSE
    #define ARRAY_KLASSE
    
    #include <iostream>
    #include <cstdlib>
    
    template <class T>
    class array
    {
        private:
            T *array_eindim;
    
            unsigned int zeilen_array;
            unsigned int index_z;  //damit verwechlungen ausgeschlossen sind
    
        public:
            array(unsigned int z); //eine dimension
            ~array();
    
            T *get_array();
    
            void ausgabe_array();
            //std::ostream& operator<<(std::ostream& out, matrix const& m) return m.printAt(out);
            void push_back(T *feld, unsigned int zeilen_array); //schiebt hinten rein(matrix)
            void push_pos(T *feld, unsigned int zeilen_array, int pos_z);  //für eindim array
    };
    
    //##############################################################################
    
    template <class T>
    inline array<T>::array(unsigned int zeilen) 
    : index_z(0), zeilen_array(zeilen)
    {
        array_eindim = new T[zeilen];
    }
    
    template <class T>
    array<T>::~array()
    {
        delete [] array_eindim;
    }
    
    template <class T>
    T *array<T>::get_array()
    {
        return array_eindim;                      
    }
    
    template <class T>
    void array<T>::ausgabe_array()
    {
        for(unsigned int i = 0; i < zeilen_array; i++)
            std::cout<< "Position " << i << ": " << array_eindim[i] << std::endl;
    }
    
    template <class T>
    void array<T>::push_back(T *feld, unsigned int feld_zeilen)
    {
        for(unsigned int i = 0; i < feld_zeilen; ++i && ++index_z)
            array_eindim[index_z] = feld[i];    
    }
    
    template <class T>
    void array<T>::push_pos(T *feld, unsigned int feld_zeilen, int position_zeile)
    {
        for(unsigned int i = position_zeile, j = 0; i < (feld_zeilen + position_zeile); i++, j++)
            array_eindim[i] = feld[j];
    
        if( (feld_zeilen + position_zeile) > index_z)
            index_z = (feld_zeilen + position_zeile);
    }
    #endif
    

    ich wollts noch machen das man beim erstellen der matrix/arrays die größe beim objekt NICHT angeben brauchsondern angefangen bei einer zeile automatisch erhöht. wie kann ich das machen? kann man da einfach immer wieder "new []" aufrufen? oder muss ich da ein neuen array tmp[] erstellen?



  • @Walli:

    Es ehrt Dich, dass Du BLAS kennst und mich darauf hinweist. Aber mein Vorschlag mit den verketteteten Listen hatte nicht den Anspruch damit zu konkurrieren.

    Und sicherlich ist die Lösung mit den doppelt verketteten Listen auch nicht die beste und schnellste.
    Was aber zum Beispiel den Aufwand oder den Schwierigkeitsgrad angeht ist es meiner Meinung ein guter Kompromiss zwischen Einfachheit und Effizienz für übliche Matrixoperationen. Das kommt aber auch wieder darauf an, ob ich gerne mit Zeigern oder Indices rechne. Was einfach ist und was nicht, hängt wahrscheinlich auch sehr vom eigenem Geschmack ab.

    Und viel höher ist der Speicherverbrauch auch nicht. So etwa das Dreifache...
    Und der Gewinn? Naja, wie schon gesagt, es wird einiges einfacher.
    Okay, bei einer (1000x1000)-Matrix mit 32 Bit Einträgen wären das statt 4 MB eben 12 MB, noch erträglich finde ich. Aber spätestens bei (1000x1000)-Matrizen sollte dann auch die Grenze dessen liegen, was man "mal eben" von Hand programmieren will.

    Viel Spass noch beim Weiterdiskutieren.

    Gruss

    turing



  • ich wollte meine arrays für ein neuronales netz benutzen, ich habe noch nie verkettete listen benutzt, wären die für solche arten der anwendung effizient?



  • dali schrieb:

    Und Code ohne Kommentare naja... Mir hat man immer Punkte bei den Übungen abgezogen 😉

    Ja, aber das liegt einfach daran, dass Tutoren notorisch nicht programmieren können. Die allermeisten Kommentare die ich in Codes lese (ob nun an der Uni, im Netz oder in sonstigen Projekten), sind vollkommen sinnfrei. Wenn man ordentlichen Code schreibt, reduziert sich der zu kommentierende Teil auf ein Minimum. In meinem Fall wäre das fast ausschließlich das Kommentieren von Funktionen und Klassen im Dokumentationsstil (JavaDoc, XML, ...).



  • stimmt, die meisten kommentare sind sinnlos und helfen nur denjenigen der das prog geschrieben hat.



  • @exigoner:
    Mit neuronalen Netzen kenne ich mich leider überhaupt nicht aus. Werden die nicht auch in der Mustererkennung eingesetzt? Schreib doch einfach auf, was Du mit der Matrix konkret machen willst.

    Zu Kommentaren:
    Ich finde Kommentare schon sehr wichtig, aber auch hier gilt eindeutig die Devise, dass weniger auch mehr sein kann.



  • keine sorge, ich kenne mich ddarin auch nicht aus, dann hab ich aber ne klasse für ein netz gefunden und wollt ein eigenes machen, nachdem ich das verstanden habe, was bei sowenig infos im netz recht schwierig ist. aber ich hab ja zeit.

    nachdem ich die klassen oben um einen standartkonstruktor bereichert habe, und noch ne set-member (für die größe) hinzugefügt habe, wollte ich damit die ein-und-ausgabe daten der neuronen speichern sollen.
    frag mich nicht wie, aber meine klasse matrix (2d array) soll die gewichte, die später justiert werden speichern.
    die arrays darunter speichern nur aus und eingabe daten.

    achtung die is von mir ein wenig modifiziert:

    class simpleNet
    {
    private:
    	matrix<float> ihWeights, hoWeights; //ursprünglich float** ihWeights
    	matrix<float> ihWDelta, hoWDelta;
    
    	array<float> in_inp, in_hid, in_outp;  //ursprünglich float* in_inp,...
    	array<float> out_inp, out_hid, out_outp;  
    	array<float> errH, errO, prefO, diffO;
    
    	int amount_inp, amount_hid, amount_outp;
    	float errTol, learnRate, absorp;
    
    public:
        anne(int neur_input, int neur_hidden, int neur_output);
        anne(int neur_input, int neur_hidden, int neur_output, float **ihW, float **hoW);
        ~anne();
    
        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);
    
        void setZero();
    };
    

    der programmmierer hat diese arrays zum speichern und die 2d-arrays anscheinend noch zum berechnen benutzt:

    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;
    }
    

    übrigens ich will wirklich nichts kopieren, ich wollte nur verstehen wie die netze funktionieren.
    nun weiß ich nicht ob sich listen, da besser machen, zumal ich noch nie welche gemacht oder benutzt habe. 😞



  • @turing
    jo die werden u.a. zur mustererkennung genutzt!
    meine matrix wird also oft verändert, es laufen wahrscheinlich sehr viele berechnungen ab...
    bringt das aber wirklich was listen zu nehmen?



  • exigoner schrieb:

    bringt das aber wirklich was listen zu nehmen?

    Das kommt drauf an, wie die Matrix besetzt ist und welche Operationen primär darauf ausgeführt werden sollen. Listen bringen z.B. nur Probleme, wenn du viele Indexzugriffe hast. Und die Erklärung, warum der Gauß und die Multiplikationen mit Listen einfacher sein sollen ist Turing auch noch schuldig geblieben.



  • hat, jemand noch einen tipp zur performanceverbesserung?



  • Zu den schuldig gebliebenen Begründungen:

    Matrixmultiplikation: C = A * B;

    Ich will das jetzt nicht explizit coden, das wird sowieso falsch aber so "on the fly" hab ich mir das wie folgt vorgestellt:
    Ich durchlaufe Matrix A immer wieder zeilenweise und B spaltenweise bilde dann über Zeilen/Spalten die Summen und gut.

    Dir schwebt irgendwie sowas vor, oder:

    for (int i=0; i < BREITE; i++)
    for (int j=0; j < HOEHE; j++)
    for (int k=0; k < BREITE; k++)
        c[i][j] += a[i][k] * b[k][j];
    

    Ok was Einfachheit angeht ist der 2. Versuch wohl kaum zu übertreffen. Da hast Du recht, Matrixmultiplikation geht mit einem Feld leichter zu implementieren.
    Wahrscheinlich wird der 2. Versuch aber ein wenig langsamer laufen, da sehr viele Adressen immer wieder berechnet werden müssen. Das ist bei meinem Vorschlag nicht nötig, da sich das nächste Paar, was multipliziert wird immer in der direkten Nachbarschaft befindet.

    Und was Gauss angeht, verhält es sich meiner Meinung nach ähnlich:
    Beim Feld müssen ständig Adressen berechnet werden, in der Liste nicht.

    Gruss

    turing



  • also würdest du eine liste bevorzugen. nun bin ich mir nicht sicher ob sich der aufwand nun lohnt. und ehrlich gesagt weiß ich im moment auch gar nicht wie ich soo eine liste machen muss.
    wie würde den grob eine liste für ein array aussehen, die das nötigst kann, also größe festlegen, etwas reinpacken, etwas löschen und indexzugriffe. 😕
    wenn die bitte nicht zu dreist ist 🤡



  • Turing schrieb:

    Beim Feld müssen ständig Adressen berechnet werden, in der Liste nicht.

    ok. aber zeigernachguckungen (inderektionen) kosten auch.
    natürlich VIEL weniger als plutimikationen. punkt für dich.

    anderster wird es, wenn wir feststellen, daß das programm felder mit bestimmten zur compilzeit bekannten größen braucht. wenn ich recht sehe, ist das der fall. selbst wenn man die größen manchmal ändern mag, wenn das programm ne stunde lang läuft, aber ein compilerlauf mit geänderter größe nur 10 sekunden und damit das prog 10% schneller wird, sind compilezeitkonstante größen eine überlegung wert.

    denen wir also mal kurz über

    template<typename T,int sizey,int sizex>
    class Matrix{
       T data[sizex*sizey];
       public:
       T& at(int y,int x){
          assert(0<=y && y<=sizey);
          assert(0<=x && x<=sizex);
          return data[y*sizex+x];
       }
    };
    

    nach.

    abgesehen von der brutalen vereinfachung des codes (und dafür bin ich immer zu haben :D) könnte das auch lecker schnell sein. schaue wir den flaschenhals an. das ist die plutimikation bei y*sizex+x. legen wir doch einfach mal fest, daß sizex eine zweierpotenz sein soll.

    template<typename T,int sizey,int sizex>
    class Matrix{
       static const int fastsizex=nextPowerOfTwo<sizex>::value;
       T data[fastsizex*sizey];
       public:
       T& at(int y,int x){
          assert(0<=y && y<=sizey);
          assert(0<=x && x<=sizex);
          return data[y*fastsizex+x];
       }
    };
    

    und voila, es fühlt sich eigentlich recht schnell an und maximal 50% speicherverschwendung.

    und dann würde ich mit dem trick mit dem proxy noch den op[][] anbieten und fest daran glauben, daß es so ausreichend in ordnung ist, um mich wieder dem hauptprogramm zuzuwenden.



  • IHR verwirrt mich 😡



  • @volkard
    Das ist tricky mit den 2er-Potenzen zu multiplizieren. Ich verteile die Daten einfach so, dass sie Multiplikation nix kostet, gute Idee.



  • @volkard
    wie is eigentlich sonn info-studium, ich überleg vielleicht nach meinem abi 2006 auch in die richtung zu gehen, vielleicht mach aber auch eher was in richtung biologie.
    wie macht sich das eigenlich auch so - geldtechnisch mit jobangeboten wenn man fertig ist?



  • exigoner schrieb:

    @volkard
    wie is eigentlich sonn info-studium, ich überleg vielleicht nach meinem abi 2006 auch in die richtung zu gehen, vielleicht mach aber auch eher was in richtung biologie.
    wie macht sich das eigenlich auch so - geldtechnisch mit jobangeboten wenn man fertig ist?

    MACH BIO!
    info kannst offensichtlich. wenn du fertig bist, biste nachgewiesener BIO und info kannste auch, zur not mit zusatzscheinen oder durch diplomarbeit mit info oder wasweisich nachweisbar.

    ich hab den fehler gemacht, info zu studieren. ich mache schon ein paar maschbauer einfach platt, weil ich noch weiß, was ein kniehebel ist, weil evonlventenverzahnung für mich nix mit mathe zu tun hat, sondern schlicht naheliegend ist usw.
    aber mich einstellen als maschbauer+info kann sich keiner wagen. it auch richtig. mein maschbaue-wissen ist kläglich. die ansätze sind gut. mit ein paar jahren training wäre ich sehr gut. mist.

    ich hätte was anderes studieren müssen, vielleicht mathe, physik, e-technik- maschbau, irgenwas, wozu ich wenig lernen muss. dann hätte ich jetzt zwei fächer mit heimspiel. so habe ich nur das, was mir eh zugeflogen ist und im studium auch erschreckend wenig gelernt.



  • volkard schrieb:

    exigoner schrieb:

    @volkard
    wie is eigentlich sonn info-studium, ich überleg vielleicht nach meinem abi 2006 auch in die richtung zu gehen, vielleicht mach aber auch eher was in richtung biologie.
    wie macht sich das eigenlich auch so - geldtechnisch mit jobangeboten wenn man fertig ist?

    MACH BIO!

    Es gäbe da ja auch noch Bioinformatik ... http://bioinformatik-berlin.de/

    Das Studium ist recht spannend, auch wenn ich noch nicht recht herausbekommen habe, was das mit Informatik zu tun hat. Die manchmal verwendete englische Bezeichnung "Computational biology" trifft es IMO besser aber das kommt wohl auch sehr auf die jeweilige Uni, an der man es studiert an.



  • Konrad Rudolph schrieb:

    Es gäbe da ja auch noch Bioinformatik ... http://bioinformatik-berlin.de/

    naja, das klingt für mich ehrlich nach halbwissen auf beiden bereichen.



  • volkard schrieb:

    Konrad Rudolph schrieb:

    Es gäbe da ja auch noch Bioinformatik ... http://bioinformatik-berlin.de/

    naja, das klingt für mich ehrlich nach halbwissen auf beiden bereichen.

    Hmm, das wäre dann für jedes "Hybrid"-Studium der Fall. Fakt ist aber, dass Bioinformatiker (zur Zeit noch) hoch im Kurs stehen. Das sieht man auch am Forschungstrend ... es vergeht z.B. kaum eine Ausgabe der Technology Review, in der nicht mindestens ein großer Artikel zu einem Thema der Bioinformatik erscheint.


Anmelden zum Antworten