Halaman ini diterjemahkan oleh Cloud Translation API.
Switch to English

Gradien terintegrasi

Lihat di TensorFlow.org Jalankan di Google Colab Lihat di GitHub Unduh buku catatan Lihat model TF Hub

Tutorial ini mendemonstrasikan cara mengimplementasikan Gradien Terpadu (IG) , teknik AI yang Dapat Dijelaskan yang diperkenalkan dalam makalah Axiomatic Attribution for Deep Networks . IG bertujuan untuk menjelaskan hubungan antara prediksi model dari segi fiturnya. Ini memiliki banyak kasus penggunaan termasuk memahami pentingnya fitur, mengidentifikasi kemiringan data, dan kinerja model debugging.

IG telah menjadi teknik interpretabilitas yang populer karena penerapannya yang luas pada model yang dapat dibedakan (misalnya gambar, teks, data terstruktur), kemudahan implementasi, justifikasi teoretis, dan efisiensi komputasi relatif terhadap pendekatan alternatif yang memungkinkannya untuk berskala ke jaringan dan fitur yang besar ruang seperti gambar.

Dalam tutorial ini, Anda akan menjelaskan implementasi IG selangkah demi selangkah untuk memahami pentingnya fitur piksel dari pengklasifikasi gambar. Sebagai contoh, perhatikan gambar kapal pemadam kebakaran yang menyemprotkan semburan air. Anda akan mengklasifikasikan gambar ini sebagai kapal pemadam kebakaran dan mungkin menyoroti piksel yang menyusun perahu dan meriam air sebagai hal yang penting untuk keputusan Anda. Model Anda juga akan mengklasifikasikan gambar ini sebagai kapal pemadam nanti dalam tutorial ini; Namun, apakah itu menyoroti piksel yang sama dengan pentingnya saat menjelaskan keputusannya?

Pada gambar di bawah yang berjudul "IG Attribution Mask" dan "Original + IG Mask Overlay", Anda dapat melihat bahwa model Anda malah menyorot (dalam warna ungu) piksel yang terdiri dari meriam air kapal dan semburan air sebagai hal yang lebih penting daripada perahu itu sendiri. keputusannya. Bagaimana model Anda akan digeneralisasi ke fireboats baru? Bagaimana dengan kapal pemadam tanpa jet air? Baca terus untuk mempelajari lebih lanjut tentang cara kerja IG dan cara menerapkan IG ke model Anda untuk lebih memahami hubungan antara prediksi dan fitur dasarnya.

Gambar Keluaran 1

Mendirikan

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

Unduh pengklasifikasi gambar yang telah dilatih sebelumnya dari TF-Hub

IG dapat diterapkan pada model yang dapat dibedakan. Sesuai dengan makalah aslinya, Anda akan menggunakan versi terlatih dari model yang sama, Inception V1, yang akan Anda download dari 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
_________________________________________________________________

Dari halaman modul, Anda perlu mengingat hal-hal berikut tentang Inception V1:

Input : Bentuk input yang diharapkan untuk model adalah (None, 224, 224, 3) . Ini adalah tensor 4D padat dari dtype float32 dan bentuk (batch_size, height, width, RGB channels) yang elemennya adalah nilai warna RGB dari piksel yang dinormalisasi ke kisaran [0, 1]. Elemen pertama adalah None untuk menunjukkan bahwa model dapat mengambil ukuran batch integer apa pun.

Output : tf.Tensor logit dalam bentuk (batch_size, 1001) . Setiap baris mewakili skor prediksi model untuk masing-masing 1.001 kelas dari ImageNet. Untuk indeks kelas prediksi teratas model, Anda dapat menggunakan tf.argmax(predictions, axis=-1) . Selain itu, Anda juga dapat mengonversi keluaran logit model menjadi probabilitas yang diprediksi di semua kelas menggunakan tf.nn.softmax(predictions, axis=-1) untuk mengukur ketidakpastian model serta menjelajahi kelas prediksi serupa untuk debugging.

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')

Muat dan praproses gambar dengan tf.image

Anda akan mengilustrasikan IG menggunakan dua gambar dari Wikimedia Commons : Fireboat , dan Giant Panda .

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

Klasifikasikan gambar

