【译】骗过神经网络:创造你自己的对抗样本

浏览: 3437

作者:Daniel Geng and Rishi Veerapaneni

来源:ML@B(Machine Learning@Berkley)

参与:Cynthia、大伟、周剑

翻译:本文为天善智能编译,未经容许,禁止转载

通过神经网络实施暗杀听起来是不是很疯狂?——它确实可能发生,不过不是通过你想象的方式。

当然,神经网络被用来可以训练无人机或使用其他大规模杀伤性武器,但即使是一种无害化的(目前可用的)网络训练,也可以用来对付它的主人。这是因为神经网络非常容易被一些所谓的对抗样本所影响。

对抗样本是导致网络输出不正确的输入。举个例子:你可以从一张熊猫的图片开始,一些网络有57.7%的自信认为这是“熊猫”,“熊猫”类也是所有类别中最有自信的一类,所以网络得出的结论是,图片中的对象是熊猫。但是,通过添加非常少量的精心构造的噪声,你可以得到一个在人类看来完全相同,但是网络认为有99.3%的概率是“长臂猿”!

Clipboard Image.png

那么,如何通过对抗样本进行暗杀呢?想象一下,用一个对抗样本来代替一个停止标志——也就是说,一个人会立即识别出的信号,而神经网络甚至不会注册。想象一下,在一个繁忙的十字路口放置一个这样的停车标志。当自动驾驶的汽车接近交叉口时,车载神经网络将看不到停车标志,并继续开入迎面而来的车流,而使它的使用者接近死亡(理论上来说)。

这可能只是一个令人费解和稍微(更加)轰动的例子,说明人们如何使用对抗样本来造成伤害,但还有更多的例子。例如,iPhone X的“Face ID”解锁功能依赖于神经网络识别人脸,因此容易受到对抗性攻击。人们可以构建对抗的图像来绕过面部ID的安全特性。其他生物识别安全系统也将面临风险,非法或不适当的内容可能会通过使用对抗样本绕过基于神经网络的内容过滤器。这些样本的存在意味着,包含深度学习模型的系统实际上有很高的安全风险。

Clipboard Image.png

你可以将对抗样本理解成神经网络的视错觉。如同视错觉可以欺骗人类的大脑,对抗样本也可以欺骗神经网络。

上面例举的熊猫是一个针对性的例子。在图像中添加了少量的精心构造的噪声,使得神经网络对图像进行了错误分类,尽管图像在人类看起来完全相同。也有一些非针对性的例子,它们只是试图找到任何能欺骗神经网络的输入。这个输入对一个人来说可能像是白噪音,但是因为我们不再需要寻找对人类有象征意义的输入项,问题就简单多了。

我们可以在任何神经网络上找到对抗样本,甚至是在有所谓“超人”能力的最先进的模型中,而这将带来一些麻烦。事实上,我们很容易就可以创建一个对抗示例,在这篇文章中我们就向您展示如何实现它。

Clipboard Image.png

MNIST的对抗实例:

我们将会尝试欺骗一个在MNIST数据集上训练的vanilla前馈神经网络。MNIST是28×28像素的图像的数据集手写数字。它们看起来是这样的:

Clipboard Image.png

首先我们输入需要的数据库

import network.network as network
import network.mnist_loader as mnist_loader
import pickle
import matplotlib.pyplot as pltimport numpy as np

有50000个训练图像和10000个测试图像。我们首先加载预训练的神经网络

with open('trained_network.pkl', 'rb') as f:
net = pickle.load(f)
training_data, validation_data, test_data = 
mnist_loader.load_data_wrapper()

pickle是python在本质上保存类和对象序列化数据(即写入磁盘)的一种方式。load()只是打开了网络已保存的版本。

简单介绍一下这个经过训练的神经网络。它有784个输入神经元(对应28×28 = 784像素),一层有30个隐藏的神经元,和10个输出神经元(对应每个数字)。所有的激活都是反曲的;它的输出是一个热矢量,表示网络的预测,并且通过最小化平均平方误差的损失来训练。

def predict(n):
# Get the data from the test set
x = test_data[n][0]
# Get output of network and prediction
activations = net.feedforward(x)
prediction = np.argmax(activations)
# Print the prediction of the network
print('Network output: ')
print(activations)
print('Network prediction: ')
print(prediction)
print('Actual image: ')
# Draw the image
plt.imshow(x.reshape((28,28)), cmap='Greys')

以下是一部分输出结果:

Clipboard Image.pngClipboard Image.png


