このページは Cloud Translation API によって翻訳されました。
Switch to English

統合された勾配

TensorFlow.orgで見る Google Colabで実行 GitHubでソースを表示する ノートブックをダウンロード

このチュートリアルでは、「 Axiomatic Attribution for Deep Networks」で紹介された説明可能なAI手法であるIntegrated Gradients(IG)を実装する方法を示します。 IGは、モデルの予測間の関係をその機能の観点から説明することを目的としています。機能の重要性の理解、データの偏りの特定、モデルのパフォーマンスのデバッグなど、多くのユースケースがあります。

IGは、あらゆる差別化可能なモデル(画像、テキスト、構造化データなど)への幅広い適用性、実装の容易さ、理論的な正当性、および大規模なネットワークと機能への拡張を可能にする代替アプローチと比較した計算効率により、人気のある解釈可能性手法になりました画像などのスペース。

このチュートリアルでは、IGの実装を段階的に説明し、画像分類子のピクセル機能の重要性を理解します。例として、消防艇が水ジェットを噴霧しているこの画像を考えてみましょう。あなたはこの画像を消防艇として分類し、ボートと水の大砲を構成するピクセルをあなたの決定にとって重要であると強調するかもしれません。モデルはこの画像をこのチュートリアルの後半で消防艇として分類します。ただし、その決定を説明するときに、同じピクセルを重要として強調表示しますか?

下の「IGアトリビューションマスク」および「オリジナル+ IGマスクオーバーレイ」というタイトルの画像では、モデルが代わりに、ボートのウォーターキャノンとウォータージェットを構成するピクセルを、ボート自体よりも重要であることを強調表示します(紫で)。その決定。モデルはどのように新しい消防艇に一般化されますか?ウォータージェットのない消防艇はどうですか? IGがどのように機能するか、モデルにIGを適用して、予測と基礎となる機能との関係をよりよく理解する方法について詳しく読んでください。

出力画像1

セットアップ

import matplotlib.pylab as plt
import numpy as np
import tensorflow as tf
import tensorflow_hub as hub

TF-Hubから事前学習済みの画像分類器をダウンロードする

IGは、あらゆる微分可能なモデルに適用できます。元の紙の精神に沿って 、同じモデルの事前トレーニング済みバージョンであるInception V1を使用します。これはTensorFlow Hubからダウンロードします。

model = tf.keras.Sequential([
                             hub.KerasLayer(name='inception_v1', 
                                            handle='https://tfhub.dev/google/imagenet/inception_v1/classification/4', 
                                            trainable=False),
                             ])
model.build([None, 224, 224, 3])
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
inception_v1 (KerasLayer)    (None, 1001)              6633209   
=================================================================
Total params: 6,633,209
Trainable params: 0
Non-trainable params: 6,633,209
_________________________________________________________________

モジュールページから、Inception V1について次の点に留意する必要があります。

入力 :モデルの予想される入力形状は(None, 224, 224, 3)です。これは、dtype float32と形状(batch_size, height, width, RGB channels)密な4Dテンソルで、要素は範囲[0、1]に正規化されたピクセルのRGBカラー値です。最初の要素はNoneで、モデルは任意の整数のバッチサイズを取ることができることを示します。

出力(batch_size, 1001)形のtf.Tensorのtf.Tensor。各行は、ImageNetの1,001クラスごとのモデルの予測スコアを表します。モデルの最上位予測クラスインデックスには、 tf.argmax(predictions, axis=-1)使用できます。さらに、 tf.nn.softmax(predictions, axis=-1)を使用して、モデルのロジット出力をすべてのクラスにわたって予測確率に変換し、モデルの不確実性を定量化し、デバッグのために同様の予測クラスを探索することもできます。

def load_imagenet_labels(file_path):
  labels_file = tf.keras.utils.get_file('ImageNetLabels.txt', file_path)
  with open(labels_file) as reader:
    f = reader.read()
    labels = f.splitlines()
  return np.array(labels)
imagenet_labels = load_imagenet_labels('https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt')

tf.image使用して画像を読み込んで前処理する

ウィキメディア・コモンズからの2つの画像( 火船ジャイアントパンダ)を使用してIGを説明します。

