7

私は、hereの例のように、Pythonでニューラルネットワークを作成しています。ニューラルネットワークが10,000回訓練された後に誤差の範囲内で正しい値を生成することができないことを前提として、逆伝播アルゴリズムは機能していないようです。具体的には、私はそれが次の例では、正弦関数を計算するために訓練しています:ニューラルネットワークバックプロパゲーションアルゴリズムがPythonで動作しません

import numpy as np 

class Neuralnet: 
    def __init__(self, neurons): 
     self.weights = [] 
     self.inputs = [] 
     self.outputs = [] 
     self.errors = [] 
     self.rate = .1 
     for layer in range(len(neurons)): 
      self.inputs.append(np.empty(neurons[layer])) 
      self.outputs.append(np.empty(neurons[layer])) 
      self.errors.append(np.empty(neurons[layer])) 
     for layer in range(len(neurons)-1): 
      self.weights.append(
       np.random.normal(
        scale=1/np.sqrt(neurons[layer]), 
        size=[neurons[layer], neurons[layer + 1]] 
        ) 
       ) 

    def feedforward(self, inputs): 
     self.inputs[0] = inputs 
     for layer in range(len(self.weights)): 
      self.outputs[layer] = np.tanh(self.inputs[layer]) 
      self.inputs[layer + 1] = np.dot(self.weights[layer].T, self.outputs[layer]) 
     self.outputs[-1] = np.tanh(self.inputs[-1]) 

    def backpropagate(self, targets): 
     gradient = 1 - self.outputs[-1] * self.outputs[-1] 
     self.errors[-1] = gradient * (self.outputs[-1] - targets) 
     for layer in reversed(range(len(self.errors) - 1)): 
      gradient = 1 - self.outputs[layer] * self.outputs[layer] 
      self.errors[layer] = gradient * np.dot(self.weights[layer], self.errors[layer + 1]) 
     for layer in range(len(self.weights)): 
      self.weights[layer] -= self.rate * np.outer(self.outputs[layer], self.errors[layer + 1]) 

def xor_example(): 
    net = Neuralnet([2, 2, 1]) 
    for step in range(100000): 
     net.feedforward([0, 0]) 
     net.backpropagate([-1]) 
     net.feedforward([0, 1]) 
     net.backpropagate([1]) 
     net.feedforward([1, 0]) 
     net.backpropagate([1]) 
     net.feedforward([1, 1]) 
     net.backpropagate([-1]) 
    net.feedforward([1, 1]) 
    print(net.outputs[-1]) 

def identity_example(): 
    net = Neuralnet([1, 3, 1]) 
    for step in range(100000): 
     x = np.random.normal() 
     net.feedforward([x]) 
     net.backpropagate([np.tanh(x)]) 
    net.feedforward([-2]) 
    print(net.outputs[-1]) 

def sine_example(): 
    net = Neuralnet([1, 6, 1]) 
    for step in range(100000): 
     x = np.random.normal() 
     net.feedforward([x]) 
     net.backpropagate([np.tanh(np.sin(x))]) 
    net.feedforward([3]) 
    print(net.outputs[-1]) 

sine_example() 

出力はtanh(sin(3)) = 0.140190616に近いことに失敗しました。私は間違ったインデックスやアラインメントを含む間違いを疑ったが、ナンシーはこれらのような間違いを提起していない。私が間違っていたところのヒント?

EDIT:バイアスニューロンを追加するのを忘れました。更新されたコードは次のとおりです。

import numpy as np 

