[论文解读] DeepMutation: Mutation Testing of Deep Learning Systems

DeepMutation: Mutation Testing of Deep Learning Systems

简介

论文标题

  • DeepMutation: Mutation Testing of Deep Learning Systems
  • DeepMutation:深度学习系统的变异测试
  • 2018.8

贡献

  • 提出了一种专门针对DL系统的变异测试框架和工作流程,实现了对测试数据集的质量评估和薄弱环节定位。
  • 我们设计了8个源级(即关于训练数据和训练程序)的变异算子,以将错误引入DL编程元素。我们进一步设计了8个变异算子,将故障直接注入到DL模型中。
  • 我们提出了两个DL特定的突变测试度量,以允许对测试质量进行定量测量。
  • 我们在广泛研究的DL数据集和模型上对所提出的突变测试框架进行了评估,以证明该技术的有效性,这也可以潜在地促进测试集的增强

即: 源级变异算子 模型级变异算子 两个变异测试度量

作者又提出了 DeepMutation++: A Mutation Testing Framework for Deep Learning Systems ,进一步扩充了变异测试

摘要

深度学习(DL)定义了一种新的数据驱动编程范例,其中内部系统逻辑在很大程度上是由训练数据塑造的。评估DL模型的标准方法是在测试数据集上检查它们的性能。测试数据集的质量对于获得训练模型的可信度非常重要。在使用不充分的测试数据集的情况下,已经达到较高测试精度的DL模型可能仍然缺乏通用性和健壮性。在传统的软件测试中,突变测试是一种成熟的测试集质量评估技术,它分析测试集在多大程度上检测到注入的故障。然而,由于传统软件与基于深度学习的软件有着根本的不同,传统的变异测试技术不能直接应用于DL系统。本文提出了一种专门用于DL系统的变异测试框架来度量测试数据的质量。为此,通过与传统软件相同的突变测试精神,我们首先定义了一组源级突变算子来向DL的源(即训练数据和训练程序)注入错误。然后,我们设计了一组模型级变异算子,直接向DL模型注入故障,而不需要训练过程。最后,通过分析注入故障能被检测到的程度来评价测试数据的质量。在两个公共数据集,即MNIST和CIFAR-10上,用三个DL模型验证了所提出的突变测试技术的有效性。

初步

突变测试

突变测试

对于传统软件来说,突变测试(MT)[6]已经被确立为系统地评估测试数据质量和定位测试数据薄弱环节的最重要技术之一。MT的一个关键步骤是设计和选择变异算子,这些变异算子将潜在的故障引入被测软件(SUT),以创建SUT[6]、[7]的修改版本(即,突变体)。MT通过检查测试集在多大程度上能够检测到突变体和对应的原始SUT的行为差异来衡量测试的质量

DL系统的突变测试

对于DL系统的突变测试,合理的方法是设计突变算子,将潜在故障注入到训练数据或DNN训练程序中。在注入故障之后,使用突变的训练数据或训练程序重新执行训练过程,以生成对应的突变的DL模型。

通过注入各种故障而产生的若干变异的DL模型: { M 1 , M 2 , , M n } \left\{M_{1}^{\prime}, M_{2}^{\prime}, \ldots, M_{n}^{\prime}\right\}

原始模型: M M

针对测试集 T T 执行和分析每个突变模型 M i M_{i}^{\prime} ,给定测试输入 t T t∈T ,当M和 M i M_{i}^{\prime} 的输出在t上不一致时,t检测到 M M M i M_{i}^{\prime} 的行为差异。

与传统软件的突变测试类似[6],原始DL模型M和突变模型 { M 1 , M 2 , , M n } \left\{M_{1}^{\prime}, M_{2}^{\prime}, \ldots, M_{n}^{\prime}\right\} 能被T检测到,说明T的质量越高。

DL与传统软件区别

详细区别可以看DL测试综述

传统软件突变测试流程

