การไล่ระดับสีแบบบูรณาการ

ดูบน TensorFlow.org ทำงานใน Google Colab ดูบน GitHub ดาวน์โหลดโน๊ตบุ๊ค ดูรุ่น TF Hub

บทช่วยสอนนี้สาธิตวิธีการใช้ Integrated Gradients (IG) ซึ่งเป็นเทคนิค AI ที่อธิบายได้ ซึ่งแนะนำในเอกสาร Axiomatic Attribution สำหรับ Deep Networks IG มีวัตถุประสงค์เพื่ออธิบายความสัมพันธ์ระหว่างการคาดการณ์ของโมเดลในแง่ของคุณลักษณะ มีกรณีการใช้งานมากมาย รวมถึงการทำความเข้าใจถึงความสำคัญของฟีเจอร์ การระบุความเอียงของข้อมูล และการดีบักประสิทธิภาพของโมเดล

IG กลายเป็นเทคนิคการตีความที่ได้รับความนิยมเนื่องจากมีการนำไปใช้ในวงกว้างกับแบบจำลองที่แตกต่างกัน (เช่น รูปภาพ ข้อความ ข้อมูลที่มีโครงสร้าง) ความง่ายในการนำไปใช้ การให้เหตุผลทางทฤษฎี และประสิทธิภาพในการคำนวณเมื่อเทียบกับวิธีการทางเลือกที่ช่วยให้สามารถปรับขนาดเป็นเครือข่ายขนาดใหญ่และคุณลักษณะ ช่องว่างเช่นภาพ

ในบทช่วยสอนนี้ คุณจะอธิบายการใช้งาน IG ทีละขั้นตอนเพื่อทำความเข้าใจความสำคัญของฟีเจอร์พิกเซลของตัวแยกประเภทรูปภาพ ตัวอย่างเช่น ลองพิจารณา ภาพ ของเรือดับเพลิงที่พ่นละอองน้ำ คุณจะจัดรูปภาพนี้เป็นเรือดับเพลิง และอาจเน้นพิกเซลที่ประกอบเป็นเรือและปืนฉีดน้ำว่ามีความสำคัญต่อการตัดสินใจของคุณ โมเดลของคุณจะจัดประเภทรูปภาพนี้เป็นเรือดับเพลิงในภายหลังในบทช่วยสอนนี้ อย่างไรก็ตาม มันเน้นพิกเซลเดียวกันว่ามีความสำคัญหรือไม่เมื่ออธิบายการตัดสินใจ

ในภาพด้านล่างชื่อ "IG Attribution Mask" และ "Original + IG Mask Overlay" คุณจะเห็นว่าโมเดลของคุณไฮไลต์ (สีม่วง) แทนพิกเซลที่ประกอบด้วยปืนใหญ่ฉีดน้ำของเรือและกระแสน้ำที่พุ่งออกมาว่ามีความสำคัญมากกว่าตัวเรือเอง การตัดสินใจของมัน แบบจำลองของคุณจะมีลักษณะทั่วไปอย่างไรกับเรือดับเพลิงใหม่ แล้วเรือดับเพลิงที่ไม่มีเครื่องฉีดน้ำล่ะ? อ่านต่อไปเพื่อเรียนรู้เพิ่มเติมเกี่ยวกับวิธีการทำงานของ 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) นี่คือเทนเซอร์ 4D หนาแน่นของ dtype float32 และรูปร่าง (batch_size, height, width, RGB channels) ซึ่งมีองค์ประกอบเป็นค่าสี RGB ของพิกเซลที่ปรับให้เป็นมาตรฐานในช่วง [0, 1] อิลิเมนต์แรกคือ None เพื่อระบุว่าโมเดลสามารถใช้ขนาดแบตช์จำนวนเต็มใดๆ ก็ได้

ผลลัพธ์ : tf.Tensor ของ logits ในรูปของ (batch_size, 1001) แต่ละแถวแสดงถึงคะแนนที่คาดการณ์ไว้ของโมเดลสำหรับแต่ละคลาส 1,001 จาก 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')
ตัวยึดตำแหน่ง36

โหลดและประมวลผลภาพล่วงหน้าด้วย tf.image

คุณจะแสดง IG โดยใช้สองภาพจาก Wikimedia Commons : Fireboat และ Giant Panda

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