class Neuralnet: 
    def __init__(self, neurons): 
     self.weights = [] 
     self.outputs = [] 
     self.inputs = [] 
     self.errors = [] 
     self.offsets = [] 
     self.rate = .01 
     for layer in range(len(neurons)-1): 
      self.weights.append(
       np.random.normal(
        scale=1/np.sqrt(neurons[layer]), 
        size=[neurons[layer], neurons[layer + 1]] 
        ) 
       ) 
      self.outputs.append(np.empty(neurons[layer])) 
      self.inputs.append(np.empty(neurons[layer])) 
      self.errors.append(np.empty(neurons[layer])) 
      self.offsets.append(np.random.normal(scale=1/np.sqrt(neurons[layer]), size=neurons[layer + 1])) 
     self.inputs.append(np.empty(neurons[-1])) 
     self.errors.append(np.empty(neurons[-1])) 

    def feedforward(self, inputs): 
     self.inputs[0] = inputs 
     for layer in range(len(self.weights)): 
      self.outputs[layer] = np.tanh(self.inputs[layer]) 
      self.inputs[layer + 1] = self.offsets[layer] + np.dot(self.weights[layer].T, self.outputs[layer]) 

    def backpropagate(self, targets): 
     self.errors[-1] = self.inputs[-1] - targets 
     for layer in reversed(range(len(self.errors) - 1)): 
      gradient = 1 - self.outputs[layer] * self.outputs[layer] 
      self.errors[layer] = gradient * np.dot(self.weights[layer], self.errors[layer + 1]) 
     for layer in range(len(self.weights)): 
      self.weights[layer] -= self.rate * np.outer(self.outputs[layer], self.errors[layer + 1]) 
      self.offsets[layer] -= self.rate * self.errors[layer + 1] 

def sine_example(): 
    net = Neuralnet([1, 5, 1]) 
    for step in range(10000): 
     x = np.random.uniform(-5, 5) 
     net.feedforward([x]) 
     net.backpropagate([np.sin(x)]) 
    net.feedforward([np.pi]) 
    print(net.inputs[-1]) 

def xor_example(): 
    net = Neuralnet([2, 2, 1]) 
    for step in range(10000): 
     net.feedforward([0, 0]) 
     net.backpropagate([-1]) 
     net.feedforward([0, 1]) 
     net.backpropagate([1]) 
     net.feedforward([1, 0]) 
     net.backpropagate([1]) 
     net.feedforward([1, 1]) 
     net.backpropagate([-1]) 
    net.feedforward([1, 1]) 
    print(net.outputs[-1]) 

def identity_example(): 
    net = Neuralnet([1, 3, 1]) 
    for step in range(10000): 
     x = np.random.normal() 
     net.feedforward([x]) 
     net.backpropagate([x]) 
    net.feedforward([-2]) 
    print(net.outputs[-1]) 

identity_example() 
+0

あなたが参照したドキュメントを読みましたが、sin(2)の対応するアルゴリズムを見つけることができませんでした。もっと詳しく説明してもらえますか? – White

+0

@ sin(2)は、あなたの質問であれば標準的な正弦関数です。 User1667423、一見するとエラーは表示されません。 2つの入力の論理関数(AND、OR、...)のような単純な関数を試しましたか?また、隠しレイヤーを1つだけ使用するか、使用しないでください。 –

+0

なぜtheano/lasagneやTensorFlowのような既存のフレームワークを使用しないのですか? –

答えて

7

NNを間違った方法でトレーニングすると思います。 10000回を超えるループを繰り返し、各サイクルで新しいサンプルをフィードします。この場合、NNは訓練されることはありません。

は(文は間違っている!更新を参照してください!)

は何をする必要がある、真のサンプルY = sin(X)の大規模な配列を生成し、ネットワークにONCEをそれを与えると反復処理することです費用関数を最小限に抑えるために、訓練は前方および後方に設定される。アルゴリズムをチェックするには、反復数に応じてコスト関数をプロットし、コストが下がることを確認する必要があります。

もう1つ重要な点は、重みの初期化です。あなたの数はかなり多く、ネットワークは収束するのに多くの時間がかかります(特に、低料金を使用する場合)。いくつかの小さな範囲で最初の重みを生成することは良い習慣です[-eps .. eps]一様に。 sigmoid()tanh()

は私のコードで私は2つの異なる活性化機能を実装しました。選択した関数に応じて入力を拡大する必要があります:それぞれ[0 .. 1][-1 .. 1]です。あなたはsigmoid()活性化は少しを与える見ることができるように

sigmoid activation

tanh activation

:ここ

は、コスト関数とsigmoid()tanh()活性化関数の結果の予測を示したいくつかの画像であり、 tanh()よりも優れています。ネットワーク[1, 6, 1]を使用した場合

はまた、私は4層[1, 6, 4, 1]との大きなネットワークに比べて、はるかに優れた予測を得ました。したがって、NNのサイズは常に重要な要素ではありません。

sigmoid for a bigger network