传统软件突变测试[6]、[16]的一般过程如图2所示。

  • 给定一个原始程序P,根据预定义的规则(突变操作符)创建一组错误程序P0(突变),每个规则(突变操作符)对P稍作修改。例如,突变操作符可以在语法上将程序中的‘+’操作符更改为‘−’操作符[17]-[19]。
  • 通常在实际的突变测试过程开始之前的预处理步骤被用来过滤掉不相关的测试。具体地说,针对P执行完整测试集T,并且仅将通过的测试T0(T的子集)用于突变测试。
  • 在下一步中,P0的每个突变体在T0上执行。如果突变体P0∈P0的测试结果与P的测试结果不同则p0被杀死;否则,p0存活。
  • 当P0中的所有突变体都已经针对T0进行了测试时,突变得分计算为杀死的突变体与所有生成的突变体的比率(即#muant kill/#muants all),这表明了测试集的质量。
  • 从概念上讲,突变分数较高的测试套件更有可能捕获程序中的真正缺陷[20]。在获得突变测试结果之后,开发者可以基于来自突变测试的反馈[21]、[22]进一步提高测试集的质量(例如,通过添加/生成更多测试)。突变测试的总体目标是评估测试集T的质量,进而提供反馈和指导测试改进。

DL系统的源级突变测试

DL系统的源代码级突变测试工作流

  • 图3显示了我们的源代码级突变测试技术的关键工作流。在初始化阶段,DL开发者准备训练程序P和一组训练数据D。在用D运行P的训练过程之后,获得DL模型M。
  • 当突变测试开始时,通过应用突变算子(在表I中定义)略微修改原始训练数据D和程序P,并生成相应的突变体D0和P0
  • 在下一步中,训练数据突变体或训练程序突变体参与训练过程,以生成突变的DL模型M0。当得到突变的DL模型时,针对过滤后的测试集T0执行和分析,以评估测试数据的质量。
  • 我们强调,本文提出的突变算子并不是为了直接模拟人的错误,而是为了提供对测试数据集的质量进行定量度量的方法。特别地,原始DL模型和突变模型(由变异算子产生)T0之间的行为差异越大,T0的质量就越高。

DL系统的源级变异算子

我们提出了两组变异算子,即数据变异算子和程序变异算子,它们对源进行相应的修改以引入潜在的故障(参见表I)。

1)数据变异算子:训练数据在建立DL模型中起着至关重要的作用。训练数据通常很大,并且手动标记[23]-[25]。准备训练数据通常很费力,有时还容易出错。我们的数据变异算子是基于对数据收集过程中可能出现的潜在问题的观察而设计的。这些运算符可以全局地应用于所有类型的数据,或者仅局部地应用于整个训练数据集中的特定类型的数据。

  • 数据重复(DR):DR操作员复制一小部分训练数据。训练数据通常来自多个来源,其中一些来源非常相似,并且同一数据点可以多次收集。
  • 标签错误(LE):训练数据集D中的每个数据点(d,l),其中d表示特征数据,l是d的标签。由于D通常相当大(例如,MNIST数据集[23]包含60,000个训练数据),一些数据点可能被错误标记的情况并不少见。le操作符通过更改数据的标签来注入此类错误。
  • 数据丢失(DM):DM操作员删除一些训练数据。由于疏忽或错误地删除了一些数据点,可能会发生这种情况。
  • 数据打乱(DF):DF操作员在训练过程之前将训练数据打乱到不同的顺序。理论上,针对同一组训练数据运行的训练程序应该获得相同的DL模型。然而,训练过程的实施往往对训练数据的顺序敏感。在准备训练数据时,开发人员通常不太注意数据的顺序,因此在训练过程中很容易忽略这些问题
  • 噪声扰动(NP):NP操作符随机向训练数据添加噪声。数据点可能携带来自各种来源的噪音。例如,相机捕获的图像可能包括由不同天气条件(即雨、雪、灰尘等)引起的噪音。NP操作员试图模拟与有噪声的训练数据相关的潜在问题(例如,NP将随机扰动添加到图像的某些像素)。

