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