通俗理解神经网络的对抗攻击及keras代码实例

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010420283/article/details/83685140

上一篇转载的博文《神经网络中的对抗攻击与对抗样本》帮助我理解了神经网络学习的本质,以及对抗攻击的来龙去脉。接下来在这篇文章:《忽悠神经网络指南:教你如何把深度学习模型骗得七荤八素》中进一步理解了神经网络中白箱攻击,本博文拟在加深学习印象,并结合自己的一些理解对该文章将的一些内容做一个重梳理。

因为本人也处于学习阶段,博文中因考虑不全面或有欠缺的地方欢迎交流指正。

为什么要进行对抗攻击研究

未来我们的社会必定是一个自动化的环境,比如智能家居,智能安防,自动驾驶等,很多的岗位通过一个传感器,摄像头、扫描仪就可以直接完成,而不需要人来干预。神经网络技术目前在占据重要的地位,如果目标检测,人脸识别中。如果有不怀好心之人入侵你的系统中,利用神经网络的特点,将非法的输入进行一些伪装,从而骗过网络得到被网络认为是合法的输出,那带来的损失和危害也会是巨大的。

比如在以下场景中:

  • 欺骗自动驾驶汽车使其认为看到的“停车”路标是一个绿灯——这可以引起车祸!

  • 欺骗内容过滤系统使其无法识别出具有攻击性的和非法的信息。

  • 欺骗ATM支票扫描系统使其错误的识别支票上面的实际金额信息。(如果你被抓到的话还可以很合理的推卸掉自己的罪责!)

现在知名国际比赛NIPS中就有一个赛道是专门针对这种对抗性模型分类研究的,所以神经网络的对抗性研究至关重要。

神经网络的不稳定性

神经网络为什么为什么能取得很大的成功,除去它是拟在模仿人脑神经元工作这个酷炫的外衣外,对分类任务来讲,本质也就是经过常见的线性变换、拉伸、旋转将低维数据投影到高维空间,继而凸显放大了不同样本之间的差异,也就是说学习到了数据的分布特征。

卷积神经网络(CNN)在2014年的ImageNet图像分类任务中大放异彩,如今被工业界广泛使用。然而,一张图像的分类结果实际上是通过网络各个卷积层的权重值共同作用,因为有这么多的值共同作用,所以一点点的改变可能对输出结果影响不大,然而从全局的思想来看,如果我们知道了影响输出结果的那个阈值,进而通过对输入图像的某些地方做一点点的改变,那么引导一个错误的输出就将会是一件很容易的事情了。所以说神经网络是可以被忽悠的,由此就有了神经网络中的对抗攻击研究。

另一方面,我的研究课题是SAR影像的海冰分类(不同海冰类型在图像中很难辨识,而且有一个分类样本两种冰型共存现象),CNN网络作为我实验的分类方法,我发现同样的网络结构如果训练多次就可以得到多个模型,每一次的网络的分类性能是一样的,但是对同一张分类样本的输出结果(比如分类概率值)有时候区别还挺大。起初我总结这种现象是因为CNN进行优化器训练方式的原因,每次寻找最优解的方向不同,所以得到的网络参数也会稍微不同。现在来看,可能神经网络学习本身就带有了一种不稳定性,而我们的研究者也很早就针对这种现象进行了对抗攻击研究,不得不让人佩服他们的洞察能力。

如何欺骗一个分类器

机器学习分类器的工作原理就是找到一条区分事物之间的分界线。 以下图示是一个简单的二维分类器,它学习的目标是将绿球(合规)与红球(违规)区分开来:

现在,分类器的精度达到100%。它找到了一条可以将所有的绿球与红球完美分开的区隔线。但是,如果我们想要调整一下模型使得一个红球被故意区分成绿球呢?我们最少要将红球移动多少才会使得它被推到绿球的判定区域呢?

如果我们把分界线旁边那个红球的Y值少量增加,那么我们就几乎可以把它推到绿球的判定区域了:

所以要想欺骗一个分类器,我们只需要知道从哪个方向来推动这个点可以使它越过区隔线即可。如果我们不想使这个错误过于明显,理想情况下我们会使这个移动尽可能的小,以至于其看起来就像是一个无心之过。

在使用深层神经网络进行图像分类时,我们分类的每个“点”其实是由成千上万个像素组成的完整图像。这就给了我们成千上万个可以通过微调来使预测结果跨过决策线的可能值。如果我们可以确保自己对图像中像素点的调整不是肉眼可见般的明显,我们就可以做到在愚弄分类器的同时又不会使图像看起来是被人为篡改过的。

换句话说,我们可以选取一张真实物品的图像,通过对特定像素点做出非常轻微地修改使得图像被神经网络完全识别为另一件物品—而且我们可以精准地控制这个替代品是什么:

