Sieć neuronowa nie rozpoznaje cyfr

0

Hej,
napisałem sieć neuronowa, która ma rozpoznawać cyfry przedstawione za pomoca macierzy 6x5. Siec ma 30 wejsc, 17 ukrytej i 10 wyjsc. Uczenie przeprowadzam za pomoca algorytmu wstecznej propagacji błędu. Sieć przechodzi przez tyle iteracji ile jej zadam po czym sieć jest niby nauczona i gdy ją testuje zazwyczaj pokazuje, ze jest to cyfra ta na której przykładzie zakończyła sie nauka. Moje główne podejrzenia padają na miejsce w którym występuje ten algorytm, czyli gdy obliczam błąd dla warstwy ukrytej nie jestem pewien wzoru, nie wiem czy podanie tam sredniego bledu warstwy wyjsciowej jest poprawne ale w warstwie wyjsciowej jest 10 bledow, a w warstwie ukrytej 17 wiec dla 7 ostatnich neuronow warstwy ukrytej nie mialbym wartosci. Metod do obliczenia wyjsc sieci nie bede pokazywal bo to proste mnozenie macierzy, tak samo z obliczaniem wyjscia sigmoidalna funkcja unipolarna. Zauwazylem tez, ze dla niektorych wartosci, ktorych pokazanie na macierzy sie znacznie rozni jest identyczne wyjscie sieci.

Metoda obliczająca błąd warstwy wyjściowej (wzor; Blad = wyjscie calej sieci * (1 - wyjscie calej sieci) * (wartosc oczekiwana - wyjscie calej sieci)):

public static Matrix errorCal(Matrix expected, Matrix our){
        Matrix temp = new Matrix(expected.rows, expected.cols);
        for(int i=0;i<expected.cols;i++){
            for(int j=0;j<expected.rows;j++){
                temp.data[j][i]= our.data[j][i] * (1 - our.data[j][i]) * (expected.data[j][i] - our.data[j][i]);
            }
        }
        return temp;
    }

Metoda obliczajaca błąd warstwy ukrytej (wzor; Blad warstwy ukrytej = wyjscie warstwy wejsciowej * ( 1 - wyjscie warstwy ejsciowej) * (średni blad warstwy ukrytej * net warstawy wyjsciowej) ):

    public static Matrix backPropError(Matrix hiddenOut, Matrix outError, Matrix inputOut, double learning){
        Matrix temp = new Matrix(hiddenOut.rows, 1, true);

        double avgOutError = 0;
        for(int i =0; i <outError.toArray().size();i++)
            avgOutError += outError.toArray().get(i);

        avgOutError = avgOutError/outError.toArray().size();

        for(int i =0;i<temp.cols;i++){
            for(int j=0;j<temp.rows;j++) {
                temp.data[j][i] = (inputOut.data[j][i] * (1 - inputOut.data[j][i] )* (avgOutError * hiddenOut.data[j][i])) * learning;
            }
        }
        return temp;
    }

