דוגמה יריבות באמצעות FGSM

הצג באתר TensorFlow.org הפעל בגוגל קולאב צפה במקור ב-GitHub הורד מחברת

מדריך זה יוצר דוגמה יריבות באמצעות התקפת Fast Gradient Signed Method (FGSM) כפי שמתואר בהסבר וניצול דוגמאות יריבות מאת Goodfellow et al . זו הייתה אחת ההתקפות הראשונות והפופולריות ביותר להטעות רשת עצבית.

מהי דוגמה יריבה?

דוגמאות נגדיות הן תשומות מיוחדות שנוצרו במטרה לבלבל רשת עצבית, וכתוצאה מכך לסיווג שגוי של קלט נתון. הקלטים הידועים לשמצה הללו אינם ניתנים להבחנה בעין האנושית, אך גורמים לרשת לא לזהות את תוכן התמונה. ישנם מספר סוגים של התקפות כאלה, עם זאת, כאן ההתמקדות היא בהתקפת שיטת השלט המהיר, שהיא התקפת קופסה לבנה שמטרתה להבטיח סיווג שגוי. התקפת קופסה לבנה היא המקום שבו לתוקף יש גישה מלאה לדגם המותקף. אחת הדוגמאות המפורסמות ביותר לתמונה יריבה המוצגת להלן לקוחה מהמאמר האמור לעיל.

דוגמה יריבות

כאן, החל מתמונה של פנדה, התוקף מוסיף שיבושים קטנים (עיוותים) לתמונה המקורית, מה שמביא לכך שהדגם מתייג את התמונה הזו כגיבון, בביטחון גבוה. תהליך הוספת ההפרעות הללו מוסבר להלן.

שיטת סימן שיפוע מהיר

שיטת סימן השיפוע המהיר פועלת על ידי שימוש בשיפועים של הרשת העצבית ליצירת דוגמה יריבה. עבור תמונת קלט, השיטה משתמשת בשיפועים של ההפסד ביחס לתמונת הקלט כדי ליצור תמונה חדשה שממקסמת את ההפסד. דימוי חדש זה נקרא דימוי יריבות. ניתן לסכם זאת באמצעות הביטוי הבא:

\[adv\_x = x + \epsilon*\text{sign}(\nabla_xJ(\theta, x, y))\]

איפה

  • adv_x : תמונה אדוורסרית.
  • x : תמונת קלט מקורית.
  • y : תווית קלט מקורית.
  • \(\epsilon\) : מכפיל כדי להבטיח שההפרעות קטנות.
  • \(\theta\) : פרמטרי מודל.
  • \(J\) : הפסד.

מאפיין מסקרן כאן, הוא העובדה שהשיפועים נלקחים ביחס לתמונת הקלט. זה נעשה מכיוון שהמטרה היא ליצור תמונה שממקסמת את ההפסד. שיטה להשיג זאת היא למצוא כמה כל פיקסל בתמונה תורם לערך ההפסד, ולהוסיף הפרעה בהתאם. זה עובד די מהר מכיוון שקל למצוא כיצד כל פיקסל קלט תורם לאובדן על ידי שימוש בכלל השרשרת ומציאת ההדרגות הנדרשות. לפיכך, ההדרגות נלקחות ביחס לתמונה. בנוסף, מכיוון שהמודל אינו מאומן יותר (לפיכך השיפוע אינו נלקח ביחס למשתנים הניתנים לאימון, כלומר, פרמטרי המודל), ולכן פרמטרי המודל נשארים קבועים. המטרה היחידה היא לרמות דוגמנית שכבר מאומנת.

אז בואו ננסה לשטות בדוגמנית שהוכשרה מראש. במדריך זה, הדגם הוא דגם MobileNetV2 , שהוכשר מראש ב- ImageNet .

import tensorflow as tf
import matplotlib as mpl
import matplotlib.pyplot as plt

mpl.rcParams['figure.figsize'] = (8, 8)
mpl.rcParams['axes.grid'] = False

בואו נטען את דגם ה-MobileNetV2 שהוכשר מראש ואת שמות מחלקות ImageNet.

pretrained_model = tf.keras.applications.MobileNetV2(include_top=True,
                                                     weights='imagenet')
pretrained_model.trainable = False

# ImageNet labels
decode_predictions = tf.keras.applications.mobilenet_v2.decode_predictions
Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/mobilenet_v2/mobilenet_v2_weights_tf_dim_ordering_tf_kernels_1.0_224.h5
14540800/14536120 [==============================] - 0s 0us/step
14548992/14536120 [==============================] - 0s 0us/step
# Helper function to preprocess the image so that it can be inputted in MobileNetV2
def preprocess(image):
  image = tf.cast(image, tf.float32)
  image = tf.image.resize(image, (224, 224))
  image = tf.keras.applications.mobilenet_v2.preprocess_input(image)
  image = image[None, ...]
  return image

