當前位置:
首頁 > 新聞 > 對抗樣本的基本原理

對抗樣本的基本原理

雷鋒網AI科技評論按:本文首發於「兜哥帶你學安全」微信公眾號。

概述

對抗樣本是機器學習模型的一個有趣現象,攻擊者通過在源數據上增加人類難以通過感官辨識到的細微改變,但是卻可以讓機器學習模型接受並做出錯誤的分類決定。一個典型的場景就是圖像分類模型的對抗樣本,通過在圖片上疊加精心構造的變化量,在肉眼難以察覺的情況下,讓分類模型產生誤判。

對抗樣本的基本原理

在原理上介紹對抗樣本,以經典的二分類問題為例,機器學習模型通過在樣本上訓練,學習出一個分割平面,在分割平面的一側的點都被識別為類別一,在分割平面的另外一側的點都被識別為類別二。

對抗樣本的基本原理

生成攻擊樣本時,我們通過某種演算法,針對指定的樣本計算出一個變化量,該樣本經過修改後,從人類的感覺無法辨識,但是卻可以讓該樣本跨越分割平面,導致機器學習模型的判定結果改變。

對抗樣本的基本原理

如何高效的生成對抗樣本,且讓人類感官難以察覺,正是對抗樣本生成演算法研究領域的熱點。

梯度演算法和損失函數

對抗樣本其實對機器學習模型都有效,不過研究的重點還是在神經網路尤其是深度學習網路領域。理解對抗樣本演算法,需要一定的神經網路的知識。在深度學習模型裡面,經常需要使用梯度演算法,針對損失函數的反饋不斷調整各層的參數,使得損失函數最小化。損失函數可以理解為理想和現實之間的差距,通常定義一個函數來描述真實值和預測值之間的差異,在訓練階段,真實值就是樣本對應的真實標籤和預測值就是機器學習模型預測的標籤值,這些都是明確的,所以損失函數是可以定義和計算的。在分類問題中,常見的損失函數包括binary_crossentropy和categorical_crossentropy。

  • binary_crossentropy

binary_crossentropy亦稱作對數損失,

  • categorical_crossentropy

categorical_crossentropy亦稱作多類的對數損失

機器學習模型訓練的過程就是不斷調整參數追求損失函數最小的過程。梯度可以理解為多元函數的指定點上升的坡度。梯度可以用偏導數來定義,通常損失函數就是這個多元函數,特徵向量就可以看成這個多元函數的某個點。在訓練過程中,針對參數的調整可以使用梯度和學習率來定義,其中學習率也叫做學習步長,物理含義就是變數在梯度方向上移動的長度,學習率是一個非常重要的參數,過大會導致損失函數的震蕩難以收斂,過小會導致計算緩慢,目前還沒有很成熟的理論來推導最合適的學習率,經驗值是0.001-0.1之間,迭代更新參數x的方法為:

xk+1=xk+??grad(x)

當我們求函數的最大值時,我們會向梯度向上的方向移動,所以使用加號,也成為梯度向上演算法。如果我們想求函數的最小值時,則需要向梯度向下的方向移動,也成為梯度下降演算法。所以使用減號,比如求損失函數最小值是,對應迭代求解的方法為:

xk+1=xk???grad(x)

我們通過一個非常簡單的例子演示這個過程,假設我們只有一個變數x,對應的損失函數定義為:

f(x)=x2+2

根據梯度的定義,可以獲得對應的梯度為:

grad(x)=?f(x)/?(x)=2x

我們隨機初始化x,學習率設置為0.1,整個過程如下:

def demo:

import random

a=0.1

x=random.randint(1,10)

y = x * x + 2

index=1

while index 0.01 :

y=x*x+2

print "batch={} x={} y={}".format(index,x,y)

x=x-2*x*a

index+=1

整個迭代過程最多100步,由於我們預先知道函數的最小值為2,所以如果當計算獲得的函數值非常接近2,我們也可以提前退出迭代過程,比如絕對值相差不超過0.01。最後果然沒讓我們失望,在迭代20次後就找到了接近理論上的最小點。

batch=14 x=0.329853488333 y=2.10880332377

batch=15 x=0.263882790666 y=2.06963412721

batch=16 x=0.211106232533 y=2.04456584141

batch=17 x=0.168884986026 y=2.02852213851

batch=18 x=0.135107988821 y=2.01825416864

batch=19 x=0.108086391057 y=2.01168266793

batch=20 x=0.0864691128455 y=2.00747690748

Keras裡面提供相應的工具返回loss函數關於variables的梯度,variables為張量變數的列表,這裡的loss函數即損失函數。

from keras import backend as K

k.gradients(loss, variables)

Keras也提供了function用於實例化一個Keras函數,inputs是輸入列表列表,其元素為佔位符或張量變數,outputs為輸出張量的列表

k.function(inputs, outputs, updates=[])

在進行神經網路訓練時,追求的是損失函數最小,因此每輪訓練時,通過訓練集數據與模型的參數進行矩陣計算,獲得預測值,這一過程成為正向傳遞。然後通過計算預測值與目標值的損失函數,通過鏈式法則,計算出梯度值,然後根據梯度下降演算法調整模型的參數值,這一過程成為反向傳遞。經過若干輪訓練後,損失函數下降到可以接受的程度,模型的參數也完成了調整,整個訓練過程結束。

