机器学习原来如此有趣:如何故意欺骗神经网络




只要程序员一直在编写计算机程序,计算机黑客就会一直寻找破解这些程序的方法。恶意黑客利用程序中最小的错误来破解系统,窃取数据,然后会造成严重破坏。



但由深度学习算法驱动的系统应该能够避免人为干扰,对吗?一个黑客如何破解经过TB级数据训练出的神经网络?



事实证明,即使是最先进的深层神经网络也容易被愚弄。有一些技巧,你可以迫使他们预测你想要的结果:


我修改了这张猫图片,所以它被认为是烤面包机。


因此,在你启动由深层神经网络驱动的新系统之前,让我们详细了解如何破解这些系统,以及如何保护自己免受攻击者的伤害。


将神经网络作为安全卫士


我们假设我们经营像Ebay这样的拍卖网站。在我们的网站上,我们想防止人们出售违禁物品 比如活的动物。


如果你有数百万的用户,执行这些规则是很困难的。我们可以聘请数百人手动审查每一个拍卖清单,但这显然是不合理的。相反,我们可以使用深度学习自动检查违禁物品的拍卖照片,并标记违反规定的拍摄照片。


这是一个典型的图像分类问题。为了构建这个,我们将训练一个深层卷积神经网络来告诉机器禁止的项目和允许上传的项目,然后我们将通过它运行我们网站上的所有照片。


首先,我们需要一个来自过去拍卖列表的成千上万个图像的数据集。我们需要允许和禁止的项目的图像,以便我们可以训练神经网络来告诉他们:


为了训练神经网络,我们将使用标准的反向传播算法。这种算法的特点是,我们输入一个训练图片,输入该图片的预期结果,然后回到神经网络中的每一层轻轻地调整他们的权重,使他们更好地产生该图片的正确输出:



我们用数千张照片重复上千次,直到模型以可接受的准确性可靠地产生正确的结果。


最终的结果是可以可靠地分类图像的神经网络:



但事情并不如他们看起来那么可靠。。。


卷积神经网络是对整个图像进行分类时考虑的强大模型。无论复杂的形状和图案出现在哪里,他都可以识别到。在许多图像识别任务中,它们们与人类的表现不相上下,有时候甚至能够击败人类。


有了像这样的杰出的模型,将图像中的几个像素更改为更暗或更轻,对最终的预测不应该有很大的影响,对吧?当然可能会稍微改变最终的可能性,但不会将图像从“禁止”转换为“允许”。


我们期望的是:输入照片的小变化只能对最终预测造成微小的变化。


但是在2013年的著名论文“神经网络”中,发现这并不总是真的。如果你知道到底是哪个像素改变了和究竟有多少个像素被改变,你可以有意迫使神经网络对于给定的照片做出错误的输出,而不需要对图片的外观改变非常多的地方。


这意味着我们可以有意制作一张明显是禁止物品的照片,但完全愚弄我们的神经网络:


为什么是这样?机器学习分类器的工作原理是找到分开的东西之间的分界线。以下是一个简单的二维分类器的图形,它被要求学习将绿点(可接受)与红点(禁止)分开:


现在,分类器的精度达到100%。它发现一条线,将所有的绿点与红点完美分开。


但是,如果我们欺骗它让它讲一个红点当做绿点来分类呢?我们可以将红点推到绿色领域的最低限度是多少?


如果我们在边界旁边的红点的Y值加少量,那么我们几乎可以把它推到绿色领域:


所以要欺骗一个分类器,我们只需要知道向哪个方向来推动这个点,以便让它在一行上。如果我们不想对恶意言论过于明确,理想情况下我们会尽可能的减少这一点,这样看起来就是一个诚实的错误。


在具有深层神经网络的图像分类中,我们分类的每个“点”是由数千个像素组成的整个图像。这给了我们数千种可能的值,让我们去调整值来将这个点推到决定界限的另一头。如果我们可以以不太明显的方式调整图像中的像素,我们就可以愚弄分类器,而不会使图像看起来受到操纵。


换句话说,我们可以为一个对象拍一张照片,然后非常轻微地改变像素,使得图像完全可以骗过神经网络 - 而且我们可以精确地控制它检测到的对象:


把一只猫变成烤面包机 来自Keras.js基于Web的演示的图像检测结果


如何欺骗神经网络


我们已经讨论了训练神经网络分类照片的基本过程:

1.饲养(Feed in)训练照片。

2.检查神经网络的预测,看看距离正确答案有多远。

3.使用反向传播调整神经网络中每一层的权重,使最终预测更接近正确答案。

4.重复步骤1-3几千次与几千个不同的训练照片。


但是,如果不调整神经网络的层次的权重,而是改变输入图像本身直到我们得到我们想要的答案为止会怎么样呢?


所以让我们使用已经训练好的神经网络,并进再次“训练”。但是这次让我们使用反向传播来调整输入图像而不是神经网络层:


所以这里是新的算法:


1.输入我们想要hack的图片

2.检查神经网络的预测,看看我们想要获得的答案还有多远。

3.使用反向传播调整我们的照片,使最终的预测更接近我们想要的答案。

4.使用相同的照片重复步骤1-3几千次, 直到网络给我们想要的答案。


在这个结尾,我们将有一个可以愚弄神经网络的图像,而不改变神经网络本身内的任何东西。