png

จำแนกภาพ

มาเริ่มด้วยการจำแนกภาพเหล่านี้และแสดงการคาดคะเนที่มั่นใจที่สุด 3 อันดับแรก ต่อไปนี้เป็นฟังก์ชันยูทิลิตี้เพื่อดึงป้ายกำกับและความน่าจะเป็นที่คาดการณ์ไว้ด้านบน

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%}')
ตัวยึดตำแหน่ง42

png

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

png

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)

png

  • ซ้าย : การไล่ระดับสีของโมเดลของคุณสำหรับพิกเซล x เป็นค่าบวกระหว่าง 0.0 ถึง 0.8 แต่ไปที่ 0.0 ระหว่าง 0.8 ถึง 1.0 Pixel x มีผลกระทบอย่างมากต่อการผลักดันโมเดลของคุณไปสู่ความน่าจะเป็นที่คาดการณ์ไว้ 80% ในคลาสจริง มันสมเหตุสมผลหรือไม่ที่ความสำคัญของ pixel x นั้นเล็กหรือไม่ต่อเนื่อง?

  • right : สัญชาตญาณเบื้องหลัง IG คือการสะสมการไล่ระดับสีในเครื่องของ pixel x และระบุความสำคัญของมันเป็นคะแนนสำหรับความน่าจะเป็นของคลาสเอาต์พุตโดยรวมของโมเดลที่เพิ่มหรือลบออก คุณสามารถแยกย่อยและคำนวณ IG ได้ 3 ส่วน:

    1. สอดแทรกขั้นตอนเล็กๆ ตามแนวเส้นตรงในช่องว่างระหว่าง 0 (เส้นฐานหรือจุดเริ่มต้น) และ 1 (ค่าพิกเซลของอินพุต)
    2. คำนวณการไล่ระดับสีในแต่ละขั้นตอนระหว่างการคาดคะเนของแบบจำลองของคุณตามแต่ละขั้นตอน
    3. ประมาณค่าอินทิกรัลระหว่างเส้นพื้นฐานและอินพุตของคุณโดยการสะสม (ค่าเฉลี่ยสะสม) การไล่ระดับสีในพื้นที่เหล่านี้

เพื่อตอกย้ำสัญชาตญาณนี้ คุณจะต้องเดินผ่าน 3 ส่วนนี้โดยใช้ IG กับภาพตัวอย่าง "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

แกะสูตรเป็นโค้ด

สูตรสำหรับ Integrated Gradients มีดังนี้:

