説明をリクエストする前に、説明メタデータ ファイルを送信して説明リクエストを構成する必要があります。このメタデータ ファイルには、モデルの入力と出力を含める必要があります。また、画像データの入力ベースラインや可視化の設定など、オプションの設定も含まれます。
モデルの入出力を指定すると、モデルを変更せずに、説明リクエスト用に特定の特徴を選択できます。新しいモデルを作成するときに、Explainable AI SDK を使用すると、この処理を自動的に行うことができます。Explainable AI SDK を使用しない場合は、入力と出力を手動で特定する必要があります。
このガイドでは、入力テンソルと出力テンソルを手動で識別する方法について重点的に説明します。これは、説明メタデータ ファイルの準備の際に役立ちます。
説明メタデータの入力と出力
説明メタデータを準備するには、explanation_metadata.json
という名前のファイルにモデルの入力と出力を指定する必要があります。
{
"inputs": {
string <input feature key>: {
"input_tensor_name": string,
},
"outputs": {
string <output value key>: {
"output_tensor_name": string
},
},
"framework": "tensorflow"
}
ファイルの inputs
オブジェクトと outputs
オブジェクト内に、説明リクエストの入力テンソルと出力テンソルの名前を指定する必要があります。
- 入力キーと出力キー(上記の例の「入力特徴キー」と「出力値キー」)を使用して、各テンソルにわかりやすい名前を付けることができます。以下のサンプルでは、入力特徴キーは
degrees_celsius
で、出力値キーはprobabilities
です。 - メタデータ
input
およびoutput
のそれぞれの値に、input_tensor_name
またはoutput_tensor_name
としてテンソルの実際の名前を指定する必要があります。以下のサンプルでは、input_tensor_name
はx:0
であり、output_tensor_name
はdense/Softmax:0
です。
{
"inputs": {
"degrees_celsius": {
"input_tensor_name": "x:0",
}
},
"outputs": {
"probabilities": {
"output_tensor_name": "dense/Softmax:0"
}
},
"framework": "tensorflow"
}
実際のテンソル名の形式は、name:index
です。
入力テンソルと出力テンソルの検索
TensorFlow モデルをトレーニングした後、SavedModel としてエクスポートします。TensorFlow SavedModel には、トレーニング済みの TensorFlow モデルのほかに、シリアル化された署名、変数、グラフの実行に必要なその他のアセットが含まれています。各 SignatureDef
によって、テンソルの入力を受け入れ、テンソルの出力を生成するグラフ内の関数が特定されます。同様に、説明メタデータ ファイルによって、AI Explanations への特徴アトリビューション リクエストのグラフの入力と出力が定義されます。
説明メタデータ ファイルで指定した入力テンソルと出力テンソルは、モデルの保存時に定義した署名と正確に対応することがよくあります。そのような場合、入力テンソルと出力テンソルの名前を見つけるのは比較的簡単です。ただし、説明に使用する入力や出力が、モデルの保存時に定義したものとは異なる場合もあります。
次の場合、説明に使用する入力と出力は、サービング SignatureDef
に設定したものと同じになります。
- 入力の形式がシリアル化されていない
SignatureDef
への各入力に、特徴の値が直接含まれている(数値または文字列のいずれか)- 出力は数値データであり、数値データとして扱われます。これには、分類データとみなされるクラス ID は含まれません。
このような場合、モデルの作成中に入力テンソルと出力テンソルの名前を取得できます。あるいは、SavedModel CLI を使用して SavedModel の SignatureDef
を調べ、入力テンソルと出力テンソルの名前を見つけることもできます。
前述の条件を満たしていない場合は、別の手法を使用して、正しい入力テンソルと出力テンソルを見つけることができます。
トレーニング中にテンソル名を取得する
トレーニング中に入力テンソルと出力テンソルの名前にアクセスするのが最も簡単です。モデルの作成時に設定した変数にプログラムや環境がまだアクセスしている間に、説明メタデータ ファイルにこれらの値を保存できます。この例では、Keras レイヤの name
フィールドで、説明メタデータに必要な基本テンソル名が生成されます。
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 = keras.Model(inputs=bow_inputs, outputs=predictions)
print('input_tensor_name:', bow_inputs.name)
print('output_tensor_name:', predictions.name)
input_tensor_name: input_1:0
output_tensor_name: dense_1/Sigmoid:0
完全な動作例については、サンプル ノートブックをご覧ください。
署名定義からテンソル名を取得
SignatureDef
と説明メタデータは両方ともテンソルの入力と出力を識別することを考慮すると、前述の条件が満たされる場合、SignatureDef
を使用して説明メタデータ ファイルを準備できます。
次の 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
という名前の出力テンソルがあります。両方のテンソルに、それぞれ my_numpy_input
および probabilities
という意味のある名前もあります。my_numpy_input
に関して probabilities
に対する説明をリクエストするために、次のように説明メタデータ ファイルを作成できます。
{
"inputs": {
"my_numpy_input": {
"input_tensor_name": "x:0",
}
},
"outputs": {
"probabilities": {
"output_tensor_name": "dense/Softmax:0"
}
},
"framework": "tensorflow"
}
SavedModel CLI を使用して、SavedModel の SignatureDef
を調べることができます。詳細については、SavedModel CLI の使用方法を確認してください。
入力と出力の差異の処理
説明メタデータ内の入力テンソルと出力テンソルが、サービング 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(またはその他のグラフ表示ツール)を使用して、正しい出力テンソル名を見つけることができます。
統合勾配に関するその他の考慮事項
AI Explanations には、サンプリングされた Shapley と統合勾配という 2 つの特徴アトリビューション方式があります。統合勾配方式を使用する場合、出力に対して入力を微分できる必要があります。このため、説明メタデータを用意する際には、これに留意する必要があります。サンプリングされた Shapley 特徴アトリビューション方式を使用する場合、入力が微分可能であるかを確認する必要はありません。AI Explanations でサポートされている特徴アトリビューション方式について学習してください。
説明メタデータはモデルの特徴を入力と論理的に分離します。出力テンソルに対して微分できない入力テンソルが含まれた統合勾配を使用する場合は、その特徴のエンコードされた(微分可能な)バージョンも指定する必要があります。
微分不可能な入力テンソルがある場合、または微分不可能なオペレーションがグラフにある場合は、次の方法を使用します。
- 微分不可能な入力を微分可能な入力としてエンコードします。
- 元の微分不可能な入力テンソルの名前に
input_tensor_name
を設定し、かつ、そのエンコードされた微分可能なバージョンにencoded_tensor_name
を設定します。
エンコードを使用する説明メタデータ ファイル
たとえば、zip_codes:0
という名前の入力テンソルを持つカテゴリ特徴のあるモデルについて考えてみます。入力データには文字列として郵便番号が含まれているため、入力テンソル zip_codes:0
は微分不可能です。モデルでこのデータの前処理も行われ、郵便番号のワンホット エンコード表記が取得される場合、前処理後の入力テンソルは微分可能になります。元の入力テンソルと識別するために、前処理後のテンソルに zip_codes_embedding:0
という名前を付けることができます。
説明リクエストで両方の入力テンソルのデータを使用するには、メタデータ inputs
を次のように設定します。
- 入力特徴キーを
zip_codes
のようなわかりやすい名前に設定する。 input_tensor_name
を、元のテンソルの名前zip_codes:0
に設定する。encoded_tensor_name
を、ワンホット エンコードの後のテンソルの名前zip_codes_embedding:0
する。encoding
をcombined_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"
}
},
"framework": "tensorflow"
}
あるいは、input_tensor_name
を、エンコードされた微分可能な入力テンソルの名前に設定し、元の微分不可能なテンソルを除外することもできます。両方のテンソルを指定する利点は、ワンホット エンコード表現ではなく、個々の郵便番号値にアトリビューションを付けることができるということです。この例では、元のテンソル(zip_codes:0
)を除外し、input_tensor_name
を zip_codes_embedding:0
に設定します。この手法は、結果的に得られる特徴属性が推測しにくいため、おすすめしません。
エンコード
説明リクエストでエンコードを有効にするには、前の例に示されるようにエンコード設定を指定します。
エンコード機能は、エンコードされたデータからアトリビューションの入力データにプロセスを戻すのに役立ちます。これにより、返されたアトリビューションを手動で後処理する必要がなくなります。現在、AI Explanations では combined_embedding
がサポートされており、変数長の特徴は埋め込みに組み込まれています。この combined_embedding
に一致するサンプル オペレーションは tf.nn.embedding_lookup_sparse
です。
combined_embedding
の場合:
入力テンソルは 1D 配列にエンコードされます。例:
- 入力:
["This", "is", "a", "test"]
- エンコード済み:
[0.1, 0.2, 0.3, 0.4]