がここにいくつかのコメントと私のコードです:ここでは4層と述べたネットワークのための予測があります。あなたの表記を可能な限り使用しようとしました。

import numpy as np 
import math 
import matplotlib.pyplot as plt 

class Neuralnet: 
    def __init__(self, neurons, activation): 
     self.weights = [] 
     self.inputs = [] 
     self.outputs = [] 
     self.errors = [] 
     self.rate = 0.5 
     self.activation = activation #sigmoid or tanh 

     self.neurons = neurons 
     self.L = len(self.neurons)  #number of layers 

     eps = 0.12; # range for uniform distribution -eps..+eps    
     for layer in range(len(neurons)-1): 
      self.weights.append(np.random.uniform(-eps,eps,size=(neurons[layer+1], neurons[layer]+1)))    


    ###################################################################################################  
    def train(self, X, Y, iter_count): 

     m = X.shape[0]; 

     for layer in range(self.L): 
      self.inputs.append(np.empty([m, self.neurons[layer]]))   
      self.errors.append(np.empty([m, self.neurons[layer]])) 

      if (layer < self.L -1): 
       self.outputs.append(np.empty([m, self.neurons[layer]+1])) 
      else: 
       self.outputs.append(np.empty([m, self.neurons[layer]])) 

     #accumulate the cost function 
     J_history = np.zeros([iter_count, 1]) 


     for i in range(iter_count): 

      self.feedforward(X) 

      J = self.cost(Y, self.outputs[self.L-1]) 
      J_history[i, 0] = J 

      self.backpropagate(Y) 


     #plot the cost function to check the descent 
     plt.plot(J_history) 
     plt.show() 


    ###################################################################################################  
    def cost(self, Y, H):  
     J = np.sum(np.sum(np.power((Y - H), 2), axis=0))/(2*m) 
     return J 

    ################################################################################################### 
    def feedforward(self, X): 

     m = X.shape[0]; 

     self.outputs[0] = np.concatenate( (np.ones([m, 1]), X), axis=1) 

     for i in range(1, self.L): 
      self.inputs[i] = np.dot(self.outputs[i-1], self.weights[i-1].T ) 

      if (self.activation == 'sigmoid'): 
       output_temp = self.sigmoid(self.inputs[i]) 
      elif (self.activation == 'tanh'): 
       output_temp = np.tanh(self.inputs[i]) 


      if (i < self.L - 1): 
       self.outputs[i] = np.concatenate( (np.ones([m, 1]), output_temp), axis=1) 
      else: 
       self.outputs[i] = output_temp 

    ################################################################################################### 
    def backpropagate(self, Y): 

     self.errors[self.L-1] = self.outputs[self.L-1] - Y 

     for i in range(self.L - 2, 0, -1): 

      if (self.activation == 'sigmoid'): 
       self.errors[i] = np.dot( self.errors[i+1], self.weights[i][:, 1:] ) * self.sigmoid_prime(self.inputs[i]) 
      elif (self.activation == 'tanh'): 
       self.errors[i] = np.dot( self.errors[i+1], self.weights[i][:, 1:] ) * (1 - self.outputs[i][:, 1:]*self.outputs[i][:, 1:]) 

     for i in range(0, self.L-1): 
      grad = np.dot(self.errors[i+1].T, self.outputs[i])/m 
      self.weights[i] = self.weights[i] - self.rate*grad 

    ################################################################################################### 
    def sigmoid(self, z): 
     s = 1.0/(1.0 + np.exp(-z)) 
     return s 

    ################################################################################################### 
    def sigmoid_prime(self, z): 
     s = self.sigmoid(z)*(1 - self.sigmoid(z)) 
     return s  

    ################################################################################################### 
    def predict(self, X, weights): 

     m = X.shape[0]; 

     self.inputs = [] 
     self.outputs = [] 
     self.weights = weights 

     for layer in range(self.L): 
      self.inputs.append(np.empty([m, self.neurons[layer]]))   

      if (layer < self.L -1): 
       self.outputs.append(np.empty([m, self.neurons[layer]+1])) 
      else: 
       self.outputs.append(np.empty([m, self.neurons[layer]])) 

     self.feedforward(X) 

     return self.outputs[self.L-1] 


################################################################################################### 
#    MAIN PART 

