2

こんにちは、numpy を使用して Python でニューラル ネットワークを実装するときに、勾配をチェックする計算に問題があります。私はmnistデータセットを使用して、ミニバッチ勾配降下法を使用しようとしています。

私は数学をチェックしましたが、紙の上では見栄えが良いので、ここで何が起こっているのかについてのヒントを教えてください:

編集: 1 つの答えは、実際にコスト関数が間違って計算されていることに気付きました。ただし、これは back_prop を使用して計算されるため、勾配の問題を説明していません。30 エポックおよび 100 バッチのminibatch gradient降下を使用して、隠れ層で 300 ユニットを使用して %7 エラー率を取得します。rmsprop( learning_rate= 0.001、rmsprop により小さい)。

各入力には 768 個の特徴があるため、100 個のサンプルに対してマトリックスがあります。Mnistには 10 のクラスがあります。

X = NoSamplesxFeatures = 100x768

Y = NoSamplesxClasses = 100x10

完全なトレーニングを行う場合、隠れ層サイズが 300 の 1 つの隠れ層ニューラル ネットワークを使用しています。私が持っている別の質問は、エラーを計算するためにソフトマックス出力関数を使用する必要があるかどうかです...私はそうは思いません。しかし、私はこれらすべての初心者であり、明白なことは私には奇妙に思えるかもしれません.

(注:コードが醜いことは知っていますが、これはプレッシャーの下で行われた最初のPython / Numpyコードです。ご容赦ください)

back_prof とアクティベーションは次のとおりです。

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

  #not calculated really - this the fake version to make it faster. 
  def sigmoid_prime(a):
     return  (a)*(1 - a)

  def _back_prop(self,W,X,labels,f=sigmoid,fprime=sigmoid_prime,lam=0.001):

    """
    Calculate the partial derivates of the cost function using backpropagation.
    """     
    #Weight for first layer and hidden layer
    Wl1,bl1,Wl2,bl2  = self._extract_weights(W)


    # get the forward prop value
    layers_outputs = self._forward_prop(W,X,f)

    #from a number make a binary vector, for mnist 1x10 with all 0 but the number.
    y = self.make_1_of_c_encoding(labels)
    num_samples = X.shape[0] # layers_outputs[-1].shape[0]

    # Dot product return  Numsamples (N) x Outputs (No CLasses)
    # Y is NxNo Clases
    # Layers output to


    big_delta = np.zeros(Wl2.size + bl2.size + Wl1.size + bl1.size)
    big_delta_wl1, big_delta_bl1, big_delta_wl2, big_delta_bl2 = self._extract_weights(big_delta)


    # calculate the gradient for each training sample in the batch and accumulate it

    for i,x in enumerate(X):

        # Error with respect  the output
        dE_dy =  layers_outputs[-1][i,:] -  y[i,:] 

        # bias hidden layer
        big_delta_bl2 +=   dE_dy


        # get the error for the hiddlen layer
        dE_dz_out  = dE_dy * fprime(layers_outputs[-1][i,:])

        #and for the input layer
        dE_dhl = dE_dy.dot(Wl2.T)

        #bias input layer
        big_delta_bl1 += dE_dhl

        small_delta_hl = dE_dhl*fprime(layers_outputs[-2][i,:])

        #here calculate the gradient for the weights in the hidden and first layer
        big_delta_wl2 += np.outer(layers_outputs[-2][i,:],dE_dz_out)
        big_delta_wl1 +=   np.outer(x,small_delta_hl)





    # divide by number of samples in the batch (should be done here)?
    big_delta_wl2 = np.true_divide(big_delta_wl2,num_samples) + lam*Wl2*2
    big_delta_bl2 = np.true_divide(big_delta_bl2,num_samples)
    big_delta_wl1 = np.true_divide(big_delta_wl1,num_samples) + lam*Wl1*2
    big_delta_bl1 = np.true_divide(big_delta_bl1,num_samples)

    # return 
    return np.concatenate([big_delta_wl1.ravel(),
                           big_delta_bl1,
                           big_delta_wl2.ravel(),
                           big_delta_bl2.reshape(big_delta_bl2.size)])

