对抗网络学习-FGSM对抗样本生成

在这里插入图片描述
对抗样本指的是一个经过微小调整就可以让机器学习算法输出错误结果的输入样本。在图像识别中,可以理解为原来被一个卷积神经网络(CNN)分类为一个类(比如“熊猫”)的图片,经过非常细微甚至人眼无法察觉的改动后,突然被误分成另一个类(比如“长臂猿”)。
在这里插入图片描述
为什么这样轻微的扰动可以对神经网络造成如此大的影响,业界目前的共识认为这不是过拟合的结果,而是因为输入特征维度过高和模型的线性性质导致的。

深度模型本实确实是一个非常非线性的模型,但是模型的组成部分都是线性的,全连接网络的矩阵乘法是线性的,卷积网络的卷积计算也是计算点乘,同样也是线性的,哪怕是激活函数,看似是为了造成模型的非线性,但是目前主流的relu激活函数其实在部分区域内也是线性的。

因此,尽管深度模型整体呈非线性,但是其中的线性部分却依旧占了很大一部分,也正是如此,轻微的扰动经过网络的积累后会形成雪崩效应,从而对最终结果造成影响。

更具体的来说,在高维空间中,每个像素值即使改变很小,这些改变会通过线性模型的参数进行点乘累计造成很明显的变化。只要方向正确,即使数据上只是迈出了一小步,在特征空间上就是一大步,极大概率会跨越决策层。

Fast Gradient Sign Method (FGSM)

关键公式

x′=x+η
η =εsign(▽xJ(θ,x,y))

参数解释:

x -输入图象 ,x^′-输出图像, η-扰动

ε-步长,即扰动大小

Sign()-符号函数,J(θ,x,y)损失函数

θ -模型参数,x-模型输入,y-标签

主要思想

攻击成功的目标是使得模型分类错误,也即是利用加入扰动的样本使得模型的损失增大,而我们沿着梯度方向添加扰动,可以对分类结果产生最大的影响,因为我们一般是沿着梯度下降的方向去减小损失函数。

代码实现

from __future__ import absolute_import, division, print_function, unicode_literals
import warnings
warnings.filterwarnings('ignore')
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

# Let's load the pretained MobileNetV2 model and the ImageNet class names.
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


# Helper function to preprocess the image so that it can be inputted in MobileNetV2
# 对图像预处理,使得图像可以输入MobileNetV2模型
def preprocess(image):
    image = tf.cast(x=image, dtype=tf.float32)
    image = image/255
    image = tf.image.resize(images=image, size=(224, 224))
    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]#只获取第一个

#image_path = tf.keras.utils.get_file(fname='YellowLabradorLooking_new.jpg', origin='https://storage.googleapis.com/download.tensorflow.org/example_images/YellowLabradorLooking_new.jpg')

#image_path=tf.keras.utils.get_file('turtle.jpg','https://storage.googleapis.com/download.tensorflow.org/example_images/Green_Sea_Turtle_grazing_seagrass.jpg')
image_path = tf.keras.utils.get_file(fname='grace_hopper.jpg', origin='https://storage.googleapis.com/download.tensorflow.org/example_images/grace_hopper.jpg')
image_raw = tf.io.read_file(filename=image_path)

image = tf.image.decode_image(contents=image_raw)#可以自动判定图像格式然后 decode

image = preprocess(image)#预处理
image_probs = pretrained_model.predict(image)  #模型预测,输入测试集,输出预测结果---概率

plt.figure()
plt.imshow(image[0])
_, image_class, class_confidence = get_imagenet_label(image_probs)#probs?
plt.title('{} : {:.2f}% Confidence'.format(image_class, class_confidence*100))#加入标签
plt.show()

#计算梯度
loss_object = tf.keras.losses.CategoricalCrossentropy()#损失函数--交叉熵损失函数
#交叉熵是用来评估当前训练得到的概率分布与真实分布的差异情况。
#它刻画的是实际输出(概率)与期望输出(概率)的距离,也就是交叉熵的值越小,两个概率分布就越接近。

def create_adversarial_pattern(input_image, input_label):
    with tf.GradientTape() as tape:  #梯度带
        tape.watch(tensor=input_image)            #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, image_probs)
plt.imshow(perturbations[0])

在这里插入图片描述

#定义函数来显示图像
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()

#加入噪声后再将图像输入模型进行判断
epsilons = [0, 0.01, 0.1, 0.15, 0.20]
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[0]
    adv_x = tf.clip_by_value(adv_x, 0, 1) # 将值限制在[0,1]范围内
    display_images(adv_x, descriptions[i])

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
参考链接
https://blog.csdn.net/nemoyy/article/details/81052301
https://blog.csdn.net/nemoyy/article/details/81052301
https://download.csdn.net/download/qq_35225463/11646431

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值