双方向rnを長くして正しい姿勢で教える


双方向RNNの使い方
『深さ学習のTensorFlow入門、原理と進級実戦』の本の9.4.2の中の第4小節では、長ダイナミックなRNNの実現を紹介したことがあります。
ここでは、拡張された二方向動的rnの長いシーケンス処理時の応用について説明します。実は双方向RNNの使用には暗黙の注意事項があり、ミスをしやすいです。
本論文では、双方向RNNの常用関数、用法及び注意事項を紹介します。
動的双方向rnには2つの関数があります。

stack_bidirectional_dynamic_rnn
bidirectional_dynamic_rnn
両者の実現は大同小異で、配置の位置も違っています。前者はcontribの下に置かれていますが、後者はさらに根が赤いように見えます。tfのコアライブラリの下に置いてあります。使用時には両者の戻り値も違います。紹介します。
サンプルコード
まずGRUのセルコードを例にします。

import tensorflow as tf
import numpy as np
tf.reset_default_graph()
#       
X = np.random.randn(2, 4, 5)#    、    、    
#         3
X[1,2:] = 0
seq_lengths = [4, 2]
Gstacked_rnn = []
Gstacked_bw_rnn = []
for i in range(3):
    Gstacked_rnn.append(tf.contrib.rnn.GRUCell(3))
    Gstacked_bw_rnn.append(tf.contrib.rnn.GRUCell(3))
#          RNN
Gmcell = tf.contrib.rnn.MultiRNNCell(Gstacked_rnn)
Gmcell_bw = tf.contrib.rnn.MultiRNNCell(Gstacked_bw_rnn)
sGbioutputs, sGoutput_state_fw, sGoutput_state_bw = tf.contrib.rnn.stack_bidirectional_dynamic_rnn([Gmcell],[Gmcell_bw], X,sequence_length=seq_lengths,                                           dtype=tf.float64)
Gbioutputs, Goutput_state_fw = tf.nn.bidirectional_dynamic_rnn(Gmcell,Gmcell_bw, X,sequence_length=seq_lengths,dtype=tf.float64)
上記の例は双方向RNNを作成する方法の例である。stackを持つ双方向RNNは3つの戻り値を出力し、stackを持たない双方向RNNは2つの戻り値を出力することが見られます。
この中で注意したいのは、エクセル初期化がない場合はdtypeパラメータを値付けしなければなりません。そうでないと、エラーを報告します。
コード:BiRNN出力
以下にコードを追加して、出力の値をプリントアウトします。この二つの関数は一体何を出力しますか?