次に、feed_forward:

def _forward_prop(self,W,X,transfer_func=sigmoid):
    """
    Return the output of the net a Numsamples (N) x Outputs (No CLasses)
    # an array containing the size of the output of all of the laye of the neural net
    """

    # Hidden layer DxHLS
    weights_L1,bias_L1,weights_L2,bias_L2 = self._extract_weights(W)    

    # Output layer HLSxOUT

    # A_2 = N x HLS
    A_2 = transfer_func(np.dot(X,weights_L1) + bias_L1 )

    # A_3 = N x  Outputs
    A_3 = transfer_func(np.dot(A_2,weights_L2) + bias_L2)

    # output layer
    return [A_2,A_3]

そして、勾配チェックのコスト関数:

 def cost_function(self,W,X,labels,reg=0.001):
    """
    reg: regularization term
    No weight decay term - lets leave it for later
    """

    outputs = self._forward_prop(W,X,sigmoid)[-1] #take the last layer out
    sample_size = X.shape[0]

    y = self.make_1_of_c_encoding(labels)

    e1 = np.sum((outputs - y)**2, axis=1))*0.5

    #error = e1.sum(axis=1)
    error = e1.sum()/sample_size + 0.5*reg*(np.square(W)).sum()

    return error
4

1 に答える 1

4

勾配チェックを実行すると、どのような結果が得られますか? 多くの場合、勾配の出力と勾配チェックによって生成された出力を比較することで、実装エラーの性質を明らかにすることができます。

さらに、二乗誤差は通常、MNIST などの分類タスクには適していないため、単純なシグモイド トップレイヤーまたはソフトマックスのいずれかを使用することをお勧めします。シグモイドでは、使用したいクロスエントロピー関数は次のとおりです。

L(h,Y) = -Y*log(h) - (1-Y)*log(1-h)

ソフトマックスの場合

L(h,Y) = -sum(Y*log(h))

ここで、Y は 1x10 ベクトルとして指定されたターゲットであり、h は予測値ですが、任意のバッチ サイズに簡単に拡張できます。

どちらの場合も、最上位のデルタは単純に次のようになります。

delta = h - Y

最上層のグラデーションは次のようになります。

grad = dot(delta, A_in)

ここで、A_in は前の層から最上層への入力です。

私はあなたのバックプロップ ルーチンに頭を悩ませていますが、あなたのコードから、勾配のエラーは、計算とともに二乗誤差を使用するときにトップレベルの dE/dw_l2 を正しく計算していないことが原因であると思われます。誤った入力に対する fprime。

二乗誤差を使用する場合、最上層のデルタは次のようになります。

delta = (h - Y) * fprime(Z_l2)

ここで、Z_l2 は層 2 の伝達関数への入力です。同様に、下位層の fprime を計算するときは、伝達関数への入力を使用します (つまり、dot(X,weights_L1) + bias_L1)。

それが役立つことを願っています。

編集: 二乗誤差よりも交差エントロピー誤差を使用するための追加の正当化として、線形分類法に関する Geoffrey Hinton の講義を参照することをお勧めします: www.cs.toronto.edu/~hinton/csc2515/notes/lec3.ppt

EDIT2: RMSPROP を使用して、さまざまなパラメーターと 1 つの非表示レイヤーを使用して、MNIST データセットにニューラル ネットを実装して、ローカルでいくつかのテストを実行しました。結果は次のとおりです。

Test1
Epochs: 30
Hidden Size: 300 
Learn Rate: 0.001
Lambda: 0.001
Train Method: RMSPROP with decrements=0.5 and increments=1.3 
Train Error: 6.1%
Test Error: 6.9%

Test2
Epochs: 30
Hidden Size: 300 
Learn Rate: 0.001
Lambda: 0.000002
Train Method: RMSPROP with decrements=0.5 and increments=1.3 
Train Error: 4.5%
Test Error: 5.7%

ラムダパラメータを数桁減らすと、パフォーマンスが向上するはずです。

于 2013-05-26T07:29:50.113 に答える