Mari kita mulai dengan mengklasifikasikan gambar-gambar ini dan menampilkan 3 prediksi paling percaya diri. Berikut ini adalah fungsi utilitas untuk mengambil label prediksi dan probabilitas teratas.

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%

Hitung Gradien Terintegrasi

Model Anda, Inception V1, adalah fungsi yang dipelajari yang mendeskripsikan pemetaan antara ruang fitur masukan, nilai piksel gambar, dan ruang keluaran yang ditentukan oleh nilai probabilitas kelas ImageNet antara 0 dan 1. Metode interpretabilitas awal untuk jaringan neural yang menetapkan skor kepentingan fitur menggunakan gradien, yang memberi tahu Anda piksel mana yang memiliki relatif lokal paling curam terhadap prediksi model Anda pada titik tertentu di sepanjang fungsi prediksi model Anda. Namun, gradien hanya mendeskripsikan perubahan lokal dalam fungsi prediksi model Anda sehubungan dengan nilai piksel dan tidak sepenuhnya mendeskripsikan seluruh fungsi prediksi model Anda. Saat model Anda sepenuhnya "mempelajari" hubungan antara rentang piksel individual dan kelas ImageNet yang benar, gradien untuk piksel ini akan tersaturasi , artinya menjadi semakin kecil dan bahkan menjadi nol. Pertimbangkan fungsi model sederhana di bawah ini:

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

  • kiri : Gradien model Anda untuk piksel x positif antara 0,0 dan 0,8 tetapi pergi ke 0,0 antara 0,8 dan 1,0. Pixel x jelas memiliki pengaruh yang signifikan dalam mendorong model Anda menuju prediksi probabilitas 80% di kelas sebenarnya. Apakah masuk akal bahwa kepentingan piksel x kecil atau terputus-putus?

  • kanan : Intuisi di balik IG adalah mengakumulasikan gradien lokal piksel x dan mengatribusikan kepentingannya sebagai skor untuk seberapa banyak ia menambah atau mengurangi probabilitas kelas keluaran model Anda secara keseluruhan. Anda dapat memecah dan menghitung IG dalam 3 bagian:

    1. interpolasi langkah-langkah kecil di sepanjang garis lurus di ruang fitur antara 0 (garis dasar atau titik awal) dan 1 (nilai piksel input)
    2. menghitung gradien di setiap langkah di antara prediksi model Anda terkait dengan setiap langkah
    3. perkirakan integral antara garis dasar dan masukan Anda dengan mengakumulasikan (rata-rata kumulatif) gradien lokal ini.

Untuk memperkuat intuisi ini, Anda akan menelusuri 3 bagian ini dengan menerapkan IG ke contoh gambar "Kapal Pengapian" di bawah.

Tetapkan garis dasar

Garis dasar adalah gambar masukan yang digunakan sebagai titik awal untuk menghitung kepentingan fitur. Secara intuitif, Anda dapat menganggap peran penjelasan garis dasar sebagai representasi dampak dari tidak adanya setiap piksel pada prediksi "Fireboat" agar kontras dengan dampaknya dari setiap piksel pada prediksi "Fireboat" saat ada dalam gambar masukan. Akibatnya, pilihan baseline memainkan peran sentral dalam menafsirkan dan memvisualisasikan pentingnya fitur piksel. Untuk diskusi tambahan tentang pemilihan garis dasar, lihat sumber daya di bagian "Langkah selanjutnya" di bagian bawah tutorial ini. Di sini, Anda akan menggunakan gambar hitam yang semua nilai pikselnya nol.

Pilihan lain yang dapat Anda coba termasuk gambar putih seluruhnya, atau gambar acak, yang dapat Anda buat dengan 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

Uraikan rumus menjadi kode

Rumus Gradien Terintegrasi adalah sebagai berikut:

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

dimana:

$ _ {i} $ = fitur
$ x $ = masukan
$ x '$ = garis dasar
$ \ alpha $ = konstanta interpolasi ke fitur perturbe oleh

Dalam praktiknya, menghitung integral tertentu tidak selalu memungkinkan secara numerik dan dapat menjadi mahal secara komputasi, jadi Anda menghitung perkiraan numerik berikut:

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

dimana:

