Vertex Explainable AI で TensorFlow を使用する

カスタム トレーニング済みの TensorFlow モデルを使用する場合、モデルの保存と説明の構成に必要な特定の情報があります。

AutoML 表形式モデルで Vertex Explainable AI を使用する場合は、構成を行う必要はありません。Vertex AI は Vertex Explainable AI 用のモデルを自動的に構成します。このドキュメントをスキップして、説明の取得をご覧ください。

このガイドでは、Vertex Explainable AI で使用できるように TensorFlow モデルをトレーニングするときに必要な情報を提供します。具体的には、このガイドで扱うトピックは次のとおりです。

  • Vertex Explainable AI の Model リソースを構成するときに指定する必要がある、トレーニング中の入力テンソルと出力テンソルの名前を見つける。これには、一般的なテンソルが機能しない場合に、特殊なケースで Vertex Explainable AI に適したテンソルを作成して見つけることも含まれます。

  • TensorFlow モデルを Vertex Explainable AI と互換性のある TensorFlow SavedModel としてエクスポートする。

  • すでにエクスポートされている TensorFlow SavedModel から入力テンソルと出力テンソルの名前を見つける。これは、モデルのトレーニング コードにアクセスできない場合に役立ちます。

トレーニング中に入力テンソルと出力テンソルの名前を見つける

TensorFlow のビルド済みコンテナを使用して予測を提供する場合、モデルの入力テンソルと出力テンソルの名前を知っておく必要があります。Vertex Explainable AI の Model を構成するときに、この名前を ExplanationMetadata メッセージの一部として指定します。

TensorFlow モデルが次の条件を満たしている場合は、次のセクションで説明する「基本的な方法」を使用して、トレーニング中にこれらのテンソル名を特定できます。

  • 入力の形式がシリアル化されていない
  • モデルの SignatureDef への各入力に、特徴の値が直接含まれている(数値または文字列のいずれか)
  • 出力は数値データであり、数値データとして扱う。これには、分類データとみなされるクラス ID は含まれません。

モデルがこれらの基準を満たさない場合は、トレーニング コードの調整と特殊なケースでのテンソル名の検索をご覧ください。

基本的な方法

トレーニング中に、モデルの入力テンソルと出力テンソルの name 属性を出力します。次の例では、Keras レイヤの name フィールドで、ExplanationMetadata に必要な基盤となるテンソル名が生成されます。

bow_inputs = tf.keras.layers.Input(shape=(2000,))
merged_layer = tf.keras.layers.Dense(256, activation="relu")(bow_inputs)
predictions = tf.keras.layers.Dense(10, activation="sigmoid")(merged_layer)
model = tf.keras.Model(inputs=bow_inputs, outputs=predictions)
print('input_tensor_name:', bow_inputs.name)
print('output_tensor_name:', predictions.name)

この Python コードを実行すると、次の出力が表示されます。

input_tensor_name: input_1:0
output_tensor_name: dense_1/Sigmoid:0

説明用に Model を構成するときに、入力テンソル名として input_1:0 を使用し、出力テンソル名として dense_1/Sigmod:0 を使用できます。

トレーニング コードの調整と特殊なケースでのテンソル名の検索

ExplanationMetadata の入力テンソルと出力テンソルが、サービング SignatureDef 内のものと同じではない場合もあります。

  • シリアル化された入力がある
  • グラフに前処理オペレーションが含まれている
  • サービング出力が確率、ロジット、その他のタイプの浮動小数点数テンソルではない

このような場合、別の手法で正しい入力テンソルと出力テンソルを見つける必要があります。全体的な目標は、ロジット(アクティブ化前)、確率(アクティブ化後)、その他の出力表記に関して、入力とテンソルについて説明する特徴値に関連するテンソルを見つけることです。

入力テンソルの特殊ケース

シリアル化した入力を使用してモデルに入力する場合や、グラフに前処理オペレーションが含まれている場合、説明メタデータ内の入力は、サービング SignatureDef 内の入力と異なります。

シリアル化された入力

TensorFlow SavedModels は、次のようなさまざまな複雑な入力を受け入れることができます。

  • シリアル化された tf.Example メッセージ
  • JSON 文字列
  • エンコードされた Base64 文字列(画像データを表す)

モデルで、このようなシリアル化された入力が受け入れられると、説明用の入力としてそれらのテンソルを直接使用する手法が機能しなくなる、あるいは無意味な結果が生成される可能性があります。代わりに、モデル内の特徴列に入力する後続の入力テンソルを配置します。

モデルをエクスポートするときに、サービング入力関数で解析関数を呼び出して、解析オペレーションを TensorFlow グラフに追加できます。解析関数は、tf.io module に記載されています。これらの解析関数は通常、レスポンスとしてテンソルを返します。これらのテンソルを説明メタデータに選択することをおすすめします。