忽æ ç¥ç»ç½ç»æåï¼æä½ å¦ä½æ深度学习模åéªå¾ä¸è¤å«ç´ 

把一只猫变成烤面包机。图像检测结果来自与Keras.js的Web演示:https://transcranial.github.io/keras-js/#/inception-v3

神经网络的白箱攻击

白箱攻击是指我们提前知道了分类网络的结构和参数,然后有针对性的对输入图像像素做一些小的调整,调整前后的图像对人的肉眼来说没有区别,但是却能得到一个与原本分类不同的、有引导性的网络输出结果。

训练神经网络以分类照片的基本过程:

  1. 添加一张训练用图片;
  2. 查看神经网络的预测结果,看看其距离正确答案有多远;
  3. 使用反向传播算法来调整神经网络中每一层的权重,使预测结果更接近于正确答案。
  4. 在数千张不同的训练照片上重复步骤1-3。

相比于调整神经网络每一层的权重,如果我们直接修改输入图像本身直到得到我们想要的答案为止呢?比如选用了已经训练好的神经网络,并再次“训练”它,不过这次我们将使用反向传播算法来直接调整输入图像而不是神经网络层的权重:

忽æ ç¥ç»ç½ç»æåï¼æä½ å¦ä½æ深度学习模åéªå¾ä¸è¤å«ç´ 

 新的算法流程:

  1. 添加一张我们想要“黑”的照片。
  2. 检查神经网络的预测结果,看看其距离我们想要的答案有多远。
  3. 使用反向传播算法来调整照片本身,使预测结果更接近于我们想要的答案。
  4. 使用相同的照片重复步骤1-3上千次,直到神经网络输出结果为我们想要的答案为止。

在此之后,我们将会得到一张可以欺骗神经网络的图片,同时并不改变神经网络本身。就生成了一张白盒攻击图像。

这样做存在一个问题:由于算法在调整上没有任何限制,允许以任何尺度来调整任何像素点,所以图像的最终更改结果可能会大到显而易见:他们会出现变色光斑或者变形波浪区域。

忽æ ç¥ç»ç½ç»æåï¼æä½ å¦ä½æ深度学习模åéªå¾ä¸è¤å«ç´ 

 一张被“黑”过的照片,由于没有对像素点可被调整的尺度做约束,你可以看到猫周围有了绿色光斑和白色墙壁上出现的波浪形图案。

为了防止这些明显的图形失真,我们可以将算法加上一个简单的限定条件。我们限定篡改的图片中每一个像素在原始的基础上的变化幅度取一个微量值,譬如0.01%。这就使算法在微调图片的时候仍然能够骗过神经网络却不会与原始图片差别太大。

在加入限定后重新生成的图片如下:

忽æ ç¥ç»ç½ç»æåï¼æä½ å¦ä½æ深度学习模åéªå¾ä¸è¤å«ç´ 

在每个像素只能在一定范围内变化的限制条件下生成的被“黑”的图片。即使这张图对人眼来说篡改后没有区别,却可以骗过神经网络!

keras代码实例

理论和实践总是要结合在一起的,此部分内容全部来自文章开头讲的对那篇忽悠神经网络指南,原作者给了用keras框架实现的代码。在这里一并贴出。

原始图像的预测代码:

