2013-08-01 8 views
5

Piszę prostą implementację MLP z pojedynczą jednostką wyjściową (klasyfikacja binarna). Potrzebuję go do celów dydaktycznych, więc nie mogę użyć istniejącej implementacji :(Implementacja wielowarstwowego perceptronu: wagi szaleją

Udało mi się stworzyć działający model manekina i zaimplementowałem funkcję treningu, ale MLP nie jest zbieżny. Rzeczywiście, gradient dla jednostki wyjściowej pozostaje wysoki nad epok, więc jego wagi podejść nieskończoność

Moja implementacja.

import numpy as np 
from sklearn.metrics import confusion_matrix 
from sklearn.metrics import classification_report 

X = np.loadtxt('synthetic.txt') 
t = X[:, 2].astype(np.int) 
X = X[:, 0:2] 

# Sigmoid activation function for output unit 
def logistic(x): 
    return 1/(1 + np.exp(-x)) 

# derivative of the tanh activation function for hidden units 
def tanh_deriv(x): 
    return 1 - np.tanh(x)*np.tanh(x) 

input_num = 2   # number of units in the input layer 
hidden_num = 2   # number of units in the hidden layer 

# initialize weights with random values: 
weights_hidden = np.array((2 * np.random.random((input_num + 1, hidden_num + 1)) - 1) * 0.25) 
weights_out = np.array((2 * np.random.random( hidden_num + 1) - 1) * 0.25) 


def predict(x): 
    global input_num 
    global hidden_num 
    global weights_hidden 
    global weights_out 

    x = np.append(x.astype(float), 1.0)  # input to the hidden layer: features + bias term 
    a = x.dot(weights_hidden)   # activations of the hidden layer 
    z = np.tanh(a)       # output of the hidden layer 
    q = logistic(z.dot(weights_out))  # input to the output (decision) layer 
    if q >= 0.5: 
     return 1 
    return 0 



def train(X, t, learning_rate=0.2, epochs=50): 
    global input_num 
    global hidden_num 
    global weights_hidden 
    global weights_out 

    weights_hidden = np.array((2 * np.random.random((input_num + 1, hidden_num + 1)) - 1) * 0.25) 
    weights_out = np.array((2 * np.random.random( hidden_num + 1) - 1) * 0.25) 

    for epoch in range(epochs): 
     gradient_out = 0.0      # gradients for output and hidden layers 
     gradient_hidden = [] 

     for i in range(X.shape[0]):    
     # forward propagation 
      x = np.array(X[i])      
      x = np.append(x.astype(float), 1.0) # input to the hidden layer: features + bias term 
      a = x.dot(weights_hidden)   # activations of the hidden layer 
      z = np.tanh(a)      # output of the hidden layer 
      q = z.dot(weights_out)    # activations to the output (decision) layer 
      y = logistic(q)      # output of the decision layer 

     # backpropagation 
      delta_hidden_s = []     # delta and gradient for a single training sample (hidden layer) 
      gradient_hidden_s = [] 

      delta_out_s = t[i] - y    # delta and gradient for a single training sample (output layer) 
      gradient_out_s = delta_out_s * z 

      for j in range(hidden_num + 1):     
       delta_hidden_s.append(tanh_deriv(a[j]) * (weights_out[j] * delta_out_s)) 
       gradient_hidden_s.append(delta_hidden_s[j] * x) 

      gradient_out = gradient_out + gradient_out_s    # accumulate gradients over training set 
      gradient_hidden = gradient_hidden + gradient_hidden_s 

    print "\n#", epoch, "Gradient out: ",gradient_out, 
     print "\n  Weights out: ", weights_out 

     # Now updating weights 
     weights_out = weights_out - learning_rate * gradient_out 

     for j in range(hidden_num + 1): 
      weights_hidden.T[j] = weights_hidden.T[j] - learning_rate * gradient_hidden[j] 



train(X, t, 0.2, 50) 

i ewolucji gradientu i wag do jednostki wyjściowej ponad epoki:

0 Gradient out: [ 11.07640724 -7.20309009 0.24776626] 
    Weights out: [-0.15397237 0.22232593 0.03162811] 

    1 Gradient out: [ 23.68791197 -19.6688382 -1.75324703] 
    Weights out: [-2.36925382 1.66294395 -0.01792515] 

    2 Gradient out: [ 79.08612305 -65.76066015 -7.70115262] 
    Weights out: [-7.10683621 5.59671159 0.33272426] 

    3 Gradient out: [ 99.59798656 -93.90973727 -21.45674943] 
    Weights out: [-22.92406082 18.74884362 1.87295478] 

...

49 Gradient out: [ 107.89975864 -105.8654327 -104.69591522] 
    Weights out: [-1003.67912726 976.87213404 922.38862049] 

Próbowałem różnych zestawów danych, różne liczby jednostek ukrytych. Próbowałem zaktualizować wagę dodając zamiast odejmowania ... Nic nie pomaga ...

Czy ktoś może mi powiedzieć, co może być nie tak? Z góry dziękuję

+0

Witam, czy możesz dołączyć "syntetyczny.txt", będę go debugować i mam nadzieję wykryć wymagane poprawki, znalazłem już brakujące części, takie jak potrzeba dodania bias-termu, który przechodzi do warstwy wyjściowej, jak również zmiana mechanizmu aktualizacji stronniczości, która jest zupełnie inna niż aktualizacja innych wag. Dzięki – Curious

+3

Witam, właściwie już rozwiązałem problem. Masz rację, przegapiłem błąd w ukrytej warstwie. Ponadto przepisałem wsteczną propagację na sumę funkcji błędu kwadratów. Dzięki za zainteresowanie. –

Odpowiedz

2

Nie wierzę, że powinieneś użyć funkcji sumy błędów kwadratów dla klasyfikacji binarnej. Zamiast tego powinieneś użyć funkcji błędu entropii krzyżowej, która jest w zasadzie funkcją prawdopodobieństwa. W ten sposób błąd stanie się znacznie droższy, im dłużej Twoje prognozy będą wynikały z prawidłowej odpowiedzi. Proszę przeczytać sekcję "Szkolenie sieciowe" s. 235 w "Rozpoznawaniu wzorów i uczeniu maszynowym" Christophera Bishopa, co da ci odpowiedni przegląd, jak wykonywać nadzorowane uczenie na FFNN.

Jednostki odchylania są niezwykle ważne, dzięki czemu umożliwiają przesyłanie funkcji. przesuwać się wzdłuż krzywej x. Wagi zmieniają nachylenie funkcji przenoszenia. krzywa. Zwróć uwagę na różnicę między odchyleniami i wagami, ponieważ pozwoli to dobrze zrozumieć, dlaczego obie muszą być obecne w FFNN.