def read_image(file_name):
  image = tf.io.read_file(file_name)
  image = tf.image.decode_jpeg(image, channels=3)
  image = tf.image.convert_image_dtype(image, tf.float32)
  image = tf.image.resize_with_pad(image, target_height=224, target_width=224)
  return image
img_url = {
    'Fireboat': 'http://storage.googleapis.com/download.tensorflow.org/example_images/San_Francisco_fireboat_showing_off.jpg',
    'Giant Panda': 'http://storage.googleapis.com/download.tensorflow.org/example_images/Giant_Panda_2.jpeg',
}

img_paths = {name: tf.keras.utils.get_file(name, url) for (name, url) in img_url.items()}
img_name_tensors = {name: read_image(img_path) for (name, img_path) in img_paths.items()}
Downloading data from http://storage.googleapis.com/download.tensorflow.org/example_images/San_Francisco_fireboat_showing_off.jpg
3956736/3954129 [==============================] - 0s 0us/step
Downloading data from http://storage.googleapis.com/download.tensorflow.org/example_images/Giant_Panda_2.jpeg
811008/802859 [==============================] - 0s 0us/step

plt.figure(figsize=(8, 8))
for n, (name, img_tensors) in enumerate(img_name_tensors.items()):
  ax = plt.subplot(1, 2, n+1)
  ax.imshow(img_tensors)
  ax.set_title(name)
  ax.axis('off')
plt.tight_layout()

png

画像を分類する

これらの画像を分類し、最も信頼できる上位3つの予測を表示することから始めましょう。以下は、上位kの予測ラベルと確率を取得するユーティリティ関数です。

def top_k_predictions(img, k=3):
  image_batch = tf.expand_dims(img, 0)
  predictions = model(image_batch)
  probs = tf.nn.softmax(predictions, axis=-1)
  top_probs, top_idxs = tf.math.top_k(input=probs, k=k)
  top_labels = imagenet_labels[tuple(top_idxs)]
  return top_labels, top_probs[0]
for (name, img_tensor) in img_name_tensors.items():
  plt.imshow(img_tensor)
  plt.title(name, fontweight='bold')
  plt.axis('off')
  plt.show()

  pred_label, pred_prob = top_k_predictions(img_tensor)
  for label, prob in zip(pred_label, pred_prob):
    print(f'{label}: {prob:0.1%}')

png

fireboat: 32.6%
pier: 12.7%
suspension bridge: 5.7%

png

giant panda: 89.4%
teddy: 0.3%
gibbon: 0.3%

統合された勾配を計算する

モデルInception V1は、入力機能空間、画像ピクセル値、および0〜1のImageNetクラス確率値によって定義される出力空間の間のマッピングを記述する学習済み関数です。ニューラルネットワークの初期の解釈可能性メソッドは、モデルの予測関数に沿った特定のポイントで、モデルの予測と比べてどのピクセルが最も急勾配であるかを示すグラデーション。ただし、勾配は、ピクセル値に関するモデルの予測関数の局所的な変化のみを説明し、モデル予測関数全体を完全には説明しません。モデルが個々のピクセルの範囲と正しいImageNetクラスとの関係を完全に「学習」すると、このピクセルの勾配が飽和し 、次第に小さくなり、ゼロになることさえあります。以下の単純なモデル関数を考えてみましょう:

def f(x):
  """A simplified model function."""
  return tf.where(x < 0.8, x, 0.8)

def interpolated_path(x):
  """A straight line path."""
  return tf.zeros_like(x)

x = tf.linspace(start=0.0, stop=1.0, num=6)
y = f(x)
fig = plt.figure(figsize=(12, 5))
ax0 = fig.add_subplot(121)
ax0.plot(x, f(x), marker='o')
ax0.set_title('Gradients saturate over F(x)', fontweight='bold')
ax0.text(0.2, 0.5, 'Gradients > 0 = \n x is important')
ax0.text(0.7, 0.85, 'Gradients = 0 \n x not important')
ax0.set_yticks(tf.range(0, 1.5, 0.5))
ax0.set_xticks(tf.range(0, 1.5, 0.5))
ax0.set_ylabel('F(x) - model true class predicted probability')
ax0.set_xlabel('x - (pixel value)')