唯一的问题是,没有任何限制的允许调整任何单个像素,图像的更改可能会非常大,他们会出现变色斑点或波浪区域:


为了防止这些明显的扭曲,我们可以为我们的算法添加一个简单的约束。我们可以规定被hacked的图像每个像素的改变范围- 比如说不能超过0.01%。这迫使我们的算法以一种仍然愚弄神经网络的方式来调整图像,而不会看起来与原始图像不同。


以下是添加该约束时生成的图像的样子:


即使这个图像看起来和我们一样,它仍然愚弄神经网络!


下面就可以开始写代码了!


为了编码,首先我们需要一个预先训练的神经网络来被欺骗。而不是从头开始培训,我们将会使用Google创建的。


受欢迎的深层学习框架Keras带有几个预先训练的神经网络。我们将使用经过预处理的Google Inception v3深层神经网络副本来检测1000种不同类型的对象


这里是Keras的基本代码,用于识别使用该神经网络的图片中的内容。在运行之前,请确保安装了Python 3和Keras:


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))

view rawpredict.py hosted with ❤ by GitHub


当我们运行它,它将正确地检测我们的图是一只波斯猫:

$ python3 predict.py
This is a Persian_cat with 85.7% confidence!


现在让我们来想一想,通过调整图像,直到它骗过神经网络,这只猫才是烤面包机。


Keras没有内置的方式来训练输入图像,只能训练神经网络层,所以我不得不来点小技巧,手动编写训练步骤。

以下是代码:

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("cat.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")

如果我们运行这个,它最终会吐出一个会欺骗神经网络的图像:

$ python3 generated_hacked_image.py
Model's predicted likelihood that the image is a toaster: 0.00072%
[ .... a few thousand lines of training .... ]
Model's predicted likelihood that the image is a toaster: 99.4212%


注意:如果你没有GPU,则可能需要几个小时才能运行。如果你的GPU正确配置了Keras和CUDA,则运行时间不应超过两分钟。


现在我们来测试一下我们刚刚通过原始模型运行的黑客图像:

$ python3 predict.py
This is a toaster with 98.09% confidence!


我们做到了!我们欺骗神经网络让它认为这只猫是烤面包机!


我们可以用黑客图像做什么?


创建了一个被这样被黑客攻击的图像称为“产生对抗的例子”。我们有意制作一个数据,以便机器学习模型将错误分类。这是一个有趣的戏法,但为什么这在现实世界中这是一个麻烦呢?


研究表明,这些黑客图像有一些令人惊讶的属性:


1.即使它们打印在纸上,黑客图像仍然可以欺骗神经网络!因此,你可以使用这些被黑客入侵的图像来愚弄物理摄像机或扫描仪,而不仅仅是直接上传图像文件的系统。


2.愚弄一个神经网络的图像倾向于以完全不同的设计愚弄其他神经网络,如果他们接受类似数据的训练。


所以我们可以用这些黑客图片做很多事情!


但是我们如何创建这些图像仍然有很大的限制 - 我们的攻击需要直接访问神经网络本身。因为我们实际上是“训练”神经网络来愚弄,所以我们需要一个它的副本。在现实世界中,没有任何公司会让你下载他们训练有素的神经网络的代码,这意味着我们不能攻击他们...对吧?


不!研究人员最近表明,你可以训练你自己的替代神经网络,通过探索另一个神经网络来观察其行为。然后,你可以使用你的替代神经网络来生成愚弄原始网络的黑客图像!这被称为黑匣子攻击。


黑匣子攻击的应用是无限的。这里有一些合理的例子:

  • 自驾车把红灯视为绿灯,这样可能会导致汽车出车祸!
  • 技巧内容过滤系统让冒犯/非法内容通过。

而这些攻击方法并不仅限于图像。你可以使用同样的方法来愚弄可用于其他类型数据的分类器。例如,你可以欺骗病毒扫描程序将你的病毒识别为安全的代码!


我们如何保护自己免受这些袭击?


那么现在我们知道有可能欺骗神经网络(和所有其他机器学习模型),我们如何防御这个攻击呢?


简单的答案是,没有人是完全确定的。防止这种攻击仍然是一个持续的研究领域。跟随最新发展的最好方法是阅读由Ian Goodfellow和Nicolas Papernot维护的这个由这个领域最有影响力的研究人员组成的cleverhans blog


但到目前为止我们知道的一些事情:

  • 如果你只是创建大量被黑客入侵的图像,并将它们包含在你未来的培训数据集中,那似乎使你的神经网络更能抵御这些攻击。这被称为对抗训练,现在可能是比较合理的方法。
  • 还有另一种有效的方法叫做防御性蒸馏,你可以在此训练第二个模型来模拟你的原始模型。但是这种方法是新的而且相当复杂的,所以我不会投资这个,除非你有专门的需求。
  • 研究人员迄今为止尝试过的其他所有想法几乎都不能有助于防止这些攻击。


由于我们还没有任何最终答案,你需要谨慎考虑使用神经网络的场景,以便减少这种攻击会对你的业务造成损害的风险。

via medium.com


D∬G   设计和代码其实都是一种艺术修行~~

设计灵感来自于梦境和现实的夹层中 ~~
     扫一扫立刻加入iGeekBar会员QQ群(545980198)
    和更多iG客会员交流分享吧~