[论文解读]Towards Improved Testing For Deep Learning

Towards Improved Testing For Deep Learning

简介

论文标题

  • Towards Improved Testing For Deep Learning
  • 走向深度学习的改进测试
  • 2019

提出了一种组合测试的覆盖方法,以三元组的方式定义目标函数并引导测试用例生成

覆盖类似于DeepCT与DeepCover

摘要

摘要-随着深度神经网络在安全关键应用中的日益广泛使用,在实际使用之前,有必要进行充分的测试,以检测和纠正角盒输入的任何不正确行为。深度神经网络缺乏明确的控制流结构,因此不可能将代码覆盖率等传统软件测试标准应用于它们。在本文中,我们检查了现有的深度神经网络测试方法,改进的机会,以及对快速、可扩展、可推广的端到端测试方法的需求。我们还提出了一个深层神经网络的复盖准则,试图捕获深层神经网络逻辑的所有可能部分。

初步

深度神经网络,或称DNNs,由于其能够达到或超过人类水平的性能,正越来越多地被用于各种应用中。大数据集、快速计算方法的可用性及其实现良好性能的能力为DNN进入安全关键领域铺平了道路,如自动驾驶、医疗诊断、安全等。这些应用的安全关键性质使得在部署之前充分测试这些DNN是势在必行的。然而,与传统软件不同的是,DNN没有清晰的控制流结构。他们通过对大数据集的训练来学习他们的决策策略,使用几种方法逐步调整参数以达到所需的精度。因此,传统的软件测试方法,如功能覆盖、分支覆盖等不能应用于DNN,从而挑战了它们对安全关键应用的使用。

最近的许多工作(在III中讨论)都着眼于为DNN开发测试框架。正如第四章所讨论的,这些方法都有一定的局限性。在我们的工作中,我们打算努力克服这些局限性,建立一种快速、可扩展、高效、可推广的深度神经网络测试方法。在V中,我们提出了一个前馈深度神经网络的覆盖准则,它试图通过结合层间关系和层内关系来更大程度地捕捉DNN逻辑。

背景

深度神经网络是在输入层和输出层之间具有多个隐层的神经网络。与传统的软件程序不同,在传统的软件程序中,程序逻辑必须由程序员手动描述,而深度神经网络能够通过在大数据集上进行训练来学习规则。今天,DNN被用于容易到复杂的任务,例如图像分类[10]、医疗诊断和端到端驾驶自动驾驶汽车[1]。这类应用程序的安全关键性质使得确保正确性、避免致命的不正确行为以及安全地从DNNs获得性能优势变得重要。

[论文解读]Towards Improved Testing For Deep Learning

传统的软件测试方法在应用于DNN时会失败,因为深度神经网络的代码不包含有关DNN的内部决策逻辑的信息,如图1所示。DNN从训练数据中学习它们的规则,并且缺乏传统软件程序中存在的控制流结构。因此,传统的代码覆盖、分支覆盖、功能覆盖等覆盖准则不能应用于深度神经网络。图2显示了DNN的大多数现有白盒测试方法的高级表示。测试过程的输入是DNN、测试输入和覆盖度量,以确保程序逻辑的所有部分都已测试。先知决定DNN的行为对于测试的输入是否正确。此外,可以使用引导测试输入生成方法来生成具有更大覆盖并且揭示更大转角情况行为的测试输入。现有测试方法的输出通常是系统正确性或对抗性比率的度量。

先验文学

深度神经网络的测试方法通常遵循黑盒方法,直到最近,DeepXplore[7]提出了第一个用于DNNs的白盒测试方法。[6]提出的方法涉及在给定输入周围随机搜索导致错误分类的更改。许多其他方法涉及通过稍微干扰输入以诱导不正确的行为来生成对抗性示例,这是手动检查的。然而,这些黑盒方法在没有覆盖标准的情况下是完全没有指导的,并且忽略了DNN的内部逻辑。在DeepXplore[7]中,作者引入了神经元覆盖的概念作为测试DNNs的覆盖度量。他们还建议将多个实现用于与Oracle相同的任务,以避免手动标记工作。此外,DeepCover[8]受修改后的软件测试代码/决策覆盖率的启发,提出了几个测试DNN的标准。它们的复盖标准考虑了连续层神经元之间的条件-决策依赖性。另一种最近的方法DeepMutation[4]是第一个源代码级突变测试技术,它提出了一组模型级突变测试算子,直接在深度学习模型上变异,而不需要训练过程。DeepCT[5]使用了一种组合测试启发的复盖标准,该标准指导对以分层方式**神经元的测试输入进行详尽的搜索。

改善的机会

为什么我们需要更好的覆盖标准?