\(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

ลองใช้ฟังก์ชันด้านบนเพื่อสร้างภาพที่สอดแทรกตามเส้นทางเชิงเส้นที่ช่วงอัลฟาระหว่างภาพเส้นฐานสีดำกับภาพตัวอย่าง "เรือไฟ"

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

การแสดงภาพความอิ่มตัวของการไล่ระดับสี

โปรดจำไว้ว่าการไล่ระดับสีที่คุณเพิ่งคำนวณข้างต้นจะอธิบาย การ เปลี่ยนแปลงในเครื่องต่อความน่าจะเป็นที่คาดการณ์ของโมเดลของคุณที่จะเป็น "เรือไฟ" และสามารถ อิ่มตัว ได้

แนวคิดเหล่านี้แสดงให้เห็นภาพโดยใช้การไล่ระดับสีที่คุณคำนวณไว้ด้านบนใน 2 แปลงด้านล่าง

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

png

  • ซ้าย : พล็อตนี้แสดงให้เห็นว่าความเชื่อมั่นของโมเดลของคุณในคลาส "Fireboat" นั้นแตกต่างกันอย่างไรในอัลฟ่า สังเกตว่าการไล่ระดับสีหรือความชันของเส้น ส่วนใหญ่แผ่หรืออิ่มตัวระหว่าง 0.6 ถึง 1.0 ก่อนที่จะตกตะกอนที่ "เรือดับเพลิง" สุดท้ายทำนายความน่าจะเป็นประมาณ 40%

  • ขวา : พล็อตด้านขวาแสดงขนาดการไล่ระดับสีเฉลี่ยเหนืออัลฟาโดยตรงมากขึ้น สังเกตว่าค่าเข้าใกล้อย่างรวดเร็วและลดลงต่ำกว่าศูนย์ในเวลาสั้นๆ อย่างไร อันที่จริง โมเดลของคุณ "เรียนรู้" มากที่สุดจากการไล่ระดับสีที่ค่าอัลฟาที่ต่ำกว่าก่อนที่จะอิ่มตัว ตามสัญชาตญาณ คุณสามารถคิดสิ่งนี้ได้เนื่องจากแบบจำลองของคุณได้เรียนรู้พิกเซล เช่น ปืนฉีดน้ำ ในการทำนายที่ถูกต้อง โดยส่งการไล่ระดับพิกเซลเหล่านี้ไปที่ศูนย์ แต่ก็ยังค่อนข้างไม่แน่นอนและมุ่งเน้นไปที่บริดจ์ปลอมหรือพิกเซลของวอเตอร์เจ็ทเมื่อค่าอัลฟาเข้าใกล้ ภาพอินพุตต้นฉบับ

เพื่อให้แน่ใจว่าพิกเซลของปืนใหญ่ฉีดน้ำที่สำคัญเหล่านี้สะท้อนให้เห็นว่ามีความสำคัญต่อการคาดคะเน "เรือดับเพลิง" คุณจะดำเนินการต่อที่ด้านล่างเพื่อเรียนรู้วิธีรวบรวมการไล่ระดับสีเหล่านี้เพื่อประมาณว่าแต่ละพิกเซลส่งผลต่อความน่าจะเป็นที่คาดการณ์ไว้ของ "เรือดับเพลิง" อย่างไร

สะสมการไล่ระดับสี (การประมาณแบบอินทิกรัล)

มีหลายวิธีที่คุณสามารถคำนวณค่าประมาณเชิงตัวเลขของอินทิกรัลสำหรับ IG ได้โดยมีจุดประนีประนอมที่แตกต่างกันในด้านความแม่นยำและการบรรจบกันในฟังก์ชันต่างๆ คลาสวิธีการที่นิยมเรียกว่า Riemann sums ที่นี่ คุณจะใช้กฎสี่เหลี่ยมคางหมู (คุณสามารถหาโค้ดเพิ่มเติมเพื่อสำรวจวิธีการประมาณต่างๆ ได้ที่ส่วนท้ายของบทช่วยสอนนี้)

$IntegratedGrads^{ประมาณ} {i}(x)::=(x {i}-x' {i})\times \overbrace{\sum {k=1}^{m} }^\text{Sum m การไล่ระดับสีในพื้นที่} \text{gradients(interpolated images)} \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 ให้ส่งคืนเทนเซอร์การไล่ระดับสีแบบรวมที่มีรูปร่างเหมือนกับรูปภาพ "Giant Panda" ดั้งเดิมได้

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

วางมันทั้งหมดเข้าด้วยกัน

ตอนนี้ คุณจะรวม 3 ส่วนทั่วไปก่อนหน้าเข้าด้วยกันเป็นฟังก์ชัน IntegratedGradients และใช้ @tf.function decorator เพื่อคอมไพล์ลงในกราฟ 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. สร้าง alphas \(\alpha\)

  2. สร้างภาพที่สอดแทรก = \((x' + \frac{k}{m}\times(x - x'))\)

  3. คำนวณการไล่ระดับสีระหว่างแบบจำลอง \(F\) การคาดการณ์เอาต์พุตที่สัมพันธ์กับคุณสมบัติอินพุต = \(\frac{\partial F(\text{interpolated path inputs})}{\partial x_{i} }\)

  4. การประมาณแบบอินทิกรัลผ่านการไล่ระดับสีเฉลี่ย = \(\sum_{k=1}^m \text{gradients} \times \frac{1}{m}\)

  5. ปรับขนาดการไล่ระดับสีแบบบูรณาการตามภาพต้นฉบับ = \((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 ขึ้นอยู่กับตัวอย่าง (แม้ว่าในทางปฏิบัติ ขั้นตอนนี้อาจสูงกว่าใน 1,000 วินาทีเพื่อประมาณค่าปริพันธ์ได้อย่างแม่นยำ) คุณสามารถค้นหาโค้ดเพิ่มเติมเพื่อตรวจสอบจำนวนขั้นตอนที่เหมาะสมได้ในแหล่งข้อมูล "ขั้นตอนถัดไป" ที่ส่วนท้ายของบทช่วยสอนนี้

เห็นภาพการแสดงที่มา

คุณพร้อมที่จะเห็นภาพการแสดงที่มาและซ้อนทับบนภาพต้นฉบับ โค้ดด้านล่างจะรวมค่าสัมบูรณ์ของการไล่ระดับสีแบบรวมในช่องสีต่างๆ เพื่อสร้างรูปแบบการระบุแหล่งที่มา วิธีการวางแผนนี้จะจับผลกระทบที่สัมพันธ์กันของพิกเซลต่อการคาดคะเนของแบบจำลอง

เมื่อพิจารณาจากที่มาของภาพ "เรือดับเพลิง" คุณจะเห็นโมเดลระบุปืนใหญ่ฉีดน้ำและท่อส่งน้ำซึ่งมีส่วนช่วยในการทำนายที่ถูกต้อง

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

ในภาพ "Giant 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

การใช้และข้อจำกัด

กรณีการใช้งาน

  • การใช้เทคนิคต่างๆ เช่น Integrated Gradients ก่อนปรับใช้โมเดลของคุณสามารถช่วยให้คุณพัฒนาสัญชาตญาณว่าทำงานอย่างไรและทำไม คุณลักษณะที่เน้นโดยเทคนิคนี้ตรงกับสัญชาตญาณของคุณหรือไม่? หากไม่เป็นเช่นนั้น นั่นอาจบ่งบอกถึงจุดบกพร่องในแบบจำลองหรือชุดข้อมูลของคุณ หรือการใส่มากเกินไป

ข้อจำกัด

  • การไล่ระดับสีแบบรวมจะให้ความสำคัญกับคุณลักษณะในแต่ละตัวอย่าง อย่างไรก็ตาม ไม่ได้ให้ความสำคัญกับคุณลักษณะโดยรวมในชุดข้อมูลทั้งหมด

  • การไล่ระดับสีแบบรวมจะให้ความสำคัญกับคุณลักษณะแต่ละอย่าง แต่ไม่ได้อธิบายการโต้ตอบและการผสมผสานของคุณลักษณะ

ขั้นตอนถัดไป

บทช่วยสอนนี้นำเสนอการใช้งานพื้นฐานของ Integrated Gradients ในขั้นตอนต่อไป คุณสามารถใช้สมุดบันทึกนี้เพื่อลองใช้เทคนิคนี้กับรุ่นและรูปภาพต่างๆ ด้วยตัวคุณเอง

สำหรับผู้อ่านที่สนใจ มีบทช่วยสอนนี้เวอร์ชันที่ยาวกว่า (ซึ่งรวมถึงโค้ดสำหรับบรรทัดฐานที่แตกต่างกัน เพื่อคำนวณค่าประมาณที่สมบูรณ์ และเพื่อกำหนดจำนวนขั้นตอนที่เพียงพอ) ซึ่งคุณจะพบได้ ที่นี่

เพื่อทำความเข้าใจให้ลึกซึ้งยิ่งขึ้น โปรดดูเอกสาร Axiomatic Attribution for Deep Networks และ Github repository ซึ่งมีการใช้งานใน TensorFlow เวอร์ชันก่อนหน้า คุณยังสามารถสำรวจการระบุแหล่งที่มาของคุณลักษณะ และผลกระทบของบรรทัดฐานต่างๆ ได้ที่ distill.pub

สนใจที่จะรวม IG เข้ากับเวิร์กโฟลว์แมชชีนเลิร์นนิงสำหรับการผลิตของคุณเพื่อให้ความสำคัญกับคุณลักษณะ การวิเคราะห์ข้อผิดพลาดของแบบจำลอง และการตรวจสอบข้อมูลเอียงหรือไม่ ลองดูผลิตภัณฑ์ AI ที่อธิบายได้ของ Google Cloud ที่รองรับการระบุแหล่งที่มาของ IG กลุ่มวิจัย Google AI PAIR ยังเปิดแหล่งที่มาของ เครื่องมือ What-if ซึ่งสามารถใช้สำหรับการแก้ไขข้อบกพร่องของโมเดล ซึ่งรวมถึงการแสดงภาพการระบุแหล่งที่มาของคุณลักษณะ IG