2)程序变异算子:与传统程序类似,训练程序通常在特定的DL框架下使用高级编程语言(如Python和Java)进行编码。传统软件[26]-[30]有很多基于语法的突变测试工具,直接将这些工具应用于培训项目似乎很简单。但是,由于DL培训计划对代码更改非常敏感,因此此方法通常不起作用。即使是微小的改变也可能导致训练程序在运行时失败或产生明显的训练过程异常(例如,在训练的早期迭代/时段中预测精度明显较低)。考虑到DL训练方案的特点,我们设计了以下操作员来注入潜在故障。

  • 层移除(LR):在删除的层的输入和输出结构相同的情况下,LR随机删除DNN的一层。虽然可以删除满足该条件的任何层,但是任意删除层可以生成与原始DL模型明显不同的DL模型。因此,LR算子主要集中在层(例如,密集的BatchNormalization层[31]),其删除不会对突变模型产生太大的影响。LR运算符模拟开发人员删除表示DNN层的一行代码的情况。
  • 层添加(LAS):与LR运算符不同,LAS运算符将层添加到DNNS结构。LA专注于添加层,如Activation、BatchNormalization,它引入了由于添加或复制表示DNN层的一行代码而可能导致的故障。
  • 激活函数去除(AFRs):由于DNN具有较高的代表性(即量化为VC维[15]),激活函数在DNNs的非线性中起着重要作用。AFRS操作符随机删除层的所有激活函数,以模拟开发人员忘记添加激活层的情况。

DL系统的变异测试度量

对于DL系统的突变测试,使用传统软件的突变得分指标进行突变测试是不合适的。在DL系统的突变测试中,当T0的规模较大时,T0相对容易杀死一个突变体m0,因此,如果我们直接使用DL系统的突变得分作为被杀死的突变体与所有突变体的比率,我们的度量将失去评估DL系统测试数据质量的精度。

本文主要研究DL系统的分类问题。3假设我们有一个k-分类问题,设 C = { c 1 , , c k } C=\left\{c_{1}, \ldots, c_{k}\right\} 是所有k类输入数据。对于测试数据点 t T t^{\prime} \in T^{\prime} ,如果满足以下条件,我们说 t t^{\prime} 杀死了 c i C c_{i} \in C 类的突变体 m M m^{\prime} \in M^{\prime} :

  • t t^{\prime} 被原始DL模型M正确分类为 c i c_{i}
  • t t^{\prime} 未被 m m^{\prime} 分类为 c i c_{i}

我们定义DL系统的突变分数如下,其中KilledClasses(T0,M0)是被T0中的测试数据杀死的m0的类别的集合
M u t a t i o n S c o r e ( T , M ) = m M  KilledClasses  ( T , m ) M × C MutationScore \left(T^{\prime}, M^{\prime}\right)=\frac{\sum_{m^{\prime} \in M^{\prime}} | \text { KilledClasses }\left(T^{\prime}, m^{\prime}\right) |}{\left|M^{\prime}\right| \times|C|}
分子: 突变模型中分错了多少个类 分母:所有的突变模型 *分类的数目

这个指标感觉不是很好,因为只跟类别挂钩,不细致

一般来说,可能很难准确预测突变算子引入的行为差异。为了避免DL突变模型与其原始模型引入过多的行为差异,我们提出了DL突变模型的质量控制程序。特别地,我们测量了每个突变体m0在T0上的错误率。如果m0的错误率对于T0来说太高,我们不认为m0是一个好的突变候选因为它引入了很大的行为差异。我们从M0中排除了这样的突变模型以供进一步分析。

我们定义了T0在每个变异模型 m M m^{\prime} \in M^{\prime} 上的平均错误率(AER),以衡量所有变异算子引入的整体行为差异效应。
A v e E r r o r R a t e ( T , M ) = m M ErrorRate ( T , m ) M AveErrorRate \left(T^{\prime}, M^{\prime}\right)=\frac{\sum_{m^{\prime} \in M^{\prime}} \operatorname{ErrorRate}\left(T^{\prime}, m^{\prime}\right)}{\left|M^{\prime}\right|}
这两个指标都是很简单的

图4显示了用于二进制分类的DL模型的示例,其中具有原始模型的决策边界和两个变异模型的决策边界。我们可以看到,突变模型更容易被绿色的数据杀死,绿色的数据位于原始DL模型的决策边界附近。数据点越接近决策边界,就越有可能杀死更多的变异模型,这反映在DL系统定义的变异分数和AER的增加上。一般而言,突变测试通过分析测试数据在多大程度上接近DNNs的决策边界,便于评估测试集的有效性,因为DNN的决策边界更容易出现健壮性问题。

突变测试可以改变DL系统的行为边界,从而发现一些边界错误

DL系统的模型级突变测试

(参见图1)。通常,为了提高突变测试的效率,许多传统的突变测试技术被设计成在低级软件表示(例如,字节码[18]、[30]、二进制代码[33]、[34])上工作,而不是在源代码上工作,从而避免了程序编译和转换工作。在这一部分中,我们提出了DL系统的模型级突变测试,以便更有效地生成DL突变模型。

