2015-11-17 18 views
5

Czytałem sporo informacji o sieciach neuronowych i szkoliłem je z odwrotnąpropagacją, głównie this Coursera course, z dodatkowym czytaniem z here i here. Pomyślałem, że mam dość prostą znajomość podstawowego algorytmu, ale moja próba zbudowania przeszkolonej sieci neuronowej nie została opracowana i nie jestem pewna dlaczego.Problemy z wdrożeniem metody propagacji sieci neuronowej

Kod jest w C++ bez wektoryzacji jak na razie.

Chciałem zbudować proste 2 neurony wejściowe, 1 ukryty neuron, 1 neuron wyjściowy, sieć do modelowania funkcji AND. Aby zrozumieć, w jaki sposób koncepcje zadziałały, zanim przejdę do bardziej złożonego przykładu Mój kod propagacji do przodu zadziałał, gdy ręcznie zakodowałem w wartościach wag i błędów.

float NeuralNetwork::ForwardPropagte(const float *dataInput) 
{ 
     int number = 0; // Write the input data into the input layer 
     for (auto & node : m_Network[0]) 
     { 
      node->input = dataInput[number++]; 
     } 

     // For each layer in the network 
     for (auto & layer : m_Network) 
     { 
      // For each neuron in the layer 
      for (auto & neuron : layer) 
      { 
       float activation; 
       if (layerIndex != 0) 
       { 
        neuron->input += neuron->bias; 
        activation = Sigmoid(neuron->input); 
       } else { 
        activation = neuron->input; 
       } 

       for (auto & pair : neuron->outputNeuron) 
       { 
        pair.first->input += static_cast<float>(pair.second)*activation; 
       } 
      } 
     } 

     return Sigmoid(m_Network[m_Network.size()-1][0]->input); 
} 

Niektóre z tych zmiennych są dość słabo nazwie, ale w zasadzie, neuron-> outputNeuron jest wektorem parach. Pierwszy to wskaźnik do następnego neuronu, a drugi to wartość wagi. neuron-> input jest wartością "z" w równaniu sieci neuronowej, sumą wszystkich wartości * aktywacji + bais. Sigmoid jest podany przez:

float NeuralNetwork::Sigmoid(float value) const 
{ 
    return 1.0f/(1.0f + exp(-value)); 
} 

Te dwa wydają się działać zgodnie z przeznaczeniem. Po przejściu przez sieć wszystkie wartości "z" lub "neuron-> wejściowe" są resetowane do zera (lub po wstecznej propagacji).

Następnie trenuję sieć zgodnie z poniższym kodem psudo. Kod treningowy jest uruchamiany wiele razy.

for trainingExample=0 to m // m = number of training examples 
    perform forward propagation to calculate hyp(x) 
    calculate cost delta of last layer 
     delta = y - hyp(x) 
    use the delta of the output to calculate delta for all layers 
    move over the network adjusting the weights based on this value 
    reset network 

Rzeczywisty kod jest tutaj:

void NeuralNetwork::TrainNetwork(const std::vector<std::pair<std::pair<float,float>,float>> & trainingData) 
{ 
    for (int i = 0; i < 100; ++i) 
    { 
     for (auto & trainingSet : trainingData) 
     { 
      float x[2] = {trainingSet.first.first,trainingSet.first.second}; 
      float y  = trainingSet.second; 
      float estimatedY = ForwardPropagte(x); 

      m_Network[m_Network.size()-1][0]->error = estimatedY - y; 
      CalculateError(); 
      RunBackpropagation(); 
      ResetActivations(); 
     } 
    } 
} 

Dzięki funkcji wstecznej propagacji błędów podane przez:

void NeuralNetwork::RunBackpropagation() 
{ 
    for (int index = m_Network.size()-1; index >= 0; --index) 
    { 
     for(auto &node : m_Network[index]) 
     { 
      // Again where the "outputNeuron" is a list of the next layer of neurons and associated weights 
      for (auto &weight : node->outputNeuron) 
      { 
       weight.second += weight.first->error*Sigmoid(node->input); 
      } 
      node->bias = node->error; // I'm not sure how to adjust the bias, some of the formulas seemed to point to this. Is it correct? 
     } 
    } 
} 

a koszt obliczany przez:

void NeuralNetwork::CalculateError() 
{ 
    for (int index = m_Network.size()-2; index > 0; --index) 
    { 
     for(auto &node : m_Network[index]) 
     { 
      node->error = 0.0f; 

      float sigmoidPrime = Sigmoid(node->input)*(1 - Sigmoid(node->input)); 

      for (auto &weight : node->outputNeuron) 
      { 
       node->error += (weight.first->error*weight.second)*sigmoidPrime; 
      } 
     } 
    } 
} 

I losowy waga i uruchom go na danych s et:

x = {0.0f,0.0f} y =0.0f 
    x = {1.0f,0.0f} y =0.0f 
    x = {0.0f,1.0f} y =0.0f 
    x = {1.0f,1.0f} y =1.0f 

