Tensorflowのtf.nn.ctc_beam_search_decoder()
を使用して、多対多のマッピング(つまり、ネットワークセルごとに複数のソフトマックス出力)を実行するRNNの出力をデコードしています。
ネットワークの出力とビーム検索デコーダの簡略版は次のとおりです。
import numpy as np
import tensorflow as tf
batch_size = 4
sequence_max_len = 5
num_classes = 3
y_pred = tf.placeholder(tf.float32, shape=(batch_size, sequence_max_len, num_classes))
y_pred_transposed = tf.transpose(y_pred,
perm=[1, 0, 2]) # TF expects dimensions [max_time, batch_size, num_classes]
logits = tf.log(y_pred_transposed)
sequence_lengths = tf.to_int32(tf.fill([batch_size], sequence_max_len))
decoded, log_probabilities = tf.nn.ctc_beam_search_decoder(logits,
sequence_length=sequence_lengths,
beam_width=3,
merge_repeated=False, top_paths=1)
decoded = decoded[0]
decoded_paths = tf.sparse_tensor_to_dense(decoded) # Shape: [batch_size, max_sequence_len]
with tf.Session() as session:
tf.global_variables_initializer().run()
softmax_outputs = np.array([[[0.1, 0.1, 0.8], [0.8, 0.1, 0.1], [0.8, 0.1, 0.1], [0.8, 0.1, 0.1], [0.8, 0.1, 0.1]],
[[0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7]],
[[0.1, 0.7, 0.2], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7]],
[[0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7]]])
decoded_paths = session.run(decoded_paths, feed_dict = {y_pred: softmax_outputs})
print(decoded_paths)
この場合の出力は次のとおりです。
[[0]
[1]
[1]
[1]]
私の理解は、出力テンソルは次元[batch_size, max_sequence_len]
、各行には、見つかったパス内の関連するクラスのインデックスが含まれています。
この場合、出力は次のようになるはずです。
[[2, 0, 0, 0, 0],
[2, 2, 2, 2, 2],
[1, 2, 2, 2, 2],
[2, 2, 2, 2, 2]]
どのように私は理解していませんctc_beam_search_decoder
機能しますか?
tf.nn.ctc_beam_search_decoder documentation に示されているように、出力の形状は_[batch_size, max_sequence_len]
_ではありません。代わりに
_[batch_size, max_decoded_length[j]]
_
(あなたのケースでは_j=0
_を使用)。
この論文 (これは githubリポジトリ で引用されています)のセクション2の冒頭に基づいて、_max_decoded_length[0]
_は_max_sequence_len
_によって上から制限されています。しかし、それらは必ずしも同じではありません。関連する引用は次のとおりです。
Sを、固定分布D_ {XxZ}から抽出されたトレーニング例のセットとします。入力空間X =(R ^ m)は、m次元の実数値ベクトルのすべてのシーケンスのセットです。ターゲット空間Z = L *は、ラベルの(有限)アルファベットL上のすべてのシーケンスのセットです。一般に、L *の要素をラベルシーケンスまたはラベリングと呼びます。 Sの各例は、シーケンス(x、z)のペアで構成されます。ターゲットシーケンスz =(z1、z2、...、zU)は、入力シーケンスx =(x1、x2、...、xT)と同じくらい長く 、すなわちU <= T。入力シーケンスとターゲットシーケンスは一般に同じ長さではないため、それらを整列させるアプリオリな方法はありません。
実際、_max_decoded_length[0]
_は特定のマトリックス_softmax_outputs
_に依存します。特に、正確に同じ次元を持つ2つのそのような行列は、異なる_max_decoded_length[0]
_になる可能性があります。
たとえば、行を置き換える場合
_softmax_outputs = np.array([[[0.1, 0.1, 0.8], [0.8, 0.1, 0.1], [0.8, 0.1, 0.1], [0.8, 0.1, 0.1], [0.8, 0.1, 0.1]],
[[0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7]],
[[0.1, 0.7, 0.2], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7]],
[[0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7]]])
_
行で
_np.random.seed(7)
r=np.random.randint(0,100,size=(4,5,3))
softmax_outputs=r/np.sum(r,2).reshape(4,5,1)
_
あなたは出力を得るでしょう
_[[1 0 1]
[1 0 1]
[1 0 0]
[1 0 0]]
_
(上記の例では、_softmax_outputs
_はロジットで構成されており、指定した行列とまったく同じ次元です)。
一方、シードをnp.random.seed(50)
に変更すると、出力が得られます
_[[1 0]
[1 0]
[1 0]
[0 1]]
_
P.S。
あなたの質問の最後の部分について:
この場合、出力は次のようになるはずです。
_[[2, 0, 0, 0, 0], [2, 2, 2, 2, 2], [1, 2, 2, 2, 2], [2, 2, 2, 2, 2]]
_
documentation に基づいて、_num_classes
_は実際には_num_labels + 1
_を表すことに注意してください。具体的には:
入力Tensorの最も内側の次元サイズ_
num_classes
_は_num_labels + 1
_クラスを表します。ここで_num_labels
_は真のラベルの数であり、最大値(_num_classes - 1
_)は空白用に予約されていますラベル。たとえば、3つのラベル[a、b、c]、_
num_classes = 4
_を含む語彙の場合、ラベルのインデックスは{a:0、b:1、c:2、空白:3}です。
したがって、実際のラベルは0と1であり、2は空白のラベル用に予約されています。空白のラベルは、ラベルがないことを示しています(セクション3.1 ここ ):
CTCネットワークには、Lのラベルよりも1ユニット多い数のソフトマックス出力レイヤー(Bridle、1990)があります。最初のアクティブ化| L |単位は、特定の時間に対応するラベルを観察する確率として解釈されます。 追加ユニットのアクティブ化は、「空白」またはラベルなしを観察する確率です。一緒に、これらの出力は、可能なすべてのラベルシーケンスを揃えるすべての可能な方法の確率を定義します。入力シーケンス。