مشاهده در TensorFlow.org | در Google Colab اجرا شود | در GitHub مشاهده کنید | دانلود دفترچه یادداشت | مدل TF Hub را ببینید |
این آموزش نحوه پیادهسازی گرادیانهای مجتمع (IG) را نشان میدهد، یک تکنیک هوش مصنوعی قابل توضیح که در مقاله Axiomatic Attribution for Deep Networks معرفی شده است. هدف IG توضیح رابطه بین پیشبینیهای یک مدل از نظر ویژگیهای آن است. موارد استفاده زیادی از جمله درک اهمیت ویژگی ها، شناسایی انحراف داده ها و اشکال زدایی عملکرد مدل دارد.
IG به دلیل کاربرد وسیع آن برای هر مدل قابل تمایز (مانند تصاویر، متن، دادههای ساختاریافته)، سهولت اجرا، توجیههای نظری، و کارایی محاسباتی نسبت به رویکردهای جایگزین که به آن اجازه میدهد تا شبکهها و ویژگیهای بزرگ مقیاس شود، به یک تکنیک تفسیرپذیری محبوب تبدیل شده است. فضاهایی مانند تصاویر
در این آموزش، پیادهسازی IG را گام به گام برای درک اهمیت ویژگیهای پیکسلی یک طبقهبندیکننده تصویر خواهید دید. به عنوان مثال، این تصویر از یک قایق آتش نشانی را در نظر بگیرید که جت های آب پاشیده است. شما می توانید این تصویر را به عنوان یک قایق آتش نشانی طبقه بندی کنید و ممکن است پیکسل های سازنده قایق و توپ های آبی را به عنوان مهم برای تصمیم گیری خود برجسته کنید. مدل شما همچنین این تصویر را به عنوان قایق آتش نشانی در آینده در این آموزش طبقه بندی می کند. با این حال، آیا هنگام توضیح تصمیم خود همان پیکسل ها را به عنوان مهم برجسته می کند؟
در تصاویر زیر با عنوان "IG Attribution Mask" و "Original + IG Mask Overlay" می توانید ببینید که مدل شما به جای آن پیکسل های متشکل از توپ های آبی و فواره های آب قایق را برجسته تر از خود قایق نشان می دهد (به رنگ بنفش). تصمیم آن چگونه مدل شما به قایق های آتش نشانی جدید تعمیم می یابد؟ در مورد قایق های آتش نشانی بدون جت آب چطور؟ برای آشنایی بیشتر با نحوه عملکرد IG و نحوه اعمال IG در مدلهای خود، ادامه دهید تا رابطه بین پیشبینیها و ویژگیهای اساسی آنها را بهتر درک کنید.
برپایی
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)
است. این یک تانسور 4 بعدی متراکم از نوع dtype float32 و شکل (batch_size, height, width, RGB channels)
است که عناصر آن مقادیر رنگی RGB پیکسلها هستند که در محدوده [0، 1] نرمال شدهاند. اولین عنصر None
است که نشان می دهد مدل می تواند هر اندازه دسته ای عدد صحیح را بگیرد.
خروجی ها: تانسور tf. tf.Tensor
به شکل (batch_size, 1001)
. هر ردیف نشان دهنده امتیاز پیش بینی شده مدل برای هر یک از 1001 کلاس از ImageNet است. برای بالاترین شاخص کلاس پیشبینیشده مدل، میتوانید از 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
شما IG را با استفاده از دو تصویر از Wikimedia Commons نشان خواهید داد: یک قایق آتش نشانی و یک پاندا غول پیکر .
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()
طبقه بندی تصاویر
بیایید با طبقه بندی این تصاویر و نمایش 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%}')
fireboat: 32.6% pier: 12.7% suspension bridge: 5.7%
giant panda: 89.4% teddy: 0.3% gibbon: 0.3%
محاسبه گرادیان های یکپارچه
مدل شما، Inception V1، یک تابع آموخته شده است که نگاشت بین فضای ویژگی ورودی، مقادیر پیکسل تصویر، و فضای خروجی تعریف شده توسط مقادیر احتمال کلاس ImageNet بین 0 و 1 را توصیف می کند. گرادیان، که به شما میگوید کدام پیکسلها نسبت به پیشبینی مدل شما در یک نقطه مشخص در طول تابع پیشبینی مدل، شیب محلی بیشتری دارند. با این حال، گرادیان ها فقط تغییرات محلی در تابع پیش بینی مدل شما را با توجه به مقادیر پیکسل توصیف می کنند و کل عملکرد پیش بینی مدل شما را به طور کامل توصیف نمی کنند. همانطور که مدل شما به طور کامل رابطه بین محدوده یک پیکسل جداگانه و کلاس 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();
سمت چپ : گرادیان های مدل شما برای پیکسل
x
بین 0.0 و 0.8 مثبت است اما بین 0.8 و 1.0 به 0.0 می رسد. Pixelx
به وضوح تأثیر قابل توجهی در سوق دادن مدل شما به سمت احتمال پیش بینی شده 80 درصدی در کلاس واقعی دارد. آیا این منطقی است که اهمیت پیکسلx
کوچک یا ناپیوسته باشد؟درست : شهود پشت IG این است که گرادیان های محلی پیکسل
x
را جمع آوری کنیم و اهمیت آن را به عنوان امتیازی نسبت دهیم که چقدر به احتمال کلاس خروجی کلی مدل شما اضافه یا کم می کند. شما می توانید IG را در 3 قسمت تجزیه و محاسبه کنید:- گام های کوچک را در امتداد یک خط مستقیم در فضای ویژگی بین 0 (خط پایه یا نقطه شروع) و 1 (مقدار پیکسل ورودی) درون یابی کنید.
- شیب ها را در هر مرحله بین پیش بینی های مدل خود با توجه به هر مرحله محاسبه کنید
- انتگرال بین خط مبنا و ورودی خود را با جمع آوری (میانگین تجمعی) این گرادیان های محلی تقریب بزنید.
برای تقویت این شهود، با اعمال IG بر روی مثال "Fireboat" تصویر زیر، از طریق این 3 قسمت قدم خواهید زد.
یک خط پایه ایجاد کنید
خط مبنا یک تصویر ورودی است که به عنوان نقطه شروع برای محاسبه اهمیت ویژگی استفاده می شود. به طور شهودی، میتوانید نقش توضیحی خط مبنا را بهعنوان نشاندهنده تأثیر عدم وجود هر پیکسل در پیشبینی «قایق آتشنشانی» در تضاد با تأثیر هر پیکسل بر پیشبینی «قایق آتشنشانی» در زمانی که در تصویر ورودی وجود دارد، در نظر بگیرید. در نتیجه، انتخاب خط مبنا نقش اساسی در تفسیر و تجسم اهمیت ویژگی های پیکسل ایفا می کند. برای بحث بیشتر در مورد انتخاب خط پایه، منابع موجود در بخش «مراحل بعدی» در پایین این آموزش را ببینید. در اینجا، شما از یک تصویر سیاه استفاده خواهید کرد که مقادیر پیکسل آن صفر است.
گزینه های دیگری که می توانید با آنها آزمایش کنید شامل یک تصویر تمام سفید یا یک تصویر تصادفی است که می توانید با 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()
فرمول ها را در کد باز کنید
فرمول گرادیان های مجتمع به شرح زیر است:
\(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(x-x'))\)ساده تر است. بنابراین تغییر متغیرها \(dx = (x-x')d\alpha\)می دهد. عبارت \((x-x')\) ثابت است و از انتگرال خارج می شود.
درون یابی تصاویر
\(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}\)
ابتدا یک درون یابی خطی بین خط مبنا و تصویر اصلی ایجاد می کنید. می توانید تصاویر درون یابی شده را به عنوان مراحل کوچک در فضای ویژگی بین خط مبنا و ورودی خود در نظر بگیرید که با \(\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();
محاسبه گرادیان
حال بیایید نگاهی به نحوه محاسبه گرادیان بیندازیم تا رابطه بین تغییرات یک ویژگی و تغییرات در پیش بینی های مدل را اندازه گیری کنیم. در مورد تصاویر، گرادیان به ما می گوید که کدام پیکسل قوی ترین اثر را بر روی مدل های پیش بینی شده احتمالات کلاس دارد.
\(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}\)
جایی که:
\(F()\) = تابع پیش بینی مدل شما
\(\frac{\partial{F} }{\partial{x_i} }\) = گرادیان (بردار مشتقات جزئی \(\partial\)) تابع پیش بینی مدل F نسبت به هر ویژگی \(x_i\)
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)
بیایید گرادیان ها را برای هر تصویر در طول مسیر درون یابی با توجه به خروجی صحیح محاسبه کنیم. به یاد بیاورید که مدل شما یک Tensor
شکل (1, 1001)
را با لجیت هایی که شما به احتمالات پیش بینی شده برای هر کلاس تبدیل می کنید، برمی گرداند. شما باید شاخص کلاس هدف 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]);
چپ : این نمودار نشان می دهد که چگونه اعتماد مدل شما به کلاس "Fireboat" در بین آلفاها متفاوت است. توجه داشته باشید که چگونه گرادیان یا شیب خط، قبل از نشستن در "Fireboat" احتمال پیش بینی شده نهایی حدود 40٪، تا حد زیادی بین 0.6 و 1.0 مسطح یا اشباع می شود.
right : نمودار سمت راست میانگین بزرگی گرادیان ها را روی آلفا مستقیمتر نشان می دهد. توجه داشته باشید که چگونه مقادیر به شدت نزدیک می شوند و حتی برای مدت کوتاهی به زیر صفر می رسند. در واقع، مدل شما قبل از اشباع کردن، بیشترین "یادگیری" را از گرادیان در مقادیر کمتر آلفا می گیرد. به طور شهودی، میتوانید به این فکر کنید، زیرا مدل شما پیکسلها را یاد گرفته است، به عنوان مثال، توپهای آب برای پیشبینی صحیح، شیب این پیکسلها را به صفر میفرستد، اما همچنان کاملا نامشخص است و با توجه به نزدیک شدن مقادیر آلفا به پیکسلهای پل جت آب یا پل کاذب تمرکز میکند. تصویر ورودی اصلی
برای اطمینان از اینکه این پیکسلهای مهم توپهای آبی بهعنوان مهم در پیشبینی «قایق آتشنشانی» منعکس میشوند، در ادامه با نحوه جمعآوری این شیبها آشنا میشوید تا به طور تقریبی نحوه تأثیرگذاری هر پیکسل بر احتمال پیشبینیشده «قایق آتشنشانی» شما را به دقت بررسی کنید.
انباشته کردن گرادیان ها (تقریبا انتگرال)
راه های مختلفی وجود دارد که می توانید برای محاسبه تقریب عددی یک انتگرال برای IG با مبادلات مختلف در دقت و همگرایی در توابع مختلف استفاده کنید. یک کلاس محبوب از روشها، مجموع ریمان نامیده میشود. در اینجا، از قانون ذوزنقه ای استفاده خواهید کرد (در پایان این آموزش می توانید کد اضافی برای کشف روش های تقریب مختلف پیدا کنید).
$IntegratedGrads^{تقریبا} {i}(x)::=(x {i}-x' {i})\times \overbrace{\sum {k=1}^{m} }^\text{جمع m شیب محلی} \text{gradients(تصاویر درونیابی)} \times \overbrace{\frac{1}{m} }^\text{تقسیم بر m گام}$
از معادله، می توانید ببینید که بر m
شیب جمع می کنید و بر m
گام تقسیم می کنید. می توانید این دو عملیات را با هم برای قسمت 3 به عنوان میانگین گرادیان های محلی 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
ترکیب میکنید و از یک دکوراتور @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.}\)
آلفاهای \(\alpha\)ایجاد کنید
ایجاد تصاویر درون یابی = \((x' + \frac{k}{m}\times(x - x'))\)
محاسبه گرادیان بین مدل \(F\) پیش بینی خروجی با توجه به ویژگی های ورودی = \(\frac{\partial F(\text{interpolated path inputs})}{\partial x_{i} }\)
تقریب انتگرال از طریق میانگین گرادیان = \(\sum_{k=1}^m \text{gradients} \times \frac{1}{m}\)
مقیاس گرادیان های یکپارچه با توجه به تصویر اصلی = \((x_{i}-x'_{i}) \times \text{integrated gradients}\). دلیل اینکه این مرحله ضروری است این است که مطمئن شویم مقادیر اسناد انباشته شده در چندین تصویر درون یابی شده در یک واحد هستند و به طور صادقانه اهمیت پیکسل را در تصویر اصلی نشان می دهند.
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)
دوباره، میتوانید بررسی کنید که ویژگیهای IG شکلی مشابه تصویر ورودی «Fireboat» دارند.
print(ig_attributions.shape)
(224, 224, 3)
این مقاله بسته به مثال، تعداد مراحل را بین 20 تا 300 نشان میدهد (اگرچه در عمل برای تقریب دقیق انتگرال، این تعداد میتواند در 1000 ثانیه بیشتر باشد). میتوانید کدهای اضافی را برای بررسی تعداد مناسب مراحل در منابع «مراحل بعدی» در انتهای این آموزش بیابید.
تجسم اسناد
شما آماده تجسم ارجاعات، و همپوشانی آنها بر روی تصویر اصلی هستید. کد زیر مقادیر مطلق گرادیان های یکپارچه را در سراسر کانال های رنگی جمع می کند تا یک ماسک انتساب تولید کند. این روش رسم تاثیر نسبی پیکسل ها بر پیش بینی های مدل را نشان می دهد.
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
با نگاهی به اسناد موجود در تصویر "قایق آتش نشانی"، می توانید ببینید که این مدل توپ های آب و فواره ها را به عنوان کمک کننده به پیش بینی صحیح آن تشخیص می دهد.
_ = 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)
در تصویر «پاندای غولپیکر»، ویژگیها بافت، بینی و خز صورت پاندا را برجسته میکنند.
_ = 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)
موارد استفاده و محدودیت ها
موارد استفاده کنید
- استفاده از تکنیکهایی مانند Gradients یکپارچه قبل از استقرار مدل خود میتواند به شما در ایجاد شهود برای چگونگی و چرایی کارکرد آن کمک کند. آیا ویژگی های برجسته شده توسط این تکنیک با شهود شما مطابقت دارد؟ در غیر این صورت، ممکن است نشان دهنده وجود اشکال در مدل یا مجموعه داده شما یا بیش از حد مناسب بودن باشد.
محدودیت ها
گرادیان های یکپارچه اهمیت ویژگی ها را در نمونه های جداگانه ارائه می دهد، با این حال، اهمیت ویژگی های کلی را در کل مجموعه داده ارائه نمی دهد.
Gradients یکپارچه اهمیت ویژگی های فردی را ارائه می دهد، اما تعامل و ترکیب ویژگی ها را توضیح نمی دهد.
مراحل بعدی
این آموزش یک پیاده سازی اساسی از Gradient های مجتمع را ارائه می دهد. به عنوان قدم بعدی، می توانید از این نوت بوک استفاده کنید تا خودتان این تکنیک را با مدل ها و تصاویر مختلف امتحان کنید.
برای خوانندگان علاقه مند، نسخه طولانی تری از این آموزش وجود دارد (که شامل کدهایی برای خطوط پایه مختلف، برای محاسبه تقریب های انتگرال، و تعیین تعداد کافی مراحل است) که می توانید در اینجا بیابید.
برای عمیقتر کردن درک خود، مقاله Axiomatic Attribution for Deep Networks و مخزن Github را بررسی کنید که شامل یک پیادهسازی در نسخه قبلی TensorFlow است. همچنین میتوانید انتساب ویژگی و تأثیر خطوط پایه مختلف را در distill.pub کاوش کنید.
آیا علاقه مندید IG را در جریان کار یادگیری ماشین تولید خود برای اهمیت ویژگی ها، تحلیل خطای مدل و نظارت بر انحراف داده ها بگنجانید؟ محصول Google Cloud's Explainable AI را بررسی کنید که از اسناد IG پشتیبانی می کند. گروه تحقیقاتی Google AI PAIR همچنین ابزار What-if را به صورت منبع باز تهیه کرد که می تواند برای اشکال زدایی مدل، از جمله تجسم ویژگی های ویژگی IG استفاده شود.