$ _ {i} $ = fitur (piksel individu)
$ x $ = masukan (tensor gambar)
$ x '$ = garis dasar (tensor gambar)
$ k $ = konstanta gangguan fitur berskala
$ m $ = jumlah langkah dalam pendekatan penjumlahan Riemann dari integral
$ (x_ {i} -x '_ {i}) $ = istilah untuk perbedaan dari garis dasar. Ini diperlukan untuk mengatur skala gradien terintegrasi dan menyimpannya dalam bentuk gambar asli. Jalur dari gambar baseline ke input berada dalam ruang piksel. Karena dengan IG Anda mengintegrasikan dalam garis lurus (transformasi linier), ini akhirnya kira-kira setara dengan suku integral dari turunan fungsi gambar yang diinterpolasi sehubungan dengan $ \ alpha $ dengan langkah yang cukup. Jumlah integral setiap gradien piksel dikalikan dengan perubahan piksel di sepanjang jalur. Lebih mudah untuk mengimplementasikan integrasi ini sebagai langkah seragam dari satu gambar ke gambar lainnya, dengan mengganti $ x: = (x '+ \ alpha (xx')) $. Jadi perubahan variabel memberikan $ dx = (xx ') d \ alpha $. Suku $ (xx ') $ konstan dan difaktorkan keluar dari integral.

Interpolasi gambar

$ IntegratedGrads ^ {kira-kira} _ {i} (x) :: = (x_ {i} -x '_ {i}) \ times \ sum_ {k = 1} ^ {m} \ frac {\ parsial F (\ melebihi {x '+ \ frac {k} {m} \ times (x - x')} ^ \ text {interpolasi m gambar dengan interval k})} {\ parsial x_ {i}} \ times \ frac {1} {m} $

Pertama, Anda akan menghasilkan interpolasi linier antara garis dasar dan gambar asli. Anda dapat menganggap gambar yang diinterpolasi sebagai langkah kecil dalam ruang fitur antara garis dasar dan masukan Anda, yang diwakili oleh $ \ alpha $ dalam persamaan asli.

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

Mari gunakan fungsi di atas untuk menghasilkan gambar interpolasi sepanjang jalur linier pada interval alfa antara gambar dasar hitam dan contoh gambar "Fireboat".

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

Mari visualisasikan gambar yang diinterpolasi. Catatan: cara lain untuk memikirkan konstanta $ \ alpha $ adalah secara konsisten meningkatkan intensitas setiap gambar yang diinterpolasi.

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

Hitung gradien

Sekarang mari kita lihat cara menghitung gradien untuk mengukur hubungan antara perubahan fitur dan perubahan dalam prediksi model. Dalam kasus gambar, gradien memberi tahu kita piksel mana yang memiliki efek terkuat pada model yang memprediksi probabilitas kelas.

$ IntegratedGrads ^ {kira-kira} _ {i} (x) :: = (x_ {i} -x '_ {i}) \ times \ sum_ {k = 1} ^ {m} \ frac {\ overbrace {\ parsial F (\ text {gambar yang diinterpolasi})} ^ \ text {menghitung gradien}} {\ sebagian x_ {i}} \ times \ frac {1} {m} $

dimana:
$ F () $ = fungsi prediksi model Anda
$ \ frac {\ partial {F}} {\ partial {x_i}} $ = gradien (vektor turunan sebagian $ \ partial $) fungsi prediksi model F Anda relatif terhadap setiap fitur $ x_i $

TensorFlow memudahkan komputasi gradien bagi Anda dengan 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)

Mari menghitung gradien untuk setiap gambar di sepanjang jalur interpolasi sehubungan dengan keluaran yang benar. Ingatlah bahwa model Anda menampilkan Tensor berbentuk (1, 1001) dengan logit yang Anda ubah menjadi probabilitas yang diprediksi untuk setiap kelas. Anda harus meneruskan indeks kelas target ImageNet yang benar ke fungsi compute_gradients untuk gambar Anda.

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

Perhatikan bentuk keluaran (n_interpolated_images, img_height, img_width, RGB) , yang memberi kita gradien untuk setiap piksel dari setiap gambar di sepanjang jalur interpolasi. Anda dapat menganggap gradien ini sebagai mengukur perubahan dalam prediksi model Anda untuk setiap langkah kecil dalam ruang fitur.

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

Memvisualisasikan saturasi gradien

Ingatlah bahwa gradien yang baru saja Anda hitung di atas mendeskripsikan perubahan lokal pada prediksi probabilitas "Fireboat" model Anda dan dapat menjenuhkan .

Konsep-konsep ini divisualisasikan menggunakan gradien yang Anda hitung di atas pada 2 plot di bawah ini.

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]);
(0.0, 1.0)

png

  • kiri : Plot ini menunjukkan bagaimana tingkat kepercayaan model Anda pada kelas "Fireboat" bervariasi di seluruh alpha. Perhatikan bagaimana gradien, atau kemiringan garis, sebagian besar mendatar atau menjenuhkan antara 0,6 dan 1,0 sebelum menetap di probabilitas prediksi "Fireboat" akhir sekitar 40%.

  • kanan : Plot kanan menunjukkan besaran gradien rata-rata di atas alfa secara lebih langsung. Perhatikan bagaimana nilai mendekati tajam dan bahkan turun sebentar di bawah nol. Faktanya, model Anda "belajar" paling banyak dari gradien pada nilai alfa yang lebih rendah sebelum jenuh. Secara intuitif, Anda dapat menganggap ini sebagai model Anda telah mempelajari piksel misalnya meriam air untuk membuat prediksi yang benar, mengirimkan gradien piksel ini ke nol, tetapi masih cukup tidak pasti dan fokus pada piksel jembatan atau jet air palsu saat nilai alfa mendekati gambar masukan asli.

Untuk memastikan piksel meriam air yang penting ini direfleksikan sebagai hal yang penting untuk prediksi "Fireboat", Anda akan melanjutkan di bawah ini untuk mempelajari cara mengumpulkan gradien ini untuk secara akurat memperkirakan bagaimana setiap piksel memengaruhi probabilitas prediksi "Fireboat" Anda.

Akumulasi gradien (perkiraan integral)

Ada banyak cara berbeda yang dapat Anda lakukan tentang menghitung perkiraan numerik dari integral untuk IG dengan pengorbanan yang berbeda dalam akurasi dan konvergensi di berbagai fungsi. Kelas metode yang populer disebut jumlah Riemann . Di sini, Anda akan menggunakan aturan Trapesium (Anda dapat menemukan kode tambahan untuk menjelajahi berbagai metode pendekatan di akhir tutorial ini).

$ IntegratedGrads ^ {kira-kira} _ {i} (x) :: = (x_ {i} -x '_ {i}) \ times \ overbrace {\ sum_ {k = 1} ^ {m}} ^ \ text { Sum m gradien lokal} \ text {gradien (gambar terinterpolasi)} \ times \ overbrace {\ frac {1} {m}} ^ \ text {Bagi dengan m langkah} $

Dari persamaan tersebut, Anda dapat melihat bahwa Anda menjumlahkan gradien m dan membaginya dengan langkah m . Anda dapat mengimplementasikan dua operasi bersama untuk bagian 3 sebagai rata - rata gradien lokal dari m prediksi yang diinterpolasi dan gambar input .

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

Fungsi integral_approximation mengambil gradien dari kemungkinan prediksi kelas target sehubungan dengan gambar yang diinterpolasi antara gambar dasar dan gambar asli.

ig = integral_approximation(
    gradients=path_gradients)

Anda dapat mengonfirmasi bahwa rata-rata di seluruh gradien m gambar yang diinterpolasi mengembalikan tensor gradien terintegrasi dengan bentuk yang sama seperti gambar "Panda Raksasa" asli.

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

Menyatukan semuanya

Sekarang Anda akan menggabungkan 3 bagian umum sebelumnya menjadi satu fungsi IntegratedGradients dan menggunakan dekorator @ tf.function untuk mengompilasinya menjadi grafik TensorFlow yang dapat dipanggil dengan performa tinggi. Ini diimplementasikan sebagai 5 langkah kecil di bawah ini:

$ IntegratedGrads ^ {kira-kira} _ {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.} \ kali (x - x '))} ^ \ text {2.}} ^ \ text {3.}} {\ sebagian x_ {i}} \ times \ overbrace {\ frac {1} {m}} ^ \ text {4.} $

  1. Hasilkan alfa $ \ alpha $

  2. Hasilkan gambar interpolasi = $ (x '+ \ frac {k} {m} \ times (x - x')) $

  3. Hitung gradien antara prediksi keluaran model $ F $ sehubungan dengan fitur masukan = $ \ frac {\ partial F (\ text {interpolated path input})} {\ partial x_ {i}} $

  4. Pendekatan integral melalui gradien rata-rata = $ \ sum_ {k = 1} ^ m \ text {gradients} \ times \ frac {1} {m} $

  5. Skala gradien terintegrasi sehubungan dengan gambar asli = $ (x_ {i} -x '_ {i}) \ times \ text {gradien terintegrasi} $. Alasan langkah ini diperlukan adalah untuk memastikan bahwa nilai atribusi yang terkumpul di beberapa gambar yang diinterpolasi berada dalam unit yang sama dan dengan tepat merepresentasikan pentingnya piksel pada gambar asli.

@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)

Sekali lagi, Anda dapat memeriksa apakah atribut fitur IG memiliki bentuk yang sama dengan gambar input "Fireboat".

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

Makalah ini menyarankan jumlah langkah untuk berkisar antara 20 hingga 300 tergantung pada contoh (meskipun dalam praktiknya ini bisa lebih tinggi dalam 1.000 untuk secara akurat mendekati integral). Anda dapat menemukan kode tambahan untuk memeriksa jumlah langkah yang sesuai di sumber daya "Langkah berikutnya" di akhir tutorial ini.

Visualisasikan atribusi

Anda siap untuk memvisualisasikan atribusi, dan menghamparkannya pada gambar asli. Kode di bawah ini menjumlahkan nilai absolut dari gradien terintegrasi di seluruh saluran warna untuk menghasilkan topeng atribusi. Metode plot ini menangkap dampak relatif piksel pada prediksi model.

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

Melihat atribusi pada gambar "Fireboat", Anda dapat melihat model tersebut mengidentifikasi meriam air dan semburan sebagai kontribusi untuk prediksi yang benar.

_ = 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

Pada gambar "Panda Raksasa", atribusi menyoroti tekstur, hidung, dan bulu wajah Panda.

_ = 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

Penggunaan dan batasan

Kasus penggunaan

  • Menerapkan teknik seperti Gradien Terpadu sebelum menerapkan model Anda dapat membantu Anda mengembangkan intuisi tentang bagaimana dan mengapa model itu bekerja. Apakah fitur yang disorot oleh teknik ini sesuai dengan intuisi Anda? Jika tidak, itu mungkin merupakan indikasi bug dalam model atau dataset Anda, atau overfitting.

Batasan

  • Gradien Terintegrasi memberikan nilai penting fitur pada masing-masing contoh, namun tidak memberikan nilai penting fitur global di seluruh kumpulan data.

  • Gradien Terintegrasi memberikan kepentingan fitur individual, tetapi tidak menjelaskan interaksi dan kombinasi fitur.

Langkah selanjutnya

Tutorial ini menyajikan implementasi dasar Gradien Terintegrasi. Sebagai langkah selanjutnya, Anda dapat menggunakan notebook ini untuk mencoba teknik ini dengan model dan gambar yang berbeda.

Untuk pembaca yang tertarik, ada versi yang lebih panjang dari tutorial ini (yang menyertakan kode untuk baseline yang berbeda, untuk menghitung perkiraan integral, dan untuk menentukan jumlah langkah yang cukup) yang dapat Anda temukan di sini .

Untuk memperdalam pemahaman Anda, lihat makalah Axiomatic Attribution untuk Deep Networks dan repositori Github , yang berisi implementasi dalam versi TensorFlow sebelumnya. Anda juga dapat menjelajahi atribusi fitur, dan dampak dari berbagai baseline, di distill.pub .

Tertarik untuk memasukkan IG ke dalam alur kerja machine learning produksi Anda untuk kepentingan fitur, analisis kesalahan model, dan pemantauan kemiringan data? Lihat produk AI Google Cloud yang Dapat Dijelaskan yang mendukung atribusi IG. Grup penelitian Google AI PAIR juga membuka sumber alat Bagaimana-jika yang dapat digunakan untuk debugging model, termasuk memvisualisasikan atribusi fitur IG.