姓名:張安琪 ?學(xué)號(hào):17021211235
轉(zhuǎn)載自:https://www.leiphone.com/news/201806/aLeiPZA0FbVtQI6M.html,有刪節(jié)谐岁。
【嵌牛導(dǎo)讀】:對(duì)抗樣本是機(jī)器學(xué)習(xí)模型的一個(gè)有趣現(xiàn)象墨礁,攻擊者通過(guò)在源數(shù)據(jù)上增加人類難以通過(guò)感官辨識(shí)到的細(xì)微改變幢竹,但是卻可以讓機(jī)器學(xué)習(xí)模型接受并做出錯(cuò)誤的分類決定。
【嵌牛鼻子】:機(jī)器學(xué)習(xí) 對(duì)抗樣本
【嵌牛提問(wèn)】:對(duì)抗樣本的基本原理是什么恩静?
【嵌牛正文】:
概述
對(duì)抗樣本是機(jī)器學(xué)習(xí)模型的一個(gè)有趣現(xiàn)象焕毫,攻擊者通過(guò)在源數(shù)據(jù)上增加人類難以通過(guò)感官辨識(shí)到的細(xì)微改變,但是卻可以讓機(jī)器學(xué)習(xí)模型接受并做出錯(cuò)誤的分類決定驶乾。一個(gè)典型的場(chǎng)景就是圖像分類模型的對(duì)抗樣本邑飒,通過(guò)在圖片上疊加精心構(gòu)造的變化量,在肉眼難以察覺(jué)的情況下级乐,讓分類模型產(chǎn)生誤判疙咸。
在原理上介紹對(duì)抗樣本,以經(jīng)典的二分類問(wèn)題為例唇牧,機(jī)器學(xué)習(xí)模型通過(guò)在樣本上訓(xùn)練罕扎,學(xué)習(xí)出一個(gè)分割平面,在分割平面的一側(cè)的點(diǎn)都被識(shí)別為類別一丐重,在分割平面的另外一側(cè)的點(diǎn)都被識(shí)別為類別二。
生成攻擊樣本時(shí)杆查,我們通過(guò)某種算法扮惦,針對(duì)指定的樣本計(jì)算出一個(gè)變化量,該樣本經(jīng)過(guò)修改后亲桦,從人類的感覺(jué)無(wú)法辨識(shí)崖蜜,但是卻可以讓該樣本跨越分割平面,導(dǎo)致機(jī)器學(xué)習(xí)模型的判定結(jié)果改變客峭。
如何高效的生成對(duì)抗樣本豫领,且讓人類感官難以察覺(jué),正是對(duì)抗樣本生成算法研究領(lǐng)域的熱點(diǎn)舔琅。
梯度算法和損失函數(shù)
對(duì)抗樣本其實(shí)對(duì)機(jī)器學(xué)習(xí)模型都有效等恐,不過(guò)研究的重點(diǎn)還是在神經(jīng)網(wǎng)絡(luò)尤其是深度學(xué)習(xí)網(wǎng)絡(luò)領(lǐng)域。理解對(duì)抗樣本算法,需要一定的神經(jīng)網(wǎng)絡(luò)的知識(shí)课蔬。在深度學(xué)習(xí)模型里面囱稽,經(jīng)常需要使用梯度算法,針對(duì)損失函數(shù)的反饋不斷調(diào)整各層的參數(shù)二跋,使得損失函數(shù)最小化战惊。損失函數(shù)可以理解為理想和現(xiàn)實(shí)之間的差距,通常定義一個(gè)函數(shù)來(lái)描述真實(shí)值和預(yù)測(cè)值之間的差異扎即,在訓(xùn)練階段吞获,真實(shí)值就是樣本對(duì)應(yīng)的真實(shí)標(biāo)簽和預(yù)測(cè)值就是機(jī)器學(xué)習(xí)模型預(yù)測(cè)的標(biāo)簽值,這些都是明確的谚鄙,所以損失函數(shù)是可以定義和計(jì)算的各拷。在分類問(wèn)題中,常見(jiàn)的損失函數(shù)包括binary_crossentropy和categorical_crossentropy襟锐。
binary_crossentropy
binary_crossentropy亦稱作對(duì)數(shù)損失,
categorical_crossentropy
categorical_crossentropy亦稱作多類的對(duì)數(shù)損失
機(jī)器學(xué)習(xí)模型訓(xùn)練的過(guò)程就是不斷調(diào)整參數(shù)追求損失函數(shù)最小的過(guò)程撤逢。梯度可以理解為多元函數(shù)的指定點(diǎn)上升的坡度。梯度可以用偏導(dǎo)數(shù)來(lái)定義粮坞,通常損失函數(shù)就是這個(gè)多元函數(shù)蚊荣,特征向量就可以看成這個(gè)多元函數(shù)的某個(gè)點(diǎn)。在訓(xùn)練過(guò)程中莫杈,針對(duì)參數(shù)的調(diào)整可以使用梯度和學(xué)習(xí)率來(lái)定義互例,其中學(xué)習(xí)率也叫做學(xué)習(xí)步長(zhǎng),物理含義就是變量在梯度方向上移動(dòng)的長(zhǎng)度筝闹,學(xué)習(xí)率是一個(gè)非常重要的參數(shù)媳叨,過(guò)大會(huì)導(dǎo)致?lián)p失函數(shù)的震蕩難以收斂,過(guò)小會(huì)導(dǎo)致計(jì)算緩慢关顷,目前還沒(méi)有很成熟的理論來(lái)推導(dǎo)最合適的學(xué)習(xí)率糊秆,經(jīng)驗(yàn)值是0.001-0.1之間,迭代更新參數(shù)x的方法為:
xk+1=xk+??grad(x)
當(dāng)我們求函數(shù)的最大值時(shí),我們會(huì)向梯度向上的方向移動(dòng)议双,所以使用加號(hào)痘番,也成為梯度向上算法。如果我們想求函數(shù)的最小值時(shí)平痰,則需要向梯度向下的方向移動(dòng)汞舱,也成為梯度下降算法。所以使用減號(hào)宗雇,比如求損失函數(shù)最小值是昂芜,對(duì)應(yīng)迭代求解的方法為:
xk+1=xk???grad(x)
我們通過(guò)一個(gè)非常簡(jiǎn)單的例子演示這個(gè)過(guò)程,假設(shè)我們只有一個(gè)變量x赔蒲,對(duì)應(yīng)的損失函數(shù)定義為:
f(x)=x2+2
根據(jù)梯度的定義泌神,可以獲得對(duì)應(yīng)的梯度為:
grad(x)=?f(x)/?(x)=2x
我們隨機(jī)初始化x良漱,學(xué)習(xí)率設(shè)置為0.1,整個(gè)過(guò)程如下:
def demo():
import random
a=0.1
x=random.randint(1,10)
y = x * x + 2
index=1
while index < 100 and abs(y-2) > 0.01 :
y=x*x+2
print "batch={} x={} y={}".format(index,x,y)
x=x-2*x*a
index+=1
整個(gè)迭代過(guò)程最多100步腻扇,由于我們預(yù)先知道函數(shù)的最小值為2债热,所以如果當(dāng)計(jì)算獲得的函數(shù)值非常接近2,我們也可以提前退出迭代過(guò)程幼苛,比如絕對(duì)值相差不超過(guò)0.01窒篱。最后果然沒(méi)讓我們失望,在迭代20次后就找到了接近理論上的最小點(diǎn)舶沿。
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里面提供相應(yīng)的工具返回loss函數(shù)關(guān)于variables的梯度墙杯,variables為張量變量的列表,這里的loss函數(shù)即損失函數(shù)括荡。
from keras import backend as K
k.gradients(loss, variables)
Keras也提供了function用于實(shí)例化一個(gè)Keras函數(shù)高镐,inputs是輸入列表列表,其元素為占位符或張量變量畸冲,outputs為輸出張量的列表
k.function(inputs, outputs, updates=[])
在進(jìn)行神經(jīng)網(wǎng)絡(luò)訓(xùn)練時(shí)嫉髓,追求的是損失函數(shù)最小,因此每輪訓(xùn)練時(shí)邑闲,通過(guò)訓(xùn)練集數(shù)據(jù)與模型的參數(shù)進(jìn)行矩陣計(jì)算算行,獲得預(yù)測(cè)值,這一過(guò)程成為正向傳遞苫耸。然后通過(guò)計(jì)算預(yù)測(cè)值與目標(biāo)值的損失函數(shù)州邢,通過(guò)鏈?zhǔn)椒▌t,計(jì)算出梯度值褪子,然后根據(jù)梯度下降算法調(diào)整模型的參數(shù)值量淌,這一過(guò)程成為反向傳遞。經(jīng)過(guò)若干輪訓(xùn)練后嫌褪,損失函數(shù)下降到可以接受的程度呀枢,模型的參數(shù)也完成了調(diào)整,整個(gè)訓(xùn)練過(guò)程結(jié)束笼痛。
攻擊InceptionV3模型
一般的卷積層只是一味增加卷積層的深度硫狞,但是在單層上卷積核卻只有一種,這樣特征提取的功能可能就比較弱晃痴。Google增加單層卷積層的寬度,即在單層卷積層上使用不同尺度的卷積核财忽,他們構(gòu)建了Inception這個(gè)基本單元倘核,基本的Inception中有1x1卷積核,3x3卷積核即彪,5x5卷積核還有一個(gè)3x3下采樣紧唱,從而產(chǎn)生了InceptionV1模型活尊。InceptionV3的改進(jìn)是使用了2層3x3的小卷積核替代了5x5卷積核。以攻擊InceptionV3模型為例漏益,介紹生成攻擊樣本的基本原理蛹锰。Keras內(nèi)置了這個(gè)模型,我們直接使用就可以了绰疤。從模型中直接獲取第一層的輸入作為輸入層铜犬,最后一層的輸出為輸出層。
model = inception_v3.InceptionV3()
model_input_layer = model.layers[0].input
model_output_layer = model.layers[-1].output
然后加載我們攻擊的圖片轻庆,比如我們的小豬癣猾。這里需要特別強(qiáng)調(diào)的是,NumPy出于性能考慮余爆,默認(rèn)的變量賦值會(huì)引用同樣一份內(nèi)存纷宇,所以我們需要使用np.copy手工強(qiáng)制復(fù)制一份圖像數(shù)據(jù)。
img = image.load_img("../picture/pig.jpg", target_size=(299, 299))
original_image = image.img_to_array(img)
hacked_image = np.copy(original_image)
為了避免圖像變化過(guò)大蛾方,超過(guò)肉眼可以接受的程度像捶,我們需要定義閾值。
max_change_above = original_image + 0.01
max_change_below = original_image - 0.01
下面我們要定義最關(guān)鍵的三個(gè)函數(shù)了桩砰,我們定義損失函數(shù)為識(shí)別為烤面包機(jī)的概率拓春,因此我們需要使用梯度上升算法,不斷追求損失函數(shù)的最大化五芝,變量object_type_to_fake定義的就是烤面包機(jī)對(duì)應(yīng)的標(biāo)簽痘儡,在InceptionV3中面包機(jī)的標(biāo)簽為859。
object_type_to_fake = 859
有了損失函數(shù)以后枢步,我們就可以通過(guò)Keras的接口獲取到對(duì)應(yīng)的梯度函數(shù)沉删。最后通過(guò)K.function獲取一個(gè)Keras函數(shù)實(shí)例,該函數(shù)的輸入列表分別為輸入層和當(dāng)前是訓(xùn)練模式還是測(cè)試模式的標(biāo)記learning_phase()醉途,輸出列表是損失函數(shù)和梯度矾瑰。關(guān)于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] )
下面我們就可以開(kāi)始通過(guò)訓(xùn)練迭代最終獲得我們需要的圖片了隘擎,我們認(rèn)為烤面包機(jī)的概率超過(guò)60%即可殴穴,所以我們定義損失函數(shù)的值超過(guò)0.6即可以完成訓(xùn)練。我們?cè)O(shè)置使用訓(xùn)練模式货葬,learning_phase()標(biāo)記為0采幌,使用梯度上升的算法迭代獲取新的圖片內(nèi)容。為了不影響肉眼識(shí)別震桶,超過(guò)閾值的部分會(huì)截?cái)嘈莅@部分功能使用NumPy的np.clip即可完成。
while cost < 0.60:
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)
我們輸出梯度的內(nèi)容蹲姐,便于我們理解磨取。
[[? 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]]]]
訓(xùn)練完成后人柿,保存圖片即可。這里需要說(shuō)明的是忙厌,圖像保存到NumPy變量后凫岖,每個(gè)維度都是0-255之間的整數(shù),需要轉(zhuǎn)換成-1到1之間的小數(shù)便于模型處理逢净。保存成圖像的時(shí)候需要再轉(zhuǎn)換回以前的范圍哥放。
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本經(jīng)過(guò)接近2個(gè)小時(shí)3070次迭代訓(xùn)練,獲得了新的家豬圖像汹胃,但是機(jī)器學(xué)習(xí)模型識(shí)別它為烤面包機(jī)的概率卻達(dá)到了95.61%婶芭,我們攻擊成功。在GPU服務(wù)器上大致運(yùn)行5分鐘可以得到一樣的結(jié)果着饥。