2013-08-01 6 views
5

私は、単一の出力単位(バイナリ分類)でMLPの簡単な実装を書いています。 (多層パーセプトロンの実装:重みが狂っていく

実際のダミーモデルを作成してトレーニング機能を実装しましたが、MLPは収束しませんでした。実際、出力ユニットのグラデーションは高いままですエポック以上、その重みが無限大に近づくように

私の実装:。

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) 

勾配とエポック以上の出力ユニットの重みの進化:

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] 

私は、隠れユニットの様々な数の異なるデータセットを試してみました。私は減算の代わりに加算で重みを更新しようとしました...何も役立たない...

誰かが間違っているかもしれないと教えてもらえますか? ありがとうございます。

+0

こんにちは、 'synthetic.txt'を添付してください。私はそれをデバッグし、うまくいけば必要な修正を見つけることができます。出力層に行くbias-termを追加する必要性他の重みを更新することとは全く異なるバイアスを更新するメカニズムを変更する。ありがとうございました – Curious

+3

こんにちは、実際に私はすでに問題を解決しました。あなたは正しいです、私は隠れた層のバイアスを逃しました。また、2乗和誤差関数のバックプロパゲーションを書き直しました。あなたの興味に感謝します。 –

答えて

2

私はバイナリ分類に2乗和誤差関数を使用するべきではないと思います。その代わりに、クロスエントロピー誤差関数を使用する必要があります。これは基本的に尤度関数です。このようにすれば、正解から予測が長くなるほど、エラーはより高価になります。 Christopher Bishopの "Pattern Recognition and Machine Learning"の "Network Training" 235ページのセクションを読んでください。これは、FFNNの教師あり学習の適切な概要を示します。

バイアスユニットは非常に重要なので、転送機能を可能にします。 xカーブに沿って移動する。ウエイトは転送機能の急峻さを変えます。曲線。バイアスとウェイトのこの違いに注意してください。なぜなら、両方がFFNNに存在する必要がある理由をよく理解するからです。

関連する問題