2016-04-02 21 views
2

私はPythonのXOR問題を解決するために次のニューラルネットワークを実装しました。私のニューラルネットワークは、2ニューロンの入力層、2ニューロンの1隠れ層、および1ニューロンの出力層からなる。私は、出力層の活性化関数として隠れ層とリニア(同一性)機能の活性化関数としてシグモイド関数を使用しています:XORニューラルネットワークが0.5に収束

import numpy as np 

def sigmoid(z): 
    return 1/(1+np.exp(-z)) 

def s_prime(z): 
    return np.multiply(sigmoid(z), sigmoid(1.0-z)) 

def init_weights(layers, epsilon): 
    weights = [] 
    for i in range(len(layers)-1): 
     w = np.random.rand(layers[i+1], layers[i]+1) 
     w = w * 2*epsilon - epsilon 
     weights.append(np.mat(w)) 
    return weights 

def fit(X, Y, w, predict=False, x=None): 
    w_grad = ([np.mat(np.zeros(np.shape(w[i]))) 
       for i in range(len(w))]) 
    for i in range(len(X)): 
     x = x if predict else X[0] 
     y = Y[0,i] 
     # forward propagate 
     a = x 
     a_s = [] 
     for j in range(len(w)): 
      a = np.mat(np.append(1, a)).T 
      a_s.append(a) 
      z = w[j] * a 
      a = sigmoid(z) 
     if predict: return a 
     # backpropagate 
     delta = a - y.T 
     w_grad[-1] += delta * a_s[-1].T 
     for j in reversed(range(1, len(w))): 
      delta = np.multiply(w[j].T*delta, s_prime(a_s[j])) 
      w_grad[j-1] += (delta[1:] * a_s[j-1].T) 
    return [w_grad[i]/len(X) for i in range(len(w))] 

def predict(x): 
    return fit(X, Y, w, True, x) 

#### 

X = np.mat([[0,0], 
      [0,1], 
      [1,0], 
      [1,1]]) 
Y = np.mat([0,1,1,0]) 
layers = [2,2,1] 
epochs = 10000 
alpha = 0.5 
w = init_weights(layers, 1) 

for i in range(epochs): 
    w_grad = fit(X, Y, w) 
    print w_grad 
    for j in range(len(w)): 
     w[j] -= alpha * w_grad[j] 

for i in range(len(X)): 
    x = X[i] 
    guess = predict(x) 
    print x, ":", guess 

バックプロパゲーションがすべて正しいと思えます。念頭に置く唯一の問題はバイアスユニットの実装に問題があることです。いずれにしても、コードを実行するたびに、各入力のすべての述語が約0.5に収束します。私はコードを精査して、何が間違っているのか分からないようです。誰でも私の実装に間違っていることを指摘できますか?私はフィードバックを感謝します。

それが役立つかもしれない何らかの理由で、ここで私が得ていた出力のようなものだ場合:フォワードおよびバックプロパゲーションの実装では、多かれ少なかれ正確である

[[0 0]] : [[ 0.5]] 
[[0 1]] : [[ 0.49483673]] 
[[1 0]] : [[ 0.52006739]] 
[[1 1]] : [[ 0.51610963]] 
+0

は、Gは、シグモイド関数、= S状結腸を意味し、 's_prime()'に 'a_s [j]'を渡すので、 's_prime()'は 'return np.multiply(z、1)'でなければなりません。(sigmoid(z)、sigmoid(1.0-z)) 'の代わりに' 'np.multiply(0-z)'を使用します。 – Belter

答えて

1

が。しかし、あなたが間違っているところはかなりシンプルです。あなたが予想されていない場合(つまり、訓練を実施する)と言っている

x = x if predict else X[0] 

、それぞれの間に選択した入力例を:具体的には、第1の文をごforループ内 - 最初の小さな誤差はごfit関数の内部を見ることです確率的勾配降下の反復は、(すなわちX[0])であるの最初の例が常にでなければなりません。これは、最初の入力を使用してトレーニングするだけなので、すべての予測に対して0.5を得ている理由です。あなたは一例iである、それは正しい例を読み取るようにこれを変更する必要があります:

x = x if predict else X[i] 

を作成する際に必要な最後の変更は、あなたのs_prime機能です。シグモイド関数の導関数は、あなたがそこに持っているもの確かです:あなたが前方伝播を計算するとき

def s_prime(z): 
    return np.multiply(sigmoid(z), sigmoid(1.0-z)) 

、あなたはすでにa_sに各ニューロンの出力アクティベーションを計算しているので、あなたは、これらのニューロンで地元の導関数を計算するとき出力アクティベーションをs_primeに直接供給するので、これらのシグモイドを再度計算する必要はありません。

ので:私はこれらの2つの変更を作ったら

def s_prime(z): 
    return np.multiply(z, 1.0-z) 

、我々は今、この出力を得る:

[[0 0]] : [[ 0.00239857]] 
[[0 1]] : [[ 0.99816778]] 
[[1 0]] : [[ 0.99816596]] 
[[1 1]] : [[ 0.0021052]] 

あなたは、これは多かれ少なかれ、XORゲートの予想出力と一致することを確認することができます。私が推薦できる最後の1つは、10000回の反復が、あなたの現在のコード構造を考慮して計算上余りにも長すぎるということです。私は上記の修正により、より少ない反復で期待される出力に到達できることに気付きました。私は反復を1000に減らし、学習率alphaを0.75まで上げました。私たちは今、取得これら二つのものを変更する: `G '(z)は*(1-a)を=ので、実際にはシグモイド関数の導関数を計算についてのあなたのコードは、少し問題を抱えている

[[0 0]] : [[ 0.03029435]] 
[[0 1]] : [[ 0.95397528]] 
[[1 0]] : [[ 0.95371525]] 
[[1 1]] : [[ 0.04796917]] 
+1

シンプルだったし、私はそれを逃したと信じることはできません。ありがとうございます。 – Sam

+2

@Samあなたは大歓迎です。私はそこにいました...私は何時間もコードを見つめていて、何が間違っているのか分からないようです。私は私の友人を示し、彼はすぐに気付き、それはそれらの小さいしかし非常に重大な間違いの1つです!あなたが何が間違っているかを気付くために目の新鮮なセットを得るなら、それは助けます:)。 – rayryeng

関連する問題