深度学习的恶意样本实践(Adversarial Example)

                                                                                  版权声明:本文为博主原创文章,未经博主允许不得转载。 http://www.thescrewshack.com/baimafujinji/article/details/89840023

                                                                                  〇、深度学习的恶意样本(Adversarial Example)

                                                                                  随着深度学习研究的深入,相关应用已经在许多领域展现出惊人的表现。一方面,深度学习的强大能力着实吸引着学术界和产业界的眼球。另外一方面,深度学习的安全问题也开始引起广泛地关注。对于一个给定的深度神经网络,经过训练,它可能在具体任务上(例如图像识别)表现出较高的准确率。但是在原本能够被正确分类的图像中引入稍许(人眼不易察觉)扰动,神经网络模型就可能被误导,从而得出错误的分类结果。例如,下图中最左侧的熊猫图片本来可以被正确分类,向其中加入一定的扰动,结果会得到右侧的熊猫图片。在人眼看来,它仍然是熊猫,但是神经网络模型却以相当高的置信率将其识别成了长臂猿。最右侧这个经过精心调整的能够误导神经网络模型的图像就被称为是恶意样本(Adversarial Example),或简称AE。

                                                                                  本文主要介绍几种流行的恶意样本(Adversarial Example)的生成方法,以下实验代码采用Python语言,环境是Ubuntu 18.04,深度学习模型以残差神经网络ResNet为例,它是基于Keras框架实现的。欢迎关注白马负金羁的博客 ,为保证公式、图表得以正确显示,强烈建议你从该地址(http://www.thescrewshack.com/baimafujinji)上查看原版博文。本博客主要关注方向包括:数字图像处理、算法设计与分析、数据结构、机器学习、数据挖掘、统计分析方法、自然语言处理。

                                                                                  ?

                                                                                  一、预备工作:CIFAR10与ResNet

                                                                                  Adversarial Example可以攻击各种深度学习应用,包括图像、声音、视频、甚至文本(在NLP领域)等。本文主要以图像的分类/识别任务为例来生成恶意样本。所选择之数据集为经典的CIFAR10(来自文献【1】),如下图所示。该数据集中的图像均为32×32的彩色图像,所有图像都被分成飞机、汽车、鸟、猫等10个类别(分类标签为0~9)。

                                                                                  我们以文献【3】中的代码为基础训练了一个专门用于对CIFAR10中之图像进行识别的分类器,特别地,这里的分类器指的是一个32层的残差神经网络ResNet。在下面的代码中,我们使用load_model()函数直接将训练好的ResNet模型导入。此外,下面的代码中还引入了一些后面将会用到的package,其中,art包是由IBM公司开发的AE工具箱(Adversarial Robustness Toolbox),参见文献【2】,在应用它之前,必须确认已经将其成功安装。

                                                                                  from os.path import abspath
                                                                                  import sys
                                                                                  import os
                                                                                  import tensorflow as tf
                                                                                  sys.path.append(abspath('.'))
                                                                                  
                                                                                  import keras
                                                                                  import numpy as np
                                                                                  import pickle
                                                                                  
                                                                                  import matplotlib.pyplot as plt
                                                                                  %matplotlib inline
                                                                                  
                                                                                  from keras.datasets import cifar10
                                                                                  from keras.models import load_model
                                                                                  from keras.utils import to_categorical
                                                                                  
                                                                                  from art.classifiers import KerasClassifier
                                                                                  from art.attacks.fast_gradient import FastGradientMethod
                                                                                  from art.attacks.iterative_method import BasicIterativeMethod
                                                                                  from art.attacks.saliency_map import SaliencyMapMethod
                                                                                  from art.attacks import DeepFool
                                                                                  
                                                                                  my_model = load_model('cifar10_ResNet32v1_model.189.h5')
                                                                                  
                                                                                  (x_train, y_train), (x_test, y_test) = cifar10.load_data()
                                                                                  x_train = x_train.astype('float32') / 255
                                                                                  x_test = x_test.astype('float32') / 255
                                                                                  x_train_mean = np.mean(x_train, axis=0)
                                                                                  x_train -= x_train_mean
                                                                                  x_test -= x_train_mean
                                                                                  
                                                                                  min_ = np.min(x_train) 
                                                                                  max_ = np.max(x_train)

                                                                                  下面来在Test集上测试一下我们训练好的ResNet32网络:

                                                                                  num_classes = 10
                                                                                  y_train_vector = keras.utils.to_categorical(y_train, num_classes)
                                                                                  y_test_vector = keras.utils.to_categorical(y_test, num_classes)
                                                                                  
                                                                                  scores = my_model.evaluate(x_test, y_test_vector, verbose=1)
                                                                                  
                                                                                  print('Test accuracy:', scores[1])

                                                                                  结果显示,这个网络在正常的测试集上可以达到91.96%的准确率。

                                                                                  10000/10000 [==============================] - 4s 375us/step
                                                                                  Test accuracy: 0.9196
                                                                                  

                                                                                  或者,你也可以使用下面的代码来测试,它的功能同之前的代码一致:

                                                                                  len_index = x_test.shape[0]
                                                                                  sum_success = 0
                                                                                  
                                                                                  for i in range(len_index):
                                                                                      y_pred = my_model.predict(x_test[i].reshape(1,32,32,3))
                                                                                      if (np.argmax(y_pred) == y_test[i]):
                                                                                          sum_success += 1
                                                                                  
                                                                                  print('Test accuracy:', sum_success/10000.0)

                                                                                  同样,可以得到91.96%的准确率:

                                                                                  Test accuracy: 0.9196
                                                                                  

                                                                                  做完上述这些必要的准备工作之后,就可以正式开启下面的AE生成实验了。再次提醒:尽管我们所使用的网络是ResNet32网络,但是你可以使用任何其他实现相同目的(即对CIFAR10中的图像进行分类)之网络来进行如下实验。欢迎关注白马负金羁的博客 ,为保证公式、图表得以正确显示,强烈建议你从该地址(http://www.thescrewshack.com/baimafujinji)上查看原版博文。本博客主要关注方向包括:数字图像处理、算法设计与分析、数据结构、机器学习、数据挖掘、统计分析方法、自然语言处理。下面的代码都是在Jupyter Notebook开发环境中完成的,其他环境可能会略有出入,请读者注意。

                                                                                  ?

                                                                                  二、FGSM

                                                                                  FGSM是一种比较简单的AE生成算法,它由来自谷歌大脑的三位研究者在文献【4】中提出,其中一位作者就是大名鼎鼎的 Goodfellow。Ian?Goodfellow因提出了生成对抗网络(GANs)而闻名,他被誉为“GANs之父”,甚至被认为是当前人工智能领域的顶级专家。他还是著名的花书《Deep Learning》的作者。文献【4】中的另外一个作者是Samy Bengio,他除了是深度学习领域的一位知名专家以外,还是新晋图灵奖得主Yoshua Bengio的兄弟。IBM ART工具箱中的FastGradientMethod函数实现了这个算法,下面我们就调用这个函数来对之前训练好的ResNet32网络发动AE攻击。

                                                                                  x_test_1K, y_test_1K = x_test[:1000], y_test_vector[:1000]
                                                                                  
                                                                                  classifier = KerasClassifier((min_, max_), model=my_model)
                                                                                  
                                                                                  # Craft adversarial samples with FGSM
                                                                                  epsilon = 0.03  # Maximum perturbation
                                                                                  adv_fgsm_crafter = FastGradientMethod(classifier)
                                                                                  
                                                                                  x_test_adv_fgsm = adv_fgsm_crafter.generate(x=x_test_1K, eps=epsilon)
                                                                                  
                                                                                  scores_adv_test = my_model.evaluate(x_test_adv_fgsm, y_test_1K, verbose=1)
                                                                                  print('Accuracy on Test AEs based on FGSM:', scores_adv_test[1])

                                                                                  基于1000个测试AE给出的模型准确率如下,可见准确率已经被大大降低:

                                                                                  1000/1000 [==============================] - 0s 309us/step
                                                                                  Accuracy on Test AEs based on FGSM: 0.187

                                                                                  下面的代码用于将原图及对应的AE绘制出来,以示对比:

                                                                                  fig=plt.figure(figsize=(8, 2))
                                                                                  columns = 8
                                                                                  rows = 2
                                                                                  for i in range(1, 9):
                                                                                      img = x_test[i+8].reshape(32,32,3) + x_train_mean
                                                                                      fig.add_subplot(rows, columns, i)
                                                                                      plt.imshow(img)
                                                                                      plt.axis('off')
                                                                                      
                                                                                  for i in range(1, 9):
                                                                                      img_adv = x_test_adv_fgsm[i+8].reshape(32,32,3) + x_train_mean
                                                                                      fig.add_subplot(rows, columns, i+8)
                                                                                      plt.imshow(img_adv)
                                                                                      plt.axis('off')

                                                                                  上述代码的执行效果如下,可见基于FGSM生成的AE图像在人眼看来仍然是可以辨识的。

                                                                                  但是将这些AE输入到神经网络后,则会发现神经网络均预测失败:

                                                                                  for i in range(9, 17):
                                                                                  ? ? y_pred = my_model.predict(x_test[i].reshape(1,32,32,3))
                                                                                  ? ? print(np.argmax(y_pred), end = ' ')
                                                                                  
                                                                                  print("")
                                                                                  for i in range(9, 17):
                                                                                  ? ? y_pred = my_model.predict(x_test_adv_fgsm[i].reshape(1,32,32,3))
                                                                                  ? ? print(np.argmax(y_pred), end = ' ')

                                                                                  如下所示,第一行给出的是正常图像的神经网络预测结果,第二行是相应AE之预测结果:

                                                                                  1 0 9 5 7 9 8 5 
                                                                                  9 3 1 4 6 1 6 3 

                                                                                  ?

                                                                                  三、IGSM

                                                                                  同样在文献【4】中,Goodfellow等人还给出了一个多次迭代版本的AE生成算法——IGSM。IBM ART工具箱中的BasicIterativeMethod函数实现了这个算法,下面的代码就调用这个函数来对之前训练好的ResNet32网络发动AE攻击。

                                                                                  epsilon=0.015  # Maximum perturbation
                                                                                  stepsize=0.005
                                                                                  adv_igsm_crafter = BasicIterativeMethod(classifier, eps=epsilon, eps_step=stepsize)
                                                                                  
                                                                                  x_test_adv_igsm = adv_igsm_crafter.generate(x=x_test_1K)
                                                                                  
                                                                                  scores_adv_test = my_model.evaluate(x_test_adv_igsm, y_test_1K, verbose=1)
                                                                                  print('Accuracy on Test AEs based on IGSM:', scores_adv_test[1])

                                                                                  基于1000个测试AE给出的模型准确率如下,可见准确率已经被大大降低:

                                                                                  1000/1000 [==============================] - 0s 317us/step
                                                                                  Accuracy on Test AEs based on IGSM: 0.063

                                                                                  欢迎关注白马负金羁的博客 ,为保证公式、图表得以正确显示,强烈建议你从该地址(http://www.thescrewshack.com/baimafujinji)上查看原版博文。本博客主要关注方向包括:数字图像处理、算法设计与分析、数据结构、机器学习、数据挖掘、统计分析方法、自然语言处理。同样我们可以将原图及对应的AE绘制出来,以示对比。代码同前,这里略去。效果如下,可见基于IGSM生成的AE图像在人眼看来仍然是可以辨识的。

                                                                                  但是将这些AE输入到神经网络后,则会发现神经网络均预测失败:

                                                                                  for i in range(9, 17):
                                                                                      y_pred = my_model.predict(x_test[i].reshape(1,32,32,3))
                                                                                      print(np.argmax(y_pred), end = ' ')
                                                                                  
                                                                                  print("")
                                                                                  for i in range(9, 17):
                                                                                      y_pred = my_model.predict(x_test_adv_igsm[i].reshape(1,32,32,3))
                                                                                      print(np.argmax(y_pred), end = ' ')

                                                                                  如下所示,第一行给出的是正常图像的神经网络预测结果,第二行是相应AE之预测结果:

                                                                                  1 0 9 5 7 9 8 5 
                                                                                  9 4 1 4 1 1 6 3 

                                                                                  ?

                                                                                  四、DeepFool

                                                                                  2016年,发表在CVPR上的文献【6】中提出了一种AE生成算法——DeepFool。IBM ART工具箱中的DeepFool函数实现了这个算法,其中需要注意的参数是max_iter 和epsilon,前者是生成算法的最大迭代次数,后者表示最大的扰动程度。

                                                                                  # Craft adversarial samples with DeepFool
                                                                                  adv_df_crafter = DeepFool(classifier, max_iter=50, epsilon=0.01)
                                                                                  
                                                                                  x_test_adv_df = adv_df_crafter.generate(x_test_1K)
                                                                                  
                                                                                  scores_adv_test = my_model.evaluate(x_test_adv_df, y_test_1K, verbose=1)
                                                                                  print('Accuracy on Test AEs based on DeepFool:', scores_adv_test[1])

                                                                                  与之前的情况类似,下面给出的是基于1000个测试AE给出的模型准确率,可见准确率已经被大大降低:

                                                                                  1000/1000 [==============================] - 0s 297us/step
                                                                                  Accuracy on Test AEs based on DeepFool: 0.325

                                                                                  欢迎关注白马负金羁的博客 ,为保证公式、图表得以正确显示,强烈建议你从该地址(http://www.thescrewshack.com/baimafujinji)上查看原版博文。本博客主要关注方向包括:数字图像处理、算法设计与分析、数据结构、机器学习、数据挖掘、统计分析方法、自然语言处理。同样我们可以将原图及对应的AE绘制出来,以示对比。代码同前,这里略去。效果如下,可见基于DeepFool生成的AE图像在人眼看来仍然是可以辨识的,而且效果比FGSM或IGSM的更贴近原图(也就是说引入的扰动更加细微)。

                                                                                  但是将这些AE输入到神经网络后,则会发现神经网络大概率地会预测失败:

                                                                                  for i in range(9, 17):
                                                                                      y_pred = my_model.predict(x_test[i].reshape(1,32,32,3))
                                                                                      print(np.argmax(y_pred), end = ' ')
                                                                                  
                                                                                  print("")
                                                                                  for i in range(9, 17):
                                                                                      y_pred = my_model.predict(x_test_adv_df[i].reshape(1,32,32,3))
                                                                                      print(np.argmax(y_pred), end = ' ')

                                                                                  如下所示,第一行给出的是正常图像的神经网络预测结果,第二行是相应AE之预测结果:

                                                                                  1 0 9 5 7 9 8 5 
                                                                                  9 4 1 4 7 8 6 7 

                                                                                  ?

                                                                                  五、JSMA

                                                                                  JSMA是由Nicolas Papernot等在2016年的Euro S&P上提出的一种L_0类型的AE生成算法,参见文献【5】。与前面介绍的几种算法不同,JSMA是一种Targeted的攻击算法。也就是说,它不仅可以误导神经网络输出错误的分类结果,还可以预设一个目标,让神经网络输出指定的(错误)分类结果。因此,我们需要先给出预设的分类目标。这里采取的方法为,总是令神经网络输出原本的正确标签的下一个作为目标标签,例如正确的标签本应该是8,则AE会误导神经网络输出9,如果正确的标签本应该是9,则AE会误导神经网络输出0... ... 下面的代码用于生成预设之标签:

                                                                                  test_len = y_test.shape[0]
                                                                                  y_test_t = np.zeros(y_test.shape)
                                                                                  
                                                                                  for i in range(test_len):
                                                                                      y_test_t[i][0] = (y_test[i][0] + 1)%num_classes
                                                                                  
                                                                                  y_test_t_vector = keras.utils.to_categorical(y_test_t, num_classes)
                                                                                  
                                                                                  y_test_target = y_test_t_vector[:1000]

                                                                                  IBM ART工具箱中的SaliencyMapMethod函数实现了JSMA算法,下面的代码就调用这个函数来对之前训练好的ResNet32网络发动AE攻击。

                                                                                  # Craft adversarial samples with JSMA
                                                                                  adv_jsma_crafter = SaliencyMapMethod(classifier, theta=0.1)
                                                                                  
                                                                                  x_test_adv_jsma = adv_jsma_crafter.generate(x_test_1K, y = y_test_target)
                                                                                  
                                                                                  scores_adv_test = my_model.evaluate(x_test_adv_jsma, y_test_1K, verbose=1)
                                                                                  print('Accuracy on Test AEs based on JSMA:', scores_adv_test[1])

                                                                                  同样可以将原图及对应的AE绘制出来,以示对比。代码同前,这里略去。效果如下,可见基于JSMA生成的AE图像在人眼看来仍然是可以辨识的。但作为一种L_0类型的AE生成算法,被引入的扰动往往是人眼可见的。

                                                                                  将这些AE输入到神经网络后,则会发现神经网络会被有方向地误导:

                                                                                  for i in range(9, 17):
                                                                                      y_pred = my_model.predict(x_test[i].reshape(1,32,32,3))
                                                                                      print(np.argmax(y_pred), end = ' ')
                                                                                  
                                                                                  print("")
                                                                                  for i in range(9, 17):
                                                                                      y_pred = my_model.predict(x_test_adv_jsma[i].reshape(1,32,32,3))
                                                                                      print(np.argmax(y_pred), end = ' ')

                                                                                  如下所示,第一行给出的是正常图像的神经网络预测结果,第二行是相应AE之预测结果。跟我们预想的一样,神经网络在面对AE时所给出的标签总是比相应的正常图像所给出的结果后移一位(当然这个误导的目标你也可以随意设定)。

                                                                                  1 0 9 5 7 9 8 5 
                                                                                  2 1 0 6 8 0 9 6 

                                                                                  ?

                                                                                  参考文献与推荐阅读材料:

                                                                                  【1】https://www.cs.toronto.edu/~kriz/cifar.html

                                                                                  【2】https://adversarial-robustness-toolbox.readthedocs.io/en/latest/

                                                                                  【3】https://github.com/keras-team/keras/blob/master/examples/cifar10_resnet.py

                                                                                  【4】Alexey Kurakin, Ian Goodfellow, Samy Bengio, Adversarial examples in the physical world,?https://arxiv.org/abs/1607.02533

                                                                                  【5】Nicolas Papernot, Patrick McDaniel, Somesh Jha, Matt Fredrikson, Z. Berkay Celik, Ananthram Swami,?The Limitations of Deep Learning in Adversarial Settings,?IEEE European Symposium on Security & Privacy, 2016

                                                                                  【6】Seyed-Mohsen Moosavi-Dezfooli, Alhussein Fawzi, Pascal Frossard, DeepFool: a simple and accurate method to fool deep neural networks, CVPR, 2016

                                                                                  ?

                                                                                  (全文完)

                                                                                  展开阅读全文

                                                                                  没有更多推荐了,返回首页