0

Tensorflow を使用して、CTC 損失のある音声認識エンジンを実装したいと考えています。各音声発話の長さは可変であるため、入力特徴の長さは可変です。各転写が異なるため、ラベルの長さも可変です。フィーチャを手動でパディングしてバッチを作成し、モデルには tf.keras.layers.Masking() レイヤーを作成して、ネットワークを介してマスクを伝播します。また、パディングを使用してラベル バッチを作成します。

これはダミーの例です。それぞれ長さが 3 フレームと 5 フレームの 2 つの発話があるとします。各フレームは 1 つの機能で表されます (通常、これは 13 の MFCC になりますが、単純にするために 1 つに減らします)。バッチを作成するために、短い発話の最後に 0 を追加します。

features = np.array([1.5 2.3 4.6 0.0 0.0],
                    [1.7 2.6 3.4 2.3 1.0])                

ラベルは、これらの発話を書き起こしたものです。長さがそれぞれ 2 と 3 であるとしましょう。ラベルのバッチ形状は [2, 3, 26] になります。ここで、バッチ サイズは 2、最大長は 3、英語の文字数は 26 (ワンホット エンコーディング) です。

モデルは次のとおりです。

input_ = tf.keras.Input(shape=(None,1))
x = tf.keras.layers.Masking()(input_)
x = tf.keras.layers.GRU(26, return_sequences=True)(input_)
output_ = tf.keras.layers.Softmax(axis=-1)(x)
model = tf.keras.Model(input_,output_)

損失関数は次のようなものです。

def ctc_loss(y_true, y_pred):
   # Do something here to get logit_length and label_length?
   # ...
   loss = tf.keras.backend.ctc_batch_cost(y_true,y_pred,logit_length,label_length)

私の質問は、logit_length と label_length を取得する方法です。logit_length はマスクにエンコードされていると思いますが、y_pred._keras_mask を実行すると、結果は None になります。label_length については、情報はテンソル自体にありますが、それを取得する最も効率的な方法はわかりません。

ありがとう。

アップデート:

Tou You の回答に従って、tf.math.count_nonzero を使用して label_length を取得し、logit_length をロジット レイヤーの長さに設定します。

したがって、損失関数内の形状は (バッチ サイズ = 10) です。

y_true.shape = (10, None)
y_pred.shape = (10, None, 27)
label_length.shape = (10,1)
logit_lenght.shape = (10,1)

もちろん、y_true と y_pred の 'None' は同じではありません。一方はバッチの最大文字列長であり、もう一方はバッチの時間フレームの最大数であるためです。ただし、 model.fit() を呼び出して、これらのパラメーターを使用して損失 tf.keras.backend.ctc_batch_cost() を呼び出すと、エラーが発生します。