Oczywiście, że nie powinny być szkolenia i badania z tymi samymi danymi określonymi ale chciałem tylko uzyskać podstawowe algortithm wstecznej propagacji błędów i działa. Kiedy uruchomić ten kod widzę wagi/uprzedzenia są następujące:

Layer 0 
    Bias 0.111129 
    NeuronWeight 0.058659 
    Bias -0.037814 
    NeuronWeight -0.018420 
Layer 1 
    Bias 0.016230 
    NeuronWeight -0.104935 
Layer 2 
    Bias 0.080982 

szkolenia zestaw działa, a średni kwadratowy błąd delta [outputLayer] wygląda somthing jak:

Error: 0.156954 
Error: 0.152529 
Error: 0.213887 
Error: 0.305257 
Error: 0.359612 
Error: 0.373494 
Error: 0.374910 
Error: 0.374995 
Error: 0.375000 

... remains at this value for ever... 

a ostateczna ciężary wyglądać następująco: (oni zawsze kończy się na roughtly tej wartości)

Layer 0 
    Bias 0.000000 
    NeuronWeight 15.385233 
    Bias 0.000000 
    NeuronWeight 16.492933 
Layer 1 
    Bias 0.000000 
    NeuronWeight 293.518585 
Layer 2 
    Bias 0.000000 

Zgadzam się, że może to wydawać się dość okrężną drogą uczenia sieci neuronowych, a realizacja jest (u m oment) bardzo nieoptymalny. Ale czy ktoś może wykryć każdy punkt, w którym podaję błędne założenie, albo implementacja lub formuła są błędne?

EDIT

Dzięki do sprzężenia dla wartości polaryzacji, że zatrzymane ich stosowane do warstwy wejściowej i zatrzymał się przepuszczając przez warstwę wejściowe funkcji esicy. Dodatkowo moja funkcja Sigmoid prime była nieprawidłowa. Ale sieć nadal nie działa. Zaktualizowałem błąd i dane wyjściowe powyżej, co będzie teraz.

+2

dlaczego masz tak wiele błędów? Sieć 2-1-1 powinna mieć łącznie 5 parametrów: 2 wagi między wejściowymi neuronami a ukrytym; 1 waga między odchyleniem w warstwie wejściowej i ukrytym neuronem; 1 waga między ukrytą warstwą a wyjściowym neuronem; 1 waga między odchyleniem w ukrytej warstwie a neuronem wyjściowym. Łącznie 5 odważników. Nawet twój kod pokazuje ci - ty i ty bez tych 2 zbędnych uprzedzeń. – lejlot

+0

Dziękuję za pomoc z uprzedzeniami, zobacz moją odpowiedź na galloguille w celu uzyskania dalszych wyjaśnień. Naprawiłem to, ale nadal mam problemy z siecią neuronową, zawsze trenując wagi do wartości w11 (15,385233), w12 (16,492933), w21 (293,518585). Wszystkie uprzedzenia stają się zerowe. Więc oczywiście jest jeszcze inny problem z kodem. – Davors72

Odpowiedz

1

Rozwiązałem mój problem (powyżej początkowego błędu uprzedniego/podpisanego problemu pierwotnego powyżej). Zacząłem odejmowanie od, zamiast dodawać do ciężarów. W źródłach, na które patrzyłem mieli znak minus w kalkulacji wartości delta, którego nie posiadam, ale zachowałem ich format dodawania zanegowanej wartości do wag. Dodatkowo byłem zdziwiony, co zrobić z wagą i błędnie odczytałem jedno źródło, które mówiło, że przypisuje to do błędu. Widzę teraz, że intuicja traktuje to jako normalną wagę, ale mnożąc ją przez stałą polaryzacji wynoszącą 1 zamiast z. Po dodaniu tych zmian, iteracja przez zestaw treningowy ~ 1000 razy może modelować proste wyrażenia bitowe, takie jak OR i AND.

4

Jak powiedział lejilot, masz wiele uprzedzeń. Nie potrzebujesz odchylenia w ostatniej warstwie, jest to warstwa wyjściowa, a uprzedzenia muszą być połączone z jej wejściem, ale nie z jego wyjściem. Spójrz na poniższe zdjęcie:

Na tym obrazie widać, że istnieje tylko jedno obciążenie na warstwę, z wyjątkiem ostatniej, w której nie ma potrzeby uprzedzenia.

Here you can read Bardzo intuicyjne podejście do sieci neuronowych. Jest w języku Python, ale może pomóc lepiej zrozumieć niektóre koncepcje sieci neuronowych.

+0

Dziękuję wam i Lejlotowi za pomoc w uprzedzeniach, zapomniałem ich wykluczyć z obliczeń warstwy wejściowej. W moim przykładzie błędy "dołączone" do każdego z węzłów są wartością * wartości obciążenia, która jest stosowana do funkcji z poprzedniej warstwy. Jak zrozumiałem, wartość odchylenia jest stosowana do funkcji w celu "przesunięcia" krzywej [http://stackoverflow.com/questions/2480650/role-of-bias-in-neural-networks], a ja niewłaściwie stosowałem funkcja esicy dla nawet neuronów wejściowych. Stąd dodatkowe błędy. – Davors72

Powiązane problemy