Path: blob/master/site/ja/guide/keras/masking_and_padding.ipynb
25118 views
Copyright 2020 The TensorFlow Authors.
Keras でマスキングとパディングをする
MNIST モデルをビルドする
はじめに
マスキングは、シーケンス処理レイヤーに入力の特定の時間ステップが欠落しているためデータを処理する際にスキップする必要があることを伝えるために使用する手法です。
パディングは、マスキングされたステップがシーケンスの先頭または末尾にある特殊なマスキングです。パディングは、シーケンスデータを連続したバッチにエンコードする必要性から生まれました。バッチ内のすべてのシーケンスを所定の標準の長さに合わせるためには、一部のシーケンスをパディングまたはトランケートする(切り詰める)必要があるためです。
では、詳しく見ていきましょう。
パディングシーケンスデータ
シーケンスデータを処理する際に個々のサンプルの長さが異なることは、非常に一般的です。次の例(単語としてトークン化されたテキスト)を考えてみます。
語彙検索の後、データは以下のように整数としてベクトル化されるかもしれません。
データは、個々のサンプルがそれぞれ 3、5、6 の長さを持つネストされたリストです。ディープラーニングモデルの入力データは,単一のテンソル(例えばこの場合だと(batch_size, 6, vocab_size)
のような形状)でなければならないため、最長のアイテムよりも短いサンプルは、何らかのプレースホルダー値でパディングする必要があります。(その代わりに、短いサンプルをパディングする前に長いサンプルをトランケートすることも可能です。)
Keras は Python のリストを共通の長さにトランケートしたりパディングしたりするユーティリティ関数を提供します:tf.keras.preprocessing.sequence.pad_sequences
マスキング
全てのサンプルが統一された長さになったので、今度はデータの一部が実際にパディングされ、無視されるべきであることをモデルに知らせなければなりません。このメカニズムがマスキングです。
Keras モデルで入力マスクを導入するには、3 つの方法があります。
keras.layers.Masking
レイヤーを追加する。keras.layers.Embedding
レイヤーをmask_zero=True
で設定する。mask
引数をサポートするレイヤー(RNN レイヤーなど)を呼び出す際に、この引数を手動で渡す。
マスク生成レイヤー : Embedding
と Masking
内部でこれらのレイヤーはマスクテンソル(形状(batch, sequence_length)
の 2 次元テンソル)を作成し、Masking
または Embedding
レイヤーによって返されるテンソル出力にアタッチします。
出力された結果から分かるように、マスクは形状が(batch_size, sequence_length)
の 2 次元ブールテンソルであり、そこでは個々の False
エントリは、対応する時間ステップを処理中に無視すべきであることを示しています。
Functional API と Sequential API のマスク伝播
Functional API または Sequential API を使用する場合、Embedding
レイヤーまたは Masking
レイヤーによって生成されたマスクは、それらを使用できる任意のレイヤー(例えば RNN レイヤーなど)にネットワークを介して伝播されます。Keras は入力に対応するマスクを自動的に取得し、その使用方法を知っている任意のレイヤーに渡します。
例えば、以下の Sequential API モデルでは、LSTM
レイヤーは自動的にマスクを取得します。つまりこれは、パディングされた値を無視するということです。
これは、以下の Functional API モデルでも同様です。
マスクテンソルを直接レイヤーに渡す
マスクを扱うことができるレイヤー(LSTM
レイヤーなど)は、それらの __call__
メソッドに mask
引数を持っています。
一方、マスクを生成するレイヤー(例えば
Embedding
)は、呼び出し可能な compute_mask(input, previous_mask)
メソッドを公開します。
例えば下記のようにして、マスクを生成するレイヤーの compute_mask()
メソッドの出力を、マスクを消費するレイヤーの __call__
メソッドに渡すことができます。
カスタムレイヤーでマスキングをサポートする
場合によっては、マスクを生成するレイヤー(Embedding
など)や、現在のマスクを変更するレイヤーを書く必要があります。
例えば、時間次元で連結する Concatenate
レイヤーのように、入力とは異なる時間次元を持つテンソルを生成するレイヤーは、現在のマスクを変更して、マスクされた時間ステップを下流のレイヤーが適切に考慮に入れられるようにする必要があります。
これを行うには、レイヤーに layer.compute_mask()
メソッドを実装します。これは、入力と現在のマスクが与えられた時に新しいマスクを生成します。
ここでは、現在のマスクを変更する必要がある TemporalSplit
レイヤーの例を示します。
もう 1 つの例として、入力値からマスクを生成できる CustomEmbedding
レイヤーの例を示します。
オプトインして互換性のあるレイヤー間でマスクを伝播する
ほとんどのレイヤーは時間次元を変更しないため、現在のマスクを変更する必要はありません。しかし、現在のマスクを変更せずにそれらを次のレイヤーに伝播したい場合があります。これはオプトイン動作です。 デフォルトでは、(フレームワークがマスクの伝播が安全かどうか判断する方法を持たないため)カスタムレイヤーは現在のマスクを破棄します。
時間次元を変更しないカスタムレイヤーを持ち、それが現在の入力マスクを伝播できるようにしたい場合は、レイヤーのコンストラクタを self.supports_masking = True
に設定する必要があります。この場合、compute_mask()
のデフォルトの動作は、現在のマスクを通過させるだけとなります。
マスク伝搬のためにホワイトリスト化されたレイヤーの例を示します。:
これで、マスク生成レイヤー(Embedding
など)とマスク消費レイヤー(LSTM
など)間でこのカスタムレイヤーの使用が可能となり、マスク消費レイヤーまで届くようにマスクを渡します。
マスク情報が必要なレイヤーを書く
一部のレイヤーはマスクコンシューマです。それらは call
で mask
引数を受け取り、それを使って特定の時間ステップをスキップするかどうかを判断します。
そのようなレイヤーを書くには、単純に call
シグネチャに mask=None
引数を追加します。入力に関連付けられたマスクは、それが利用可能な時にいつでもレイヤーに渡されます。
以下に簡単な例を示します。これは入力シーケンスの時間次元(軸 1)のソフトマックスを計算し、マスクされたタイムステップを破棄するレイヤーです。
要約
Keras のパディングとマスキングについて知っておくべきことはこれだけです。以下に要約します。
「マスキング」とは、シーケンス入力の特定の時間ステップをスキップしたり無視したりするタイミングをレイヤーが分かるようにする方法です。
一部のレイヤーはマスクジェネレーターです :
Embedding
は入力値からマスクを生成することができ(mask_zero=True
の場合)、Masking
レイヤーも同様に生成することができます。一部のレイヤーはマスクコンシューマです : これらは
mask
引数を__call__
メソッドで公開します。RNN レイヤーはこれに該当します。Functional API および Sequential API では、マスク情報は自動的に伝搬されます。
レイヤーをスタンドアロンで使用する場合には、
mask
引数をレイヤーに手動で渡すことができます。現在のマスクを変更するレイヤー、新しいマスクを生成するレイヤー、入力に関連付けられたマスクを消費するレイヤーを簡単に書くことができます。