传统软件程序的覆盖率标准,如代码覆盖率和分支覆盖率,检查程序中的所有逻辑部分是否已由至少一个测试输入测试,并且所有条件均已测试,以独立影响相关决策。在类似的线路上,任何深度神经网络的覆盖准则都必须能够保证完备性,即必须能够确保DNN的内部决策结构的所有部分至少由一个测试输入执行。

典型的前馈深度神经网络包含多个非线性处理层,每个隐层使用前一隐层的输出作为其输入。每一层都由多个神经元组成。神经元是一个计算单元,松散地模仿人脑中的神经元,当它接收到足够的刺激或输入时,它就会激发/**。从数学上讲,如果Lk−1和Lk表示此DNN的两个连续层(图1):

[论文解读]Towards Improved Testing For Deep Learning

[论文解读]Towards Improved Testing For Deep Learning

因此,随着每个神经元的数值对下一隐层神经元的**有独立的影响,同一层神经元数值的组合也会影响下一层神经元的数值。任何深度神经网络的复盖标准都必须能够兼顾这两个因素。此外,覆盖标准应该能够扩展到更大的真实DNN和不同的网络体系结构。以前的工作提出的覆盖标准受到以下几个限制:

神经元覆盖率[7]根据输入**的神经元数量测量测试输入执行的DNN逻辑的部分。然而,它不能完全解释DNN可能表现出的所有可能行为。文献[8]的实验证明神经元复盖率相当容易实现,25个随机测试输入能够达到接近100%的神经元复盖率。此外,我们观察到角例行为可以被发现超过100%的神经元覆盖率。我们的实验1发现,在某些模型体系结构的情况下,例如用于MNIST手写数字分类的LeNet-1,可以通过两个测试输入获得100%的神经元覆盖率,因为对于大多数测试输入,神经元总是被激发/**的。因此,神经元覆盖率是衡量DNN覆盖率的一个相当粗糙和不足的标准。

DeepCover的[8]覆盖标准考虑了DNN相邻层中的条件-决策相关性。除了他们的方法在相对较小的网络上进行测试外,它假设DNN是一个前馈的、全连接的网络,不能推广到RNN、LSTM、注意网络等体系结构。这样的方法没有考虑自己层中神经元的上下文,以及同一层中神经元输出的组合。

DeepCT的[5]组合测试启发覆盖标准根据每一层中**的神经元的比例来确定测试输入所执行的逻辑的比例。它没有考虑DNN内的层间关系,并且没有被验证可扩展到具有不同层的真实世界DNN。

为什么我们需要更好的测试输入生成?

以引导方式生成或选择测试输入通常有两个主要目标-最大化未覆盖故障的数量和最大化覆盖率。[7]介绍了一种基于联合优化的测试输入生成方法,在该方法中,递归地修改现有的测试输入(使用图像处理),直到找到导致差异行为的测试输入。[9]使用类似的贪婪搜索技术,其中应用随机转换,直到找到合适的测试输入。这种测试输入生成方法存在一些主要缺陷:

  • 操作现有测试输入直到找到满足标准的测试输入的迭代过程,每次执行都有相当长的时间。
  • 与测试和生成的输入的总数之和相比,实际导致覆盖范围增加和/或未覆盖的角盒行为的数量增加的测试输入的数量相当低。

为什么我们需要一个更好的oracle呢?

测试DNN的正确性需要存在基本事实(Oracle),它决定行为是否正确。现有的用于测试DNN的Oracle存在几个限制:

  • 在像DNNs这样的数据驱动方案中,最直接的方法是收集尽可能多的真实世界数据,并手动标记以检查其正确性。然而,这样的过程需要大量的人工工作。
  • 在作为一个先知的多个DNN实现[7]中,对同一任务的多个实现进行比较,并将差异行为标记为角例行为。然而,我们观察到,该方法错误地将某些角例输入分类为正确的行为,因为所有实现预测的标签都是相似的,并且错误地将几个正确的输入分类为角例行为。此外,此方法仅在具有多个现有高精度实现的应用程序中有效。通常,DNN可以部署在没有很多现有实现的任务中,和/或实现可以由必然使用相同方法或犯下相同错误的同一组专家来制作。

初步探讨和结果

在本文中,我们只关注于提出一个更精细的覆盖准则。一个理想的深度神经网络的覆盖标准必须能够保证完备性,即DNN的内部决策逻辑的所有部分都经过了至少一个输入的测试。回想一下,DNN中特定层的神经元的值是上一层神经元加权和的非线性函数,如公式1所示。在这些线上,我们提出了一个覆盖准则,它综合了两个因素-每个神经元对下一层神经元值的条件效应和一层神经元的值的组合[3]。

对于给定的(前馈)深度神经网络Lk−1和Lk,设这些层中的神经元分别表示为 { n 1 , k − 1 , n 2 , k − 1 , … , n N k − 1 , k − 1 } \left\{n_{1, k-1}, n_{2, k-1}, \ldots, n_{N_{k-1}, k-1}\right\} {n1,k1,n2,k1,,nNk1,k1} { n 1 , k , n 2 , k , … , n N k , k } \left\{n_{1, k}, n_{2, k}, \ldots, n_{N_{k}, k}\right\} {n1,k,n2,k,,nNk,k},其中 N k N_{k} Nk表示 L k L_{k} Lk中的神经元总数。对于任何测试输入t,如果神经元n的值大于某一阈值(例如,0),则称其为**。形式上,如果 ϕ ( t , n ) \phi(t, n) ϕ(t,n)表示当深层神经网络的输入为t时神经元n的**,则如果φ(t,n)>0(或任何其他阈值,取决于**函数),则该神经元被**或激发。因此,对于给定的神经元n和测试输入t,条件φ(t,n)>0可以有两个值,TRUE或FALSE,这取决于神经元是否被**。

基于这些定义,我们的覆盖准则被定义为DNN中每个这样的三元组的双向覆盖[3]: ( n i , k − 1 , n j , k − 1 , n q , k ) \left(n_{i, k-1}, n_{j, k-1}, n_{q, k}\right) (ni,k1,nj,k1,nq,k)。形式上,对于n个变量的给定测试集,简单t-way组合覆盖率是完全覆盖所有变量赋值配置的n个变量的t-way组合的比例。通过确保对三个这样的不同神经元的双向覆盖,我们能够覆盖(1)条件(LK−1中的神经元的**)对结果(下一层中的神经元的值,LK)的独立影响,(2)由于同一层LK−1中的神经元的‘相互作用’或**值而可能出现的故障。第一个覆盖更多地受到MC/DC[2]和其他传统软件覆盖标准的启发,而第二个覆盖则受到组合测试[3]的启发。这种测试是基于这样一个事实,即并非每个参数都会导致每一次失败,经验数据表明,几乎所有的失败都是由相对较少的参数之间的相互作用引起的。这一发现对测试具有重要的意义,因为它表明测试(较少的)参数组合可以提供高效的故障检测。在我们的场景中,由于前一层中的多个(但不总是全部)神经元的值对下一层中的神经元的值有贡献,因此这种方法能够测试一个条件(等式1中的加权和)可以采用的多个值,这也是传统软件覆盖标准(如MC/DC[2])的要求之一。

类似于DeepCT和MCD/DC 三元组两个是上层的,一个是下层的
它寻找1)同一层中具有所有可能值组合的所有神经元对,以及2)具有所有可能值组合的连续层中的所有神经元对

对于初步的结果,我们通过联合优化来实现引导测试输入的生成[7]。随机选择没有达到100%覆盖率的任何三元组,以确定哪个(哪些)**值组合没有被覆盖。例如,考虑DNN实例,其中 n i , k − 1 \mathrm{n}_{i, k-1} ni,k1被激发但 n j , k − 1 \mathrm{n}_{\mathrm{j}, \mathrm{k}-1} nj,k1未被**。决定神经元 n q , k \mathrm{n}_{\mathrm{q}, \mathrm{k}} nq,k被激发。目标变成了
F n , t = f n i , k − 1 ( t ) + f n j , k − 1 ( t ) + f n q , k ( t ) F_{n, t}=f_{n_{i, k-1}}(t)+f_{n_{j, k-1}}(t)+f_{n_{q, k}}(t) Fn,t=fni,k1(t)+fnj,k1(t)+fnq,k(t)

因此最大化覆盖的目标函数变成,

  • f n i , k − 1 ( t ) = ϕ ( t , n i , k − 1 ) f_{n_{i, k-1}}(t)=\phi\left(t, n_{i, k-1}\right) fni,k1(t)=ϕ(t,ni,k1)需要最大化使得 ϕ ( t , n i , k − 1 ) > 0 \phi\left(t, n_{i, k-1}\right)>0 ϕ(t,ni,k1)>0(或者大于决定的阈值)
  • f n j , k − 1 ( t ) = ϕ ( t , n j , k − 1 ) f_{n_{j, k-1}}(t)=\phi\left(t, n_{j, k-1}\right) fnj,k1(t)=ϕ(t,nj,k1)需要最小化使得 ϕ ( t , n j , k − 1 ) = 0 \phi\left(t, n_{j, k-1}\right)=0 ϕ(t,nj,k1)=0,并且
  • f n q , k ( t ) = ϕ ( t , n q , k ) f_{n_{q, k}}(t)=\phi\left(t, n_{q, k}\right) fnq,k(t)=ϕ(t,nq,k)需要最大化使得 ϕ ( t , n q , 1 ) > 0 \phi\left(t, n_{q, 1}\right)>0 ϕ(t,nq,1)>0

因此,最大化覆盖范围的目标函数变成
F n , t = ϕ ( t , n i , k − 1 ) − ϕ ( t , n j , k − 1 ) + ϕ ( t , n q , k ) F_{n, t}=\phi\left(t, n_{i, k-1}\right)-\phi\left(t, n_{j, k-1}\right)+\phi\left(t, n_{q, k}\right) Fn,t=ϕ(t,ni,k1)ϕ(t,nj,k1)+ϕ(t,nq,k)
**的尽可能大,没**的尽可能小
因为 F n , t F_{n, t} Fn,t中的单个项,即某些层中某些神经元的**值,以及任意n的 ϕ ( t , n ) \phi(t, n) ϕ(t,n)都是一个堆叠函数序列,所以梯度 ∂ F n ( t ) ∂ t \frac{\partial F_{n}(t)}{\partial t} tFn(t)可以使用微积分中的链规则来计算,即从包含神经元的层向后计算逐层导数,直到到达接受输入t的输入层[7]。因此,可以分步操作输入t以最大化 F n , t F_{n, t} Fn,t。我们使用的oracle与[7]相同,因此第二个目标是产生引起输入的差异行为。
对t求导则可以生成新的测试
即: 选定没有完全覆盖的神经元三元组,带入目标函数,求导,生成新用例

我们在三个DNN上评估了我们的覆盖度量,这三个DNN对手写数字的MNIST数据集进行了分类:LeNet-1、LeNet-4和LeNet-5。由于我们工作的主要目标是引入和测试更细粒度的覆盖指标,因此我们的测试输入生成方法和Oracle共享第四节中提到的限制。用于确定我们的覆盖标准有效性的指标是:

  • 在十个随机测试输入上获得的覆盖率,以及
  • 找到的corner cases 与总测试输入数之比。

理想情况下,10个随机测试输入(不是使用引导方法生成的)的覆盖率必须很低,即随机输入的标准必须很难达到,并且对抗性比率必须很高。我们目前使用多个实现[7]作为一个预言,在IV中引入,并且只有一种图像操作,即亮度。结果摘要载於表I。然后,我们将我们提出的覆盖准则与现有的覆盖度量进行了比较。我们发现,对于相同的数据集和DNN,在三个DNN上的10个随机测试输入的平均神经元覆盖率为30.5%(使用的阈值为0),而我们的覆盖标准为8.9%。此外,对于LENet-1,只需两个角例输入就可以实现100%的神经元覆盖,并且除了达到100%的神经元覆盖之外,还可以找到大量的角例输入。另一方面,对于我们的标准,LENet-1在550个测试输入上实现了接近11.6%的覆盖率。这是因为对于给定的测试输入,DNN中最常见的**模式是所有神经元都被激发/**,因此很难实现双向覆盖。对于550个测试输入,使用引导式测试输入生成的所有三个DNN的平均神经元覆盖率为98.5%,而使用相同的测试输入生成方法,我们提出的覆盖标准的平均神经元覆盖率为31%。对于相似大小的DNN,使用DeepCover[8]获得的最大对抗性比率为11%。类似地,DeepCT[5]对于相似大小的DNN,对于10,000个测试输入,达到不到10%的对抗性。这些结果证实,对于DNNs的测试,重要的是具有更细粒度的覆盖度量,该度量不仅包含层间关系,而且包括同一层中神经元的相对**。虽然大量的三元组似乎是一个计算瓶颈,但是更新具有最多三元组数量(651720)的LENET-5的覆盖范围所需的平均时间是2.08秒。

[论文解读]Towards Improved Testing For Deep Learning

结论

由于缺乏透明的决策逻辑,使得传统的软件测试方法不可能应用于DNNs。本文研究了现有的深度神经网络测试方法,认识到覆盖标准粗略、过程开放、oracle不可靠、测试输入生成方法效率低、无法扩展到较大的DNN和不同的网络结构等缺陷,进而提出了一种细粒度的前馈DNN覆盖准则,该准则考虑了相邻层之间的条件-决策关系和同层神经元的值组合。一组10个随机测试输入只能达到我们覆盖率标准的8.9%。此外,当结合基于梯度的搜索技术和多个Oracle实现时,它能够在三个模型上实现平均87.8%的对抗性。在更大程度上测试DNN的内部逻辑的能力使其性能优于现有方法。覆盖方法对更大规模真实DNN的可扩展性和对不同网络体系结构的适应性还有待测试。