(原代码地址:https://gist.github.com/ageitgey/8a010ee99f55fe2ef93cae7d02e170e8#file-predict-py

import numpy as np
from keras.preprocessing import image
from keras.applications import inception_v3

# Load pre-trained image recognition model
model = inception_v3.InceptionV3()

# Load the image file and convert it to a numpy array
img = image.load_img("cat.png", target_size=(299, 299))
input_image = image.img_to_array(img)

# Scale the image so all pixel intensities are between [-1, 1] as the model expects
input_image /= 255.
input_image -= 0.5
input_image *= 2.

# Add a 4th dimension for batch size (as Keras expects)
input_image = np.expand_dims(input_image, axis=0)

# Run the image through the neural network
predictions = model.predict(input_image)

# Convert the predictions into text and print them
predicted_classes = inception_v3.decode_predictions(predictions, top=1)
imagenet_id, name, confidence = predicted_classes[0][0]
print("This is a {} with {:.4}% confidence!".format(name, confidence * 100))

篡改一下图片直到能够骗过这个神经网络让它认为图片是一个烤面包机。

原作者代码地址:https://gist.github.com/ageitgey/873e74b7f3a75b435dcab1dcf4a88131#file-generated_hacked_image-py

import numpy as np
from keras.preprocessing import image
from keras.applications import inception_v3
from keras import backend as K
from PIL import Image

# Load pre-trained image recognition model
model = inception_v3.InceptionV3()

# Grab a reference to the first and last layer of the neural net
model_input_layer = model.layers[0].input
model_output_layer = model.layers[-1].output

# Choose an ImageNet object to fake
# The list of classes is available here: https://gist.github.com/ageitgey/4e1342c10a71981d0b491e1b8227328b
# Class #859 is "toaster"
object_type_to_fake = 859

# Load the image to hack
img = image.load_img("cat2.png", target_size=(299, 299))
original_image = image.img_to_array(img)

# Scale the image so all pixel intensities are between [-1, 1] as the model expects
original_image /= 255.
original_image -= 0.5
original_image *= 2.

# Add a 4th dimension for batch size (as Keras expects)
original_image = np.expand_dims(original_image, axis=0)

# Pre-calculate the maximum change we will allow to the image
# We'll make sure our hacked image never goes past this so it doesn't look funny.
# A larger number produces an image faster but risks more distortion.
max_change_above = original_image + 0.01
max_change_below = original_image - 0.01

# Create a copy of the input image to hack on
hacked_image = np.copy(original_image)

# How much to update the hacked image in each iteration
learning_rate = 0.1

# Define the cost function.
# Our 'cost' will be the likelihood out image is the target class according to the pre-trained model
cost_function = model_output_layer[0, object_type_to_fake]

# We'll ask Keras to calculate the gradient based on the input image and the currently predicted class
# In this case, referring to "model_input_layer" will give us back image we are hacking.
gradient_function = K.gradients(cost_function, model_input_layer)[0]

# Create a Keras function that we can call to calculate the current cost and gradient
grab_cost_and_gradients_from_model = K.function([model_input_layer, K.learning_phase()], [cost_function, gradient_function])

cost = 0.0

# In a loop, keep adjusting the hacked image slightly so that it tricks the model more and more
# until it gets to at least 80% confidence
while cost < 0.80:
    # Check how close the image is to our target class and grab the gradients we
    # can use to push it one more step in that direction.
    # Note: It's really important to pass in '0' for the Keras learning mode here!
    # Keras layers behave differently in prediction vs. train modes!
    cost, gradients = grab_cost_and_gradients_from_model([hacked_image, 0])

    # Move the hacked image one step further towards fooling the model
    hacked_image += gradients * learning_rate

    # Ensure that the image doesn't ever change too much to either look funny or to become an invalid image
    hacked_image = np.clip(hacked_image, max_change_below, max_change_above)
    hacked_image = np.clip(hacked_image, -1.0, 1.0)

    print("Model's predicted likelihood that the image is a toaster: {:.8}%".format(cost * 100))

# De-scale the image's pixels from [-1, 1] back to the [0, 255] range
img = hacked_image[0]
img /= 2.
img += 0.5
img *= 255.

# Save the hacked image!
im = Image.fromarray(img.astype(np.uint8))
im.save("hacked-image.png")

备注:

原始图像预测的代码中需要外网连接imageNet 的classes列表,我的电脑总连不上,于是直接把那个列表下载到了本地,代码稍做了一点改变。有需要可以在百度云上自取:链接:https://pan.baidu.com/s/1sNMEUj3mTnT7PlzL2efVQQ ,提取码:gs0s 

本人实验中原始图像用InceptionV3预测为波斯猫的可能性是:84.01%。生成的攻击图像输入网络预测为toaster的可能性是89.8%,人直观的看两张图像并没有区别,实在是太可怕了!

       

神经网络的黑箱攻击

黑箱攻击是指并不知道原始网络的内部构造

上面我们的操作需要有能够直接进入神经网络的权限,因为我们实际上是“训练”神经网络来欺骗自身,我们需要它的拷贝版。在实际生活中,没有公司会让你下载的到他们受过训练的神经网络的代码,这也就意味着我们无法来进行这个攻击性的操作了……对吗?

并没有!研究者发现,我们可以通过探测另一个神经网络的运转训练一个自己的神经网络替代品以此镜像这个网络。然后,使用我们的替代品神经网络来生成通用的欺骗原来神经网络的黑客图像!这被称为黑箱攻击(black-box attack)。

我觉得黑箱攻击就是指我们不停的改变输入图像进入到拟攻击网络,根据拟攻击网络的输出获取到该网络的一定规律,然后建立一个该网络的镜像网络(即对抗网络)改变我们的输入,这样就能够达到欺骗拟攻击网络的目的了。但是这样也需要拿大量的样本去试错,类似穷举了。公司应该会对这样的用户采取一些反攻击策略吧。

猜你喜欢

转载自blog.csdn.net/u010420283/article/details/83685140