文章目錄
FGSM介紹
Adversarial Example
Adversarial example是爲了混淆神經網絡而產生的特殊輸入,會導致模型對給定輸入進行錯誤分類。這些輸入對人眼來說是無法辨別的,但卻導致網絡無法識別圖像的內容。FGSM(Fast Gradient Signed Method) 是一種白盒攻擊,其目標是確保分類錯誤。
關於攻擊的分類有很多種,從攻擊環境來說,可以分爲黑盒攻擊,白盒攻擊或者灰盒攻擊:
- 黑盒攻擊:攻擊者對攻擊的模型的內部結構,訓練參數,防禦方法(如果加入了防禦手段的話)等等一無所知,只能通過輸出與模型進行交互。
- 白盒攻擊:與黑盒模型相反,攻擊者對模型一切都可以掌握。目前大多數攻擊算法都是白盒攻擊。
- 灰盒攻擊:介於黑盒攻擊和白盒攻擊之間,僅僅瞭解模型的一部分。(例如僅僅拿到模型的輸出概率,或者只知道模型結構,但不知道參數)
FGSM原理
在這裏,從熊貓的圖像開始,攻擊者在原始圖像上添加小的擾動,這導致模型將此圖像標記爲長臂猿,且具有很高的可信度。
FGSM的工作原理是利用神經網絡的梯度來創建一個Adversarial example。對於輸入圖像,該方法使用相對於輸入圖像的損失的梯度來創建使損失函數最大化的新圖像。這個新圖像被稱爲對抗圖像。可以使用以下表達式對其進行總結:
在這裏,梯度是相對於輸入的圖像的。這樣做是因爲其目標是創造一個最大化損失的圖像。實現這一點的方法是找出圖像中每個像素對損失值的貢獻程度,並相應地添加一個擾動(使用鏈式規則去計算梯度可以很容易地找到每個輸入像素的貢獻程度)。此外,由於模型不再被訓練(因此梯度不針對可訓練變量,即模型參數),因此模型參數保持不變。唯一的目的就是使一個已經受過訓練的模型發生錯誤的分類。
在這篇文章中,模型是MobileNetV2模型,在ImageNet上進行了預訓練。
代碼實現
1、導入需要的庫
import tensorflow as tf
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rcParams['figure.figsize'] = (8, 8)
mpl.rcParams['axes.grid'] = False
2、載入MobileNetV2模型
pretrained_model = tf.keras.applications.MobileNetV2(include_top=True,
weights='imagenet')
pretrained_model.trainable = False
有關遷移學習的內容可以參考:Tensorflow2.0之tf.keras.applacations遷移學習。
3、圖像預處理
def preprocess(image):
image = tf.cast(image, tf.float32)
image = image/255
image = tf.image.resize(image, (224, 224))
image = image[None, ...]
return image
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)
4、將圖像輸入模型並得到概率最高的分類結果
# Helper function to extract labels from probability vector
def get_imagenet_label(probs):
return tf.keras.applications.mobilenet_v2.decode_predictions(probs, top=1)[0][0]
image_probs = pretrained_model.predict(image)
plt.figure()
plt.imshow(image[0])
_, image_class, class_confidence = get_imagenet_label(image_probs)
plt.title('{} : {:.2f}% Confidence'.format(image_class, class_confidence*100))
plt.show()
可見MobileNetV2準確地判斷出圖像中是拉布拉多犬。
5、計算梯度
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
6、將要添加的噪聲打印出來
# 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])
7、定義函數來顯示圖像
def display_images(image, description):
_, label, confidence = get_imagenet_label(pretrained_model.predict(image))
plt.figure()
plt.imshow(image[0])
plt.title('{} \n {} : {:.2f}% Confidence'.format(description,
label, confidence*100))
plt.show()
8、加入噪聲後再將圖像輸入模型進行判斷
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, 0, 1)
display_images(adv_x, descriptions[i])
其中epsilons 表示噪聲的干擾程度。
由此可見,這個訓練好的模型已經不能對這張照片進行正確地分類了。