activation1 = 'sigmoid'  # the input should be scaled into [ 0..1] 
activation2 = 'tanh'  # the input should be scaled into [-1..1] 

activation = activation1 

net = Neuralnet([1, 6, 1], activation) # structure of the NN and its activation function 


########################################################################################## 
#    TRAINING 

m = 1000 #size of the training set 
X = np.linspace(0, 4*math.pi, num = m).reshape(m, 1); # input training set 


Y = np.sin(X) # target 

kx = 0.1 # noise parameter 
noise = (2.0*np.random.uniform(0, kx, m) - kx).reshape(m, 1) 
Y = Y + noise # noisy target 

# scaling of the target depending on the activation function 
if (activation == 'sigmoid'): 
    Y_scaled = (Y/(1+kx) + 1)/2.0 
elif (activation == 'tanh'): 
    Y_scaled = Y/(1+kx) 


# number of the iteration for the training stage 
iter_count = 20000 
net.train(X, Y_scaled, iter_count) #training 

# gained weights 
trained_weights = net.weights 

########################################################################################## 
#     PREDICTION 

m_new = 40 #size of the prediction set 
X_new = np.linspace(0, 4*math.pi, num = m_new).reshape(m_new, 1); 

Y_new = net.predict(X_new, trained_weights) # prediction 

#rescaling of the result 
if (activation == 'sigmoid'): 
    Y_new = (2.0*Y_new - 1.0) * (1+kx) 
elif (activation == 'tanh'): 
    Y_new = Y_new * (1+kx) 

# visualization 
plt.plot(X, Y) 
plt.plot(X_new, Y_new, 'ro') 
plt.show() 

raw_input('press any key to exit') 

UPDATE

私はあなたのコード内で使用されるトレーニング法に関するステートメントを取り戻すしたいと思います。ネットワークは、反復ごとに1つのサンプルのみを使用して実際に訓練することができます。シグモイド TANHを(使用して(コスト関数および予測)

Sigmoid

オンライントレーニングを使用して

オンライントレーニングを:私は両方のシグモイドとTANH活性化機能を使用してオンライン・トレーニングで興味深い結果を得ましたコスト関数および予測)

Tanh

Sigmoidを活性化関数として選択すると、パフォーマンスが向上します。コスト関数は、オフライントレーニングの場合と同じようには見えませんが、少なくとも低下する傾向があります。私はあなたの実装では、コスト関数をプロット

、それは同様にかなりぎくしゃくになります:

enter image description here

は、シグモイドあるいはReLU機能を使用してコードを試してみるとよいでしょうおそれ。

ここに更新されたソースコードがあります。 onlineofflineトレーニングモードを切り替えるには、method変数を変更するだけです。

import numpy as np 
import math 
import matplotlib.pyplot as plt 

