精华内容
下载资源
问答
  • negativerial_attacks 进行对抗攻击并构建故意混淆我们ResNet模型的对抗图像 原始图片 对手形象
  • 该存储库包含论文“使用自适应降噪技术在深度网络中检测对抗性图像示例”的代码。 它将重现论文中报告的结果。 DeepDetector是一种用于检测对抗图像示例的简单方法。 该方法可以有效地检测通过, 制作的对抗示例...
  • 生成潜在最近邻的非对抗图像合成

    千次阅读 2018-12-27 20:29:18
    生成对抗网络GAN在图像生成方面得到广泛的应用,其他VAE、流模型在应用都有一些差距。Wasserstein距离虽然极大提升GAN的效果,但理论上存在训练不稳定和模式丢失的问题。Facebook融合两种对抗方法的优势,提出本文...

    背景

    这是Facebook的一篇论文。生成对抗网络GAN在图像生成方面得到广泛的应用,其他VAE、流模型在应用都有一些差距。Wasserstein距离虽然极大提升GAN的效果,但理论上存在训练不稳定和模式丢失的问题。Facebook融合两种对抗方法的优势,提出本文GLANN的模型。

    无条件生成模型通过给定有限的数量的训练样本学习得到生成整个图像分布的函数。其中,GAN具有以下优点:
    1.能有效训练无条件图像生成器;
    2.几乎是唯一一种能用于不同域之间的无监督图像转换方法;
    3.有效的感知式图像损失函数。
    缺点:
    1.难于训练,训练过程不稳定,对超参数敏感;
    2.GAN有模型丢失问题,只能建模目标的某些模式,而非所有模式。例如,GAN生成0-9十个数字,GAN很可能只关注生成1这个数字,很少生成其他9个数字。

    目前非对抗式生成模型,有GLO,IMLE两种方法。GLO是将训练图像嵌入到低维空间,并在该嵌入向量输入到一个联合训练的深度生成器重建他们。GLO具有优势:
    1.无模式丢失编码整个分布;
    2.学习的隐含空间能与图像的形义属性相对应,即隐含编码之间的欧几里得距离对应形义方面的含义差异。
    GLO的缺点是,没有一种从嵌入空间采样新图像的原则性方法。尽管GLO提出者建议使用一个高斯分布来拟合训练图像的隐编码,但会导致图像合成质量不高。

    IMIE,训练生成模型的方式是,从任意分布采样大量隐含编码,使用一个训练后的生成器将每个编码映射到图像域中,并确保 每张训练图像都存在一张相近的生成图像。当使用L2损失直接在图像像素上训练时,IMLE合成的图像是模糊不清的。

    2 模型

    本研究提出,生成式隐含最近邻(GLANN),使用GLO嵌入训练图像,并训练一个基于IMLE的模型来实现任意噪声分布E和GLO隐含空间Z之间的映射。
    图 1:我们的架构的示意图:采样一个随机噪声向量 e 并将其映射到隐含空间,得到隐含编码 z = T(e)。该隐含编码再由生成器投射到像素空间,得到图像 I = G(z)
    图 1:我们的架构的示意图:采样一个随机噪声向量 e 并将其映射到隐含空间,得到隐含编码 z = T(e)。该隐含编码再由生成器投射到像素空间,得到图像 I = G(z)

    2.1 GLO
    分解一组数据点{x1,...,xt}\left\{ x_1,...,x_t\right\}
    xi=Wzi,ix_i = Wz_i, \forall i
    GLO使用深度方法来获取隐向量zz,并考虑以下方面:
    1.把隐向量z约束在单位球面上;
    2.使用CNN生成器G()来代替线性矩阵W,更适合于图像建模;
    3.使用拉普拉斯金字塔损失函数。(VGG感知损失函数效果更佳)
    GLO优化目标为:
    argminG,{zi}iL(G(zi),xi)s.t.zi=1\arg \min\limits_{G,\left\{ z_i\right\}} \sum\limits_i {\mathcal{L}(G(z_i),x_i)} \quad s.t.||z_i||=1

    L\mathcal{L}用拉普拉斯金字塔实现,所有权重训练用随机梯度下降(SGD)来训练,最终,每张训练图片xix_i获得生成器G(),和隐向量ziz_i.

    2.2 IMLE
    对每张训练图片xix_i,最近的生成图片是ei=argminejG(ej),xi22e_i = \arg \min_{e_j}||G(e_j), x_i||_2^2.
    G()使用最近领域进行优化:
    G=argminGiG~(ei),xi22G = \arg \min_G{\sum_i{||\tilde{G}(e_i),x_i||_2^2}}

    2.3 GLANN
    2.3.1 阶段1:潜在嵌入(latent Embedding)
    图像高维像素空间使用度量(如L1,L2)效果较差,计算量大。所以,先使用GLO把训练图像嵌入到地位空间,并且使用VGG感知损失函数:
    argminG,{zi}iLperceptual(G(zi),xi)s.t.zi=1\arg \min\limits_{G,\left\{ z_i\right\}} \sum\limits_i {\mathcal{L_{perceptual}}(G(z_i),x_i)} \quad s.t.||z_i||=1

    2.3.2 阶段2:从隐空间采样
    GLO是使用对Z\mathcal{Z}采样,来代替从原图像素空间采样,但是使用高斯分布拟合训练的隐变量ziz_i,通常效果不是很好。
    因此,使用IMLE学习Z\mathcal{Z}空间分布。

    每个周期开始,从噪声分布采样,并且映射到隐空间。
    z~m=T(em)\tilde{z}_m =T(e_m)

    对于每一个ziz_i,都可以从最邻近的映射噪声向量近似(使用欧氏距离度量):
    et=argminemztT(em)22e_t = \arg \min\limits_{e_m} {||z_t - T(e_m)||_2^2}
    微调映射函数T的方法:
    T=argminT~tztT~(et)22T = \arg \min\limits_{\tilde{T} } {\sum\limits_t {||z_t - \tilde{T}(e_t)||_2^2}}

    2.3.3 采样新图像

    合成新图像:首先从多元正态分布eN(0,I)e\thicksim N(0,I)采样噪声向量,新的采样向量映射到隐空间(latent code space)中。
    ze=T(e)z_e = T(e)

    使用GLO训练好的生成器G()投影zez_e到图像空间中。
    Ie=G(ze)I_e = G(z_e)
    IeI_e基本服从输入图像xx的分布。
    给定生成图像I,使用反变换来优化噪声向量e:
    e=argmine~L(G(T(e~)),I)e = \arg \min\limits_{\tilde{e}} {\mathcal{L}(G(T(\tilde{e})),I)}


    reference:
    1.zhihu: 本论文翻译
    2. Non-Adversarial Image Synthesis with Generative Latent Nearest Neighbors

    展开全文
  • ,我们知道利用GAN的生成能力可以生成较为真实的图片,但是在面对高分辨的图片时,在保证图像的全局结构的一致性的情况下,需要更加关注图像的细节,而传统GAN的鉴别器通常只能够关注到全局的信息。 本文的主要改进...

    1.介绍

    对高分辨率图像的去模糊、去噪、修复等,对于现实的纹理合成的一个关键的问题是:如何保证真实性或者是自然性?,我们知道利用GAN的生成能力可以生成较为真实的图片,但是在面对高分辨的图片时,在保证图像的全局结构的一致性的情况下,需要更加关注图像的细节,而传统GAN的鉴别器通常只能够关注到全局的信息。

    本文的主要改进点在于对鉴别器网络进行改进,整个鉴别器网络包括global GAN和 patch GAN.对于global GAN我们已经很熟悉了,主要就是鉴别器网络的输入是一张图片,而输出是一个标量,用来进行二分类的鉴别。这里来介绍一下patch GAN 的discriminator:

    在这里插入图片描述

    图1,PatchGAN 判别器,输出是一个矩阵,矩阵中的每个元素表示输入图像的一个局部区域,如果局部区域是真实的,我们会得到1,否则是0

    patch GAN最早是用在图像风格迁移领域上的,与典型的GAN中的鉴别器相比,patch GAN的输出不在是一个标量,而是一个二维的矩阵,GAN的鉴别器用来判断这幅图片是合成的还是真实的,它考虑的是图像的全局,因此有可能忽略了图像的局部细节。而patchGAN的输出是二维的矩阵,每一个值代表着的是对图像的局部区域的判断,这样图像的局部纹理细节可以得到关注和增强。

    本文采用Global GAN和patch GAN联合的鉴别器,称为PGGAN的鉴别器,在卷积网络的前面几层,二者共享同样的卷积层,然后引出两个分支分别是global GAN鉴别器和patch GAN鉴别器,具体结构可以看图2部分的鉴别器网络结构。

    2.方案

    在这里插入图片描述

    图2,修复网络架构和鉴别器网络架构

    1.采用 ResNet 网络作为修复网络的基础架构,同时在ResNet网络架构中引入了空洞卷积。

    2.鉴别网络则是用上述提到的PGGAN的鉴别器。

    2.1生成网络

    这里主要用到了ResNet中的残差块的思想并进行了一些改动。网络先进行下采样再上采样,下采样用带步长的卷积来完成而不用池化层来做。下采样和上采样保持对称,因为修复网络的输出也是一张图像。我们知道感受野的尺寸对于纹理生成有至关重要的作用。空洞卷积不需要增加额外的参数就可以增大感受野,研究表明空洞卷积对纹理合成有一定的影响。本文在残差块中引入了空洞卷积,如下图所示:第一个是标准的残差块,第二个在normalizetion层前引入空洞卷积层,第三个在激活函数后面引入空洞卷积层。

    在这里插入图片描述

    2.2鉴别器网络

    本文的鉴别器网络称为PGGAN鉴别器,是由global GAN和patch GAN的鉴别器组合成的,但是不是同时分来训练这个两个网络,而是在网络的前几层二者共享权重参数,这样能够保证它们都能学习到图像的低级视觉特征,在后面它们被分成两个网络,一个用来判断图像是真还是假,另一个则用来判断图像局部纹理的相似度。

    3.损失函数

    总损失包含三个部分:

    3.1重建损失(L1)

    比较合成部分的图像和真实图像之间的L1距离:
    Lrec=1N1N1WHCyx1 L_{rec}=\frac{1}{N}\sum_1^N\frac{1}{WHC}||y-x||_1
    N为样本数量,y为预测的像素,x为真实图片的像素,WHC分别为图像的宽高和通道数

    3.2对抗损失

    LGAN(G,D)=Exp(x)[log(Dx)]+EyPG(x)[log(1D(G(x)))] L_{GAN}(G,D)=E_{x-p(x)}[log(D{x})]+E_{y-PG(x')}[log(1-D(G(x')))]

    该损失由PGGAN中的鉴别器D来计算,生成器和鉴别器同时最小化上述公式来被训练。x’是输入的破损图像。

    3.3联合损失

    L=λ1Lrec+λ2Lgadv+λ3Lpadv L=\lambda_1L_{rec}+\lambda_2L_{g-adv}+\lambda_3L_{p-adv}

    在这里插入图片描述

    4.贡献

    • 将patchGAN和G-GAN结合起来,并共享前面几层的权重,后面再独立分来计算生成对抗损失,保证了图像局部的纹理信息和全局一致性
    • 将空洞卷积和残差思想结合在一起形成端到端的修复网络,并可以应用在高分辨率的图像的修复上
    • 通过实验分析了网络的各个组件对网络的影响

    5.总结

    1.将残差块和空洞卷积结合起来嵌入到修复网络中

    以应用在高分辨率的图像的修复上

    • 通过实验分析了网络的各个组件对网络的影响

    5.总结

    1.将残差块和空洞卷积结合起来嵌入到修复网络中

    2.将Patch GAN判别器和传统的GAN的全局判别器结合起来,既考虑了局部纹理信息又保证了全局的一致性。

    参考文献:

    Patch-Based Image Inpainting with Generative Adversarial Networks

    展开全文
  • 作者:Adrian Rosebrock翻译:吴振东校对:张达敏本文约8000字,建议阅读10+分钟本文将会告诉你如何用基于图像的对抗攻击来破坏深度学习模型,利用Keras和Tenso...

    作者:Adrian Rosebrock 翻译:吴振东 校对:张达敏

    本文约8000字,建议阅读10+分钟

    本文将会告诉你如何用基于图像的对抗攻击来破坏深度学习模型,利用Keras和TensorFlow深度学习库来实现你自己的对抗攻击。

    [ 摘要 ]在这篇教程中,你将会学到如何用基于图像的对抗攻击来破坏深度学习模型。我们将会利用Keras和TensorFlow深度学习库来实现自己的对抗攻击。

                  

    试想下从现在起的二十年后。现在路上所有的车辆都是利用人工智能、深度学习和计算机视觉来驱动的无人驾驶交通工具。每一次转弯、车道转换、加速和刹车都是由深度神经网络来提供技术支持。现在,想象自己在高速路上,你正坐在“驾驶室(当车自主行驶时,驾驶室还能被称为‘驾驶室’吗?)”里,你的妻子坐在副驾上,你的孩子们坐在后座。

     

    朝前看,你看到一张巨大的贴纸正在车辆所行驶的车道上,这看上去对车的前进毫无影响。看上去这像是一张受欢迎的大幅涂鸦艺术版画,可能是几个高中生开玩笑把它放在这里,或者他们只是为了完成某个大冒险游戏。

    图一:执行一次对抗攻击需要一张输入图像(左),故意用一个噪声向量来扰乱它(中),迫使神经网络对输入图像进行错误分类,最后得到一个错误的分类结果,很可能会出现一次严重的后果(右)。

    一瞬间,你的汽车突然急刹车,然后立即变道,因为放在路上的那张贴画可能印的是行人、动物或者另一辆汽车。你在车里被猛推了一下,感到颈部似乎受了伤。你的妻子尖叫着,孩子们的零食在后座上蹦了起来,弹在挡风玻璃上后洒在中控台上。你和你的家人都很安全,但所经历的这一切看上去不能再糟糕了。

    发生了什么?为什么你的自动驾驶车辆会做出这样的反应?是不是车内的某段代码或者某个软件存在奇怪的“bug”?

     

    答案就是,为车辆视觉组件提供技术支持的深度神经网络看到了一张对抗图像。

     

    对抗图像是指:含有蓄意或故意干扰像素来混淆或欺骗模型的图像。

     

    但与此同时,这张图像对于人类来说看上去是无害且无恶意的。

     

    这些图像导致深度神经网络故意做出错误的预测。对抗图像在某种方式上去干扰模型,导致它们无法做出正确的分类。

     

    事实上,人类通过视觉可能无法区分正常图片和对抗攻击的图片——本质上,这两张图片对于肉眼来说是相同的。

     

    这或许不是一个准确(或者说正确)的类比,但我喜欢在图像密码学的背景下来解释对抗进攻。利用密码学算法,我们可以把数据(例如纯文本信息)嵌入到图像中,且不改变图像本身的表象。这幅图像可以纯粹地传送到接收者那里,然后接收者再去提取图像中所隐藏的信息。

     

    同样的,对抗攻击在输入图像中嵌入一条信息,但是这条信息并非是人们可以理解的纯文本信息,因为对抗攻击所嵌入到输入图像的是一个噪声向量。这个噪声向量是用于戏弄或混淆深度学习模型而故意构建的。

     

    对抗攻击是如何起作用的?我们应该如何去进行防御呢?

     

    在这篇教程中,以及这个系列的其他推文中,我们将会准确地去回答这些问题。

     

    想要了解如何用Keras/TensorFlow在对抗攻击和图像中来破坏深度学习模型,请继续往下读。

     

    利用Keras和TensorFlow来实现对抗图像和攻击

    在这篇教程中的第一部分,会讨论下对抗攻击是什么以及它们是如何影响深度学习模型的。

    在那之后,我们会实现三段独立的Python脚本:

    1. 第一段Python脚本是加载ImageNet数据集并解析类别标签的使用助手。

    2. 第二段Python脚本是利用在ImageNet数据集上预训练好的ResNet模型来实现基本的图像分类(由此来演示“标准”的图像分类)。

    3. 最后一段Python脚本用于执行一次对抗攻击,并且组成一张故意混淆我们的ResNet模型的对抗图像,而这两张图像对于肉眼来说看上去是一样的。

    让我们开始吧!

     

    什么是对抗对象和对抗攻击呢?它们是如何影响深度学习模型的呢?

    图二:当执行对抗攻击时,给予神经网络一张图像(左),然后利用梯度下降来构建一个噪声向量(中)。这个噪声向量被加入到输入图像中,生成一个误分类(右)。

     

    在2014年,古德费洛等人发表了一篇名为《Explaining and HarnessingAdversarial Examples(解释并驯服对抗样本)》的论文,展示了深度神经网络吸引人的属性——有可能故意扰乱一张输入图像,导致神经网络对其进行错误的分类。这种扰乱就被称为对抗攻击。

     

    经典的对抗攻击示例就像上面图二所展示的一样。在左边,我们的输入图像在神经网络中被分在“熊猫”类别,置信度为57.7%。

     

    在中间有一个噪音向量,在人类眼中看上去是随机的,但事实上绝非如此。

     

    恰恰相反,这一噪声向量中的像素“等于输入图像的损失函数的梯度元素符号”(Goodfellow et al.)。

     

    把这个噪声向量嵌入到输入图像中,产出了图二中的输出(右)。对于我们来说,这副新图像看起来与输入图像完全一样,但我们的神经网络却会将这站图像分到“长臂猿”类别,置信度高达99.7%。很奇怪吧?

      

    一段对抗攻击和对抗图像的简短历史

    图三:一个关于对抗机器学习和深度神经网络安全性出版物的时间轴(图片来源:CanMachine Learning Be Secure?图8)

     

    对抗机器学习并不是一个新兴领域,这些攻击也不是针对深度神经网络。在2006年,巴雷诺等人发表了一篇名为《CanMachine Learning Be Secure?》的论文。论文讨论了对抗攻击,包括提出了一些对抗攻击的防御方式。

     

    回到2006年,最先进的机器学习模型包括支持向量机(SVMs)和随机森林(RFs),这两种类型的模型均易受对抗攻击的影响。

     

    随着2012年深度神经网络的普及度开始升高,曾寄希望于这些非线性的模型不会轻易受到这种攻击的影响,然而古德费洛等人打破了这一幻想。

     

    他们发现深度神经网络和“前辈们”一样,都很容易受到对抗攻击的影响。

     

    想要了解更多关于对抗攻击的历史,我建议你们去看下比格奥(Biggio)和罗利(Roli)在2017年发表的论文《Wild Patterns: Ten Years Afterthe Rise of Adversarial Machine Learning.》

     

    为什么对抗攻击和对抗图像会成为一个麻烦呢?

    图四:为什么对抗攻击会是一种麻烦?为什么我们应该关注它?(图片来源imagesource)

     

    本篇教程顶部所谈到的示例中概述了为什么对抗攻击会给我们的健康、生活和财产带来严重损失。

     

    另外一些后果没有那么严重的示例,例如一群黑客识别了一个谷歌用于给Gmail过滤垃圾邮件的模型,或者识别了一个Facebook自动检测色情内容的NSFW(不适合上班时间浏览)过滤器模型。

     

    如果这些黑客想要绕过Gmail垃圾邮件过滤器来让用户受到资源过载攻击,或者绕过Facebook的NSFW过滤器来上传大量的色情内容,理论上讲他们是可以做到的。

     

    这些都是对抗攻击中造成轻微后果的示例。

     

    关于到对抗攻击带有严重后果的剧本可以包括黑客恐怖分子识别了全世界自动驾驶汽车所使用的深度神经网络(试想一下如果特斯拉垄断了市场,成为世界唯一自动驾驶汽车生产商)。

     

    对抗图片有可能被有战略性地摆放在车道或公路上,造成连环车祸、财产损失或车内乘客的受伤甚至死亡。

     

    只有你的想象力,对已知模型的了解程度以及对模型的使用程度是对抗攻击的天花板。

     

    我们能够抵御对抗攻击吗?

    好消息是我们可以降低对抗攻击所造成的影响(但无法将它们完全消除)。

     

    这方面的话题将不会在今天的教程中展开,可能会在未来的教程中进行讨论。

     

    配置你的开发环境

    在这篇教程中配置你的系统,我建议你跟随这两篇教程:

    • 如何在Ubuntu系统下配置TensorFlow2.0 ?(How to installTensorFlow 2.0 on Ubuntu)

    • 如何在macOS系统下配置TensorFlow2.0 ?How to install TensorFlow 2.0 on macOS

    这两篇教程都会协助你在便捷的Python虚拟环境中利用必要的软件来配置系统。

    项目结构:

    $ tree --dirsfirst
    .
    ├── pyimagesearch
    │ ├── __init__.py
    │ ├── imagenet_class_index.json
    │ └── utils.py
    ├── adversarial.png
    ├── generate_basic_adversary.py
    ├── pig.jpg
    └── predict_normal.py
    1 directory, 7 files
    

     

    在pyimagesearch模块中,有两个文件:

    1. imagenet_class_index.json: 一个JSON文件,将ImageNet类别标签标记为可读的字符串。我们将会利用这个JSON文件来决定这样一组特殊标签的整数值索引,在构建对抗图像攻击时,这个索引将会给予我们帮助。

    2. utils.py: 包含简单的Python辅助函数,用于载入和解析imagenet_class_index.json

     

    这里面还有两个我们今天需要检验的Python脚本:

    1. predict_normal.py: 接收一张输入图像(pig.jpg),载入ResNet50模型,对输入图像进行分类。这个脚本的输出会是预测类别标签在ImageNet的类别标签索引。

    2. generate_basic_adversary.py:利用predict_normal.py脚本中的输出,我们将构建一次对抗攻击来欺骗ResNet,这个脚本的输出(adversarial.png)将会存储在硬盘中。

     

    做好准备来实现你的第一个Keras和TensorFlow中的对抗攻击了吗?让我们开始吧。

     

    ImageNet 类别标签/索引帮助实用程序

    在我们开始执行正常的图像分类或者对抗攻击使用的混淆图像分类之前,首先需要创建一个Python辅助函数来载入和解析ImageNet数据集的类别标签。

     

    我们提供了一个JSON文件包含所有的类别标签索引、标识符和可读的字符串,全都包含在项目目录结构中pyimagesearch模块的imagenet_class_index.json文件里。

     

    在这里展示JSON文件的前几行:

    {
    "0": [
    "n01440764",
    "tench"
    ],
    "1": [
    "n01443537",
    "goldfish"
    ],
    "2": [
    "n01484850",
    "great_white_shark"
    ],
    "3": [
    "n01491361",
    "tiger_shark"
    ],
    ...
    "106": [
    "n01883070",
    "wombat"
    ],
    ...
    

     

    在这里可以看到这个文件是一个字典格式的。字典的关键字是类别标签的整数值索引,而值由二元元组组成:

    1. ImageNet标签的唯一标识符;

    2. 有可读性的类别标签。

     

    我们的目标是实现一个Python函数可以解析JSON文件:

    1. 接收一个输入标签;

    2. 转化成其对应标签的类别标签整数值索引。

     

    实际上,我们就是转换imagenet_class_index.json文件中的键与值(key/value)的关系。

     

    让我们来实现这个辅助函数吧。

     

    打开pyimagesearch模块的utils.py文件,插入下列代码:

    # importnecessary packages
    import json
    import os
    defget_class_idx(label):
    # build the path to theImageNet class label mappings file
    labelPath = os.path.join(os.path.dirname(__file__),
    "imagenet_class_index.json")
    

     

    第2行和第3行引入我们所需要的Python包。我们要用到json Python模块来载入JSON文件,而os包用于构建文件路径,这与你使用的是什么操作系统并无关系。

     

    接下来我们去定义get_class_idx辅助函数。这个函数的目标是接收一个输入类别标签,然后获得预测(即在ImageNet上所训练出的模型在1000个标签类别中做出的预测)的标签类别的整数值索引。

     

    第7行是组成能够载入 pyimagesearch模块中的imagenet_class_index.json的路径。

     

    现在载入JSON文件中的内容:

    # open theImageNet class mappings file and load the mappings as
    # a dictionary with the human-readable class label as the keyand
    # the integerindex as the value
    withopen(labelPath)as f:
    imageNetClasses = {labels[1]: int(idx)for(idx, labels)in
    json.load(f).items()}
    # check to see if the inputclass label has a corresponding
    # integer index value, and if so return it; otherwise return
    # a None-type value
    return imageNetClasses.get(label, None)
    

     

    第4-6行,打开labelPath文件,然后将键值对的关系进行转换,这样键才是可读的标签字符串,而值是那个标签的整数值索引。

     

    为了获得输入标签的整数值索引,可以调用imageNetClasses字典中的.get方法(最后一行),会返回:

    • 如果在字典中存在改标签的话,则返回该标签的整数值索引;

    • 否则返回None。

     

    这个值返回到调用函数。

     

    让我们在下一章节来构建get_class_idx辅助函数。

     

    利用Keras和TensorFlow在没有对抗攻击的情况下进行图片分类

    在实现了ImageNet 类标签/索引辅助函数后,让我们构造一个图像分类脚本,在没有对抗攻击的情况下实现基本分类的图像分类脚本。

     

    这个脚本可以证明我们的ResNet模型表现正常(做出正确地预测)。在这篇教程的后半部分,你们将会发现如何构建一张对抗图像用于混淆ResNet。

     

    让我们开始基本的图像分类脚本——在你的工程文件结构中打开predict_normal.py文件,并插入以下代码:

    # import necessarypackages
    from pyimagesearch.utils import get_class_idx
    from tensorflow.keras.applications import ResNet50
    from tensorflow.keras.applications.resnet50 import decode_predictions
    from tensorflow.keras.applications.resnet50 import preprocess_input
    import numpy as np
    import argparse
    import imutils
    import cv2
    

     

    在第2-9行,我们引入了所需的Python包。如果你之前使用过Keras,TensorFlow和OpenCV的话,这些对你来说都是常规操作。

     

    如果你是Keras和TensorFlow的新手,我强烈建议你去看一下我的这篇《KerasTutorial: How to get started with Keras, Deep Learning, and Python》教程。另外,你或许想要读一读我的书《DeepLearning for Computer Vision with Python》加深你对训练自定义神经网络的理解。

     

    在第2行,我们引入了在上一章节中定义的get_class_idx函数,这个函数可以获得ResNet50模型中最高预测标签的整数索引值。

     

    让我们定义下 preprocess_image辅助函数:

    defpreprocess_image(image):
    # swap color channels,preprocess the image, and add in a batch
    # dimension
    image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
    image = preprocess_input(image)
    image = cv2.resize(image, (224, 224))
    image = np.expand_dims(image, axis=0)
    # return the preprocessed image
    return image
    

     

    preprocess_image 方法接收一个单一的必需参数,那就是我们想要预处理的图片。

     

    对这张图片进行预处理有以下几步:

    1. 将图片的BGR通道组合转化为RGB;

    2. 执行preprocess_input函数,用于完成ResNet50中特别的预处理和比例缩放过程;

    3. 将图片大小调整为224×224;

    4. 增加一个批次维度。

     

    这张预处理好的图像会被返回到调用函数中。

     

    接下来,让我们解析下指令参数:

    # construct the argument parser and parsethe arguments
    ap = argparse.ArgumentParser()
    ap.add_argument("-i", "--image",required=True,
    help="pathto input image")
    args = vars(ap.parse_args())
    

     

    我们在这里只需要一个命令行参数,--image,即输入图像存放在硬盘上的路径。

     

    如果你从来没有处理过命令行参数和argparse ,我建议你看一下这篇教程。

     

    接下来让载入输入图像并进行预处理:

    # load image fromdisk and make a clone for annotation
    print("[INFO] loadingimage...")
    image = cv2.imread(args["image"])
    output = image.copy()
    # preprocess the input image
    output = imutils.resize(output, width=400)
    preprocessedImage = preprocess_image(image)
    

     

    通过调用cv2.imread来载入输入图片。在第4行对这张图片进行了复制,以便后期在输出结果上面画框并标注上预测结果类别标签。

     

    我们调整下输出图片的尺寸,让它的宽变为400像素,这样可以适配我们的电脑屏幕。在这里同样使用preprocess_image函数将其处理为可用于ResNet进行分类的输入图片。

     

    加上我们预处理好的图片,接着载入ResNet并对图片进行分类:

    # load thepre-trained ResNet50 model
    print("[INFO] loadingpre-trained ResNet50 model...")
    model = ResNet50(weights="imagenet")
    # makepredictions on the input image and parse the top-3 predictions
    print("[INFO] makingpredictions...")
    predictions =model.predict(preprocessedImage)
    predictions = decode_predictions(predictions, top=3)[0]
    

     

    第3行,载入ResNet和该模型用ImageNet数据集预训练好的权重。

     

    第6和7行,针对预处理好的图片进行预测,然后再用 Keras/TensorFlow 中的decode_predictions辅助函数对图片进行解码。

     

    现在让我们看看神经网络预测的Top 3 (置信度前三)类别以及所展示的类别标签:

    # loop over thetop three predictions
    for(i, (imagenetID, label,prob))inenumerate(predictions):
    # print the ImageNet class label ID of the top prediction to our
    # terminal (we'll need thislabel for our next script which will
    # perform the actual adversarial attack)
    if i == 0:
    print("[INFO] {} => {}".format(label, get_class_idx(label)))
    # display the prediction to our screen
    print("[INFO] {}.{}: {:.2f}%".format(i + 1, label, prob * 100))
    

     

    第2行开始循环Top-3预测结果。

     

    如果这是第一个预测结果(即Top-1预测结果),在输出终端显示可读的标签,然后利用 get_class_idx函数找出该标签对应的ImageNet的整数值索引。

     

    还可以在终端上展示Top-3的标签和对应的概率值。

     

    最终一步就是将Top-1预测结果标注在输出图片中:

    # draw thetop-most predicted label on the image along with the
    # confidence score
    text = "{}:{:.2f}%".format(predictions[0][1],
    predictions[0][2] * 100)
    cv2.putText(output, text, (3, 20),cv2.FONT_HERSHEY_SIMPLEX, 0.8,
    (0, 255, 0), 2)
    # show the output image
    cv2.imshow("Output", output)
    cv2.waitKey(0)
    

     

    输出图像在终端显示,如果你单击OpenCV窗口或按下任意键,输出图像将会关闭。

     

    非对抗图像的分类结果

    现在可以用ResNet来执行基本的图像分类(非对抗攻击)了。

     

    首先在“下载“页获取源代码和图像范例。

     

    从这开始,打开一个终端并执行以下命令:

    $ pythonpredict_normal.py --image pig.jpg
    [INFO] loading image...
    [INFO] loadingpre-trained ResNet50 model...
    [INFO] making predictions...
    [INFO] hog => 341
    [INFO] 1. hog: 99.97%
    [INFO] 2.wild_boar: 0.03%
    [INFO] 3. piggy_bank: 0.00%
    

    图五:预训练好的ResNet模型可以正确地将这张图片分类为“猪(hog)”。

     

    在这里你可以看到我们将一张猪的图片进行了分类,置信度为99.97%。

     

    另外,这里还加上了hog标签的ID(341)。我们将会在下一章用到这个标签ID,我们会针对这张猪的输入图片进行一次对抗攻击。

     

    在Keras和TensorFlow上实现对抗图像和对抗攻击

    接下来就要学习如何在Keras和TensorFlow上实现对抗图像和对抗攻击。

     

    打开generate_basic_adversary.py文件,插入以下代码:

    # import necessary packages
    from tensorflow.keras.optimizers import Adam
    from tensorflow.keras.applications import ResNet50
    from tensorflow.keras.losses importSparseCategoricalCrossentropy
    from tensorflow.keras.applications.resnet50 import decode_predictions
    from tensorflow.keras.applications.resnet50 import preprocess_input
    import tensorflow as tf
    import numpy as np
    import argparse
    import cv2
    

     

    在第2-10行中引入我们所需的Python包。你会注意到我们再次用到了ResNet50 架构,以及对应的preprocess_input函数(用于预处理/缩放输入图像)和 decode_predictions用于解码预测输出和显示可读的ImageNet标签。

     

    SparseCategoricalCrossentropy 用于计算标签和预测值之间的分类交叉熵损失。利用稀疏版本的分类交叉熵,我们不需要像使用scikit-learn的LabelBinarizer或者Keras/TensorFlow的to_categorical功能一样用one-hot对类标签编码。

     

    例如在predict_normal.py脚本中有preprocess_image 功能,我们在这个脚本上同样需要:

    defpreprocess_image(image):
    # swap color channels, resizethe input image, and add a batch
    # dimension
    image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
    image = cv2.resize(image, (224, 224))
    image = np.expand_dims(image, axis=0)
    # return the preprocessedimage
    return image
    

     

    除了省略了调用preprocess_input函数,这一段代码与上一段代码相同,当我们开始创建对抗图像时,你们马上就会明白为什么省去调用这一函数。

     

    接下来,我们有一个简单的辅助程序,clip_eps:

    defclip_eps(tensor, eps):
    # clip the values of thetensor to a given range and return it
    return tf.clip_by_value(tensor,clip_value_min=-eps,
    clip_value_max=eps)
    

     

    这个函数的目的就是接受一个输入张量tensor,然后在范围值 [-eps, eps]内对输入进行截取。

     

    被截取后的tensor会被返回到调用函数。

     

    接下来看看generate_adversaries 函数,这是对抗攻击的灵魂:

    defgenerate_adversaries(model, baseImage,delta, classIdx, steps=50):
    # iterate over the number ofsteps
    for step inrange(0, steps):
    # record our gradients
    with tf.GradientTape()as tape:
    # explicitly indicate thatour perturbation vector should
    # be tracked for gradient updates
    tape.watch(delta)
    

     

    generate_adversaries 方法是整个脚本的核心。这个函数接收四个必需的参数,以及第五个可选参数:

    1. model:ResNet50模型(如果你愿意,你可以换成其他预训练好的模型,例如VGG16,MobileNet等等);

    2. baseImage:原本没有被干扰的输入图像,我们有意针对这张图像创建对抗攻击,导致model参数对它进行错误的分类。

    3. delta:噪声向量,将会被加入到baseImage中,最终导致错误分类。我们将会用梯度下降均值来更新这个delta 向量。

    4. classIdx:通过predict_normal.py脚本所获得的类别标签整数值索引。

    5. steps:梯度下降执行的步数(默认为50步)。

     

    第3行开始循环设定好的步数。

     

    接下来用GradientTape来记录梯度。在tape上调用 .watch方法指出扰动向量是可以用来追踪更新的。

     

    现在可以建造对抗图像了:

    # add our perturbation vector to the base image and
    # preprocess the resulting image
    adversary = preprocess_input(baseImage + delta)
    # run this newly constructed image tensor through our
    # model and calculate theloss with respect to the
    # *original* class index
    predictions = model(adversary,training=False)
    loss = -sccLoss(tf.convert_to_tensor([classIdx]),
    predictions)
    # check to see if we arelogging the loss value, and if
    # so, display it to our terminal
    if step % 5 == 0:
    print("step: {},loss: {}...".format(step,
    loss.numpy()))
    # calculate the gradients ofloss with respect to the
    # perturbation vector
    gradients = tape.gradient(loss, delta)
    # update the weights, clipthe perturbation vector, and
    # update its value
    optimizer.apply_gradients([(gradients, delta)])
    delta.assign_add(clip_eps(delta, eps=EPS))
    # return the perturbationvector
    return delta
    

     

    第3行将delta扰动向量加入至baseImage的方式来组建对抗图片,所得到的结果将放入ResNet50的preprocess_input函数中来进行比例缩放和结果对抗图像进行归一化。

     

    接下来几行的意义是:

    • 第7行用model参数导入的模型对新创建的对抗图像进行预测。

    • 第8和9行针对原有的classIdx(通过运行predict_normal.py得到的top-1 ImageNet类别标签整数值索引)计算损失。

    • 第12-14行表示每5步就显示一次损失值。

     

    第17行,在with声明外根据扰动向量计算梯度损失。

     

    接着,可以更新delta向量,截取掉超出 [-EPS,EPS] 范围外的值。

     

    最终,把得到的扰动向量返回至调用函数——即最终的delta值,该值能让我们建立用来欺骗模型的对抗攻击。

     

    在对抗脚本的核心实现后,接下来就是解析命令行参数:

    # construct the argumentparser and parse the arguments
    ap = argparse.ArgumentParser()
    ap.add_argument("-i", "--input", required=True,
    help="path tooriginal input image")
    ap.add_argument("-o", "--output", required=True,
    help="path tooutput adversarial image")
    ap.add_argument("-c", "--class-idx", type=int,required=True,
    help="ImageNetclass ID of the predicted label")
    args = vars(ap.parse_args())
    

     

    我们的对抗攻击Python脚本需要三个指令行参数:

    1. --input: 输入图像的磁盘路径(例如pig.jpg);

    2. --output: 在构建进攻后的对抗图像输出(例如adversarial.png);

    3. --class-idex:ImageNet数据集中的类别标签整数值索引。我们可以通过执行在“非对抗图像的分类结果”章节中提到的predict_normal.py来获得这一索引。

     

    接下来是几个变量的初始化,以及加载/预处理--input图像:

    # define theepsilon and learning rate constants
    EPS = 2 / 255.0
    LR = 0.1
    # load the inputimage from disk and preprocess it
    print("[INFO] loadingimage...")
    image = cv2.imread(args["input"])
    image = preprocess_image(image)
    

     

    第2行定义了用于在构建对抗图像时来裁剪tensor的epsilon值(EPS)。2 / 255.0 是EPS的一个用于对抗类刊物或教程的标准值和指导值(如果你想要了解更多的默认值,你可以参考这份指导)。

     

    在第3行定义了学习速率。经验之谈,LR的初始值一般设为0.1,在创建你自己的对抗图像时可能需要调整这个值。

     

    最后两行载入输入图像,利用preprocess_image辅助函数来对其进行预处理。

     

    接下来,可以载入ResNet模型:

    # load thepre-trained  ResNet50 model for running inference
    print("[INFO] loadingpre-trained ResNet50 model...")
    model = ResNet50(weights="imagenet")
    # initializeoptimizer and loss function
    optimizer = Adam(learning_rate=LR)
    sccLoss = SparseCategoricalCrossentropy()
    

     

    第3行载入在ImageNet数据集上训练好的ResNet50模型。

     

    我们将会用到Adam优化器,以及稀疏的分类损失用于更新我们的扰动向量。

     

    让我们来构建对抗图像:

    # create a tensorbased off the input image and initialize the
    # perturbation vector (we will update this vector via training)
    baseImage = tf.constant(image,dtype=tf.float32)
    delta = tf.Variable(tf.zeros_like(baseImage), trainable=True)
    # generate the perturbation vector to create an adversarialexample
    print("[INFO]generating perturbation...")
    deltaUpdated = generate_adversaries(model, baseImage,delta,
    args["class_idx"])
    # create theadversarial example, swap color channels, and save the
    # output image to disk
    print("[INFO]creating adversarial example...")
    adverImage = (baseImage +deltaUpdated).numpy().squeeze()
    adverImage = np.clip(adverImage, 0, 255).astype("uint8")
    adverImage = cv2.cvtColor(adverImage,cv2.COLOR_RGB2BGR)
    cv2.imwrite(args["output"], adverImage)
    

     

    第3行根据输入图像构建了一个tensor,第4行初始化扰动向量delta。

     

    我们可以把ResNet50、输入图像、初始化后的扰动向量、及类标签整数值索引作为参数,用来调用generate_adversaries并更新delta向量。

     

    在 generate_adversaries函数执行时,会一直更新delta扰动向量,生成最终的噪声向量deltaUpdated。

     

    在倒数第4行,在baseImage上加入deltaUpdated 向量,就生成了最终的对抗图像(adverImage)。

     

    然后,对生成的对抗图像进行以下三步后处理:

    1. 将超出[0,255] 范围的值裁剪掉;

    2. 将图片转化成一个无符号8-bit(unsigned 8-bit)整数(这样OpenCV才能对图片进行处理);

    3. 将通道顺序从RGB转换成BGR。

     

    在经过这些处理步骤后,就可以把对抗图像写入到硬盘里了。

     

    真正的问题来了,我们新创建的对抗图像能够欺骗我们的ResNet模型吗?

     

    下一段代码就可以回答这一问题:

    # run inferencewith this adversarial example, parse the results,
    # and display the top-1 predicted result
    print("[INFO]running inference on the adversarial example...")
    preprocessedImage = preprocess_input(baseImage +deltaUpdated)
    predictions =model.predict(preprocessedImage)
    predictions = decode_predictions(predictions, top=3)[0]
    label = predictions[0][1]
    confidence = predictions[0][2] * 100
    print("[INFO] label:{} confidence: {:.2f}%".format(label,
    confidence))
    # draw the top-most predicted label on the adversarial imagealong
    # with theconfidence score
    text = "{}: {:.2f}%".format(label, confidence)
    cv2.putText(adverImage, text, (3, 20),cv2.FONT_HERSHEY_SIMPLEX, 0.5,
    (0, 255, 0), 2)
    # show the output image
    cv2.imshow("Output", adverImage)
    cv2.waitKey(0)
    

     

    在第4行又一次创建了一个对抗图像,方式还是在原始输入图像中加入delta噪声向量,但这次我们利用ResNet的preprocess_input功能来处理。

     

    生成的预处理图像进入到ResNet,然后会得到top-3预测结果并对他们进行解码(第5和6行)。

     

    接着我们获取到top-1标签和对应的概率/置信度,并将这些值显示在终端上(第7-10行)。

     

    最后一步就是把最高的预测值标在输出的对抗图像上,并展示在屏幕上。

    对抗图像和攻击的结果

    准备好见证一次对抗攻击了吗?

     

    从这里开始,你就可以打开终端并执行下列代码了:

    $ python generate_basic_adversary.py --inputpig.jpg --output adversarial.png --class-idx 341
    [INFO] loading image...
    [INFO] loading pre-trained ResNet50 model...
    [INFO] generatingperturbation...
    step: 0, loss:-0.0004124982515349984...
    step: 5, loss:-0.0010656398953869939...
    step: 10, loss:-0.005332294851541519...
    step: 15, loss: -0.06327803432941437...
    step: 20, loss: -0.7707189321517944...
    step: 25, loss: -3.4659299850463867...
    step: 30, loss: -7.515471935272217...
    step: 35, loss: -13.503922462463379...
    step: 40, loss: -16.118188858032227...
    step: 45, loss: -16.118192672729492...
    [INFO] creating adversarial example...
    [INFO] running inference on theadversarial example...
    [INFO] label: wombat confidence: 100.00%
    

    图六:之前,这张输入图片被正确地分在了“猪(hog)”类别中,但现在因为对抗攻击而被分在了“袋熊(wombat)”类别里!

     

    我们的输入图片 pig.jpg 之前被正确地分在了“猪(hog)”类别中,但现在它的标签却成为了“袋熊(wombat)”!

     

    将原始图片和用generate_basic_adversary.py脚本生成的对抗图片放在一起进行对比:

    图七:在左边是原始图片,分类结果正确。右边将是对抗图片,被错误地分在了“袋熊(wombat)”类别中。而对于人类的眼睛来看完全分辨不出两张图片的有什么区别。

     

    左边是最初猪的图像,在右边是输出的对抗图像,这张图像被错误的分在了“袋熊(wombat)”类别。

     

    就像你看到的一样,这两张图片没有任何可感知的差别,我们人类的眼睛看不出任何区别,但对于ResNet来说确实完全不同的。

     

    这很好,但我们无法清晰地掌控对抗图像被最终识别的类别标签。这会引起以下问题:

    我们有可能掌控输入图片的最终类别标签吗?答案是肯定的,这会成为我下一篇教程的主题。

     

    总结来说,对抗图像和对抗攻击真的是令人细思极恐。但如果等我们看到下一篇教程,就可以提前防御这种类型的进攻。稍后再详细说明下。

    致谢

    如果没有Goodfellow, Szegedy和其他深度学习的研究者的工作,这篇教程就无法完成。

     

    另外,这篇教程所用到的实现代码灵感来自于TensorFlow官方实现的《Fast Gradient Signed Method》。我强烈建议你去看看其他的示例,每一段代码都比这篇教程中的在理论和数学上更加明确。

     

    总结

    在这篇教程中,你学到关于对抗攻击的知识,关于他们是怎样工作的,以及随着人工智能和深度神经网络与这个世界的关联越来越高,对抗攻击就会构成更大的威胁。

    接着我们利用深度学习库Keras 和TensorFlow实现了基本的对抗攻击算法。

    利用对抗攻击,我们可以蓄意扰乱一张输入图片,例如:

    1. 这张输入图片会被错误分类。

    2. 然而,肉眼看上去被扰乱的图片还是和之前一样。

    利用这篇教程所使用的方法,我们并不能控制图片最终被判别的类别标签——我们所做的只是创造一个噪声向量,并将其嵌入到输入图像中,导致深度神经网络对其错误分类。

    如果我们能够控制最终的类别标签会怎样呢?比如说,我们拿一张“狗”的图片,然后制造一次对抗攻击,让卷积神经网络认为这是一张“猫”的图片,这有没有可能呢?

    答案是肯定的——我们会在下一篇教程中来谈论这一话题。

    原文链接:

    https://www.pyimagesearch.com/2020/10/19/adversarial-images-and-attacks-with-keras-and-tensorflow/

    原文标题:Adversarial images andattacks with Keras and TensorFlow

    译者简介:吴振东,法国洛林大学计算机与决策专业硕士。现从事人工智能和大数据相关工作,以成为数据科学家为终生奋斗目标。来自山东济南,不会开挖掘机,但写得了Java、Python和PPT。

    END

    版权声明:本号内容部分来自互联网,转载请注明原文链接和作者,如有侵权或出处有误请和我们联系。


    合作请加QQ:365242293  

    数据分析(ID : ecshujufenxi )互联网科技与数据圈自己的微信,也是WeMedia自媒体联盟成员之一,WeMedia联盟覆盖5000万人群。

    展开全文
  • 作者:Adrian Rosebrock翻译:吴振东校对:张达敏本文约8000字,建议阅读10+分钟本文将会告诉你如何用基于图像的对抗攻击来破坏深度学习模型,利用Keras和TensorF...

    作者:Adrian Rosebrock

    翻译:吴振东

    校对:张达敏

    本文约8000字,建议阅读10+分钟

    本文将会告诉你如何用基于图像的对抗攻击来破坏深度学习模型,利用Keras和TensorFlow深度学习库来实现你自己的对抗攻击。

    [ 摘要 ]在这篇教程中,你将会学到如何用基于图像的对抗攻击来破坏深度学习模型。我们将会利用Keras和TensorFlow深度学习库来实现自己的对抗攻击。

                  

    试想下从现在起的二十年后。现在路上所有的车辆都是利用人工智能、深度学习和计算机视觉来驱动的无人驾驶交通工具。每一次转弯、车道转换、加速和刹车都是由深度神经网络来提供技术支持。现在,想象自己在高速路上,你正坐在“驾驶室(当车自主行驶时,驾驶室还能被称为‘驾驶室’吗?)”里,你的妻子坐在副驾上,你的孩子们坐在后座。

     

    朝前看,你看到一张巨大的贴纸正在车辆所行驶的车道上,这看上去对车的前进毫无影响。看上去这像是一张受欢迎的大幅涂鸦艺术版画,可能是几个高中生开玩笑把它放在这里,或者他们只是为了完成某个大冒险游戏。

    图一:执行一次对抗攻击需要一张输入图像(左),故意用一个噪声向量来扰乱它(中),迫使神经网络对输入图像进行错误分类,最后得到一个错误的分类结果,很可能会出现一次严重的后果(右)。

    一瞬间,你的汽车突然急刹车,然后立即变道,因为放在路上的那张贴画可能印的是行人、动物或者另一辆汽车。你在车里被猛推了一下,感到颈部似乎受了伤。你的妻子尖叫着,孩子们的零食在后座上蹦了起来,弹在挡风玻璃上后洒在中控台上。你和你的家人都很安全,但所经历的这一切看上去不能再糟糕了。

    发生了什么?为什么你的自动驾驶车辆会做出这样的反应?是不是车内的某段代码或者某个软件存在奇怪的“bug”?

     

    答案就是,为车辆视觉组件提供技术支持的深度神经网络看到了一张对抗图像。

     

    对抗图像是指:含有蓄意或故意干扰像素来混淆或欺骗模型的图像。

     

    但与此同时,这张图像对于人类来说看上去是无害且无恶意的。

     

    这些图像导致深度神经网络故意做出错误的预测。对抗图像在某种方式上去干扰模型,导致它们无法做出正确的分类。

     

    事实上,人类通过视觉可能无法区分正常图片和对抗攻击的图片——本质上,这两张图片对于肉眼来说是相同的。

     

    这或许不是一个准确(或者说正确)的类比,但我喜欢在图像密码学的背景下来解释对抗进攻。利用密码学算法,我们可以把数据(例如纯文本信息)嵌入到图像中,且不改变图像本身的表象。这幅图像可以纯粹地传送到接收者那里,然后接收者再去提取图像中所隐藏的信息。

     

    同样的,对抗攻击在输入图像中嵌入一条信息,但是这条信息并非是人们可以理解的纯文本信息,因为对抗攻击所嵌入到输入图像的是一个噪声向量。这个噪声向量是用于戏弄或混淆深度学习模型而故意构建的。

     

    对抗攻击是如何起作用的?我们应该如何去进行防御呢?

     

    在这篇教程中,以及这个系列的其他推文中,我们将会准确地去回答这些问题。

     

    想要了解如何用Keras/TensorFlow在对抗攻击和图像中来破坏深度学习模型,请继续往下读。

     

    利用Keras和TensorFlow来实现对抗图像和攻击

    在这篇教程中的第一部分,会讨论下对抗攻击是什么以及它们是如何影响深度学习模型的。

    在那之后,我们会实现三段独立的Python脚本:

    1. 第一段Python脚本是加载ImageNet数据集并解析类别标签的使用助手。

    2. 第二段Python脚本是利用在ImageNet数据集上预训练好的ResNet模型来实现基本的图像分类(由此来演示“标准”的图像分类)。

    3. 最后一段Python脚本用于执行一次对抗攻击,并且组成一张故意混淆我们的ResNet模型的对抗图像,而这两张图像对于肉眼来说看上去是一样的。

    让我们开始吧!

     

    什么是对抗对象和对抗攻击呢?它们是如何影响深度学习模型的呢?

    图二:当执行对抗攻击时,给予神经网络一张图像(左),然后利用梯度下降来构建一个噪声向量(中)。这个噪声向量被加入到输入图像中,生成一个误分类(右)。

     

    在2014年,古德费洛等人发表了一篇名为《Explaining and HarnessingAdversarial Examples(解释并驯服对抗样本)》的论文,展示了深度神经网络吸引人的属性——有可能故意扰乱一张输入图像,导致神经网络对其进行错误的分类。这种扰乱就被称为对抗攻击。

     

    经典的对抗攻击示例就像上面图二所展示的一样。在左边,我们的输入图像在神经网络中被分在“熊猫”类别,置信度为57.7%。

     

    在中间有一个噪音向量,在人类眼中看上去是随机的,但事实上绝非如此。

     

    恰恰相反,这一噪声向量中的像素“等于输入图像的损失函数的梯度元素符号”(Goodfellow et al.)。

     

    把这个噪声向量嵌入到输入图像中,产出了图二中的输出(右)。对于我们来说,这副新图像看起来与输入图像完全一样,但我们的神经网络却会将这站图像分到“长臂猿”类别,置信度高达99.7%。很奇怪吧?

      

    一段对抗攻击和对抗图像的简短历史

    图三:一个关于对抗机器学习和深度神经网络安全性出版物的时间轴(图片来源:CanMachine Learning Be Secure?图8)

     

    对抗机器学习并不是一个新兴领域,这些攻击也不是针对深度神经网络。在2006年,巴雷诺等人发表了一篇名为《CanMachine Learning Be Secure?》的论文。论文讨论了对抗攻击,包括提出了一些对抗攻击的防御方式。

     

    回到2006年,最先进的机器学习模型包括支持向量机(SVMs)和随机森林(RFs),这两种类型的模型均易受对抗攻击的影响。

     

    随着2012年深度神经网络的普及度开始升高,曾寄希望于这些非线性的模型不会轻易受到这种攻击的影响,然而古德费洛等人打破了这一幻想。

     

    他们发现深度神经网络和“前辈们”一样,都很容易受到对抗攻击的影响。

     

    想要了解更多关于对抗攻击的历史,我建议你们去看下比格奥(Biggio)和罗利(Roli)在2017年发表的论文《Wild Patterns: Ten Years Afterthe Rise of Adversarial Machine Learning.

     

    为什么对抗攻击和对抗图像会成为一个麻烦呢?

    图四:为什么对抗攻击会是一种麻烦?为什么我们应该关注它?(图片来源imagesource)

     

    本篇教程顶部所谈到的示例中概述了为什么对抗攻击会给我们的健康、生活和财产带来严重损失。

     

    另外一些后果没有那么严重的示例,例如一群黑客识别了一个谷歌用于给Gmail过滤垃圾邮件的模型,或者识别了一个Facebook自动检测色情内容的NSFW(不适合上班时间浏览)过滤器模型。

     

    如果这些黑客想要绕过Gmail垃圾邮件过滤器来让用户受到资源过载攻击,或者绕过Facebook的NSFW过滤器来上传大量的色情内容,理论上讲他们是可以做到的。

     

    这些都是对抗攻击中造成轻微后果的示例。

     

    关于到对抗攻击带有严重后果的剧本可以包括黑客恐怖分子识别了全世界自动驾驶汽车所使用的深度神经网络(试想一下如果特斯拉垄断了市场,成为世界唯一自动驾驶汽车生产商)。

     

    对抗图片有可能被有战略性地摆放在车道或公路上,造成连环车祸、财产损失或车内乘客的受伤甚至死亡。

     

    只有你的想象力,对已知模型的了解程度以及对模型的使用程度是对抗攻击的天花板。

     

    我们能够抵御对抗攻击吗?

    好消息是我们可以降低对抗攻击所造成的影响(但无法将它们完全消除)。

     

    这方面的话题将不会在今天的教程中展开,可能会在未来的教程中进行讨论。

     

    配置你的开发环境

    在这篇教程中配置你的系统,我建议你跟随这两篇教程:

    • 如何在Ubuntu系统下配置TensorFlow2.0 ?(How to installTensorFlow 2.0 on Ubuntu

    • 如何在macOS系统下配置TensorFlow2.0 ?How to install TensorFlow 2.0 on macOS

    这两篇教程都会协助你在便捷的Python虚拟环境中利用必要的软件来配置系统。

    项目结构:

    $ tree --dirsfirst
    .
    ├── pyimagesearch
    │ ├── __init__.py
    │ ├── imagenet_class_index.json
    │ └── utils.py
    ├── adversarial.png
    ├── generate_basic_adversary.py
    ├── pig.jpg
    └── predict_normal.py
    1 directory, 7 files
    

     

    在pyimagesearch模块中,有两个文件:

    1. imagenet_class_index.json: 一个JSON文件,将ImageNet类别标签标记为可读的字符串。我们将会利用这个JSON文件来决定这样一组特殊标签的整数值索引,在构建对抗图像攻击时,这个索引将会给予我们帮助。

    2. utils.py: 包含简单的Python辅助函数,用于载入和解析imagenet_class_index.json

     

    这里面还有两个我们今天需要检验的Python脚本:

    1. predict_normal.py: 接收一张输入图像(pig.jpg),载入ResNet50模型,对输入图像进行分类。这个脚本的输出会是预测类别标签在ImageNet的类别标签索引。

    2. generate_basic_adversary.py:利用predict_normal.py脚本中的输出,我们将构建一次对抗攻击来欺骗ResNet,这个脚本的输出(adversarial.png)将会存储在硬盘中。

     

    做好准备来实现你的第一个Keras和TensorFlow中的对抗攻击了吗?让我们开始吧。

     

    ImageNet 类别标签/索引帮助实用程序

    在我们开始执行正常的图像分类或者对抗攻击使用的混淆图像分类之前,首先需要创建一个Python辅助函数来载入和解析ImageNet数据集的类别标签。

     

    我们提供了一个JSON文件包含所有的类别标签索引、标识符和可读的字符串,全都包含在项目目录结构中pyimagesearch模块的imagenet_class_index.json文件里。

     

    在这里展示JSON文件的前几行:

    {
    "0": [
    "n01440764",
    "tench"
    ],
    "1": [
    "n01443537",
    "goldfish"
    ],
    "2": [
    "n01484850",
    "great_white_shark"
    ],
    "3": [
    "n01491361",
    "tiger_shark"
    ],
    ...
    "106": [
    "n01883070",
    "wombat"
    ],
    ...
    

     

    在这里可以看到这个文件是一个字典格式的。字典的关键字是类别标签的整数值索引,而值由二元元组组成:

    1. ImageNet标签的唯一标识符;

    2. 有可读性的类别标签。

     

    我们的目标是实现一个Python函数可以解析JSON文件:

    1. 接收一个输入标签;

    2. 转化成其对应标签的类别标签整数值索引。

     

    实际上,我们就是转换imagenet_class_index.json文件中的键与值(key/value)的关系。

     

    让我们来实现这个辅助函数吧。

     

    打开pyimagesearch模块的utils.py文件,插入下列代码:

    # importnecessary packages
    import json
    import os
    defget_class_idx(label):
    # build the path to theImageNet class label mappings file
    labelPath = os.path.join(os.path.dirname(__file__),
    "imagenet_class_index.json")
    

     

    第2行和第3行引入我们所需要的Python包。我们要用到json Python模块来载入JSON文件,而os包用于构建文件路径,这与你使用的是什么操作系统并无关系。

     

    接下来我们去定义get_class_idx辅助函数。这个函数的目标是接收一个输入类别标签,然后获得预测(即在ImageNet上所训练出的模型在1000个标签类别中做出的预测)的标签类别的整数值索引。

     

    第7行是组成能够载入 pyimagesearch模块中的imagenet_class_index.json的路径。

     

    现在载入JSON文件中的内容:

    # open theImageNet class mappings file and load the mappings as
    # a dictionary with the human-readable class label as the keyand
    # the integerindex as the value
    withopen(labelPath)as f:
    imageNetClasses = {labels[1]: int(idx)for(idx, labels)in
    json.load(f).items()}
    # check to see if the inputclass label has a corresponding
    # integer index value, and if so return it; otherwise return
    # a None-type value
    return imageNetClasses.get(label, None)
    

     

    第4-6行,打开labelPath文件,然后将键值对的关系进行转换,这样键才是可读的标签字符串,而值是那个标签的整数值索引。

     

    为了获得输入标签的整数值索引,可以调用imageNetClasses字典中的.get方法(最后一行),会返回:

    • 如果在字典中存在改标签的话,则返回该标签的整数值索引;

    • 否则返回None。

     

    这个值返回到调用函数。

     

    让我们在下一章节来构建get_class_idx辅助函数。

     

    利用Keras和TensorFlow在没有对抗攻击的情况下进行图片分类

    在实现了ImageNet 类标签/索引辅助函数后,让我们构造一个图像分类脚本,在没有对抗攻击的情况下实现基本分类的图像分类脚本。

     

    这个脚本可以证明我们的ResNet模型表现正常(做出正确地预测)。在这篇教程的后半部分,你们将会发现如何构建一张对抗图像用于混淆ResNet。

     

    让我们开始基本的图像分类脚本——在你的工程文件结构中打开predict_normal.py文件,并插入以下代码:

    # import necessarypackages
    from pyimagesearch.utils import get_class_idx
    from tensorflow.keras.applications import ResNet50
    from tensorflow.keras.applications.resnet50 import decode_predictions
    from tensorflow.keras.applications.resnet50 import preprocess_input
    import numpy as np
    import argparse
    import imutils
    import cv2
    

     

    在第2-9行,我们引入了所需的Python包。如果你之前使用过Keras,TensorFlow和OpenCV的话,这些对你来说都是常规操作。

     

    如果你是Keras和TensorFlow的新手,我强烈建议你去看一下我的这篇《KerasTutorial: How to get started with Keras, Deep Learning, and Python》教程。另外,你或许想要读一读我的书《DeepLearning for Computer Vision with Python》加深你对训练自定义神经网络的理解。

     

    在第2行,我们引入了在上一章节中定义的get_class_idx函数,这个函数可以获得ResNet50模型中最高预测标签的整数索引值。

     

    让我们定义下 preprocess_image辅助函数:

    defpreprocess_image(image):
    # swap color channels,preprocess the image, and add in a batch
    # dimension
    image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
    image = preprocess_input(image)
    image = cv2.resize(image, (224, 224))
    image = np.expand_dims(image, axis=0)
    # return the preprocessed image
    return image
    

     

    preprocess_image 方法接收一个单一的必需参数,那就是我们想要预处理的图片。

     

    对这张图片进行预处理有以下几步:

    1. 将图片的BGR通道组合转化为RGB;

    2. 执行preprocess_input函数,用于完成ResNet50中特别的预处理和比例缩放过程;

    3. 将图片大小调整为224×224;

    4. 增加一个批次维度。

     

    这张预处理好的图像会被返回到调用函数中。

     

    接下来,让我们解析下指令参数:

    # construct the argument parser and parsethe arguments
    ap = argparse.ArgumentParser()
    ap.add_argument("-i", "--image",required=True,
    help="pathto input image")
    args = vars(ap.parse_args())
    

     

    我们在这里只需要一个命令行参数,--image,即输入图像存放在硬盘上的路径。

     

    如果你从来没有处理过命令行参数和argparse ,我建议你看一下这篇教程

     

    接下来让载入输入图像并进行预处理:

    # load image fromdisk and make a clone for annotation
    print("[INFO] loadingimage...")
    image = cv2.imread(args["image"])
    output = image.copy()
    # preprocess the input image
    output = imutils.resize(output, width=400)
    preprocessedImage = preprocess_image(image)
    

     

    通过调用cv2.imread来载入输入图片。在第4行对这张图片进行了复制,以便后期在输出结果上面画框并标注上预测结果类别标签。

     

    我们调整下输出图片的尺寸,让它的宽变为400像素,这样可以适配我们的电脑屏幕。在这里同样使用preprocess_image函数将其处理为可用于ResNet进行分类的输入图片。

     

    加上我们预处理好的图片,接着载入ResNet并对图片进行分类:

    # load thepre-trained ResNet50 model
    print("[INFO] loadingpre-trained ResNet50 model...")
    model = ResNet50(weights="imagenet")
    # makepredictions on the input image and parse the top-3 predictions
    print("[INFO] makingpredictions...")
    predictions =model.predict(preprocessedImage)
    predictions = decode_predictions(predictions, top=3)[0]
    

     

    第3行,载入ResNet和该模型用ImageNet数据集预训练好的权重。

     

    第6和7行,针对预处理好的图片进行预测,然后再用 Keras/TensorFlow 中的decode_predictions辅助函数对图片进行解码。

     

    现在让我们看看神经网络预测的Top 3 (置信度前三)类别以及所展示的类别标签:

    # loop over thetop three predictions
    for(i, (imagenetID, label,prob))inenumerate(predictions):
    # print the ImageNet class label ID of the top prediction to our
    # terminal (we'll need thislabel for our next script which will
    # perform the actual adversarial attack)
    if i == 0:
    print("[INFO] {} => {}".format(label, get_class_idx(label)))
    # display the prediction to our screen
    print("[INFO] {}.{}: {:.2f}%".format(i + 1, label, prob * 100))
    

     

    第2行开始循环Top-3预测结果。

     

    如果这是第一个预测结果(即Top-1预测结果),在输出终端显示可读的标签,然后利用 get_class_idx函数找出该标签对应的ImageNet的整数值索引。

     

    还可以在终端上展示Top-3的标签和对应的概率值。

     

    最终一步就是将Top-1预测结果标注在输出图片中:

    # draw thetop-most predicted label on the image along with the
    # confidence score
    text = "{}:{:.2f}%".format(predictions[0][1],
    predictions[0][2] * 100)
    cv2.putText(output, text, (3, 20),cv2.FONT_HERSHEY_SIMPLEX, 0.8,
    (0, 255, 0), 2)
    # show the output image
    cv2.imshow("Output", output)
    cv2.waitKey(0)
    

     

    输出图像在终端显示,如果你单击OpenCV窗口或按下任意键,输出图像将会关闭。

     

    非对抗图像的分类结果

    现在可以用ResNet来执行基本的图像分类(非对抗攻击)了。

     

    首先在“下载“页获取源代码和图像范例。

     

    从这开始,打开一个终端并执行以下命令:

    $ pythonpredict_normal.py --image pig.jpg
    [INFO] loading image...
    [INFO] loadingpre-trained ResNet50 model...
    [INFO] making predictions...
    [INFO] hog => 341
    [INFO] 1. hog: 99.97%
    [INFO] 2.wild_boar: 0.03%
    [INFO] 3. piggy_bank: 0.00%
    

    图五:预训练好的ResNet模型可以正确地将这张图片分类为“猪(hog)”。

     

    在这里你可以看到我们将一张猪的图片进行了分类,置信度为99.97%。

     

    另外,这里还加上了hog标签的ID(341)。我们将会在下一章用到这个标签ID,我们会针对这张猪的输入图片进行一次对抗攻击。

     

    在Keras和TensorFlow上实现对抗图像和对抗攻击

    接下来就要学习如何在Keras和TensorFlow上实现对抗图像和对抗攻击。

     

    打开generate_basic_adversary.py文件,插入以下代码:

    # import necessary packages
    from tensorflow.keras.optimizers import Adam
    from tensorflow.keras.applications import ResNet50
    from tensorflow.keras.losses importSparseCategoricalCrossentropy
    from tensorflow.keras.applications.resnet50 import decode_predictions
    from tensorflow.keras.applications.resnet50 import preprocess_input
    import tensorflow as tf
    import numpy as np
    import argparse
    import cv2
    

     

    在第2-10行中引入我们所需的Python包。你会注意到我们再次用到了ResNet50 架构,以及对应的preprocess_input函数(用于预处理/缩放输入图像)和 decode_predictions用于解码预测输出和显示可读的ImageNet标签。

     

    SparseCategoricalCrossentropy 用于计算标签和预测值之间的分类交叉熵损失。利用稀疏版本的分类交叉熵,我们不需要像使用scikit-learn的LabelBinarizer或者Keras/TensorFlow的to_categorical功能一样用one-hot对类标签编码。

     

    例如在predict_normal.py脚本中有preprocess_image 功能,我们在这个脚本上同样需要:

    defpreprocess_image(image):
    # swap color channels, resizethe input image, and add a batch
    # dimension
    image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
    image = cv2.resize(image, (224, 224))
    image = np.expand_dims(image, axis=0)
    # return the preprocessedimage
    return image
    

     

    除了省略了调用preprocess_input函数,这一段代码与上一段代码相同,当我们开始创建对抗图像时,你们马上就会明白为什么省去调用这一函数。

     

    接下来,我们有一个简单的辅助程序,clip_eps:

    defclip_eps(tensor, eps):
    # clip the values of thetensor to a given range and return it
    return tf.clip_by_value(tensor,clip_value_min=-eps,
    clip_value_max=eps)
    

     

    这个函数的目的就是接受一个输入张量tensor,然后在范围值 [-eps, eps]内对输入进行截取。

     

    被截取后的tensor会被返回到调用函数。

     

    接下来看看generate_adversaries 函数,这是对抗攻击的灵魂:

    defgenerate_adversaries(model, baseImage,delta, classIdx, steps=50):
    # iterate over the number ofsteps
    for step inrange(0, steps):
    # record our gradients
    with tf.GradientTape()as tape:
    # explicitly indicate thatour perturbation vector should
    # be tracked for gradient updates
    tape.watch(delta)
    

     

    generate_adversaries 方法是整个脚本的核心。这个函数接收四个必需的参数,以及第五个可选参数:

    1. model:ResNet50模型(如果你愿意,你可以换成其他预训练好的模型,例如VGG16,MobileNet等等);

    2. baseImage:原本没有被干扰的输入图像,我们有意针对这张图像创建对抗攻击,导致model参数对它进行错误的分类。

    3. delta:噪声向量,将会被加入到baseImage中,最终导致错误分类。我们将会用梯度下降均值来更新这个delta 向量。

    4. classIdx:通过predict_normal.py脚本所获得的类别标签整数值索引。

    5. steps:梯度下降执行的步数(默认为50步)。

     

    第3行开始循环设定好的步数。

     

    接下来用GradientTape来记录梯度。在tape上调用 .watch方法指出扰动向量是可以用来追踪更新的。

     

    现在可以建造对抗图像了:

    # add our perturbation vector to the base image and
    # preprocess the resulting image
    adversary = preprocess_input(baseImage + delta)
    # run this newly constructed image tensor through our
    # model and calculate theloss with respect to the
    # *original* class index
    predictions = model(adversary,training=False)
    loss = -sccLoss(tf.convert_to_tensor([classIdx]),
    predictions)
    # check to see if we arelogging the loss value, and if
    # so, display it to our terminal
    if step % 5 == 0:
    print("step: {},loss: {}...".format(step,
    loss.numpy()))
    # calculate the gradients ofloss with respect to the
    # perturbation vector
    gradients = tape.gradient(loss, delta)
    # update the weights, clipthe perturbation vector, and
    # update its value
    optimizer.apply_gradients([(gradients, delta)])
    delta.assign_add(clip_eps(delta, eps=EPS))
    # return the perturbationvector
    return delta
    

     

    第3行将delta扰动向量加入至baseImage的方式来组建对抗图片,所得到的结果将放入ResNet50的preprocess_input函数中来进行比例缩放和结果对抗图像进行归一化。

     

    接下来几行的意义是:

    • 第7行用model参数导入的模型对新创建的对抗图像进行预测。

    • 第8和9行针对原有的classIdx(通过运行predict_normal.py得到的top-1 ImageNet类别标签整数值索引)计算损失。

    • 第12-14行表示每5步就显示一次损失值。

     

    第17行,在with声明外根据扰动向量计算梯度损失。

     

    接着,可以更新delta向量,截取掉超出 [-EPS,EPS] 范围外的值。

     

    最终,把得到的扰动向量返回至调用函数——即最终的delta值,该值能让我们建立用来欺骗模型的对抗攻击。

     

    在对抗脚本的核心实现后,接下来就是解析命令行参数:

    # construct the argumentparser and parse the arguments
    ap = argparse.ArgumentParser()
    ap.add_argument("-i", "--input", required=True,
    help="path tooriginal input image")
    ap.add_argument("-o", "--output", required=True,
    help="path tooutput adversarial image")
    ap.add_argument("-c", "--class-idx", type=int,required=True,
    help="ImageNetclass ID of the predicted label")
    args = vars(ap.parse_args())
    

     

    我们的对抗攻击Python脚本需要三个指令行参数:

    1. --input: 输入图像的磁盘路径(例如pig.jpg);

    2. --output: 在构建进攻后的对抗图像输出(例如adversarial.png);

    3. --class-idex:ImageNet数据集中的类别标签整数值索引。我们可以通过执行在“非对抗图像的分类结果”章节中提到的predict_normal.py来获得这一索引。

     

    接下来是几个变量的初始化,以及加载/预处理--input图像:

    # define theepsilon and learning rate constants
    EPS = 2 / 255.0
    LR = 0.1
    # load the inputimage from disk and preprocess it
    print("[INFO] loadingimage...")
    image = cv2.imread(args["input"])
    image = preprocess_image(image)
    

     

    第2行定义了用于在构建对抗图像时来裁剪tensor的epsilon值(EPS)。2 / 255.0 是EPS的一个用于对抗类刊物或教程的标准值和指导值(如果你想要了解更多的默认值,你可以参考这份指导)。

     

    在第3行定义了学习速率。经验之谈,LR的初始值一般设为0.1,在创建你自己的对抗图像时可能需要调整这个值。

     

    最后两行载入输入图像,利用preprocess_image辅助函数来对其进行预处理。

     

    接下来,可以载入ResNet模型:

    # load thepre-trained  ResNet50 model for running inference
    print("[INFO] loadingpre-trained ResNet50 model...")
    model = ResNet50(weights="imagenet")
    # initializeoptimizer and loss function
    optimizer = Adam(learning_rate=LR)
    sccLoss = SparseCategoricalCrossentropy()
    

     

    第3行载入在ImageNet数据集上训练好的ResNet50模型。

     

    我们将会用到Adam优化器,以及稀疏的分类损失用于更新我们的扰动向量。

     

    让我们来构建对抗图像:

    # create a tensorbased off the input image and initialize the
    # perturbation vector (we will update this vector via training)
    baseImage = tf.constant(image,dtype=tf.float32)
    delta = tf.Variable(tf.zeros_like(baseImage), trainable=True)
    # generate the perturbation vector to create an adversarialexample
    print("[INFO]generating perturbation...")
    deltaUpdated = generate_adversaries(model, baseImage,delta,
    args["class_idx"])
    # create theadversarial example, swap color channels, and save the
    # output image to disk
    print("[INFO]creating adversarial example...")
    adverImage = (baseImage +deltaUpdated).numpy().squeeze()
    adverImage = np.clip(adverImage, 0, 255).astype("uint8")
    adverImage = cv2.cvtColor(adverImage,cv2.COLOR_RGB2BGR)
    cv2.imwrite(args["output"], adverImage)
    

     

    第3行根据输入图像构建了一个tensor,第4行初始化扰动向量delta。

     

    我们可以把ResNet50、输入图像、初始化后的扰动向量、及类标签整数值索引作为参数,用来调用generate_adversaries并更新delta向量。

     

    在 generate_adversaries函数执行时,会一直更新delta扰动向量,生成最终的噪声向量deltaUpdated。

     

    在倒数第4行,在baseImage上加入deltaUpdated 向量,就生成了最终的对抗图像(adverImage)。

     

    然后,对生成的对抗图像进行以下三步后处理:

    1. 将超出[0,255] 范围的值裁剪掉;

    2. 将图片转化成一个无符号8-bit(unsigned 8-bit)整数(这样OpenCV才能对图片进行处理);

    3. 将通道顺序从RGB转换成BGR。

     

    在经过这些处理步骤后,就可以把对抗图像写入到硬盘里了。

     

    真正的问题来了,我们新创建的对抗图像能够欺骗我们的ResNet模型吗?

     

    下一段代码就可以回答这一问题:

    # run inferencewith this adversarial example, parse the results,
    # and display the top-1 predicted result
    print("[INFO]running inference on the adversarial example...")
    preprocessedImage = preprocess_input(baseImage +deltaUpdated)
    predictions =model.predict(preprocessedImage)
    predictions = decode_predictions(predictions, top=3)[0]
    label = predictions[0][1]
    confidence = predictions[0][2] * 100
    print("[INFO] label:{} confidence: {:.2f}%".format(label,
    confidence))
    # draw the top-most predicted label on the adversarial imagealong
    # with theconfidence score
    text = "{}: {:.2f}%".format(label, confidence)
    cv2.putText(adverImage, text, (3, 20),cv2.FONT_HERSHEY_SIMPLEX, 0.5,
    (0, 255, 0), 2)
    # show the output image
    cv2.imshow("Output", adverImage)
    cv2.waitKey(0)
    

     

    在第4行又一次创建了一个对抗图像,方式还是在原始输入图像中加入delta噪声向量,但这次我们利用ResNet的preprocess_input功能来处理。

     

    生成的预处理图像进入到ResNet,然后会得到top-3预测结果并对他们进行解码(第5和6行)。

     

    接着我们获取到top-1标签和对应的概率/置信度,并将这些值显示在终端上(第7-10行)。

     

    最后一步就是把最高的预测值标在输出的对抗图像上,并展示在屏幕上。

    对抗图像和攻击的结果

    准备好见证一次对抗攻击了吗?

     

    从这里开始,你就可以打开终端并执行下列代码了:

    $ python generate_basic_adversary.py --inputpig.jpg --output adversarial.png --class-idx 341
    [INFO] loading image...
    [INFO] loading pre-trained ResNet50 model...
    [INFO] generatingperturbation...
    step: 0, loss:-0.0004124982515349984...
    step: 5, loss:-0.0010656398953869939...
    step: 10, loss:-0.005332294851541519...
    step: 15, loss: -0.06327803432941437...
    step: 20, loss: -0.7707189321517944...
    step: 25, loss: -3.4659299850463867...
    step: 30, loss: -7.515471935272217...
    step: 35, loss: -13.503922462463379...
    step: 40, loss: -16.118188858032227...
    step: 45, loss: -16.118192672729492...
    [INFO] creating adversarial example...
    [INFO] running inference on theadversarial example...
    [INFO] label: wombat confidence: 100.00%
    

    图六:之前,这张输入图片被正确地分在了“猪(hog)”类别中,但现在因为对抗攻击而被分在了“袋熊(wombat)”类别里!

     

    我们的输入图片 pig.jpg 之前被正确地分在了“猪(hog)”类别中,但现在它的标签却成为了“袋熊(wombat)”!

     

    将原始图片和用generate_basic_adversary.py脚本生成的对抗图片放在一起进行对比:

    图七:在左边是原始图片,分类结果正确。右边将是对抗图片,被错误地分在了“袋熊(wombat)”类别中。而对于人类的眼睛来看完全分辨不出两张图片的有什么区别。

     

    左边是最初猪的图像,在右边是输出的对抗图像,这张图像被错误的分在了“袋熊(wombat)”类别。

     

    就像你看到的一样,这两张图片没有任何可感知的差别,我们人类的眼睛看不出任何区别,但对于ResNet来说确实完全不同的。

     

    这很好,但我们无法清晰地掌控对抗图像被最终识别的类别标签。这会引起以下问题:

    我们有可能掌控输入图片的最终类别标签吗?答案是肯定的,这会成为我下一篇教程的主题。

     

    总结来说,对抗图像和对抗攻击真的是令人细思极恐。但如果等我们看到下一篇教程,就可以提前防御这种类型的进攻。稍后再详细说明下。

    致谢

    如果没有Goodfellow, Szegedy和其他深度学习的研究者的工作,这篇教程就无法完成。

     

    另外,这篇教程所用到的实现代码灵感来自于TensorFlow官方实现的《Fast Gradient Signed Method》。我强烈建议你去看看其他的示例,每一段代码都比这篇教程中的在理论和数学上更加明确。

     

    总结

    在这篇教程中,你学到关于对抗攻击的知识,关于他们是怎样工作的,以及随着人工智能和深度神经网络与这个世界的关联越来越高,对抗攻击就会构成更大的威胁。

    接着我们利用深度学习库Keras 和TensorFlow实现了基本的对抗攻击算法。

    利用对抗攻击,我们可以蓄意扰乱一张输入图片,例如:

    1. 这张输入图片会被错误分类。

    2. 然而,肉眼看上去被扰乱的图片还是和之前一样。

    利用这篇教程所使用的方法,我们并不能控制图片最终被判别的类别标签——我们所做的只是创造一个噪声向量,并将其嵌入到输入图像中,导致深度神经网络对其错误分类。

    如果我们能够控制最终的类别标签会怎样呢?比如说,我们拿一张“狗”的图片,然后制造一次对抗攻击,让卷积神经网络认为这是一张“猫”的图片,这有没有可能呢?

    答案是肯定的——我们会在下一篇教程中来谈论这一话题。

    原文链接:

    https://www.pyimagesearch.com/2020/10/19/adversarial-images-and-attacks-with-keras-and-tensorflow/

    原文标题:

    Adversarial images andattacks with Keras and TensorFlow

    编辑:黄继彦

    校对:林亦霖

    译者简介

    吴振东,法国洛林大学计算机与决策专业硕士。现从事人工智能和大数据相关工作,以成为数据科学家为终生奋斗目标。来自山东济南,不会开挖掘机,但写得了Java、Python和PPT。

    翻译组招募信息

    工作内容:需要一颗细致的心,将选取好的外文文章翻译成流畅的中文。如果你是数据科学/统计学/计算机类的留学生,或在海外从事相关工作,或对自己外语水平有信心的朋友欢迎加入翻译小组。

    你能得到:定期的翻译培训提高志愿者的翻译水平,提高对于数据科学前沿的认知,海外的朋友可以和国内技术应用发展保持联系,THU数据派产学研的背景为志愿者带来好的发展机遇。

    其他福利:来自于名企的数据科学工作者,北大清华以及海外等名校学生他们都将成为你在翻译小组的伙伴。

    点击文末“阅读原文”加入数据派团队~

    转载须知

    如需转载,请在开篇显著位置注明作者和出处(转自:数据派ID:DatapiTHU),并在文章结尾放置数据派醒目二维码。有原创标识文章,请发送【文章名称-待授权公众号名称及ID】至联系邮箱,申请白名单授权并按要求编辑。

    发布后请将链接反馈至联系邮箱(见下方)。未经许可的转载以及改编者,我们将依法追究其法律责任。

    点击“阅读原文”拥抱组织

    展开全文
  • 原文
  • 对抗学习,用于网络上的图片检测的对抗对抗NPC的检测
  • 对抗攻击图片代码.zip

    2020-04-21 18:54:42
    生成对抗网络白箱攻击实验相关代码,可结合使用文档,见博客记录内容。简单的实现白盒下的图片对抗攻击,将cat图片识别成面包机,且人肉眼分不出,只欺骗模型。
  • 原始图片(matlab自带),FGSM生成的对抗样本两组,各10000张,测试数据200张
  • 图片对抗样本的生成

    2020-09-27 16:18:42
    #图片对抗样本的生成 https://wizardforcel.gitbooks.io/tf-tut-hvass/content/11_Adversarial_Examples_zh_CN/11_Adversarial_Examples_zh_CN.html
  • 利用python实现深度学习生成对抗样本,为任一图片加扰动并恢复原像素一、前言(一)什么是深度学习(二)什么是样本模型(三)什么是对抗样本1、对抗的目的2、谁来对抗?3、对抗的敌人是谁?4、怎么对抗?(1)...
  • GAN (生成对抗网络) 手写数字图片生成 文章目录GAN (生成对抗网络) 手写数字图片生成Discriminator NetworkGenerator Network简单版本的生成对抗网络判别器 Discriminator生成器 Generator超参数设置训练网络生成...
  • 使用TensorFlow生成对抗样本

    千次阅读 2017-10-24 10:12:03
    对抗学习训练为指导人工智能完成复杂任务提供了一个全新的思路,生成对抗图片能够非常轻松的愚弄之前训练好的分类器,因此如何利用生成对抗图片提高系统的鲁棒性是一个很有研究的热点问题。 神经网络合成的对抗...
  • 对抗样本与对抗训练

    万次阅读 多人点赞 2016-12-07 11:03:28
    本文将会介绍对抗样本与对抗训练的相关知识(请将此对抗训练与Ian Goodfellow的生成对抗网络区别开来)。综合Ian Goodfelow在Burkeley CS 294-131的deeplearning topic上面的讲义,我将从以下几个方面介绍: 什么是...
  • 对抗样本和对抗网络

    2018-03-03 14:44:05
    前言:本文转载lancezhange 的博文《对抗样本和对抗网络》,文章介绍了对抗样本的概念和相关文献,并且进一步介绍了生成式对抗网络(Generative Adversarial Nets, GAN)。 所谓对抗 样本是指将实际样本略加扰动而...
  • 神经网络对抗攻击与防御PPT,分享了Nettack和GNNGUARD
  • 图对抗学习文学:关于结构数据的对抗性攻击和防御论文精选清单
  • 对抗样本&对抗训练

    万次阅读 2018-05-03 18:14:10
    原文本文将会介绍对抗样本与对抗训练的相关知识(请将此对抗训练与Ian Goodfellow的生成对抗网络区别开来)。综合Ian Goodfelow在Berkeley CS 294-131的deeplearning topic上面的讲义,我将从以下几个方面介绍:什么...
  • 1.背景 对抗样本:数据集中通过故意添加细微的干扰所形成的输入样本,受干扰之后的输入导致... 1 对抗样本的定义 正如1右边展示的那样,当对熊猫数据加上一定的噪声,深度模型以99.3%的置信度将熊猫识别
  • 这是一读一篇论文的笔记,主要写了生成对抗网络的表示学习,其中对生成模型和判别模型进行简单介绍,其次本文中对提出的softmax进行了介绍
  • 对抗训练

    万次阅读 多人点赞 2018-10-18 21:21:09
    在对图像算法研究的过程中发现,一些机器学习方法(包括深度学习)对对抗样本非常敏感,这些对抗样本和非对抗样本非常相似,但是模型(已经在非对抗样本中训练好的模型)却会错分这些样本。为了能更好的分类该类样本...
  • 生成对抗网络 图像生成Machines are generating perfect images these days and it’s becoming more and more difficult to distinguish the machine-generated images from the originals.如今,机器正在生成完美...
  • 下面是统计的图像对抗样本研究方向的文章:主要包括比较常见的分类任务与目标检测任务中对抗样本生成方法。先放在这里,找到时间就来整理。 https://github.com/gmt710/adversarial-example ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 54,617
精华内容 21,846
关键字:

对抗图