Lihat di TensorFlow.org | Jalankan di Google Colab | Lihat di GitHub | Unduh buku catatan | Lihat model TF Hub |
Tutorial ini menunjukkan cara menerapkan Gradien Terpadu (IG) , teknik AI yang Dapat Dijelaskan yang diperkenalkan dalam makalah Atribusi Aksiomatik untuk Jaringan Dalam . IG bertujuan untuk menjelaskan hubungan antara prediksi model dalam hal fitur-fiturnya. Ini memiliki banyak kasus penggunaan termasuk memahami pentingnya fitur, mengidentifikasi kemiringan data, dan men-debug kinerja model.
IG telah menjadi teknik interpretasi yang populer karena penerapannya yang luas untuk setiap model yang dapat dibedakan (misalnya gambar, teks, data terstruktur), kemudahan implementasi, pembenaran teoretis, dan efisiensi komputasi relatif terhadap pendekatan alternatif yang memungkinkannya untuk skala ke jaringan dan fitur besar. ruang seperti gambar.
Dalam tutorial ini, Anda akan berjalan melalui implementasi IG langkah demi langkah 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 membentuk perahu dan meriam air sebagai hal yang penting untuk keputusan Anda. Model Anda juga akan mengklasifikasikan gambar ini sebagai kapal pemadam kebakaran nanti dalam tutorial ini; namun, apakah ini menyoroti piksel yang sama dengan pentingnya saat menjelaskan keputusannya?
Pada gambar di bawah berjudul "IG Attribution Mask" dan "Original + IG Mask Overlay" Anda dapat melihat bahwa model Anda malah menyoroti (dalam warna ungu) piksel yang terdiri dari meriam air dan semburan air sebagai hal yang lebih penting daripada perahu itu sendiri. keputusannya. Bagaimana model Anda akan digeneralisasi ke kapal pemadam kebakaran baru? Bagaimana dengan kapal pemadam kebakaran 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 mereka dan fitur yang mendasarinya.
Mempersiapkan
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 terdiferensiasi apa pun. Dalam semangat makalah asli, Anda akan menggunakan versi pra-latihan dari model yang sama, Inception V1, yang akan Anda unduh 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 berikut tentang Inception V1:
Masukan : Bentuk masukan 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 piksel yang dinormalisasi ke kisaran [0, 1]. Elemen pertama adalah None
untuk menunjukkan bahwa model dapat mengambil ukuran batch bilangan bulat apa pun.
Keluaran : Sebuah tf.Tensor
dari logit dalam bentuk (batch_size, 1001)
. Setiap baris mewakili skor prediksi model untuk masing-masing dari 1.001 kelas dari ImageNet. Untuk indeks kelas prediksi teratas model, Anda dapat menggunakan tf.argmax(predictions, axis=-1)
. Selanjutnya, Anda juga dapat mengonversi keluaran logit model ke 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 : Kapal Api , dan Panda Raksasa .
def read_image(file_name):
image = tf.io.read_file(file_name)
image = tf.io.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 3964928/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 819200/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()
Mengklasifikasikan gambar
Mari kita mulai dengan mengklasifikasikan gambar-gambar ini dan menampilkan 3 prediksi paling percaya diri. Berikut ini adalah fungsi utilitas untuk mengambil k label dan probabilitas prediksi 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%}')
fireboat: 32.6% pier: 12.7% suspension bridge: 5.7%
giant panda: 89.4% teddy: 0.3% gibbon: 0.3%
Hitung Gradien Terintegrasi
Model Anda, Inception V1, adalah fungsi yang dipelajari yang menjelaskan pemetaan antara ruang fitur masukan, nilai piksel gambar, dan ruang keluaran yang ditentukan oleh nilai probabilitas kelas ImageNet antara 0 dan 1. Metode interpretasi awal untuk jaringan saraf menetapkan skor pentingnya 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 menjelaskan perubahan lokal dalam fungsi prediksi model Anda sehubungan dengan nilai piksel dan tidak sepenuhnya menggambarkan 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 jenuh , artinya menjadi semakin kecil dan bahkan menjadi nol. Perhatikan 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();
kiri : Gradien model Anda untuk piksel
x
positif antara 0,0 dan 0,8 tetapi menuju 0,0 antara 0,8 dan 1,0. Pixelx
jelas memiliki dampak signifikan dalam mendorong model Anda menuju probabilitas prediksi 80% pada kelas sebenarnya. Apakah masuk akal bahwa kepentingan pikselx
kecil atau terputus-putus?kanan : Intuisi di balik IG adalah untuk mengakumulasi gradien lokal piksel
x
dan mengaitkan kepentingannya sebagai skor untuk seberapa banyak ia menambah atau mengurangi probabilitas kelas keluaran keseluruhan model Anda. Anda dapat memecah dan menghitung IG dalam 3 bagian:- interpolasi langkah-langkah kecil di sepanjang garis lurus di ruang fitur antara 0 (garis dasar atau titik awal) dan 1 (nilai piksel masukan)
- menghitung gradien pada setiap langkah antara prediksi model Anda sehubungan dengan setiap langkah
- kira-kira integral antara baseline dan input Anda dengan mengumpulkan (rata-rata kumulatif) gradien lokal ini.
Untuk memperkuat intuisi ini, Anda akan berjalan melalui 3 bagian ini dengan menerapkan IG pada contoh gambar "Fireboat" di bawah ini.
Tetapkan garis dasar
Garis dasar adalah gambar masukan yang digunakan sebagai titik awal untuk menghitung pentingnya fitur. Secara intuitif, Anda dapat menganggap peran penjelas garis dasar sebagai merepresentasikan dampak tidak adanya setiap piksel pada prediksi "Fireboat" untuk kontras dengan dampaknya dari setiap piksel pada prediksi "Fireboat" saat ada di gambar input. Akibatnya, pilihan baseline memainkan peran sentral dalam menafsirkan dan memvisualisasikan pentingnya fitur piksel. Untuk diskusi tambahan tentang pemilihan dasar, lihat sumber daya di bagian "Langkah berikutnya" di bagian bawah tutorial ini. Di sini, Anda akan menggunakan gambar hitam yang nilai pikselnya nol.
Pilihan lain yang dapat Anda coba dengan menyertakan gambar serba putih, 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()
Buka paket formula ke dalam kode
Rumus untuk Gradien Terintegrasi adalah sebagai berikut:
\(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}\)
di mana:
\(_{i}\) = fitur
\(x\) = masukan
\(x'\) = baseline
\(\alpha\) = konstanta interpolasi untuk mengganggu fitur dengan
Dalam praktiknya, menghitung integral tertentu tidak selalu memungkinkan secara numerik dan dapat menjadi mahal secara komputasi, jadi Anda menghitung perkiraan numerik berikut:
\(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}\)
di mana:
\(_{i}\) = fitur (piksel individual)
\(x\) = input (tensor gambar)
\(x'\) = garis dasar (tensor gambar)
\(k\) = konstanta gangguan fitur berskala
\(m\) = jumlah langkah dalam pendekatan jumlah Riemann dari integral
\((x_{i}-x'_{i})\) = istilah untuk perbedaan dari baseline. Ini diperlukan untuk menskalakan gradien terintegrasi dan menjaganya tetap dalam bentuk gambar aslinya. Jalur dari gambar dasar ke input berada dalam ruang piksel. Karena dengan IG Anda berintegrasi dalam garis lurus (transformasi linier), ini pada akhirnya setara dengan suku integral turunan dari fungsi gambar yang diinterpolasi sehubungan dengan \(\alpha\) dengan langkah-langkah yang cukup. Integral menjumlahkan gradien setiap piksel dikalikan perubahan piksel di sepanjang jalur. Lebih mudah untuk menerapkan integrasi ini sebagai langkah seragam dari satu gambar ke gambar lainnya, menggantikan \(x := (x' + \alpha(x-x'))\). Jadi perubahan variabel memberikan \(dx = (x-x')d\alpha\). Suku \((x-x')\) adalah konstan dan difaktorkan di luar integral.
Interpolasi gambar
\(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{interpolate m images at k intervals})}{\partial 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 di ruang fitur antara baseline dan input 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 yang diinterpolasi di sepanjang jalur linier pada interval alfa antara gambar garis dasar hitam dan contoh gambar "Perahu Pemadam Kebakaran".
interpolated_images = interpolate_images(
baseline=baseline,
image=img_name_tensors['Fireboat'],
alphas=alphas)
Mari kita memvisualisasikan gambar interpolasi. Catatan: cara berpikir lain tentang konstanta \(\alpha\) adalah bahwa ia 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();
Hitung gradien
Sekarang mari kita lihat bagaimana menghitung gradien untuk mengukur hubungan antara perubahan fitur dan perubahan prediksi model. Dalam kasus gambar, gradien memberi tahu kita piksel mana yang memiliki efek terkuat pada model yang diprediksi probabilitas kelas.
\(IntegratedGrads^{approx}_{i}(x)::=(x_{i}-x'_{i})\times\sum_{k=1}^{m}\frac{\overbrace{\partial F(\text{interpolated images})}^\text{compute gradients} }{\partial x_{i} } \times \frac{1}{m}\)
di mana:
\(F()\) = fungsi prediksi model Anda
\(\frac{\partial{F} }{\partial{x_i} }\) = gradien (vektor turunan parsial \(\partial\)) dari fungsi prediksi model F Anda relatif terhadap setiap fitur \(x_i\)
TensorFlow memudahkan Anda menghitung gradien 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 kita hitung gradien untuk setiap gambar di sepanjang jalur interpolasi sehubungan dengan keluaran yang benar. Ingatlah bahwa model Anda mengembalikan Tensor
berbentuk (1.1001 (1, 1001)
dengan logit yang Anda konversi ke 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 setiap gambar di sepanjang jalur interpolasi. Anda dapat menganggap gradien ini sebagai pengukuran perubahan 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 menggambarkan perubahan lokal pada probabilitas prediksi model "Fireboat" dan dapat memenuhi .
Konsep-konsep ini divisualisasikan menggunakan gradien yang Anda hitung di atas dalam 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]);
kiri : Plot ini menunjukkan bagaimana kepercayaan model Anda di kelas "Fireboat" bervariasi di seluruh alfa. Perhatikan bagaimana gradien, atau kemiringan garis, sebagian besar mendatar atau jenuh antara 0,6 dan 1,0 sebelum menetap di "Fireboat" akhir yang diprediksi probabilitas sekitar 40%.
kanan : Plot kanan menunjukkan besaran gradien rata-rata di atas alfa secara lebih langsung. Perhatikan bagaimana nilainya mendekati 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 piksel ini gradien ke nol, tetapi masih cukup tidak pasti dan fokus pada jembatan palsu atau piksel air jet sebagai nilai alpha mendekati gambar masukan asli.
Untuk memastikan piksel meriam air penting ini direfleksikan sama pentingnya dengan prediksi "Perahu Pemadam Kebakaran", Anda akan melanjutkan di bawah untuk mempelajari cara mengumpulkan gradien ini untuk secara akurat memperkirakan bagaimana setiap piksel memengaruhi probabilitas prediksi "Perahu Pemadam Kebakaran" Anda.
Akumulasi gradien (perkiraan integral)
Ada banyak cara berbeda yang dapat Anda lakukan untuk menghitung perkiraan numerik 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 aproksimasi di akhir tutorial ini).
$IntegratedGrads^{perkiraan} {i}(x)::=(x {i}-x' {i})\times \overbrace{\sum {k=1}^{m} }^\text{Jumlah m gradien lokal} \text{gradien(gambar interpolasi)} \times \overbrace{\frac{1}{m} }^\text{Bagi dengan m langkah}$
Dari persamaan, Anda dapat melihat bahwa Anda menjumlahkan m
gradien dan membaginya dengan m
langkah. Anda dapat menerapkan dua operasi bersama-sama untuk bagian 3 sebagai rata- rata gradien lokal dari m
prediksi interpolasi dan gambar masukan .
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 probabilitas yang diprediksi dari kelas target sehubungan dengan gambar yang diinterpolasi antara garis dasar dan gambar asli.
ig = integral_approximation(
gradients=path_gradients)
Anda dapat mengonfirmasi bahwa rata-rata di seluruh gradien dari m
gambar yang diinterpolasi mengembalikan tensor gradien terintegrasi dengan bentuk yang sama seperti gambar "Giant Panda" asli.
print(ig.shape)
(224, 224, 3)
Menyatukan semuanya
Sekarang Anda akan menggabungkan 3 bagian umum sebelumnya menjadi sebuah 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^{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.}\)
Hasilkan alfa \(\alpha\)
Hasilkan gambar interpolasi = \((x' + \frac{k}{m}\times(x - x'))\)
Hitung gradien antara prediksi keluaran model \(F\) sehubungan dengan fitur input = \(\frac{\partial F(\text{interpolated path inputs})}{\partial x_{i} }\)
Pendekatan integral melalui gradien rata-rata = \(\sum_{k=1}^m \text{gradients} \times \frac{1}{m}\)
Skala gradien terintegrasi sehubungan dengan gambar asli = \((x_{i}-x'_{i}) \times \text{integrated gradients}\). Alasan langkah ini diperlukan adalah untuk memastikan bahwa nilai atribusi yang terakumulasi di beberapa gambar yang diinterpolasi berada dalam unit yang sama dan dengan tepat mewakili kepentingan piksel pada gambar asli.
def integrated_gradients(baseline,
image,
target_class_idx,
m_steps=50,
batch_size=32):
# Generate alphas.
alphas = tf.linspace(start=0.0, stop=1.0, num=m_steps+1)
# Collect gradients.
gradient_batches = []
# 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]
gradient_batch = one_batch(baseline, image, alpha_batch, target_class_idx)
gradient_batches.append(gradient_batch)
# Stack path gradients together row-wise into single tensor.
total_gradients = tf.stack(gradient_batch)
# Integral approximation through averaging gradients.
avg_gradients = integral_approximation(gradients=total_gradients)
# Scale integrated gradients with respect to input.
integrated_gradients = (image - baseline) * avg_gradients
return integrated_gradients
@tf.function
def one_batch(baseline, image, alpha_batch, target_class_idx):
# Generate interpolated inputs between baseline and input.
interpolated_path_input_batch = interpolate_images(baseline=baseline,
image=image,
alphas=alpha_batch)
# Compute gradients between model outputs and interpolated inputs.
gradient_batch = compute_gradients(images=interpolated_path_input_batch,
target_class_idx=target_class_idx)
return gradient_batch
ig_attributions = integrated_gradients(baseline=baseline,
image=img_name_tensors['Fireboat'],
target_class_idx=555,
m_steps=240)
Sekali lagi, Anda dapat memeriksa bahwa atribusi fitur IG memiliki bentuk yang sama dengan gambar input "Fireboat".
print(ig_attributions.shape)
(224, 224, 3)
Makalah ini menyarankan jumlah langkah berkisar antara 20 hingga 300 tergantung pada contoh (walaupun dalam praktiknya ini bisa lebih tinggi dalam 1.000 detik 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 melapisinya pada gambar asli. Kode di bawah ini menjumlahkan nilai absolut dari gradien terintegrasi di seluruh saluran warna untuk menghasilkan topeng atribusi. Metode ploting 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 "Perahu Pemadam Kebakaran", Anda dapat melihat model 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)
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)
Penggunaan dan batasan
Gunakan kasus
- Menggunakan teknik seperti Gradien Terintegrasi 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 menunjukkan adanya bug dalam model atau set data Anda, atau overfitting.
Keterbatasan
Gradien Terpadu memberikan pentingnya fitur pada contoh individual, namun tidak memberikan pentingnya 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 Terpadu. Sebagai langkah selanjutnya, Anda dapat menggunakan notebook ini untuk mencoba teknik ini dengan model dan gambar yang berbeda sendiri.
Untuk pembaca yang tertarik, ada versi yang lebih panjang dari tutorial ini (yang mencakup kode untuk garis dasar yang berbeda, untuk menghitung perkiraan integral, dan untuk menentukan jumlah langkah yang memadai) yang dapat Anda temukan di sini .
Untuk memperdalam pemahaman Anda, lihat makalah Axiomatic Attribution for Deep Networks dan repositori Github , yang berisi implementasi di TensorFlow versi sebelumnya. Anda juga dapat menjelajahi atribusi fitur, dan dampak dari dasar yang berbeda, di distill.pub .
Tertarik untuk memasukkan IG ke dalam alur kerja pembelajaran mesin produksi Anda untuk kepentingan fitur, analisis kesalahan model, dan pemantauan kemiringan data? Lihat produk AI yang Dapat Dijelaskan Google Cloud yang mendukung atribusi IG. Grup riset Google AI PAIR juga membuka sumber alat What-if yang dapat digunakan untuk debugging model, termasuk memvisualisasikan atribusi fitur IG.