DL系统模型级突变测试工作流

图5显示了DL模型级别突变测试工作流的总体工作流。与修改原始训练数据D和训练程序P的源级突变测试不同,模型级突变测试直接从D和P改变通过训练获得的DL模型M。对于我们在表II中定义的模型级突变算子定义的每个DL突变模型M0∈M0,输入测试数据集T在M上运行以过滤所有错误数据,并将通过的数据发送到运行每个M0。获得的执行结果采用第III-C节中定义的相同突变度量进行分析和报告。

与源级突变测试类似,模型级突变测试也试图评估测试数据集的有效性,并定位测试数据集的弱点,这有助于开发人员进一步增强测试数据,以练习被测DL模型的脆弱区域。由于DL模型的直接修改避免了训练过程,因此,与传统软件的低级(例如,Java字节码等中间代码表示)突变测试技术类似,模型级突变测试有望更有效地生成DL突变模型。

DL系统的模型级变异算子

变异的训练数据和训练计划最终会变异DL模型。然而,训练过程可能很复杂,受各种参数(例如训练周期数)的影响。为了有效地引入可能的故障,我们进一步提出了模型级变异算子,直接对DL模型的结构和参数进行变异。表II总结了所提出的模型级变异算子,根据算子的应用范围,这些算子的范围从权重级别到层级。

  • 高斯模糊(GF):权重是DNN的基本元素,它描述神经元之间连接的重要性。权重对DNNs的决策逻辑有很大的贡献。改变权重的一种自然方法是模糊化其值以更改其表示的连接重要性。GF运算符遵循高斯分布 N ( w , σ 2 ) \mathcal{N}\left(w, \sigma^{2}\right) 以改变给定权重值w,其中σ是用户可配置的标准偏差参数。GF运算符主要将权重模糊化到其附近的值范围(即,模糊化值以99.7%的概率位于[w−3σ,w+3σ]中),但也允许以较小的机会将权重改变到更大的距离。
  • 权重混洗(WS):神经元的输出通常由来自上一层的神经元决定,每一层神经元都与权重有关。WS操作符随机选择一个神经元,并将其连接到上一层的权重置乱。
  • 神经元效应阻塞(NEB):当测试数据点被读取到DNN中时,它通过具有不同权重和神经元层的连接进行处理和传播,直到产生最终结果。每个神经元根据其连接强度在一定程度上对DNN的最终决策做出贡献。NEB算子阻止对下一层中所有连接神经元的神经元影响,这可以通过将其下一层的连接权重置为零来实现。NEB消除了神经元对最终DNN决策的影响。
  • 神经元激活反转(NAI):激活函数在创造DNNs的非线性行为中起着关键作用。许多广泛使用的激活函数(例如RELU[35]、Leaky
    REU[36])根据它们的激活状态表现出相当不同的行为。NAI操作符尝试反转神经元的激活状态,这可以通过在应用神经元的激活函数之前改变其输出值的符号来实现。这有助于创建更多的突变神经元激活模式,每个模式可以显示DNNs的新的数学属性(例如,线性属性)[37]。
  • 神经元交换(NS):DNN层的神经元经常对下一层连接的神经元产生不同的影响。NS操作符在一层内切换两个神经元,以交换它们对下一层的作用和影响。
  • 层停用(LD):DNN的每一层都转换其上一层的输出,并将其结果传播到其后续层。LD运算符是一种层级突变运算符,它移除整个层的变换效果,就像从DNN中删除一样。但是,简单地从训练的DL模型中删除一个层可能会破坏模型结构。我们将LD运算符限制为输入和输出形状一致的层。
  • 层添加(LAM):LAM运算符试图通过向DNN添加一层来产生与LD运算符相反的效果。与LD运算符类似,LAM运算符在相同的条件下工作,以避免破坏原始DNN;此外,LAM运算符还包括在其原始层之后复制和插入复制的层,这也要求层输入和输出的形状一致
  • 激活函数去除(AFRm):AFRm 操作符去除整层激活函数的影响。AFRM运算符与NAI运算符有两个不同之处(1)AFRM在层级上工作,(2)AFRm算法去除了激活函数的影响,而NAI算子保留了激活函数,并试图反转神经元的激活状态。
发布了71 篇原创文章 · 获赞 21 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_33935895/article/details/105346363
今日推荐