class Neuralnet: 
    def __init__(self, neurons, activation): 
     self.weights = [] 
     self.inputs = [] 
     self.outputs = [] 
     self.errors = [] 
     self.rate = 0.2 
     self.activation = activation #sigmoid or tanh 

     self.neurons = neurons 
     self.L = len(self.neurons)  #number of layers 

     eps = 0.12; #range for uniform distribution -eps..+eps    
     for layer in range(len(neurons)-1): 
      self.weights.append(np.random.uniform(-eps,eps,size=(neurons[layer+1], neurons[layer]+1)))    


    ###################################################################################################  
    def train(self, X, Y, iter_count): 

     m = X.shape[0]; 

     for layer in range(self.L): 
      self.inputs.append(np.empty([m, self.neurons[layer]]))   
      self.errors.append(np.empty([m, self.neurons[layer]])) 

      if (layer < self.L -1): 
       self.outputs.append(np.empty([m, self.neurons[layer]+1])) 
      else: 
       self.outputs.append(np.empty([m, self.neurons[layer]])) 

     #accumulate the cost function 
     J_history = np.zeros([iter_count, 1]) 


     for i in range(iter_count): 

      self.feedforward(X) 

      J = self.cost(Y, self.outputs[self.L-1]) 
      J_history[i, 0] = J 

      self.backpropagate(Y) 


     #plot the cost function to check the descent 
     #plt.plot(J_history) 
     #plt.show() 


    ###################################################################################################  
    def cost(self, Y, H):  
     J = np.sum(np.sum(np.power((Y - H), 2), axis=0))/(2*m) 
     return J 


    ################################################################################################### 
    def cost_online(self, min_x, max_x, iter_number): 
     h_arr = np.zeros([iter_number, 1]) 
     y_arr = np.zeros([iter_number, 1]) 

     for step in range(iter_number): 
      x = np.random.uniform(min_x, max_x, 1).reshape(1, 1) 

      self.feedforward(x) 
      h_arr[step, 0] = self.outputs[-1] 
      y_arr[step, 0] = np.sin(x) 



     J = np.sum(np.sum(np.power((y_arr - h_arr), 2), axis=0))/(2*iter_number) 
     return J 

    ################################################################################################### 
    def feedforward(self, X): 

     m = X.shape[0]; 

     self.outputs[0] = np.concatenate( (np.ones([m, 1]), X), axis=1) 

     for i in range(1, self.L): 
      self.inputs[i] = np.dot(self.outputs[i-1], self.weights[i-1].T ) 

      if (self.activation == 'sigmoid'): 
       output_temp = self.sigmoid(self.inputs[i]) 
      elif (self.activation == 'tanh'): 
       output_temp = np.tanh(self.inputs[i]) 


      if (i < self.L - 1): 
       self.outputs[i] = np.concatenate( (np.ones([m, 1]), output_temp), axis=1) 
      else: 
       self.outputs[i] = output_temp 

    ################################################################################################### 
    def backpropagate(self, Y): 

     self.errors[self.L-1] = self.outputs[self.L-1] - Y 

     for i in range(self.L - 2, 0, -1): 

      if (self.activation == 'sigmoid'): 
       self.errors[i] = np.dot( self.errors[i+1], self.weights[i][:, 1:] ) * self.sigmoid_prime(self.inputs[i]) 
      elif (self.activation == 'tanh'): 
       self.errors[i] = np.dot( self.errors[i+1], self.weights[i][:, 1:] ) * (1 - self.outputs[i][:, 1:]*self.outputs[i][:, 1:]) 

     for i in range(0, self.L-1): 
      grad = np.dot(self.errors[i+1].T, self.outputs[i])/m 
      self.weights[i] = self.weights[i] - self.rate*grad 


    ################################################################################################### 
    def sigmoid(self, z): 
     s = 1.0/(1.0 + np.exp(-z)) 
     return s 

    ################################################################################################### 
    def sigmoid_prime(self, z): 
     s = self.sigmoid(z)*(1 - self.sigmoid(z)) 
     return s  

    ################################################################################################### 
    def predict(self, X, weights): 

     m = X.shape[0]; 

     self.inputs = [] 
     self.outputs = [] 
     self.weights = weights 

     for layer in range(self.L): 
      self.inputs.append(np.empty([m, self.neurons[layer]]))   

      if (layer < self.L -1): 
       self.outputs.append(np.empty([m, self.neurons[layer]+1])) 
      else: 
       self.outputs.append(np.empty([m, self.neurons[layer]])) 

     self.feedforward(X) 

     return self.outputs[self.L-1] 


################################################################################################### 
#    MAIN PART 

activation1 = 'sigmoid'  #the input should be scaled into [0..1] 
activation2 = 'tanh'  #the input should be scaled into [-1..1] 

activation = activation1 

net = Neuralnet([1, 6, 1], activation) # structure of the NN and its activation function 


method1 = 'online' 
method2 = 'offline' 

method = method1 

kx = 0.1 #noise parameter 

################################################################################################### 
#    TRAINING 

if (method == 'offline'): 

    m = 1000 #size of the training set 
    X = np.linspace(0, 4*math.pi, num = m).reshape(m, 1); #input training set 


    Y = np.sin(X) #target 


    noise = (2.0*np.random.uniform(0, kx, m) - kx).reshape(m, 1) 
    Y = Y + noise #noisy target 

    #scaling of the target depending on the activation function 
    if (activation == 'sigmoid'): 
     Y_scaled = (Y/(1+kx) + 1)/2.0 
    elif (activation == 'tanh'): 
     Y_scaled = Y/(1+kx) 


    #number of the iteration for the training stage 
    iter_count = 20000 
    net.train(X, Y_scaled, iter_count) #training 