#      
sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
sgbresult,sgstate_fw,sgstate_bw=sess.run([sGbioutputs,sGoutput_state_fw,sGoutput_state_bw])
print("   :
", sgbresult[0]) print(" :
", sgbresult[1]) print('Gru :',len(sgstate_fw[0]),'
',sgstate_fw[0][0],'
',sgstate_fw[0][1],'
',sgstate_fw[0][2]) print('Gru :',len(sgstate_bw[0]),'
',sgstate_bw[0][0],'
',sgstate_bw[0][1],'
',sgstate_bw[0][2])
まず、スタック付きの双方向RNN出力の内容を見てみます。
这里写图片描述
私達が入力したデータのロットは2で、最初のシーケンスの長さは4で、第二のシーケンスの長さは2です。
図中には4つの部分が出力されていますが、第一部分(全シーケンス)はシーケンス長が4の結果で、第二部分(短いシーケンス)はシーケンス長が2の結果です。このような結果出力は、3つのRNNのGRUセルで構成されていないので、各シーケンスの出力は3であることは明らかであり、短いシーケンスの後の0を削除しなければならない。
幸い、この関数は2番目の出力値、GRUの状態があります。元の結果を0に変更することなく、そのまま状態の値を使用することができます。
一つのGRUはもともと状態がないからです。この関数は最後の出力を状態として返します。この関数は2つの状態から戻り、それぞれ前方向と後方向を表します。各方向の状態は3つの要素を返します。これは各方向のネットワークが3層のGRUで構成されているからです。使う時は最後の状態を取るのが普通です。図中の赤色の部分は前方向で、二つのサンプルが対応する出力であることが分かります。
ポイントは青の部分、つまり逆の状態値に対応するのが元のデータの中で一番実際のシーケンス入力です。逆方向RNNなので、逆循環の場合は、シーケンスの最後を一番前に置くので、逆方向ネットワークの生成結果は最初のシーケンスに対応します。
特徴抽出タスク処理には、順方向と逆方向の最後の値がこのシーケンスの特徴であり、統合処理が必要である。しかし、次のシーケンス予測タスクに対しては、順方向のRNNネットワークを直接使用することを推奨します。
双方向RNNの結果を得るためには、特に長くなると、状態によって値を得て直接つなぎ合わせるのが正しいです。長くなくてもいいです。直接出力値を使ってつなぎ合わせますと、逆方向の特徴結果の一部が失われます。これは注意すべきところです。
コード:BiRNN出力
はい。次に、stackを持たない関数の出力はどうなりますか?

gbresult,state_fw=sess.run([Gbioutputs,Goutput_state_fw])
print("  :
", gbresult[0]) print(" :
", gbresult[1]) print(' :',len(state_fw),'
',state_fw[0],'
',state_fw[1]) #state_fw[0]:【 , ,cell 】 print(state_fw[0][-1],state_fw[1][-1]) out = np.concatenate((state_fw[0][-1],state_fw[1][-1]),axis = 1) print(" ",out)
今回は、基本的な内容を出力した上で、直接に結果をつなぎ合わせます。上のコードを実行したら下記の内容を出力します。
这里写图片描述
同じように赤色を使い、反対に青色を使います。関数から返された出力値を変更しても、正反対のスプライスはありません。出力の状態は一つの値ですが、中には二つの要素があり、一つは正の状態、一つは逆の状態を表します。
出力から見ると、最後の一行は最終結果の真のスプライスを実現しました。双方向rnを使う時は上の例のコードに従ってその状態を一つの完全な出力につなぎ合わせて処理してもいいです。
コード:LSTMの双方向RNN
似たようなLSTMセルを使いたいなら。前のGRU部分を置き換えればいいです。コードは以下の通りです。

stacked_rnn = []
stacked_bw_rnn = []
for i in range(3):
    stacked_rnn.append(tf.contrib.rnn.LSTMCell(3))
    stacked_bw_rnn.append(tf.contrib.rnn.LSTMCell(3))
mcell = tf.contrib.rnn.MultiRNNCell(stacked_rnn)
mcell_bw = tf.contrib.rnn.MultiRNNCell(stacked_bw_rnn)    
bioutputs, output_state_fw, output_state_bw = tf.contrib.rnn.stack_bidirectional_dynamic_rnn([mcell],[mcell_bw], X,sequence_length=seq_lengths,
                                              dtype=tf.float64)
bioutputs, output_state_fw = tf.nn.bidirectional_dynamic_rnn(mcell,mcell_bw, X,sequence_length=seq_lengths,
                                              dtype=tf.float64)
出力内容は何ですか?前のGRUの出力部分によって自分で観察できます。どのようにつなぎ合わせるかは、GRUの例を参照しても良い。
正逆の状態をつなぎ合わせることで双方向RNNの最終出力特徴が得られます。絶対に直接に出力を持って処理しないでください。これは大部分の演算特徴を失います。
この部分は『深い学習のTensorFlow入門、原理と進級実戦』の本の内容に属しています。RNNの詳細については、本の第九章の詳細を参照してください。
私は双方向RNNの理解について
1、双方向RNNが使用するシーン:場合によっては、現在の出力は前のシーケンス要素だけでなく、後のシーケンス要素にも依存することがある。例えば、完形穴埋め、機械翻訳などの応用をします。

2、Tensorflowで双方向RNNを実現するAPIは:bidirectionaldynamic_rn;その本質は主に2回のreverseを作ったのです。
初回reverse:入力シーケンスをreverseし、dynamic_に送る。rnnは一回の計算をします
第二回reverse:上をdynamic_rnnが戻ってきたoutputsはreverseを行い、正方向と逆方向に出力されるtimeが正しいことを保証します。
以上は個人の経験ですので、参考にしていただければと思います。