左边是MNIST的图像。右侧绘制神经网络的10个输出,称为激活。在输出中激活的越大,神经网络就越认为图像是这个数字。

好啦,我们已经有了一个经过训练的网络,但我们要怎么骗过它呢?我们将首先从一个简单的非针对性方法开始,然后一旦我们掌握了这个方法,我们就可以用一个小技巧将它修改作为有针对性的方法。


  • 非针对性的攻击
  • 为此,我们将采用与训练神经网络相同的方法:梯度下降法。我们可以求出关于输入的函数的导数 xC

    利用反向传播,然后使用梯度下降法更新找到最好的Clipboard Image.png将成本降至最低。

    反向传播通常用于发现权重的梯度和相对于成本的偏差,但在全面的概括性的反向传播中,仅仅是一种算法,它能有效地计算出计算图上的梯度(这正是神经网络)。因此它也可以用来计算关于神经网络输入的成本函数的梯度。

    好了,让我们看一下实际产生对抗例子的代码:

    def adversarial(net, n, steps, eta):
    """
    net : network object
    neural network instance to use
    n : integer
    our goal label (just an int, the function transforms it into a one-hot vector)
    steps : integer
    number of steps for gradient descent
    eta : integer
    step size for gradient descent
    """
    # Set the goal output
    goal = np.zeros((10, 1))
    goal[n] = 1
    # Create a random image to initialize gradient descent with
    x = np.random.normal(.5, .3, (784, 1))
    # Gradient descent on the input
    for i in range(steps):
    # Calculate the derivative
    d = input_derivative(net,x,goal)
    # The GD update on x
    x -= eta * d
    return x

    首先,我们在代码中创建一个名为 goal的ygoal。接下来,我们将Clipboard Image.png作为随机的784-维度向量初始化。有了这个向量,我们现在可以开始梯度下降,这实际上只有两行代码。第一行 d = input_derivative(net,x,goal)使用反向传播计算∇xC。梯度下降循环的第二行 x -= eta * d  表示我们沿着相反的梯度方向以步长eta移动。

    以下是非针对性对抗样本示例,以及神经网络的预测:

    Clipboard Image.png

    非针对性“3”

    Clipboard Image.png

    非针对性“1”

    令人难以置信的是,神经网络认为一些图像实际上是具有高度自信的数字。“3”就是很好的例子。对于大多数其他的数字,神经网络对每个数字的激活率都很低,这表明它非常混乱。看起来很不错!

    在所有这些照片中,只有一个很小很小的部分在人眼中看起来像数字。而鉴于有很多图片,许多在神经网络看来都像是数字(这个问题的部分原因是,我们的神经网络从来没有被看起来不像数字的图像训练过,所以被给予此类图片时神经网络的输出几乎是随机的)。所以当我们寻找对神经网络来说像数字的图片时,我们更容易找到一个噪音或静态的图像,而不仅仅是人眼中看起来像是数字的图像。


  • 针对性的攻击
  • 这些对抗性的例子很酷,但对人类来说,它们只是像噪音一样。如果我们能有一个看起来像什么东西的对抗性的例子,这不是很酷吗?也许一个“2”的图像让神经网络是5?事实证明这是可能的!而且我们对原始代码的修改非常小。我们只要将一个术语加入到我们的最小化成本函数中。新的成本函数是:

    Clipboard Image.png

    实现最小化新成本函数的代码几乎与原始代码相同(我们称其为 sneaky_adversarial(),因为我们狡猾地使用了有针对性的攻击。)

    def sneaky_adversarial(net, n, x_target, steps, eta, lam=.05):
    """
    net : network object
    neural network instance to use
    n : integer
    our goal label (just an int, the function transforms it into a one-hot vector)
    x_target : numpy vector
    our goal image for the adversarial example
    steps : integer
    number of steps for gradient descent
    eta : integer
    step size for gradient descent
    lam : float
    lambda, our regularization parameter. Default is .05
    """
    # Set the goal output
    goal = np.zeros((10, 1))
    goal[n] = 1
    # Create a random image to initialize gradient descent with
    x = np.random.normal(.5, .3, (784, 1))
    # Gradient descent on the input
    for i in range(steps):
    # Calculate the derivative
    d = input_derivative(net,x,goal)
    # The GD update on x, with an added penalty
    # to the cost function
    # ONLY CHANGE IS RIGHT HERE!!!
    x -= eta * (d + lam * (x - x_target))
    return x

    我们唯一改变的是梯度下降更新: x -= eta * (d + lam * (x - x_target)) 额外的术语解释了我们的成本函数中的新术语。 让我们来看看新一代方法的结果:

    Clipboard Image.png

    目标为 “0” [x_target=6]

    Clipboard Image.png

    目标为"1" [x_target=7]

    非针对性的攻击有两种模式。神经系统要么完全被骗过了,对于错误的数字有很高的激活率;要么它只是很疑惑,每种数字的激活率都很低。有趣的是,现在前一种情况大大增加了,神经系统不再仅仅是疑惑,而是完全被欺骗了。 看起来,在梯度下降过程中,一些已被正则化成更加“像数字一样”的对抗示例能使收敛性更好。


  • 应对对抗样本
  • 我们刚刚创造了能够骗过神经网络的图片。下一个问题是我们是否能对抗此类袭击。如果你仔细看看针对性对抗样本的图片,你会发现它们的背景中有某种浅灰色的图案。

    我们可以尝试的一种很简单的方法是使用二进制阈值(binary thresholding)来将背景完全变白:

    def binary_thresholding(n, m):
        """
        n: int 0-9, the target number to match
        m: index of example image to use (from the test set)
        """
        
        # Generate adversarial example
        x = sneaky_generate(n, m)
        # Binarize image
        x = (x > .5).astype(float)
        
        print("With binary thresholding: ")
        
        plt.imshow(x.reshape(28,28), cmap="Greys")
        plt.show()
        # Get binarized output and prediction
        binary_activations = net.feedforward(x)
        binary_prediction = np.argmax(net.feedforward(x))
        
        print("Prediction with binary thresholding: ")
        print(binary_prediction)
        
        print("Network output: ")
        print(binary_activations)

    成果如下:

    Clipboard Image.pngClipboard Image.png

    看起来二进制阈值是有效的,但这却不是一种很好的防护措施。不是所有图片都拥有白色背景。比如我们一开始例举的熊猫图片。在那张图片上使用二进制阈值能够去除噪点,但也会很大地影响原图——到人眼都几乎无法识别出熊猫来的程度;

    Clipboard Image.png

    另一种更常用的方法是我们可以试着用被正确标记出来的对抗样本来训练一个新的神经网络,这一步骤能使得神经网络在测试中有94%的几率辨认出对抗图片,成绩相当不错。然而,这一方法也有局限性。在现实生活中,你很可能不知道袭击者是如何生成对抗样本的。

    当然,还有许其他的对抗手段,我们不会在本文中提及,但在学术研究领域这依旧是个开放课题。


  • 黑盒攻击
  • 关于对抗样本的一个重要发现是它们通常不是一个特定的模型或架构。为一个神经网络生成的对抗样本往往能成功地转移到其他架构上。换句话说,如果你想要骗过一个模型你可以先建立自己的模型,然后生成对抗样本。同样的样本很可能也能够骗过其他模型。

    这一发现极大地暗示了对抗样本很可能能够从一个完全的黑盒模型中制作出来——我们不需要掌握任何关于内部结构的知识。事实上,通过这种方法,加州大学伯克利分校的一个小组已经对一个商业AI识别系统发起了一次成功的袭击。


  • 结论
  • 当我们走向融合了越来越多的神经网络和深度学习算法的未来时,我们必须小心地记住这些模型很容易被愚弄。虽然神经网络在某些方面是被生物学的神经网络所启发,并在广泛的任务面前拥有接近或超越人类的能力,但对抗样本告诉我们神经网络的运算方式和生物的思维方式完全不同。所以我们才会看到神经网络可以轻易地被对我们人类来说完全陌生的方式打败。

    我们不完全理解神经网络,且用人类的直觉来描述神经网络是不明智的。比如说,你常听人说:“神经网络能够辨识出猫的图片是因为它橙色的绒毛质地。”事实上,神经网络并不像人类那样“思考”。它们的起源只是一系列矩阵乘法与一些附加的非线性特征。正如对抗样本展示给我们的,这些模型的输出是极其脆弱的。我们必须注意不要把人类的特性归因于神经网络,尽管它们具有人类的能力。也就是说,我们不能将机器学习模式人格化

    总而言之,对抗样本应该使我们谦虚。虽然我们已经取得了巨大的飞跃,但我们不知道的还有许多。

    推荐 0
    本文由 sw_Yang 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
    转载、引用前需联系作者,并署名作者且注明文章出处。
    本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

    0 个评论

    要回复文章请先登录注册