# Helper function to extract labels from probability vector
def get_imagenet_label(probs):
  return decode_predictions(probs, top=1)[0][0]

תמונה מקורית

בואו נשתמש בתמונה לדוגמה של לברדור רטריבר מאת Mirko CC-BY-SA 3.0 מ-Wikimedia Common וניצור ממנה דוגמאות יריבות. השלב הראשון הוא לעבד אותו מראש כך שניתן יהיה להזין אותו כקלט לדגם MobileNetV2.

image_path = tf.keras.utils.get_file('YellowLabradorLooking_new.jpg', 'https://storage.googleapis.com/download.tensorflow.org/example_images/YellowLabradorLooking_new.jpg')
image_raw = tf.io.read_file(image_path)
image = tf.image.decode_image(image_raw)

image = preprocess(image)
image_probs = pretrained_model.predict(image)
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/YellowLabradorLooking_new.jpg
90112/83281 [================================] - 0s 0us/step
98304/83281 [===================================] - 0s 0us/step

בואו נסתכל על התמונה.

plt.figure()
plt.imshow(image[0] * 0.5 + 0.5)  # To change [-1, 1] to [0,1]
_, image_class, class_confidence = get_imagenet_label(image_probs)
plt.title('{} : {:.2f}% Confidence'.format(image_class, class_confidence*100))
plt.show()
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/imagenet_class_index.json
40960/35363 [==================================] - 0s 0us/step
49152/35363 [=========================================] - 0s 0us/step

png

צור את התמונה היריב

יישום שיטת סימן שיפוע מהיר

הצעד הראשון הוא יצירת הפרעות שישמשו לעיוות התמונה המקורית וכתוצאה מכך תדמית אדוורסרית. כאמור, עבור משימה זו, ההדרגות נלקחות ביחס לתמונה.

loss_object = tf.keras.losses.CategoricalCrossentropy()

def create_adversarial_pattern(input_image, input_label):
  with tf.GradientTape() as tape:
    tape.watch(input_image)
    prediction = pretrained_model(input_image)
    loss = loss_object(input_label, prediction)

  # Get the gradients of the loss w.r.t to the input image.
  gradient = tape.gradient(loss, input_image)
  # Get the sign of the gradients to create the perturbation
  signed_grad = tf.sign(gradient)
  return signed_grad

ניתן גם לדמיין את ההפרעות שנוצרו.

# Get the input label of the image.
labrador_retriever_index = 208
label = tf.one_hot(labrador_retriever_index, image_probs.shape[-1])
label = tf.reshape(label, (1, image_probs.shape[-1]))

perturbations = create_adversarial_pattern(image, label)
plt.imshow(perturbations[0] * 0.5 + 0.5);  # To change [-1, 1] to [0,1]

png

בואו ננסה את זה עבור ערכים שונים של אפסילון ונצפה בתמונה שנוצרה. תבחין שככל שהערך של אפסילון גדל, קל יותר לשטות ברשת. עם זאת, זה בא בתור פשרה שגורמת לכך שההפרעות הופכות לניתנות יותר לזיהוי.

def display_images(image, description):
  _, label, confidence = get_imagenet_label(pretrained_model.predict(image))
  plt.figure()
  plt.imshow(image[0]*0.5+0.5)
  plt.title('{} \n {} : {:.2f}% Confidence'.format(description,
                                                   label, confidence*100))
  plt.show()
epsilons = [0, 0.01, 0.1, 0.15]
descriptions = [('Epsilon = {:0.3f}'.format(eps) if eps else 'Input')
                for eps in epsilons]

for i, eps in enumerate(epsilons):
  adv_x = image + eps*perturbations
  adv_x = tf.clip_by_value(adv_x, -1, 1)
  display_images(adv_x, descriptions[i])

png

png

png

png

הצעדים הבאים

עכשיו כשאתה יודע על התקפות יריבות, נסה זאת על מערכי נתונים שונים וארכיטקטורות שונות. אתה יכול גם ליצור ולאמן מודל משלך, ולאחר מכן לנסות לרמות אותו באותה שיטה. אתה יכול גם לנסות ולראות כיצד האמון בתחזיות משתנה כאשר אתה מחליף אפסילון.

למרות עוצמה, המתקפה המוצגת במדריך זה הייתה רק ההתחלה של מחקר על התקפות יריבות, ומאז היו מספר מאמרים שיצרו התקפות חזקות יותר. בנוסף להתקפות יריבות, מחקר הוביל גם ליצירת הגנות, שמטרתן ליצור מודלים חזקים של למידת מכונה. אתה יכול לעיין בנייר סקר זה לקבלת רשימה מקיפה של התקפות והגנות יריבות.

עבור יישומים רבים נוספים של התקפות והגנות יריבות, אולי תרצה לראות את ספריית הדוגמאות היריבית CleverHans .