たとえば、モデルをエクスポートするときに、tf.parse_example() を使用するとします。これにより、シリアル化された tf.Example メッセージが取得され、特徴列に入力するテンソルの辞書が出力されます。その出力を使用して説明メタデータに入力できます。これらの出力の一部が、3 つのテンソルで構成されている名前付きのタプルである tf.SparseTensor である場合、インデックスの名前、値、dense_shape テンソルを取得して、メタデータ内の対応するフィールドに入力する必要があります。

次の例は、デコード オペレーションの後に入力テンソルの名前を取得する方法を示しています。

float_pixels = tf.map_fn(
    lambda img_string: tf.io.decode_image(
        img_string,
        channels=color_depth,
        dtype=tf.float32
    ),
    features,
    dtype=tf.float32,
    name='input_convert'
  )

print(float_pixels.name)
前処理入力

モデルグラフにいくつかの前処理オペレーションが含まれている場合、前処理ステップの後に、テンソルで説明を取得する必要が生じることがあります。このような場合、tf.Tensor の name プロパティを使用してそれらのテンソルの名前を取得した後、それらを説明メタデータに入力できます。

item_one_hot = tf.one_hot(item_indices, depth,
    on_value=1.0, off_value=0.0,
    axis=-1, name="one_hot_items:0")
print(item_one_hot.name)

デコードされたテンソル名は input_pixels:0 になります。

出力テンソルの特殊ケース

ほとんどの場合、サービング SignatureDef の出力は確率かロジットのいずれかです。

モデルは確率に起因しているが、その代わりにロジット値を入力したい場合、ロジットに対応する適切な出力テンソル名を見つける必要があります。

サービング SignatureDef に、確率またはロジットではない出力が含まれている場合、トレーニング グラフで確率オペレーションを参照する必要があります。このシナリオは、Keras モデルではあまり発生しません。これが発生した場合、TensorBoard(またはその他のグラフ表示ツール)を使用して、正しい出力テンソル名を見つけることができます。

統合勾配に関する考慮事項

Vertex Explainable AI の統合勾配特徴アトリビューション方式を使用する場合は、出力に対して入力を微分できる必要があります。

説明メタデータはモデルの特徴を入力と論理的に分離します。出力テンソルに対して微分できない入力テンソルが含まれた統合勾配を使用する場合は、その特徴のエンコードされた(微分可能な)バージョンも指定する必要があります。

微分不可能な入力テンソルがある場合、または微分不可能なオペレーションがグラフにある場合は、次の方法を使用します。

  1. 微分不可能な入力を微分可能な入力としてエンコードします。
  2. 元の微分不可能な入力テンソルの名前に input_tensor_name を設定し、かつ、そのエンコードされた微分可能なバージョンに encoded_tensor_name を設定します。

エンコードを使用する説明メタデータ ファイル

たとえば、zip_codes:0 という名前の入力テンソルを持つカテゴリ特徴のあるモデルについて考えてみます。入力データには文字列として郵便番号が含まれているため、入力テンソル zip_codes:0 は微分不可能です。モデルでこのデータの前処理も行われ、郵便番号のワンホット エンコード表記が取得される場合、前処理後の入力テンソルは微分可能になります。元の入力テンソルと識別するために、前処理後のテンソルに zip_codes_embedding:0 という名前を付けることができます。

説明リクエストで両方の入力テンソルのデータを使用するには、説明用の Model の構成時に ExplanationMetadata を次のように設定します。

  • 入力特徴キーを zip_codes のようなわかりやすい名前に設定する。
  • input_tensor_name を、元のテンソルの名前 zip_codes:0 に設定する。
  • encoded_tensor_name を、ワンホット エンコードの後のテンソルの名前 zip_codes_embedding:0 する。
  • encodingCOMBINED_EMBEDDING に設定する。
{
    "inputs": {
      "zip_codes": {
        "input_tensor_name": "zip_codes:0",
        "encoded_tensor_name": "zip_codes_embedding:0",
        "encoding": "COMBINED_EMBEDDING"
      }
    },
    "outputs": {
      "probabilities": {
        "output_tensor_name": "dense/Softmax:0"
      }
    }
}

あるいは、input_tensor_name を、エンコードされた微分可能な入力テンソルの名前に設定し、元の微分不可能なテンソルを除外することもできます。両方のテンソルを指定する利点は、ワンホット エンコード表現ではなく、個々の郵便番号値にアトリビューションを付けることができるということです。この例では、元のテンソル(zip_codes:0)を除外し、input_tensor_namezip_codes_embedding:0 に設定します。この手法は、結果的に得られる特徴属性が推測しにくいため、おすすめしません

エンコード

Model のエンコードを有効にするには、上の例のようにエンコード設定を指定します。

エンコード機能は、エンコードされたデータからアトリビューションの入力データにプロセスを戻すのに役立ちます。これにより、返された属性を手動で後処理する必要がなくなります。Vertex Explainable AI でサポートされているエンコードの一覧をご覧ください。

COMBINED_EMBEDDING エンコードの場合、入力テンソルは 1D 配列にエンコードされます。

