2016-11-13 20 views
3

MNISTの単純な3層ニューラルネットワークでbackpropagationを理解しようとしています。numpy:softmax関数の導関数を計算する

weightsbiasという入力層があります。ラベルはMNISTなので10クラスベクトルです。

第2層はlinear tranformです。第3層は、出力を確率として得るためにsoftmax activationです。

Backpropagationは、各ステップで微分を計算し、これを勾配と呼びます。

以前のレイヤーでは、globalまたはpreviousのグラディエントがlocal gradientに追加されます。私は、誘導体はに関連して説明されるトラブルソフトマックスの説明を通過し、その誘導体、さらにはソフトマックス自体

def softmax(x): 
    """Compute the softmax of vector x.""" 
    exps = np.exp(x) 
    return exps/np.sum(exps) 

のコードサンプルを与えるオンラインsoftmax

いくつかのリソースのlocal gradientを計算が生じていますi = jおよびi != jの場合。これは私が作ってみた簡単なコードスニペットで、私の理解を確認するために期待していた。

def softmax(self, x): 
    """Compute the softmax of vector x.""" 
    exps = np.exp(x) 
    return exps/np.sum(exps) 

def forward(self): 
    # self.input is a vector of length 10 
    # and is the output of 
    # (w * x) + b 
    self.value = self.softmax(self.input) 

def backward(self): 
    for i in range(len(self.value)): 
     for j in range(len(self.input)): 
      if i == j: 
       self.gradient[i] = self.value[i] * (1-self.input[i)) 
      else: 
       self.gradient[i] = -self.value[i]*self.input[j] 

その後self.gradientがベクトルであるlocal gradientです。これは正しいです?これを書くには良い方法がありますか?

+1

これは非常に明確ではない...あなたが実際に計算するためにどのような勾配をしようとしていますか? SMはR^nからR^nへのマップなので、n^2の偏微分dSM [i]/dx [k] ... – Julien

+1

を定義することができます@JulienBernu質問を更新しました。何かご意見は? –

答えて

10

私はあなたがの3層NNを持っていると仮定しています入力層から隠れ層への線形変換に関連し、W2,b2は、隠れ層から出力層への線形変換に関連する。 Z1およびZ2は、隠れ層および出力層への入力ベクトルです。 a1およびa2は、隠れ層および出力層の出力を表す。 a2は予測される出力です。 delta3delta2はエラー(逆伝播)で、モデルパラメータに関して損失関数の勾配を見ることができます。

enter image description hereenter image description here

これは、3層NN(入力層、唯一1つの隠れ層と1つの出力層)のための一般的なシナリオです。上記の手順に従って、計算しやすい勾配を計算することができます。この記事への別の答えはあなたのコードの問題を既に指しているので、私は同じことを繰り返すわけではありません。

+0

もう1つのことを明確にします。 z2で始める場合、つまりz1は決して存在しませんでした。それは2層NNにしますか? 2回起こっている線形変換は、それを3層NNにしますか? –

+0

方程式の層の名前を説明できますか?あなたのケースの入力層はz1ですか?いくつの隠れたレイヤーがありますか? –

+0

私の回答を更新しました@SamHammamy –

6

私が言ったように、あなたはn^2部分的な派生物を持っています。代わりに、これはより簡潔にそうように計算することができる。ところで

 if i == j: 
      self.gradient[i] = self.value[i] * (1-self.input[i)) 
     else: 
      self.gradient[i] = -self.value[i]*self.input[j] 

 if i == j: 
      self.gradient[i,j] = self.value[i] * (1-self.value[i)) 
     else: 
      self.gradient[i,j] = -self.value[i] * self.value[j] 

:あなたが数学を行う場合

、あなたはdSM[i]/dx[k]SM[i] * (dx[i]/dx[k] - SM[j])ので、あなたが持つべきであることを見つけます:

SM = self.value.reshape((-1,1)) 
jac = np.diag(self.value) - np.dot(SM, SM.T) 
+0

これはヤコビアンなのですか? –

+0

はいそれは...... – Julien

+0

別の切断があると思います。 @ wasiの答えが隠れたレイヤーの線形変換ですか? –