2016-10-17 28 views
2

私はLSTM細胞がどのように働くかを私自身の理解から、最初からLSTMネットワークを構築しています。無階層のLSTMネットワークをゼロから構築する、順方向パスと逆方向パスを行う方法?

レイヤーがないので、私はチュートリアルの方程式のベクトル化されていない形式を実装しようとしています。私はまた、細胞の状態から覗き穴を使用しています。

これまでのところ、私はそれがこのようになっていることを理解して:私は往路用ゲートの各々のためにこれらの式を作ったことでLSTM network

そのため_wの平均体重
i_t = sigmoid(i_w * (x_t + c_t) + i_b) 
f_t = sigmoid(f_w * (x_t + c_t) + f_b) 

cell_gate = tanh(c_w * x_t + c_b) 

c_t = (f_t * c_t) + (i_t * cell_gate) 

o_t = sigmoid(o_w * (x_t + c_t) + o_b) 

h_t = o_t * tanh(c_t) 

バイアスのためにそれぞれのゲートと_b。また、私は最初のS字状の名前を "cell_gate"の左端に付けました。


バックパスとは、私にとっては曖昧なものですが、これらの式を正しく引き出す方法がわかりません。

私は一般的にエラーを計算することを知っていますが、方程式はerror = f '(x_t)*(received_error)です。ここで、f '(x_t)は活性化関数の一次導関数であり、received_errorは出力ニューロンの場合は(target-output)、隠れニューロンの場合はΣ(o_e * w_io)のいずれかになります。

ここで、o_eは現在のセルが出力するセルの1つのエラーで、w_ioはそれらを接続する重みです。

LSTMセル全体がニューロンと見なされるかどうかはわかりません。そのため、各ゲートをニューロンとして扱い、それぞれのエラー信号を計算しようとしました。その後...バックネットワークを渡すために単独で細胞ゲートからの誤差信号を使用:

o_e = sigmoid'(o_w * (x_t + c_t) + o_b) * (received_error) 
o_w += o_l * x_t * o_e 
o_b += o_l * sigmoid(o_b) * o_e 

...ゲートの残りの部分は同じフォーマットに従う...

を次にためのエラーLSTMセル全体はo_eに等しい。

そして、現在のセルの上LSTM細胞のために、それは受信エラーがに等しいです:

tanh'(x_t) * ∑(o_e * w_io) 

はこのすべて正しいですか?私は何か完全に間違っているのですか?

答えて

0

私はこの仕事を引き受ける午前、私はあなたのアプローチが正しいと信じて:

https://github.com/evolvingstuff/LongShortTermMemory/blob/master/src/com/evolvingstuff/LSTM.java

いくつかの素敵な作品から:また、トーマス・ラホール

////////////////////////////////////////////////////////////// 
    ////////////////////////////////////////////////////////////// 
    //BACKPROP 
    ////////////////////////////////////////////////////////////// 
    ////////////////////////////////////////////////////////////// 

    //scale partials 
    for (int c = 0; c < cell_blocks; c++) { 
     for (int i = 0; i < full_input_dimension; i++) { 
      this.dSdwWeightsInputGate[c][i] *= ForgetGateAct[c]; 
      this.dSdwWeightsForgetGate[c][i] *= ForgetGateAct[c]; 
      this.dSdwWeightsNetInput[c][i] *= ForgetGateAct[c]; 

      dSdwWeightsInputGate[c][i] += full_input[i] * neuronInputGate.Derivative(InputGateSum[c]) * NetInputAct[c]; 
      dSdwWeightsForgetGate[c][i] += full_input[i] * neuronForgetGate.Derivative(ForgetGateSum[c]) * CEC1[c]; 
      dSdwWeightsNetInput[c][i] += full_input[i] * neuronNetInput.Derivative(NetInputSum[c]) * InputGateAct[c]; 
     } 
    } 

    if (target_output != null) { 
     double[] deltaGlobalOutputPre = new double[output_dimension]; 
     for (int k = 0; k < output_dimension; k++) { 
      deltaGlobalOutputPre[k] = target_output[k] - output[k]; 
     } 

     //output to hidden 
     double[] deltaNetOutput = new double[cell_blocks]; 
     for (int k = 0; k < output_dimension; k++) { 
      //links 
      for (int c = 0; c < cell_blocks; c++) { 
       deltaNetOutput[c] += deltaGlobalOutputPre[k] * weightsGlobalOutput[k][c]; 
       weightsGlobalOutput[k][c] += deltaGlobalOutputPre[k] * NetOutputAct[c] * learningRate; 
      } 
      //bias 
      weightsGlobalOutput[k][cell_blocks] += deltaGlobalOutputPre[k] * 1.0 * learningRate; 
     } 

     for (int c = 0; c < cell_blocks; c++) { 

      //update output gates 
      double deltaOutputGatePost = deltaNetOutput[c] * CECSquashAct[c]; 
      double deltaOutputGatePre = neuronOutputGate.Derivative(OutputGateSum[c]) * deltaOutputGatePost; 
      for (int i = 0; i < full_input_dimension; i++) { 
       weightsOutputGate[c][i] += full_input[i] * deltaOutputGatePre * learningRate; 
      } 
      peepOutputGate[c] += CEC3[c] * deltaOutputGatePre * learningRate; 

      //before outgate 
      double deltaCEC3 = deltaNetOutput[c] * OutputGateAct[c] * neuronCECSquash.Derivative(CEC3[c]); 

      //update input gates 
      double deltaInputGatePost = deltaCEC3 * NetInputAct[c]; 
      double deltaInputGatePre = neuronInputGate.Derivative(InputGateSum[c]) * deltaInputGatePost; 
      for (int i = 0; i < full_input_dimension; i++) { 
       weightsInputGate[c][i] += dSdwWeightsInputGate[c][i] * deltaCEC3 * learningRate; 
      } 
      peepInputGate[c] += CEC2[c] * deltaInputGatePre * learningRate; 

      //before ingate 
      double deltaCEC2 = deltaCEC3; 

      //update forget gates 
      double deltaForgetGatePost = deltaCEC2 * CEC1[c]; 
      double deltaForgetGatePre = neuronForgetGate.Derivative(ForgetGateSum[c]) * deltaForgetGatePost; 
      for (int i = 0; i < full_input_dimension; i++) { 
       weightsForgetGate[c][i] += dSdwWeightsForgetGate[c][i] * deltaCEC2 * learningRate; 
      } 
      peepForgetGate[c] += CEC1[c] * deltaForgetGatePre * learningRate; 

      //update cell inputs 
      for (int i = 0; i < full_input_dimension; i++) { 
       weightsNetInput[c][i] += dSdwWeightsNetInput[c][i] * deltaCEC3 * learningRate; 
      } 
      //no peeps for cell inputs 
     } 
    } 

    ////////////////////////////////////////////////////////////// 

    //roll-over context to next time step 
    for (int j = 0; j < cell_blocks; j++) { 
     context[j] = NetOutputAct[j]; 
     CEC[j] = CEC3[j]; 
    } 

、そしておそらくさらに興味深いですAndrej Karpathyの講義と講義ノート:

https://youtu.be/cO0a0QYmFm8?t=45m36s

http://cs231n.stanford.edu/slides/2016/winter1516_lecture10.pdf

関連する問題