Metoda do aktualizacji wag (wzor; Nowe wagi = Stare wagi + (wspolczynik uczenia * blad * wartosc wejsciowa do warstwy ktora aktualizujemy) :

public static Matrix weightActualization(Matrix weights, Matrix error, double learningRate, Matrix hiddenLayerOut){
        Matrix temp = new Matrix(weights.rows, weights.cols);

        Matrix one = null;
        Matrix two = null;
        Matrix three = null;

        if(weights.toArray().size() == 51) {

            one = new Matrix(17, 1);
            two = new Matrix(17, 1);
            three = new Matrix(17, 1);
        }else if (weights.toArray().size() == 30){
            one = new Matrix(10, 1);
            two = new Matrix(10, 1);
            three = new Matrix(10, 1);
        }

        for(int i=0;i<one.cols;i++){
            for(int j=0;j<one.rows;j++){
                one.data[j][i]= weights.data[j][i] + (learningRate*error.data[j][i]* hiddenLayerOut.data[j][i]);
                temp.data[j][i] = one.data[j][i];
            }
        }

        for(int i=0;i<two.cols;i++){
            for(int j=0;j<two.rows;j++){
                two.data[j][i]= weights.data[j][i+1] + (learningRate*error.data[j][i]*hiddenLayerOut.data[j][i]);
                temp.data[j][i+1] = two.data[j][i];
            }
        }

        for(int i=0;i<three.cols;i++){
            for(int j=0;j<three.rows;j++){
                three.data[j][i]= weights.data[j][i+2] + (learningRate*error.data[j][i]*hiddenLayerOut.data[j][i]);
                temp.data[j][i+2] = three.data[j][i];
            }
        }

        return temp;
    }

Metoda uczenia laczaca to wszystko:

public void train(List<double []> inList, List<double []> expectedList,  int epos, double LEARNING_RATE) {

        Matrix expectedArray = null;
        Matrix in;

        for (int i = 0; i < epos; i++) {
            for(int j=0;j<inList.size();j++) {

                if(iteration == 0) { // Jesli przeszlismy wszystkie wektory losowo zmieniamy ich kolejnosc i zaczynamy wykorzysytwac powtornie

                    in = Matrix.fromArray(inList.get(j));
                    expectedArray = Matrix.fromArray(expectedList.get(j));
                }else{
                    int random = (int)(Math.random() * 29 + 1);
                    in = Matrix.fromArray(inList.get(random));
                    expectedArray = Matrix.fromArray(expectedList.get(random));
                }

                Matrix net = inputLayer.inputLayerOut(in);

                Matrix a = Matrix.sigomidChange(net); //Wyjscie pierwszej warstwy

                Matrix net2 = hiddenLayer.hiddenLayerOut(a);

                Matrix b = Matrix.sigomidChange(net2); // Wyjsciej warstwy ukrytej

                outputLayer.outLayerOut(b);

                Matrix c = Matrix.sigomidChange(outputLayer.getOutLayerOutMatrix()); // Wyjscie calej sieci

                outputLayer.setExpectedResponse(expectedArray);

                Matrix outError = outputLayer.calOutLayerErrorBetter(expectedArray, c); // Blad sieci

                outputLayer.weightActualization(outputLayer.getMatrix(), outError, LEARNING_RATE, b); // Aktualizacja wag warstwy wyjsciowej

                Matrix hiddenError = hiddenLayer.calOutLayerError(net2, outError, a, LEARNING_RATE); // Blad warstwy ukrytej

                hiddenLayer.weightActualization(hiddenLayer.getMatrix(), hiddenError, LEARNING_RATE, a); // Aktualizacja wag warstwy ukrytej

            }
            iteration++;
            }
        }

Metoda testowania:

 public int test (double [] inTest){
            Matrix net = inputLayer.inputLayerOut(Matrix.fromArray(inTest));

            Matrix a = Matrix.sigomidChange(net); //Wyjscie pierwszej warstwy

            Matrix net2 = hiddenLayer.hiddenLayerOut(a);

            Matrix b = Matrix.sigomidChange(net2); // Wyjsciej warstwy ukrytej

            Matrix c = Matrix.sigomidChange(outputLayer.outLayerOut(b)); // Wyjscie calej sieci
            System.out.println(c.toArray());

            double max = Collections.max(c.toArray());

            return c.toArray().indexOf(max);
        }
0

Twoje weightActualization() wygląda dziwnie - na sam start: gdzie wykorzystujesz macierz zwracaną przez tę metodę?

0

Twoje weightActualization() wygląda dziwnie - na sam start: gdzie wykorzystujesz macierz zwracaną przez tę metodę?

Wiem, ze dziwnie potem to poprawie na razie zrobilem zeby dzialalo. Macierz wracana przez weightActualization() odczytuje w klasie HiddenLayer i OutputLayer gdzie poprzednie wagi zamieniam na te zmienione.

https://github.com/MrNobod/NAI tutaj masz caly kod, bedzie wszystko lepiej widoczne

//Tresc klasy HiddenLayer, w OutputLayer wyglada to tak samo
private Matrix matrix;

    public HiddenLayer(int neuronCount) {
        this.matrix = new Matrix(neuronCount, 3);
    }

    public Matrix weightActualization(Matrix outWeight, Matrix error, double learningRate, Matrix inputLayerOut){
        this.matrix = Matrix.weightActualization(outWeight,error, learningRate, inputLayerOut);
        return this.matrix;
    }
0

na razie zrobilem zeby dzialalo

No chyba nie, bo twój problem wygląda wlaśnie tak, jakby aktualizacja wag w zasadzie "nadpisywała" je na takie, zeby błąd ostatniego zestawu testowego był minimalny.

1 użytkowników online, w tym zalogowanych: 0, gości: 1