elif (method == 'online'): 

    sampling_count = 100000 # number of samplings during the training stage 


    m = 1 #batch size 

    iter_count = sampling_count/m 

    for layer in range(net.L): 
     net.inputs.append(np.empty([m, net.neurons[layer]]))   
     net.errors.append(np.empty([m, net.neurons[layer]])) 

     if (layer < net.L -1): 
      net.outputs.append(np.empty([m, net.neurons[layer]+1])) 
     else: 
      net.outputs.append(np.empty([m, net.neurons[layer]]))  

    J_history = [] 
    step_history = [] 

    for i in range(iter_count): 
     X = np.random.uniform(0, 4*math.pi, m).reshape(m, 1) 

     Y = np.sin(X) #target 
     noise = (2.0*np.random.uniform(0, kx, m) - kx).reshape(m, 1) 
     Y = Y + noise #noisy target 

     #scaling of the target depending on the activation function 
     if (activation == 'sigmoid'): 
      Y_scaled = (Y/(1+kx) + 1)/2.0 
     elif (activation == 'tanh'): 
      Y_scaled = Y/(1+kx) 

     net.feedforward(X) 
     net.backpropagate(Y_scaled) 


     if (np.remainder(i, 1000) == 0): 
      J = net.cost_online(0, 4*math.pi, 1000) 
      J_history.append(J) 
      step_history.append(i) 

    plt.plot(step_history, J_history) 
    plt.title('Batch size ' + str(m) + ', rate ' + str(net.rate) + ', samples ' + str(sampling_count)) 
    #plt.ylim([0, 0.1]) 

    plt.show() 

#gained weights 
trained_weights = net.weights 

########################################################################################## 
#     PREDICTION 

m_new = 40 #size of the prediction set 
X_new = np.linspace(0, 4*math.pi, num = m_new).reshape(m_new, 1); 

Y_new = net.predict(X_new, trained_weights) #prediction 

#rescaling of the result 
if (activation == 'sigmoid'): 
    Y_new = (2.0*Y_new - 1.0) * (1+kx) 
elif (activation == 'tanh'): 
    Y_new = Y_new * (1+kx) 

#visualization 

#fake sine curve to show the ideal signal 
if (method == 'online'): 
    X = np.linspace(0, 4*math.pi, num = 100) 
    Y = np.sin(X) 

plt.plot(X, Y) 

plt.plot(X_new, Y_new, 'ro') 
if (method == 'online'): 
    plt.title('Batch size ' + str(m) + ', rate ' + str(net.rate) + ', samples ' + str(sampling_count)) 
plt.ylim([-1.5, 1.5]) 
plt.show() 

raw_input('press any key to exit') 

今私はあなたの現在のコードにはいくつかの発言を持っている:あなたは、あなたの目標入力にTANHを使用する理由

わからない。:

あなたの正弦関数は次のようになります。 tanh(sin(x))が範囲[-0.76..0.76]の値を返すので、本当にsineのターゲットをターゲットとして使用する場合は、[-1..1]にスケーリングする必要があります。

次は、トレーニングセットの範囲です。サンプルを生成するにはx = np.random.normal()を使用します。ここでは、そのような入力の分布は以下のとおりです。

enter image description here

それはあなたがあなたのネットワークが3のサインを予測したいのですが、ネットワークは、ほとんどトレーニング段階でこの番号を見たことがないていた後。代わりにサンプル生成のために広い範囲で一様分布を使用します。

+0

固定トレーニングセットが各反復で新しいサンプルよりも優れている特定の理由はありますか(基本的にオンライン学習です)? –

+0

オンラインソース([here](http://neuralnetworksanddeeplearning.com/chap3.html#weight_initialization)と[ここ](http://andyljones.tumblr.com/post/110998971763/an-explanation-of-xavier)例えば、ある層の重みは、その層の入力ニューロンの数に反比例する分散から初期化されるべきであると言われている。 – user76284

+0

私は双曲線正接関数を使用する方が勾配降下でシグモイド関数を使うよりも良いと聞いています([こちら](http://stats.stackexchange.com/questions/101560/tanh-activation-function-vs-sigmoid参照) -activation-function))。 – user76284

関連する問題