ax1 = fig.add_subplot(122)
ax1.plot(x, f(x), marker='o')
ax1.plot(x, interpolated_path(x), marker='>')
ax1.set_title('IG intuition', fontweight='bold')
ax1.text(0.25, 0.1, 'Accumulate gradients along path')
ax1.set_ylabel('F(x) - model true class predicted probability')
ax1.set_xlabel('x - (pixel value)')
ax1.set_yticks(tf.range(0, 1.5, 0.5))
ax1.set_xticks(tf.range(0, 1.5, 0.5))
ax1.annotate('Baseline', xy=(0.0, 0.0), xytext=(0.0, 0.2),
             arrowprops=dict(facecolor='black', shrink=0.1))
ax1.annotate('Input', xy=(1.0, 0.0), xytext=(0.95, 0.2),
             arrowprops=dict(facecolor='black', shrink=0.1))
plt.show();

png

  • :モデルのピクセルxの勾配は0.0から0.8の間で正ですが、0.8から1.0の間で0.0になります。 Pixel x明らかに、真のクラスの予測確率を80%に向けてモデルを推進することに大きな影響を与えます。 ピクセルxの重要性が小さいか不連続であることは理にかなっていますか?

  • :IGの背後にある直観は、ピクセルxのローカルグラディエントを累積し、モデルの全体的な出力クラス確率にどれだけ追加または減算するかのスコアとしてその重要性を属性化することです。 IGを3つの部分に分解して計算できます。

    1. 0(ベースラインまたは開始点)と1(入力ピクセルの値)の間のフィーチャ空間の直線に沿って小さなステップを補間します
    2. 各ステップに関するモデルの予測間の各ステップで勾配を計算する
    3. これらの局所勾配を累積(累積平均)することにより、ベースラインと入力の間の積分を概算します。

この直感を強化するために、下の「Fireboat」画像の例にIGを適用して、これら3つの部分をウォークスルーします。

ベースラインを確立する

ベースラインは、フィーチャの重要度を計算するための開始点として使用される入力画像です。直感的に、ベースラインの説明的な役割は、「Fireboat」予測に各ピクセルが存在しない場合の影響を表し、入力画像に存在する場合の「Fireboat」予測への各ピクセルの影響と対照的であると考えることができます。その結果、ベースラインの選択は、ピクセル機能の重要性を解釈および視覚化する上で中心的な役割を果たします。ベースラインの選択の詳細については、このチュートリアルの下部にある「次のステップ」セクションのリソースを参照してください。ここでは、ピクセル値がすべてゼロの黒の画像を使用します。

試すことができる他の選択肢には、真っ白な画像、またはtf.random.uniform(shape=(224,224,3), minval=0.0, maxval=1.0)作成できるランダムな画像が含まれます。

baseline = tf.zeros(shape=(224,224,3))
plt.imshow(baseline)
plt.title("Baseline")
plt.axis('off')
plt.show()

png

数式をコードに展開する

統合グラデーションの式は次のとおりです。