次に例を示します。

  • 入力: ["This", "is", "a", "test"]
  • エンコードされた入力: [0.1, 0.2, 0.3, 0.4]

Vertex Explainable AI 用 TensorFlow SavedModel のエクスポート

TensorFlow モデルをトレーニングした後、SavedModel としてエクスポートします。TensorFlow SavedModel には、トレーニング済みの TensorFlow モデルのほかに、シリアル化された署名、変数、グラフの実行に必要なその他のアセットが含まれています。SavedModel の各 SignatureDef によって、テンソル入力を受け入れ、テンソル出力を生成するグラフ内の関数が特定されます。

SavedModel と Vertex Explainable AI の互換性を確保するには、TensorFlow 2 と TensorFlow 1 のどちらを使用するかに応じて、以下のいずれかのセクションの手順を行います。

TensorFlow 2

TensorFlow 2.x を使用している場合は、tf.saved_model.save を使用してモデルを保存します。モデルを保存するときに、入力署名を指定できます。入力署名が 1 つの場合、Vertex Explainable AI は説明リクエストにデフォルトのサービス関数を使用します。複数の入力署名が存在する場合は、モデルを保存するときに、以下のとおりサービス デフォルト関数の署名を指定する必要があります。

tf.saved_model.save(m, model_dir, signatures={
    'serving_default': serving_fn,
    'xai_model': model_fn # Required for XAI
    })

この場合、Vertex Explainable AI は、説明リクエスト用に xai_model キーで保存したモデル関数の署名を使用します。キーの正確な文字列 xai_model を使用してください。

前処理関数を使用する場合は、前処理関数とモデル関数の署名も指定する必要があります。正確な文字列 xai_preprocessxai_model をキーとして使用する必要があります。

tf.saved_model.save(m, model_dir, signatures={
    'serving_default': serving_fn,
    'xai_preprocess': preprocess_fn, # Required for XAI
    'xai_model': model_fn # Required for XAI
    })

この場合、Vertex Explainable AI は、説明リクエストに前処理関数とモデル関数を使用します。モデル関数が想定する入力と前処理関数の出力が一致することを確認します。

詳しくは、TensorFlow におけるサービス署名の指定をご覧ください。

TensorFlow 1.15

TensorFlow 1.15 を使用している場合は、tf.saved_model.save使用しないでください。Vertex Explainable AI は、この方法で保存された TensorFlow 1 モデルをサポートしていません

Keras でモデルを作成してトレーニングする場合は、モデルを TensorFlow Estimator に変換して、SavedModel にエクスポートする必要があります。このセクションでは、モデルの保存を中心に説明します。

Keras モデルを作成、コンパイル、トレーニング、評価した後、次を行う必要があります。

  • tf.keras.estimator.model_to_estimator を使用して、Keras モデルを TensorFlow Estimator に変換します。
  • tf.estimator.export.build_raw_serving_input_receiver_fn を使用して、サービング入力関数を入力します。
  • tf.estimator.export_saved_model を使用して、SavedModel としてモデルをエクスポートします。
# Build, compile, train, and evaluate your Keras model
model = tf.keras.Sequential(...)
model.compile(...)
model.fit(...)
model.predict(...)

## Convert your Keras model to an Estimator
keras_estimator = tf.keras.estimator.model_to_estimator(keras_model=model, model_dir='export')

## Define a serving input function appropriate for your model
def serving_input_receiver_fn():
  ...
  return tf.estimator.export.ServingInputReceiver(...)

## Export the SavedModel to Cloud Storage, using your serving input function
export_path = keras_estimator.export_saved_model(
  'gs://' + 'YOUR_BUCKET_NAME',
  serving_input_receiver_fn
).decode('utf-8')

print("Model exported to: ", export_path)

SavedModel の SignatureDef からテンソル名を取得する

前のセクションで説明した「基本的な方法」の基準を満たしている場合、TensorFlow SavedModel の SignatureDef を使用して説明メタデータを準備できます。これは、モデルを生成したトレーニング コードにアクセスできない場合に役立ちます。

SavedModel CLI を使用して、SavedModel の SignatureDef を調べることができます。詳細については、SavedModel CLI の使用方法を確認してください。

次の SignatureDef の例について考えてみます。

The given SavedModel SignatureDef contains the following input(s):
  inputs['my_numpy_input'] tensor_info:
      dtype: DT_FLOAT
      shape: (-1, 1)
      name: x:0
The given SavedModel SignatureDef contains the following output(s):
  outputs['probabilities'] tensor_info:
      dtype: DT_FLOAT
      shape: (-1, 1)
      name: dense/Softmax:0
Method name is: tensorflow/serving/predict

グラフには、x:0 という名前の入力テンソルと、dense/Softmax:0 という名前の出力テンソルがあります。説明用に Model を構成する場合は、ExplanationMetadata メッセージの入力テンソル名として x:0 を、出力テンソル名として dense/Softmax:0 を使用します。

次のステップ