DeepMutation:DL系统的模糊测试
DeepMutation:DL系统的模糊测试概述介绍背景编程范例(传统的)模糊测试DL系统的源码级突变测试DL系统的源码级突变测试工作流程突变算子数据突变算子程序突变算子DL系统的突变测试度量DL系统的模型级突变测试模型级突变测试工作流程模型级突变算子
概述
传统软件测试中,变异测试是其中很重要且完善的测试技术,它用来评估软件多大程度上能够检测到注入的错误。
然而,由于传统软件与深度学习软件之间的根本区别,因此将变异测试迁移到DL系统需要进行适应性调整。
本文首先提出了一些针对DL系统的模型层变异算子,包括需要重新训练的,以及不需要重新训练的突变。
介绍
image-20200922165606860-
差别:
传统软件系统决策逻辑,通常是由开发人员通过代码直接设计的。
而DL系统则的决策逻辑,则是由DNN结构以及网络的连接权重所决定的,这些值是由训练程序+训练数据集决定的。
因此,训练程序和训练数据集是DL系统测试的两个重要方向。所以DL系统的变异测试,一个直观的思路就是,通过引入变异算子,将突变注入到训练程序,或者是训练数据集上。
注入突变后,可以得到不同的DNN突变模型,记作,然后再通过一组测试输入,来得到在测试输入集上,原模型与突变模型的差异,以评估测试输入的质量。
-
主要贡献:
本文提出一个变异测试框架和工作流程,使得我们能够评估测试数据的质量,并进行弱点定位。
作者给出了八个源码级突变算子
并给出了专门面向DL突变测试的测试质量评估度量
同时还分析了的其所提出的内容在不同数据集和模型上的表现,以论证有效性,并指出其可能有助于促进测试集增强。
image-20200922192420269
背景
编程范例
传统软件是开发人员以源代码的形式精心制作的逻辑流的实现,它可以被分解成单元(例如,类、方法、语句、分支)。每个单元指定一些逻辑,并允许作为软件质量度量的目标进行测试(例如,语句覆盖、分支覆盖)。在源代码被编程之后,它被编译成可执行的形式,这些形式将在各自的运行时环境中运行,以满足系统的要求。比如在面向对象编程中,开发人员分析需求,设计相应的软件架构。每个架构单元(例如,类)代表特定的功能,并且通过单元的协作和交互来实现总体目标。
测试目的性明确//可分解性强
而深度学习则遵循数据驱动的编程范式,使用大量的训练数据,通过模型训练过程对核心逻辑进行编程。该逻辑被编码在一个深度神经网络中,由输入非线性激活函数的权重集表示。为了获得一个用于特定任务M的DL软件F,一个DL开发人员需要收集训练数据,该数据指定了F对M的期望行为,并准备一个训练程序,该程序描述了DNN的结构和运行时训练行为。通过对训练数据运行训练程序来构建DNN。DL开发人员的主要工作是准备一组训练数据和设计一个DNN模型结构,DL逻辑是通过训练过程自动确定的。与传统软件相反,描述语言模型通常很难分解或解释,这使得它们对于大多数现有的软件测试技术来说是不可理解的。此外,很难找到高质量的训练和测试数据来评估它们的通用性,这些数据代表问题空间并具有模型的良好覆盖。
任务不可分解且难以度量//实现改进途径不明确
(传统的)模糊测试
给定一个原程序P,一组错误的程序P'(变异)是基于预定义的规则(变异操作符)创建的,每个规则都会稍微修改P。通常在实际的突变测试程序开始之前,使用预处理步骤来过滤掉不相关的测试。具体来说,完整的测试集T针对P执行,只有通过的测试T‘ (T的子集)用于突变测试。下一步,每个突变体P’ 都执行T‘。如果测试结果为突变不同于P,那么p'被杀死;否则,p'活下来。当P里所有的变异P’都被T‘测试过时,突变分数计算为杀死的突变体与所有产生的突变体的比率(即),这表明测试集的质量。
从概念上来说,突变分数较高的测试套件更有可能捕捉到程序中的真实缺陷。在获得突变测试结果之后,开发者可以基于来自突变测试的反馈进一步提高测试集的质量(例如,通过添加/生成更多测试)。变异测试的总体目标是评估测试集T的质量,并进一步提供反馈和指导测试增强。
DL系统的源码级突变测试
本着对传统软件进行突变测试的精神,将潜在缺陷直接引入到DL系统的编程源中是创建突变体的合理方法。在这一节中,我们提出了一种用于数据链系统的源级变异测试技术。我们设计了一个通用的DL系统变异测试工作流程,并提出了一组变异算子作为关键组件。
DL系统的源码级突变测试工作流程
image-20200922203330529具体的操作思想与传统突变测试一致,算子如表中所讲。
作者强调,本文提出的变异算子并不是为了直接模拟人的失误;相反,他们旨在提供测试数据集质量的定量测量方法。特别的,原DL模型和突变模型(由突变算子生成)的T‘能检测出的行为差异越大,就意味着T’的质量越高。
突变算子
image-20200922200825390提出两组算子,分别是数据变异算子,和程序变异算子,以引入潜在的故障。
数据突变算子
作者认为,准备训练数据通常很费力,有时容易出错。本文的数据变异算子是基于对数据收集过程中可能出现的潜在问题的观察而设计的。这些运算符可以全局应用于所有类型的数据,也可以局部应用于整个训练数据集中的特定类型的数据。
-
DR:重复一小部分训练数据
-
LE:更改部分数据的标签
-
DM:移除一些训练数据
-
DF:打乱训练数据集顺序
- 注意:训练过程通常对训练数据集的顺序是敏感的,因此这类问题是很容易被忽略的。
-
NP:向训练数据集添加一些噪音
程序突变算子
传统软件有很多基于语法的变异测试工具,将这些工具直接应用于培训计划似乎很简单。然而,这种方法通常不起作用,因为事实上DL训练程序对代码变化很敏感。即使是微小的变化也会导致训练程序在运行时失败,或者产生明显的训练过程异常(例如,在训练的早期迭代/时期明显的低预测精度)。考虑到DL培训项目的特点,我们设计了以下算子来注入潜在故障。
-
LR:随机删去DNN中的一层(主要是Dense, BatchNormalization层等)这些层的选择对DL系统的影响相对较小
-
LA_s:向网络结构中添加一层(主要是Activation,BatchNormalization等)
-
AFR_s:激活函数对于非线性DNN而言十分重要。这一突变模仿的是开发人员忘记添加激活层的情况。
DL系统的突变测试度量
模型中添加突变之后,就能够得到一组突变DL模型
每一个里的测试数据点都是能够被原始模型正确处理的数据点。
将代入一组突变模型中后,如果存在一个测试输入,使得突变模型的结果错误,我们认为测试数据杀死了突变.
作者还对突变得分进行了适应性调整。针对分类问题,是k类输入数据。对于每一个测试数据点,我们说在突变上杀死了,当且仅当它满足:(1)能够被原始DL模型M正确分类到(2)被突变模型误分类到其他类。
我们定义DL系统的突变得分如下:(简单来讲,就是将原度量细分成杀死每一类)
然后作者还提出了一个DL突变模型的质量控制程序。如果在测试集上的错误率过高,作者认为这就不是一个很好的突变,因为它引入了一个过大的行为差异。并将这类突变模型放在之后讨论。
具体的度量如下:
作者认为这种突变测试有助于我们评估测试数据集的有效性,通过观察和分析那些靠近决策边界的数据集,我们可以更好的探讨鲁棒性容易出现问题的数据。
DL系统的模型级突变测试
image-20200923191734595接下来,为了提高突变测试的效率,许多传统突变测试技术会基于更底层的软件表现而非源代码,以避免程序无法编译。
因此在这节,作者提出了模型层级的DL系统突变测试,面向更高效的DL突变模型生成。
模型级突变测试工作流程
image-20200923194326987模型级别的突变直接改变DL模型M以得到突变模型
之后还是一样的取出所有在原始模型下正确的测试数据,并在突变模型集上进行测试。
作者认为,这类变异类似于传统软件的低级(如Java字节码等中间代码表示)变异测试技术。
模型级突变算子
表二总结了模型级的突变算子,这类算子基本都是直接变异结构或参数,而不需要重新训练模型的。
-
GF:高斯模糊,权重是DNN最基础的成分,描述了神经元间链接的重要程度。也是决定决策逻辑的重要成分。一个自然的突变权重的方法就是模糊它的值,来改变连接的重要程度。具体的说,就是对一个初始为的值,改成一个超参数为的高斯分布上的值
-
WS:神经元的输出通常取决于上一个层神经元,以及与该神经元相连的权重。这一算子选择某一神经元,并打乱它与前一层链接的权重。
-
NEB:将某一神经元通往下一层的所有权重置0.等价于移除了一个神经元对于最终决策的影响。
-
NAI:反转神经元激活状态(在输入激活函数前,改变神经元输出的符号)
-
NS:交换一层中两个神经元,以交换两者的作用,并影响到下一层。
-
LD:移除某一个输入输出向量规格一致的层
-
LA_m:通过向DNN中添加一层,实现与LD恰好相反的效果。
-
AFR_m:移除整个层的激活函数的作用。与NAI区别:1,作用在一整层上。2,消除激活函数的影响,NAI是反转
一个好的测试数据集应该是全面的,覆盖了DL软件用例的多样方面的,因此它可以评估DL的泛化能力,并揭示模型缺陷。所以后续的实验主要验证了DeepMutation在区分均匀与非均匀取样上的能力。
网友评论