$ IntegratedGradients_ {i}(x):: =(x_ {i}-x '_ {i})\ times \ int _ {\ alpha = 0} ^ 1 \ frac {\ partial F(x' + \ alpha \ times (x-x '))} {\ partial x_i} {d \ alpha} $

どこ:

$ _ {i} $ =機能
$ x $ =入力
$ x '$ =ベースライン
$ \ alpha $ =特徴を摂動するための補間定数

実際には、定積分の計算は常に数値的に可能であるとは限らず、計算コストがかかる可能性があるため、次の数値近似を計算します。

$ IntegratedGrads ^ {approx} _ {i}(x):: =(x_ {i} -x '_ {i})\ times \ sum_ {k = 1} ^ {m} \ frac {\ partial F(x '+ \ frac {k} {m} \ times(x-x'))} {\ partial x_ {i}} \ times \ frac {1} {m} $

どこ:

$ _ {i} $ =機能(個々のピクセル)
$ x $ =入力(画像テンソル)
$ x '$ =ベースライン(画像テンソル)
$ k $ =スケーリングされた特徴摂動定数
$ m $ =積分のリーマン合計近似のステップ数
$(x_ {i} -x '_ {i})$ =ベースラインとの差の項。これは、統合されたグラデーションをスケーリングし、元の画像に関してそれらを維持するために必要です。ベースライン画像から入力へのパスはピクセル空間です。 IGを使用すると、直線(線形変換)で積分するので、これは、十分なステップのある$ \ alpha $に関する補間されたイメージ関数の導関数の積分項にほぼ等しくなります。積分は、各ピクセルの勾配に経路に沿ったピクセルの変化を掛けたものを合計します。 $ x:=(x '+ \ alpha(xx'))$に置き換えて、この統合を1つのイメージから別のイメージへの均一なステップとして実装する方が簡単です。したがって、変数の変更により、$ dx =(xx ')d \ alpha $が得られます。 $(xx ')$項は定数であり、積分から除算されます。

画像を補間する

$ IntegratedGrads ^ {approx} _ {i}(x):: =(x_ {i} -x '_ {i})\ times \ sum_ {k = 1} ^ {m} \ frac {\ partial F(\ overbrace {x '+ \ frac {k} {m} \ times(x-x')} ^ \ text {k個の間隔でm個の画像を補間})} {\ partial x_ {i}} \ times \ frac {1} {m} $

最初に、ベースラインと元の画像の間に線形補間を生成します。補間された画像は、ベースラインと入力の間の特徴空間の小さなステップと考えることができ、元の方程式の$ \ alpha $で表されます。

m_steps=50
alphas = tf.linspace(start=0.0, stop=1.0, num=m_steps+1) # Generate m_steps intervals for integral_approximation() below.
def interpolate_images(baseline,
                       image,
                       alphas):
  alphas_x = alphas[:, tf.newaxis, tf.newaxis, tf.newaxis]
  baseline_x = tf.expand_dims(baseline, axis=0)
  input_x = tf.expand_dims(image, axis=0)
  delta = input_x - baseline_x
  images = baseline_x +  alphas_x * delta
  return images

上記の関数を使用して、黒いベースライン画像とサンプルの「Fireboat」画像の間のアルファ間隔で線形パスに沿って補間画像を生成してみましょう。

interpolated_images = interpolate_images(
    baseline=baseline,
    image=img_name_tensors['Fireboat'],
    alphas=alphas)

補間された画像を視覚化しましょう。注:$ \ alpha $定数についての別の考え方は、補間された各画像の強度を常に増加させているということです。

fig = plt.figure(figsize=(20, 20))

i = 0
for alpha, image in zip(alphas[0::10], interpolated_images[0::10]):
  i += 1
  plt.subplot(1, len(alphas[0::10]), i)
  plt.title(f'alpha: {alpha:.1f}')
  plt.imshow(image)
  plt.axis('off')

plt.tight_layout();

png

勾配を計算する

次に、フィーチャの変更とモデルの予測の変更との関係を測定するために、勾配を計算する方法を見てみましょう。画像の場合、勾配は、どのピクセルがモデル予測クラス確率に最も強い影響を与えるかを示します。

$ IntegratedGrads ^ {approx} _ {i}(x):: =(x_ {i} -x '_ {i})\ times \ sum_ {k = 1} ^ {m} \ frac {\ overbrace {\ partial F(\ text {補間画像})} ^ \ text {計算勾配}} {\ partial x_ {i}} \ times \ frac {1} {m} $

どこ:
$ F()$ =モデルの予測関数
$ \ frac {\ partial {F}} {\ partial {x_i}} $ =各特徴$ x_i $に対するモデルFの予測関数の勾配(偏導関数のベクトル$ \ partial $)

TensorFlowでは、 tf.GradientTapeを使用して簡単にグラデーションを計算できます。

def compute_gradients(images, target_class_idx):
  with tf.GradientTape() as tape:
    tape.watch(images)
    logits = model(images)
    probs = tf.nn.softmax(logits, axis=-1)[:, target_class_idx]
  return tape.gradient(probs, images)

正しい出力に関して、補間パスに沿った各画像の勾配を計算してみましょう。モデルが、各クラスの予測確率に変換するロジットを含む(1、1001 (1, 1001)形状のTensorを返すことを思い出してください。正しいImageNetターゲットクラスインデックスをイメージのcompute_gradients関数に渡す必要があります。

path_gradients = compute_gradients(
    images=interpolated_images,
    target_class_idx=555)

(n_interpolated_images, img_height, img_width, RGB)の出力形状に注意してください。これにより、補間パスに沿ったすべての画像のすべてのピクセルの勾配が得られます。これらの勾配は、特徴空間の小さなステップごとのモデルの予測の変化を測定するものと考えることができます。

print(path_gradients.shape)
(51, 224, 224, 3)

勾配飽和の視覚化

上記で計算した勾配は、モデルの予測される「Fireboat」の確率に対する局所的な変化を表し、 飽和する可能性があることを思い出してください。

これらの概念は、下の2つのプロットで上で計算した勾配を使用して視覚化されます。

pred = model(interpolated_images)
pred_proba = tf.nn.softmax(pred, axis=-1)[:, 555]

plt.figure(figsize=(10, 4))
ax1 = plt.subplot(1, 2, 1)
ax1.plot(alphas, pred_proba)
ax1.set_title('Target class predicted probability over alpha')
ax1.set_ylabel('model p(target class)')
ax1.set_xlabel('alpha')
ax1.set_ylim([0, 1])

ax2 = plt.subplot(1, 2, 2)
# Average across interpolation steps
average_grads = tf.reduce_mean(path_gradients, axis=[1, 2, 3])
# Normalize gradients to 0 to 1 scale. E.g. (x - min(x))/(max(x)-min(x))
average_grads_norm = (average_grads-tf.math.reduce_min(average_grads))/(tf.math.reduce_max(average_grads)-tf.reduce_min(average_grads))
ax2.plot(alphas, average_grads_norm)
ax2.set_title('Average pixel gradients (normalized) over alpha')
ax2.set_ylabel('Average pixel gradients')
ax2.set_xlabel('alpha')
ax2.set_ylim([0, 1]);

png

  • :このプロットは、 "Fireboat"クラスに対するモデルの信頼度がアルファ全体でどのように変化するかを示しています。約40%の最終的な "Fireboat"予測確率に落ち着く前に、勾配、つまりラインの勾配が0.6〜1.0の間で大幅に平坦化または飽和することに注意してください。

  • right :右側のプロットは、アルファの平均勾配の大きさをより直接的に示しています。値が急激に近づき、一時的にゼロを下回ることに注意してください。実際、モデルは飽和する前に、アルファの低い値での勾配から最も「学習」します。直感的に、これはモデルがピクセルなどのピクセルを学習して正しい予測を行い、これらのピクセルグラディエントをゼロに送信するが、アルファ値が元の入力画像。

これらの重要なウォーターキャノンピクセルが "Fireboat"予測に重要であるように反映されるように、これらの勾配を累積して、各ピクセルが "Fireboat"予測確率にどのように影響するかを正確に概算する方法を学習します。

勾配の累積(積分近似)

IGの積分の数値近似を計算するには、さまざまな関数の精度と収束のトレードオフが異なる多くの方法があります。メソッドの人気のあるクラスはリーマン和と呼ばれます。ここでは、台形規則を使用します(このチュートリアルの最後に、さまざまな近似方法を調べるための追加コードを見つけることができます)。

$ IntegratedGrads ^ {approx} _ {i}(x):: =(x_ {i} -x '_ {i})\ times \ overbrace {\ sum_ {k = 1} ^ {m}} ^ \ text { m個のローカルグラデーションを合計} \ text {gradients(interpolated images)} \ times \ overbrace {\ frac {1} {m}} ^ \ text {Mステップで除算} $

方程式から、 m勾配を合計し、 mステップで除算していることがわかります。パート3の2つの演算を一緒に実装してm内挿予測と入力画像の局所勾配の平均として実装できます

def integral_approximation(gradients):
  # riemann_trapezoidal
  grads = (gradients[:-1] + gradients[1:]) / tf.constant(2.0)
  integrated_gradients = tf.math.reduce_mean(grads, axis=0)
  return integrated_gradients

integral_approximation関数は、ベースラインと元の画像の間の補間された画像に関して、ターゲットクラスの予測確率の勾配を取得します。

ig = integral_approximation(
    gradients=path_gradients)

m内挿画像の勾配全体の平均化により、元の「ジャイアントパンダ」画像と同じ形状の統合勾配テンソルが返されることを確認できます。

print(ig.shape)
(224, 224, 3)

すべてを一緒に入れて

次に、前の3つの一般的な部分をIntegratedGradientsしてIntegratedGradients関数にし、 @ tf.functionデコレーターを使用して、それを高性能の呼び出し可能なTensorFlowグラフにコンパイルします。これは、以下の5つの小さなステップとして実装されます。

$ IntegratedGrads ^ {approx} _ {i}(x):: = \ overbrace {(x_ {i} -x '_ {i})} ^ \ text {5。} \ times \ overbrace {\ sum_ {k = 1} ^ {m}} ^ \ text {4。} \ frac {\ partial \ overbrace {F(\ overbrace {x '+ \ overbrace {\ frac {k} {m}} ^ \ text {1。} \ times(x-x '))} ^ \ text {2。}} ^ \ text {3。}} {\ partial x_ {i}} \ times \ overbrace {\ frac {1} {m}} ^ \ text {4。} $

  1. アルファ$ \ alpha $を生成

  2. 補間画像を生成= $(x '+ \ frac {k} {m} \ times(x-x'))$

  3. 入力特徴に関するモデル$ F $出力予測間の勾配を計算= $ \ frac {\ partial F(\ text {interpolated path input})} {\ partial x_ {i}} $

  4. 勾配の平均化による積分近似= $ \ sum_ {k = 1} ^ m \ text {gradients} \ times \ frac {1} {m} $

  5. 元の画像に対して統合された勾配をスケーリング= $(x_ {i} -x '_ {i})\ times \ text {integrated gradients} $。この手順が必要な理由は、複数の補間画像にわたって累積された属性値が同じ単位になり、元の画像のピクセルの重要性を忠実に表すようにするためです。

@tf.function
def integrated_gradients(baseline,
                         image,
                         target_class_idx,
                         m_steps=50,
                         batch_size=32):
  # 1. Generate alphas.
  alphas = tf.linspace(start=0.0, stop=1.0, num=m_steps+1)

  # Initialize TensorArray outside loop to collect gradients.    
  gradient_batches = tf.TensorArray(tf.float32, size=m_steps+1)
    
  # Iterate alphas range and batch computation for speed, memory efficiency, and scaling to larger m_steps.
  for alpha in tf.range(0, len(alphas), batch_size):
    from_ = alpha
    to = tf.minimum(from_ + batch_size, len(alphas))
    alpha_batch = alphas[from_:to]

    # 2. Generate interpolated inputs between baseline and input.
    interpolated_path_input_batch = interpolate_images(baseline=baseline,
                                                       image=image,
                                                       alphas=alpha_batch)

    # 3. Compute gradients between model outputs and interpolated inputs.
    gradient_batch = compute_gradients(images=interpolated_path_input_batch,
                                       target_class_idx=target_class_idx)
    
    # Write batch indices and gradients to extend TensorArray.
    gradient_batches = gradient_batches.scatter(tf.range(from_, to), gradient_batch)    
  
  # Stack path gradients together row-wise into single tensor.
  total_gradients = gradient_batches.stack()

  # 4. Integral approximation through averaging gradients.
  avg_gradients = integral_approximation(gradients=total_gradients)

  # 5. Scale integrated gradients with respect to input.
  integrated_gradients = (image - baseline) * avg_gradients

  return integrated_gradients
ig_attributions = integrated_gradients(baseline=baseline,
                                       image=img_name_tensors['Fireboat'],
                                       target_class_idx=555,
                                       m_steps=240)

ここでも、IG機能の属性が入力「Fireboat」画像と同じ形状であることを確認できます。

print(ig_attributions.shape)
(224, 224, 3)

このペーパーでは、例に応じてステップ数を20から300の範囲で指定することを推奨しています(実際には、積分を正確に概算するために、1,000でこれを高くすることができます)。このチュートリアルの最後にある「次のステップ」リソースで、適切な数のステップを確認するための追加のコードを見つけることができます。

アトリビューションを視覚化する

属性を視覚化し、元の画像にオーバーレイする準備が整いました。以下のコードは、カラーチャネル全体の統合されたグラデーションの絶対値を合計して、属性マスクを生成します。このプロット方法は、モデルの予測に対するピクセルの相対的な影響をキャプチャします。

def plot_img_attributions(baseline,
                          image,
                          target_class_idx,
                          m_steps=50,
                          cmap=None,
                          overlay_alpha=0.4):

  attributions = integrated_gradients(baseline=baseline,
                                      image=image,
                                      target_class_idx=target_class_idx,
                                      m_steps=m_steps)

  # Sum of the attributions across color channels for visualization.
  # The attribution mask shape is a grayscale image with height and width
  # equal to the original image.
  attribution_mask = tf.reduce_sum(tf.math.abs(attributions), axis=-1)

  fig, axs = plt.subplots(nrows=2, ncols=2, squeeze=False, figsize=(8, 8))

  axs[0, 0].set_title('Baseline image')
  axs[0, 0].imshow(baseline)
  axs[0, 0].axis('off')

  axs[0, 1].set_title('Original image')
  axs[0, 1].imshow(image)
  axs[0, 1].axis('off')

  axs[1, 0].set_title('Attribution mask')
  axs[1, 0].imshow(attribution_mask, cmap=cmap)
  axs[1, 0].axis('off')

  axs[1, 1].set_title('Overlay')
  axs[1, 1].imshow(attribution_mask, cmap=cmap)
  axs[1, 1].imshow(image, alpha=overlay_alpha)
  axs[1, 1].axis('off')

  plt.tight_layout()
  return fig

「Fireboat」の画像の属性を見ると、モデルが水の大砲と注ぎ口を正確な予測に寄与していると識別していることがわかります。

_ = plot_img_attributions(image=img_name_tensors['Fireboat'],
                          baseline=baseline,
                          target_class_idx=555,
                          m_steps=240,
                          cmap=plt.cm.inferno,
                          overlay_alpha=0.4)

png

「ジャイアントパンダ」の画像では、属性がパンダの顔の質感、鼻、毛皮を強調しています。

_ = plot_img_attributions(image=img_name_tensors['Giant Panda'],
                          baseline=baseline,
                          target_class_idx=389,
                          m_steps=55,
                          cmap=plt.cm.viridis,
                          overlay_alpha=0.5)

png

使用と制限

ユースケース

  • モデルをデプロイする前に統合グラデーションなどの手法を採用すると、モデルが機能する方法と理由を直感的に理解できるようになります。この手法で強調表示された機能はあなたの直感と一致していますか?そうでない場合は、モデルまたはデータセットのバグ、または過剰適合を示している可能性があります。

制限事項

  • 統合グラデーションは、個々の例に機能の重要性を提供しますが、データセット全体にわたるグローバルな機能の重要性は提供しません。

  • 統合グラデーションは、個々の機能の重要性を提供しますが、機能の相互作用や組み合わせについては説明していません。

次のステップ

このチュートリアルでは、統合グラデーションの基本的な実装について説明しました。次のステップとして、このノートブックを使用して、この手法をさまざまなモデルや画像で自分で試すことができます。

興味のある読者のために、このチュートリアルのより長いバージョン(さまざまなベースラインのコードを含み、積分近似を計算し、十分な数のステップを決定するため)がここにあります

理解を深めるには、TensorFlowの以前のバージョンの実装が含まれている、ペーパー「 Axiomatic Attribution for Deep Networks and Github repository 」を確認してください。また、機能の属性と、さまざまなベースラインがdistill.pubに与える影響を調べることもできます。

IGを機能の重要性、モデルエラー分析、データスキューモニタリングのために本番の機械学習ワークフローに組み込むことに興味がありますか? IG属性をサポートするGoogle Cloudの説明可能なAI製品をご覧ください。また、Google AI PAIR研究グループは、IG機能の属性の視覚化など、モデルのデバッグに使用できるWhat-ifツールをオープンソース化しました。