DeepLearning | 快速梯度符号法(FGSM)生成对抗样本(Adversarial Examples)的原理与python实现

最近基于对抗样本做了一些工作,这里写一篇论文介绍对抗样本基本的原理和生成方法。内容上参考Goodfellow的论文 Explaining and Harnessing Adversarial Examples

一、什么是对抗样本?

对抗样本的概念最早提出于2014年Szegedy的论文 Intriguing Properties of Neural Networks. 在论文,作者发现了一种有趣的现象,即:当前流行的机器学习模型包括神经网络会容易以很高的置信度分错和原始样本仅仅有轻微不同的样本,这类样本被称为对抗样本。这一现象揭示了现有机器学习算法的盲点和不足,即没有完全掌握数据的本质特点,从而容易受到被精心设计的对抗样本的攻击
下图很好的描述了对抗样本的作用, 即原始图片在被加上轻微的噪声之后,分类器会以很高的置信度将图片识别为另外一类
在这里插入图片描述
那么,对抗样本的原理是什么呢?

二、对抗样本的线性解释

Goodfellow在论文中给出了一个解释:在线性高维情况下,即使是很小的扰动,也会对输出造成非常大的影响。这里将对抗样本记为 x ˉ \bar{x} , 线性模型的权重为 w w , 扰动为 η \eta , 同时扰动的强度限制在一定范围内 η L < ε \left \|\eta\right \|_L<\varepsilon . 我们可以有式(1)

w x ˉ = w x + x η w\bar{x}=wx+x\eta (1)

从上式我们可以知道,当 w w 的维度很高时,即使扰动 η \eta 很小,最终的输出也会受到很大的影响。Goodfellow认为,当前主流的机器学习模型中存在太多的线性性质,如神经网络的每一层其实都是一个线性模型,而常用的ReLu激活函数也局部线性的,所以,在高维情况下,小的扰动也会造成很大的输出误差

三、快速梯度符号法FGSM生成对抗样本

基于提出的线性解释,Goodfellow提出了一种非常简单的生成对抗样本的方法称为fast gradient sign method (FGSM). 式(1)中的扰动 η \eta

η = ε s i g n ( x J ( Θ , x , y ) ) \eta =\varepsilon sign(\bigtriangledown_{x}J(\Theta,x,y)) (2)

这里 J J 表示损失函数,简单来说,就是模型的损失函数对样本求导,再取符号函数,乘上扰动强度,便得到了对抗样本

这里给出一份为普通多层神经网络生成对抗样本的代码

from sklearn.datasets import load_boston
from sklearn import preprocessing
from sklearn.model_selection import train_test_split 
from keras import optimizers
import keras.backend as K
from keras import losses

from keras.models import Sequential
from keras.layers import Dense
import warnings

warnings.filterwarnings("ignore")

boston = load_boston()

data = boston.data
data = preprocessing.StandardScaler().fit_transform(data) 
label = boston.target
traindata, testdata, trainlabel, testlabel = train_test_split(data,label,test_size=0.2, random_state=0)

model = Sequential()
model.add(Dense(128,input_dim=13,activation='relu'))
model.add(Dense(64,activation='relu'))
model.add(Dense(64,activation='relu'))
model.add(Dense(32,activation='relu'))
model.add(Dense(1))

adam = optimizers.adam(lr=0.01, decay=1e-2)
model.compile(loss='mse',optimizer=adam)

model.fit(traindata,trainlabel,batch_size=64, epochs=200,verbose=0,shuffle=True,validation_split=0.1)
testdata += 0.1
score = model.evaluate(testdata,testlabel,verbose=0,batch_size=64)
print(score)

sess = K.get_session()
testdata_adv = testdata

epochs = 1
epsilon = 0.1

loss = losses.mse(testlabel,model.output)
grads = K.gradients(loss,model.input)
    
delta = K.sign(grads[0])
testdata_adv += epsilon*delta
    
testdata_adv = sess.run(testdata_adv, feed_dict={model.input:testdata})
    
testdata_adv = preprocessing.StandardScaler().fit_transform(testdata_adv)
score = model.evaluate(testdata_adv,testlabel,verbose=0,batch_size=64)
print(score)

发布了74 篇原创文章 · 获赞 269 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/Liangjun_Feng/article/details/94045777