Traceback (most recent call last):
  File "train.py", line 164, in <module>
    model.fit(dataset, batch_size=batch_size, epochs=10)
  File "/home/pablo/miniconda3/envs/lightvoice/lib/python3.8/site-packages/tensorflow/python/keras/engine/training.py", line 66, in _method_wrapper
    return method(self, *args, **kwargs)
  File "/home/pablo/miniconda3/envs/lightvoice/lib/python3.8/site-packages/tensorflow/python/keras/engine/training.py", line 848, in fit
    tmp_logs = train_function(iterator)
  File "/home/pablo/miniconda3/envs/lightvoice/lib/python3.8/site-packages/tensorflow/python/eager/def_function.py", line 580, in __call__
    result = self._call(*args, **kwds)
  File "/home/pablo/miniconda3/envs/lightvoice/lib/python3.8/site-packages/tensorflow/python/eager/def_function.py", line 644, in _call
    return self._stateless_fn(*args, **kwds)
  File "/home/pablo/miniconda3/envs/lightvoice/lib/python3.8/site-packages/tensorflow/python/eager/function.py", line 2420, in __call__
    return graph_function._filtered_call(args, kwargs)  # pylint: disable=protected-access
  File "/home/pablo/miniconda3/envs/lightvoice/lib/python3.8/site-packages/tensorflow/python/eager/function.py", line 1661, in _filtered_call
    return self._call_flat(
  File "/home/pablo/miniconda3/envs/lightvoice/lib/python3.8/site-packages/tensorflow/python/eager/function.py", line 1745, in _call_flat
    return self._build_call_outputs(self._inference_function.call(
  File "/home/pablo/miniconda3/envs/lightvoice/lib/python3.8/site-packages/tensorflow/python/eager/function.py", line 593, in call
    outputs = execute.execute(
  File "/home/pablo/miniconda3/envs/lightvoice/lib/python3.8/site-packages/tensorflow/python/eager/execute.py", line 59, in quick_execute
    tensors = pywrap_tfe.TFE_Py_Execute(ctx._handle, device_name, op_name,
tensorflow.python.framework.errors_impl.InvalidArgumentError: 2 root error(s) found.
  (0) Invalid argument:  Incompatible shapes: [10,92] vs. [10,876]
         [[node Equal (defined at train.py:164) ]]
  (1) Invalid argument:  Incompatible shapes: [10,92] vs. [10,876]
         [[node Equal (defined at train.py:164) ]]
         [[ctc_loss/Log/_62]]
0 successful operations.
0 derived errors ignored. [Op:__inference_train_function_3156]

Function call stack:
train_function -> train_function

y_true (92) の長さが y_pred (876) の長さと同じではないと不平を言っているようです。私は何が欠けていますか?

4

1 に答える 1

0

少なくとも Tensorflow の最新バージョン (2.2 以降) では、Softmax レイヤーはマスキングをサポートしています。マスキングされた値の出力はゼロではなく、前の値を繰り返すだけです。

features = np.array([[1.5, 2.3 ,4.6, 0.0 ,0.0],
                [1.7, 2.6, 3.4 ,2.3 ,1.0]])

input_ = tf.keras.Input(shape=(None,1))
x = tf.keras.layers.Masking()(input_)

x = tf.keras.layers.GRU(2, return_sequences=True)(x)

output_ = tf.keras.layers.Softmax(axis=-1)(x)

model = tf.keras.Model(input_,output_)

r = model(features)
print(r)
 

最初のサンプルの出力には、マスクに対応する値が繰り返されます。

<tf.Tensor: shape=(2, 5, 2), dtype=float32, numpy=array([[[0.53308547, 0.46691453],
    [0.5477166 , 0.45228338],
    [0.55216545, 0.44783455],
    [0.55216545, 0.44783455],
    [0.55216545, 0.44783455]],

   [[0.532052  , 0.46794805],
    [0.54557794, 0.454422  ],
    [0.55263203, 0.44736794],
    [0.56076777, 0.4392322 ],
    [0.5722393 , 0.42776066]]], dtype=float32)>

シーケンス ( label_length ) の non_masked 値を取得するには、tf を使用しています。バージョン== 2.2 であり、それは私にとってはうまくいきます:

get_mask = r._keras_mask

get_mask tensor value から label_length を抽出できます:

   <tf.Tensor: shape=(2, 5), dtype=bool, numpy=array([[ True,  
    True,  True, False, False],
   [ True,  True,  True,  True,  True]])>

または、ゼロ以外のテンソル y_true の値を数えることで、label_length を取得できます。

label_length = tf.math.count_nonzero(y_true, axis=-1, keepdims=True) 

logit_length の値については、私が見たすべての実装は time_step の長さを返すだけなので、logit_length は次のようになります。

logit_length = tf.ones(shape = (your_batch_size ,1 ) * time_step

または、マスク tensor を使用して、マスクされていない time_step を取得できます。

logit_length = tf.reshape(tf.reduce_sum( 
        tf.cast(y_pred._keras_mask,tf.float32),axis=1),(your_batch_size,-1) ) 
    

これは完全な例です:

features = np.array([[1.5, 2.3 ,4.6, 0.0 ,0.0],
                [1.5, 2.3 ,4.6, 2.0 ,1.0]]).reshape(2,5,1)  
labels = np.array([[1., 2. ,3., 0. ,0.],
               [1., 2. ,3., 2. ,1.]]).reshape(2,5 ) 

input_ = tf.keras.Input(shape=(5,1))
x = tf.keras.layers.Masking()(input_)
x = tf.keras.layers.GRU(5, return_sequences=True)(x)# 5 is the number of classes + blank .(in your case == 26 + 1)
output_ =  tf.keras.layers.Softmax(axis = -1)(x) 

model = tf.keras.Model(input_,output_)


def ctc_loss(y_true, y_pred):

  label_length = tf.math.count_nonzero(y_true, axis=-1, keepdims=True) 
  logit_length = tf.reshape(tf.reduce_sum(
                 tf.cast(y_pred._keras_mask,tf.float32),axis=1),(2,-1) ) 
                      
  loss =tf.keras.backend.ctc_batch_cost(y_true,y_pred,logit_length,
                  label_length)
  return  tf.reduce_mean(loss)

model.compile(loss =ctc_loss , optimizer = 'adam')
model.fit(features , labels ,epoch = 10)
于 2020-10-13T11:15:02.777 に答える