攻擊InceptionV3模型

一般的卷積層只是一味增加卷積層的深度,但是在單層上卷積核卻只有一種,這樣特徵提取的功能可能就比較弱。Google增加單層卷積層的寬度,即在單層卷積層上使用不同尺度的卷積核,他們構建了Inception這個基本單元,基本的Inception中有1x1卷積核,3x3卷積核,5x5卷積核還有一個3x3下採樣,從而產生了InceptionV1模型。InceptionV3的改進是使用了2層3x3的小卷積核替代了5x5卷積核。以攻擊InceptionV3模型為例,介紹生成攻擊樣本的基本原理。Keras內置了這個模型,我們直接使用就可以了。從模型中直接獲取第一層的輸入作為輸入層,最後一層的輸出為輸出層。

model = inception_v3.InceptionV3

model_input_layer = model.layers[0].input

model_output_layer = model.layers[-1].output

然後載入我們攻擊的圖片,比如我們的小豬。這裡需要特彆強調的是,NumPy出於性能考慮,默認的變數賦值會引用同樣一份內存,所以我們需要使用np.copy手工強制複製一份圖像數據。

img = image.load_img("../picture/pig.jpg", target_size=(299, 299))

original_image = image.img_to_array(img)

hacked_image = np.copy(original_image)

為了避免圖像變化過大,超過肉眼可以接受的程度,我們需要定義閾值。

max_change_above = original_image + 0.01

max_change_below = original_image - 0.01

下面我們要定義最關鍵的三個函數了,我們定義損失函數為識別為烤麵包機的概率,因此我們需要使用梯度上升演算法,不斷追求損失函數的最大化,變數object_type_to_fake定義的就是烤麵包機對應的標籤,在InceptionV3中麵包機的標籤為859。

object_type_to_fake = 859

有了損失函數以後,我們就可以通過Keras的介面獲取到對應的梯度函數。最後通過K.function獲取一個Keras函數實例,該函數的輸入列表分別為輸入層和當前是訓練模式還是測試模式的標記learning_phase,輸出列表是損失函數和梯度。關於K.function的使用建議閱讀Keras的在線文檔。

cost_function = model_output_layer[0, object_type_to_fake]

gradient_function = K.gradients(cost_function, model_input_layer)[0]

grab_cost_and_gradients_from_model =

K.function([model_input_layer,K.learning_phase()],

[cost_function, gradient_function] )

下面我們就可以開始通過訓練迭代最終獲得我們需要的圖片了,我們認為烤麵包機的概率超過60%即可,所以我們定義損失函數的值超過0.6即可以完成訓練。我們設置使用訓練模式,learning_phase標記為0,使用梯度上升的演算法迭代獲取新的圖片內容。為了不影響肉眼識別,超過閾值的部分會截斷,這部分功能使用NumPy的np.clip即可完成。

while cost cost, gradients = grab_cost_and_gradients_from_model([hacked_image, 0])

hacked_image += gradients * learning_rate

hacked_image = np.clip(hacked_image, max_change_below, max_change_above)

hacked_image = np.clip(hacked_image, -1.0, 1.0)

我們輸出梯度的內容,便於我們理解。

[[ 2.29095144e-06 4.88560318e-07 -1.26309533e-06]

[ -1.21029143e-06 -7.01245654e-06 -9.00149917e-06]

[ -8.28917791e-07 -3.46928073e-06 3.33982143e-06]

...,

[ -2.91559354e-06 -8.72657665e-07 6.22621087e-07]

[ 2.66754637e-06 1.84044097e-06 -2.53160965e-06]

[ -4.96620885e-07 3.94217068e-07 -7.95937069e-07]]]]

訓練完成後,保存圖片即可。這裡需要說明的是,圖像保存到NumPy變數後,每個維度都是0-255之間的整數,需要轉換成-1到1之間的小數便於模型處理。保存成圖像的時候需要再轉換回以前的範圍。

img = hacked_image[0]

img /= 2.

img += 0.5

img *= 255.

im = Image.fromarray(img.astype(np.uint8))

im.save("../picture/hacked-pig-image.png")

在我的Mac本經過接近2個小時3070次迭代訓練,獲得了新的家豬圖像,但是機器學習模型識別它為烤麵包機的概率卻達到了95.61%,我們攻擊成功。在GPU伺服器上大致運行5分鐘可以得到一樣的結果。

對抗樣本的基本原理

總結

本章介紹了對抗樣本的基本原理,並以最簡單的梯度下降演算法演示了生成對抗樣本的基本過程,大家可能會因為它的效率如此低而印象深刻。後面我們將進一步介紹常見的幾種生成對抗樣本的演算法。

參考文獻

  • https://medium.com/@ageitgey/machine-learning-is-fun-part-8-how-to-intentionally-trick-neural-networks-b55da32b7196

  • https://blog.csdn.net/u012223913/article/details/68942581

  • Ian J. Goodfellow, Jonathon Shlens & Christian Szegedy,EXPLAINING AND HARNESSING ADVERSARIAL EXAMPLES,arXiv:1412.6572

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 雷鋒網 的精彩文章:

CCF-GAIR 2018將在6月底席捲鵬城,三大新玩法了解一下?

TAG:雷鋒網 |