深度学习(DL)系统被广泛应用于飞机防撞系统、阿尔茨海默病诊断、自动驾驶汽车等领域。尽管 DL 系统要求高可靠性,但其测试难度较大。现有的 DL 测试工作侧重于测试 DL 模型,而不是模型的实现(如 DL 软件库)。测试 DL 库的一个关键挑战是难以知道给定输入实例的 DL 库的预期输出。幸运的是,同一 DL 算法在不同的 DL 库中有多种实现。
因此,我们提出了 CRADLE,这是一种专注于发现和定位 DL 软件库中 bug 的新方法。CRADLE(1)执行跨实现歧义检查来检测 DL 库中的 bug,(2)利用异常传播跟踪和分析来定位 DL 库中导致 bug 的故障函数。我们在三个库(TensorFlow、CNTK 和 Theano)、11 个数据集(包括 ImageNet、MNIST 和 KGS Go game)和 30 个预训练模型上对 CRADLE 进行了评估。CRADLE 检测出 12 个 bug 和 104 个唯一的歧义,CRADLE 检测到 12 个 bug 和 104 个独特的歧义,并为所有 104 个独特的歧义突出了与歧义原因相关的函数。
图 1 展示了典型 DL 库的结构。开发者使用高级库 API(如 Keras API)编写代码。这些 API 调用实现特定 DL 算法的低级库。低级库如 TensorFlow(Google)、Theano 和 CNTK(Mi-crosoft)实现了相同的算法,如卷积神经网络(CNN)和递归神经网络(RNN)。低级库使用不同的输入格式,提供不同的 API,而高级库允许用户在不同的低级库之间无缝切换。调用低级库的组件被称为高级库和低级库之间的接口。每个接口和底层库(称为后端)提供了 DL 算法的实现。后端对 DL 模型进行训练和测试。一个 DL 模型包含一个 DL 网络和参数(也称为权重)。
后端和高级库包含 bug,发现和修复这些 bug 特别具有挑战性。一个关键的挑战是,开发人员很难知道给定一个输入实例的预期输出。DL 后端实现的 DL 模型使用复杂的网络和数学公式。因此,对于给定任意输入实例的 DL 后端,人们很难生成预期的输出。例如,给定一个数字“1”的输入图像(基本事实“1”),和一个数字分类模型,该模型在该图像上的预期输出不一定是“1”,因为模型由于其局限性而导致误分类是很常见的(很少能达到 100%的分类准确率)。现有的 DL 测试工作主要集中在生成输入实例,使基本事实和模型输出歧义,以便 DL 用户和构建者改进模型。
图 1:DL 库的概述
模型必须由后端库实现。如果后端库不能如实地实现一个模型(例如,由于后端的一个错误),即使模型是正确的,后端库的输出也可能是错误的,反之亦然。错误实现的 DL 后端可能导致上述数字分类模型对“1”的同一图像输出“9”,即使 DL 模型的预期输出是“7”。或者,DL 后端可能会意外地输出“1”与基本事实相匹配。错误的输出可能会在调试和修复过程中误导 DL 用户和构建器。输出掩盖了实现的 bug,使其难以被发现。
同一功能(即同一 DL 算法)的多种实现(即 DL 后端)为我们提供了一个独特的机会来检测这些实现之间的歧义,以发现 DL 后端库的 bug。例如,如果同一个 CNN 模型—也就是具有相同权重的 CNN 网络—在两个 CNN 实现(如 TensorFlow 和 CNTK)上运行时表现不同,在不知道预期的输出情况下,那么其中一个 CNN 实现很可能是不正确的。
图 2 显示了一个导致两个后端歧义的 bug。输入图像(图 2a)在 ImageNet(一个流行的手动标记图像的数据集)中被手动标记为一个培养皿(基本事实)。图 2b 显示了在 Keras2.2.0 上用 TensorFlow 和 CNTK 后端分别预训练的模型 InceptionResNetV2 对该图像的分类结果。采用 TensorFlow 后端的模型将图像正确地分类为培养皿,作为其首选项,而采用 CNTK 的同一模型则将图像分类为模拟时钟,培养皿不在前 5 位。
为了自动检测和定位这种跨 DL 后端的歧义,我们提出并实现了一种新的方法—CRADLE。给定一个 DL 模型及其输入数据,CRADLE(1)使用两个距离度量来比较模型在不同后端上的输出,以检测歧义的输出;(2)通过跟踪异常在执行图中的传播来识别歧义的位置。通过识别两个后端之间差异幅度的峰值,CRADLE 指出了后端中引入歧义的函数,这将对开发人员调试和理解错误非常有用。
包括图 2 中的例子,CRADLE 识别了 580 张图像(从 ImageNet 的 5000 个随机样本中),这些图像触发了 InceptionResNetV2 模型的歧义分类。然后 CRADLE 成功地定位了有问题的 function(bath_normalization)。在我们在接口中报告了这个 bug 之后,开发人员从 Keras 2.2.1 开始修复了这个 bug。图 2c 显示了修复的情况。在 CNTK 后台的函数 batch_normalization 中,批量归一化公式的实现是错误的:它应该取(var + epsilon)的平方根,而不是 var 的平方根。
为了评估 CRADLE 的有效性,我们将回答以下研究问题。
RQ1:CRADLE 能够检测深度学习后端的 bug 和歧义吗?
RQ2:CRADLE 能否定位歧义的来源?
RQ3:CRADLE 的检测和定位时间是多少?
本文主要贡献如下:
• 一种通过交叉检查同一模型的多个实现来测试 DL 软件的新方法,以检测其中的一致性和错误。
• 利用异常传播跟踪和分析,首次确定交叉模型歧义的故障功能的方法;
• 对 30 个 DL 模型、11 个数据集(包括 ImageNet、MNIST、Udacity challenge 2 和 KGS Go game)和 15 个 Keras 版本(包括最新版本)的测试和定位技术进行评估。
我们的结果表明,CRADLE 检测到 DL 软件中的 12 个 bug(9 个已经被开发者修复),这些 bug 导致了 30 个模型中 28 个模型的歧义,其中 3 个是以前未知的 bug,2 个已经被开发者确认(RQ1)。CRADLE 对所有 104 个独特的歧义的原因突出了相关的功能(RQ2)。CRADLE 的端到端运行时间中位数小于 5 分钟,说明 CRADLE 是实用的(RQ3)。
DL 网络是一种结构(即图),它包含了为执行特定任务(如回归或分类)而堆叠的节点或层。每个层代表了输入数据的特定低级变换(如卷积、池化等),具有特定的参数(如权重)。
每个层都映射到一个函数调用,将权重和输入数据转换为输出。虽然网络中的多个层可以具有相同的类型,但由于这些层的参数不同,所以执行的操作一般也不同。这类似于,在传统的程序中,同样的方法/函数,在源代码中的一个特定的地方定义,用不同的输入参数被多次调用。同样,在 DL 网络中,同一个层类型可以用不同的输入参数(即权重)被多次调用(即在多个层中)。通过一个输入实例,一个模型就映射到这些低级函数(即层)的执行图上。
为了获得每层的正确权重,网络需要在一个训练集上进行训练。我们把这个阶段称为训练阶段。一旦训练阶段结束,各层的权重(或参数)就固定下来,不会改变,模型就可以用于推理阶段。验证集是一组不同于训练集的输入,用于调整模型。在这项工作中,我们将其作为模型的输入,因为我们知道这种输入的基本事实标签。
预训练模型是指在之前的工作中已经训练(并保存)过的网络,它的网络结构和权重是固定的,不会改变。它的网络结构和权重是固定的,不会改变。在本文中,训练模型也指预训练模型。虽然训练阶段通常是非确定性的(例如,网络的权重可以随机初始化),但预训练模型在推理阶段有望表现为确定性的,因为每层的权重不会改变。
A. 概述和挑战
图 3 显示了 CRADLE 的两个阶段:检测阶段和定位阶段。检测阶段将预先训练好的 DL 模型及其相应的验证数据作为输入。由于 DL 训练的非确定性,我们只关注推理阶段。
CRADLE 使用多个 DL 后端运行一个预训练的模型。具体来说,输出提取器将验证集作为输入反馈给训练好的模型,并在多个后端提取模型的输出集。一般来说,我们将输出表示为一个数字矩阵。如果一个 DL 后端在这个提取阶段崩溃,则会记录故障,并在之后进行审查和报告。否则,输出比较器会对在不同后端上评估的每个模型的输出进行配对比较,以检测歧义的地方。
一旦检测到歧义,CRADLE 就会执行定位阶段。具体来说,隐藏状态提取器记录每个歧义模型在不同后端的隐藏状态。这些隐藏状态被反馈给歧义定位器,它产生的定位图中,不同后端上隐藏状态之间传播的显著偏差峰值会被高亮显示,表明有问题的位置。
为了有效地检测和定位跨后端的歧义性和错误,我们需要解决两个主要难题:
1.如何判断一个模型在两个后端的输出是否歧义?由于不同的后端对计算过程的优化方式不同,同一计算结果几乎总是略有不同。天真地期望输出是相同的方法会检测到所有后端上几乎所有模型的歧义,这对于识别 DL 系统中的 bug 是没有用的。正如我们的实验所示,Theano 和 CNTK 后端输出的数值总是略有不同(差异从 10-5 到小于 10-10 不等)。
\2. 如何精确定位歧义的源头?在检测到歧义后,由于 DL 后端的复杂性,歧义的内部来源往往很难定位。例如,在图 2 中暴露出歧义错误的一个运行中,包含了 781 次对具有复杂数学联系的后端函数的调用。我们提出了一种新型的定位和可视化方法,通过分析这些后端函数的内部输入和输出,并对通过执行图传播的错误峰值进行定位,将引入歧义的后端库中的错误函数进行定位。
B. 检测阶段
输出提取器将预先训练的模型及其相应的验证实例作为输入。它加载提供的 权重(无需训练),并使用加载的模型执行分类或回归任务。它对每个输入实例使用所有被测后端产生模型输出。例如,在 3 个不同的后端上比较 5,000 个验证实例和一个相关模型,将产生 15,000 个输出向量。在这个阶段,CRADLE 会检测特定后端上的崩溃,并将其报告给开发人员。
一个直接使用的指标是整个验证集的 top-k 准确率。Top-k 准确率计算正确实例的部分—一个实例的基本事实标签在 top-k 预测标签范围内在被分类的总实例数量中的比例。Top-k 精度可能无法识别某些歧义的地方。例如,犬类物种分类模型,受提出的 Batch Normalization bug 的影响,诱发了 Tensorflow 和 CNTK 之间的歧义。然而,当在这些后端上运行时,该模型具有相同的 top-1(29.9%)和 top-5(64.4%)准确率。
识别歧义:给定一个模型(及其验证集)、两个后端和一个 Keras 版本,如果至少有 p%的验证输入实例导致这两组输出之间的距离大于给定的阈值 T(TC 表示基于类度量的阈值, 表示基于 MAD 的度量),我们就认为这对后端歧义。我们称这种输入实例为歧义触发。
对于基于 MAD 的度量,使用 =1 是最严格的。例如,对于 Dave-2 模型,如果一个输入图像导致一个后端预测的角度与记录的角度完全匹配,而导致另一个后端预测不同的角度,那么 =1 时,该输入图像就是歧义触发。另一方面,使用 =0 意味着我们认为任何输入图像都是歧义触发的。
阈值越严格,检测到的歧义就越少,但是,检测到的歧义会更严重( 或 越高意味着每个触发歧义的实例越严重,而 p 越高意味着更多的输出实例歧义)。如果覆盖所有的歧义是优先级,应该使用更低和更宽松的阈值(例如,第四节中推荐的阈值)。然而,如果发现严重影响模型准确度的严重错误是优先事项,那么更严格的设置将确保以较少的检查工作量更快地发现和修复这些严重错误。
识别独特的歧义之处。表 1 显示了四个歧义的例子。这些歧义是使用基于类的度量来识别的。列‘7-4’是导致两个后端基于类的距离为 7、6、5 或 4 的验证输入实例的数量。第一行中的歧义(歧义 1)表示 TensorFlow 和 CNTK(Keras 2.2.2)之间的模型 Xception 在其相关的 ImageNet 验证集上歧义,其中 10 个输入实例触发的基于 Class 的距离为 16,202 个实例触发的距离范围为 15-8,等等。
C. 本地化阶段
给定每个唯一的歧义,隐藏状态提取器和歧义定位器会产生一个定位图。定位图是两个实现(后端)的执行偏差图,它突出了一个函数(层类型)的歧义执行(隐藏状态),指向其中一个后端的潜在故障函数。
由于模型的顺序性,在某一层出现明显的 MAD 偏差并不能说明该层的歧义性,因为偏差可以通过执行图传播,并在途中被放大。理想的情况是,我们希望定位歧义的来源。为此,歧义定位器计算连续函数执行之间的偏差变化率。最后,它通过高亮显示执行偏差图中执行歧义的函数来生成定位图。
训练的模型和数据集。为了评估 CRADLE,我们收集了 11 个公共数据集和 30 个 DL 模型,并从这些数据集中预先训练。表 2 列出了这些数据集。
我们通过从之前的工作和 GitHub 中寻找与 Keras 兼容的预训练模型来收集模型。为了避免低质量的模型(例如,类项目和简单的 demo),我们只检查至少有两颗星的资源库。总的来说,我们收集了 13 个 ImageNet 模型(Xception,VGG16-19,ResNet50,InceptionV3,InceptionResNetV2,MobileNetV1-V2,DenseNet121-169-201,NASNetLarge-Mobile)。前期工作中使用的 3 个自动驾驶模型(DaveOrig-NorminitDropout),3 个 MNIST 模型(LeNet1-4-5),以及为其他任务训练的各种模型(泰数检测器-ThaiMnist。围棋游戏--Betago,动漫面孔识别--AnimeFaces,猫狗分类器--CatDog(Basic,Augmented),犬类分类器--Dog[,性别检测--Gender,宝可梦分类器--Pokedex,以及 GTSRB 交通标志识别--TrafficSigns(1,2,3))。我们使用提供的验证数据集为每个模型运行我们的实验。对于 ImageNet,我们使用从超过 80,000 张提供的裁剪验证图像中随机抽取 5,000 张图像。
我们改变了阈值( , 和 p),发现基于类的度量的最佳设置(覆盖了最多的歧义性,无误报)是 =8 和 p=0%,基于 MAD 的度量是 =0.2 和 p=0%。我们使用 80-20%的模型进行交叉验证,以确认阈值在所有 5 倍范围中的表现一致。这些是我们在 RQ1 和 RQ2 中使用的阈值。
A. RQ1:CRADLE 可以检测深度学习后端的 bug 和歧义吗?
CRADLE 在 30 个模型中的 28 个模型中检测到 DL 软件的 12 个 bug,造成 104 个特有的歧义。这 12 个 bug(9 个已经修复)包括 7 个歧义的 bug(3 个以前不知道,3 个中的 2 个已经被开发人员确认,例如图 2 中的 bug 在我们报告后已经被开发人员修复),以及 5 个崩溃的 bug,这些 bug 会使 Keras 或其中一个后端库崩溃。12 个 bug 中没有一个是通过 Keras 自带的测试用例(包括接口)检测到的,Keras 做的是简单的单元和集成测试。结果表明,跨后端歧义的情况经常发生,而 CRADLE 能够有效地检测到这些歧义。
我们的方法不会报告错误的歧义,因为它是一种动态的方法:对于每个歧义,我们都有触发两个后端歧义的输入。理论上讲,一些真实的歧义可能表示一个错误的 bug,因为我们的方法可能会识别出并不关心的歧义(例如,第三节 A 中解释的自然计算差异)。在我们的实验中,所有的 12 个 bug 都是真实的(即没有检测到假 bug)。
歧义和歧义触发的输入:在分类任务上使用基于类的度量,在回归任务上使用基于 MAD 的度量,CRADLE 共检测到 361 个歧义。基于歧义模式,CRADLE 自动将歧义归为 104 个特有的歧义(第三节 B)。
表 2 显示了 CRADLE 对每个数据集和一对后端发现的歧义的数量。例如,CRADLE 检测到 13 个 ImageNet 模型触发的两个后端 TensorFlow 和 CNTK 之间的‘21(54)’歧义。这里的‘21(54)’表示 CRADLE 检测到 54 个歧义,这些歧义映射到 21 个独特的歧义模式上。表 1 显示了其中的两种模式(第一行和第二行)。
平均而言,这些歧义是由数据集中 21.9%的输入实例触发的(分类任务为 22.2%,回归任务为 13.9%)。图 5 提供了歧义触发输入的例子。一个新郎的图像被 TensorFlow 正确识别,但被 Theano 错误地识别为印度大象。在一些极端的情况下,有 TensorFlow 后台意外地将香蕉的图像标记为“正确”,而 CNTK 却将其识别为网球。
歧义的 bug:我们使用 CRADLE 对所有 104 个检测到的特有歧义的源函数进行定位(详细的定位结果在第五章 B 节)。我们发现它们是由后端库中的 7 个 bug 引起的(表 3)。有些 bug 由于是同一函数中的不同 bug,或者影响到多个后端,需要对多个后端进行多次修复,因此具有相同的根源歧义。
除了图 2 中的批量归一化 bug,我们还详细介绍了 CRADLE 发现的另外两个确认的 bug。
填充方案的 bug:填充方案人为地增加了输入图像的大小,这样内核函数就可以应用于原始图像的所有像素,并产生与输入相同形状的输出。当应用于奇数或偶数大小的输入和内核的不同组合时,相同的填充方案在后端的行为歧义。这就造成了输入的偏移,这种偏移会通过模型传播,并导致模型有时会完全错过一些它被训练识别的形状。最终,它导致 Theano 或 TensorFlow(取决于输入和内核大小的不同组合)和其他两个后端之间的歧义。图 5 的中间一列显示了一个揭示这个 bug 的输入图像的例子。虽然在接口源代码中还没有修复,但这个 bug 已经被证实是一个重要的问题,因为各种模型(即 ResNet50、MobileNet、NASNetsLarge-Mobile 和 MobileNetV2)已经被它们的开发者更新,包含了使它们的模型在不同后端之间保持一致的工作方法。
池化方案 bug:Theano 后台的这个 bug 会导致 Gender、InceptionResNetV2 和 InceptionV3 模型的行为错误。在 Keras 2.1.4 和更早的版本中,Theano 接口中的 pool2d 根据填充方案确定平均池化方案。如果填充相同,则使用池 average_inc_pad 方案,该方案在平均值计算中包括填充。但是,如果没有填充,则使用 average_exc_pad 方案。这就给使用平均池化层的模型带来了歧义的地方,这些模型的填充是相同的。图 6 介绍了不管填充方案如何,都使用 average_exc_pad 的修复方法。
崩溃的 Bug:排除不支持的模型导致的崩溃,在 1173 次可能的运行中,我们遇到了 86 次崩溃。我们发现了 3 个 Keras bug(发生在所有后端)和 2 个特定的后端 bug。总共有 4 个崩溃 bug 已经被修复,并且在崩溃的模型中添加了一个变通方法来解决最后一个问题。它们通常是由不正确的对象形状引起的(例如,不正确的权重或卷积核形状)。
B. RQ2:CRADLE 能否确定歧义的来源?
CRADLE 突出了与所有 104 个唯一的歧义原因相关的执行。对于其中的 4 个 bug,第一个定位的歧义执行正是被开发人员修复的有问题的函数的执行。这表明定位技术能有效地定位有问题的函数,这应该有助于开发人员理解和修复 bug。当我们考虑所有(而不是只考虑第一个)局部歧义的执行时,有 5 个错误的局部歧义的执行中,有问题的方法被调用。对于第 5 个 bug,这代表要检查的函数数量减少了 22-44%。对于剩下的 2 个 bug,局部的歧义执行与 bug 修复有关。事实上,局部的执行情况对我们理解 bug 有很大的帮助,这样我们就能写出好的 bug 报告。
图 4 显示了批量归一化 bug(针对涉及 InceptionResNetV2、TensorFlow 和 CNTK 后端以及 Keras 2.2.0 的独特歧义)的部分定位图。所示的输入图像是该歧义的歧义最大的输入实例。密集框显示的是输出。来自 TensorFlow 的“jean”和来自 CNTK 的“mailbag”,而真实情况是“jean”。该图包括 781 个后端函数的调用,为了便于展示,省略了其中的 772 个。每个方框代表一个神经网络函数的调用,箭头表示数据流。每个框中都标明了函数名称,而 δ 是隐藏状态之间的 MAD 距离(定义于公式 3),R 是歧义引入率(定义于公式 6)。在这个例子中,函数 batch_normalization 的执行被定位为有问题(用红色显示)。白框表示 R 较低或为负的执行(即它们不太可能是歧义的来源)。这个图正确地突出了最早调用函数 batch_normalization 作为歧义的来源。我们检查了其他受影响模型(例如,InceptionV3、DenseNets(121、169、201))的定位图,注意到它们都指向 batch_normalization 函数。我们向开发者报告了这个 bug,它已经在 Keras 2.2.1 中得到了修复。
图 7 显示了定位图的一部分,突出显示了 TensorFlow 和 Theano 在 Keras 2.1.4 上的模型 InceptionV3 的池化方案 bug 的错误执行。第一个突出显示的执行正确地表明了这个唯一的歧义的源头是函数 average_pooling。我们看看 average_pooling 的源代码,它指向 Theano 后端有问题的 pool2d 函数。图 6 显示了 Theano 后端源代码中的修复方法(针对 Keras 2.1.5),其中平均池方案被设置为 average_exc_pad,而不考虑填充方案。
C. RQ3: CRADLE 的检测和定位时间是多少?
我们使用所有 30 个模型在最新版本的 Keras(2.2.2)上测量了 CRADLE 的执行时间。总的来说,CRA- DLE 的检测和定位时间相当合理,典型的端到端执行时间低于 5 分钟。
输出提取器和隐藏状态提取器的运行时间主要是模型执行时间,这取决于模型的复杂度、验证数据集大小和后台的性能。在极少数情况下,提取器的速度很慢,例如,在包含 1000 多个层的大型 NASNetLarge 模型中,提取器的运行时间接近 10 小时。然而,典型的运行时间在几分钟之内,中位数小于 2 分钟。输出比较器和歧义性定位器的速度要快得多,运行时间的中位数小于 20 秒,最大值小于 5 分钟。运行时间与后端实现无关,它分别取决于数据集大小和模型复杂度。
由于我们专注于检测揭示 bug 的歧义,CRADLE 可能会错过导致内部错误但不是故障(即不正确的外部行为)的歧义。这是我们的设计选择,以避免检测到过多的误报。
我们的方法可能无法推广到其他模型或 DL 库。为了减轻这种威胁,我们使用了从不同的 GitHub 项目中提取的 30 个模型,并在最流行的高级 DL 库 Keras 和三个流行的后端上评估我们的方法。我们的检测和定位歧义的方法应该可以适用于其他模型和库,而不需要做其他额外工作。
我们的方法使用预先训练好的模型,这是我们的设计选择,因为我们相信那些由真实用户使用的预先训练的模型很可能会引起开发人员关心的 bug。或者,我们可以使用虚拟模型或变异模型来测试后端,以便找到更多的 bug,这将作为未来的工作。
测试机器学习(ML)库:最近,ML 库的测试变得活跃起来。Srisakaokul 等人检测了常见 ML 算法(即 kNN 或奈夫贝叶斯(NB))的多种实现之间的歧义。这种方法使用多数票来估计预期输出。然而,它需要对同一算法的许多实现(使用了 19 个 kNN 和 7 个 NB),并假设它们中的大多数是正确实现的。相比之下,CRADLE 执行成对比较,正如我们的实验所显示的那样,它在不知道预期输出的情况下就能检测出歧义性,并且至少使用两个实现。另一个主要的区别是,Srisakaokul 等人基于 top-1 分类的歧义性来定义偏差,而没有将它们与基本事实进行比较。而 CRADLE 则将歧义性定义为基本事实标签预测排名的偏差,因为我们希望关注影响 DL 模型在真实世界验证数据集上性能的歧义实现。Dwarakanath 等人通过在训练和测试数据上应用变换来测试 ML 库,以检测歧义。然而,他们只能识别人为注入的 bug。Dutta 等人使用模糊来测试概率编程系统。这些技术都没有执行定位。
DL 库的基准测试:Liu 等人观察到,配置相同的 DL 算法,如训练集和学习率,在使用不同的低级 DL 库训练时,会产生不同的执行时间和精度。然而,这项工作的目的是对 DL 库进行基准测试,而不是检测或定位歧义的 bug,因为它没有在不同的后端上比较完全相同的模型。由于每个模型都是在每个后端上重新训练的,而且训练过程中包含了非确定性(例如,操作优化函数的种子),所以预计会有小的精度差异。文献中已经对 DL 库进行了比较。然而,之前的工作只关注性能比较,并没有检测或定位 DL 库的非性能 bug。
DL 模型的对抗性测试:最近的许多工作集中在测试 DL 模型上。许多技术都会产生对抗性的例子。一些工作验证了 DL 软件。DeepXplore 引入神经元覆盖率来衡量 CNN 模型的测试覆盖率。这些方法与我们的工作是相互的,因为它们测试 DL 模型的正确性,而我们测试 DL 软件库中模型实现的正确性。
差异测试和歧义性检测:差分测试包括测试不同编译器是否产生相同的结果。很多工作都是通过比较多个编译器的输出或不同的编译器优化水平来使用差异测试来发现编译器中的错误。歧义检测已经被用于其他领域,如跨平台,网络浏览器或文档阅读器。我们的工作是差分测试和歧义检测在 DL 软件中的新应用,它有其独特的挑战,如识别错误触发的歧义(第三节 A)。此外,我们还将歧义点定位在有缺陷的函数上。
调试和故障本地化:尽管有大量针对一般软件缺陷的调试和故障定位工作,但我们还没有意识到之前对 DL 库中歧义缺陷进行定位的工作。虽然这些方法可以用于调试 DL 网络,但将这些技术应用于 DL 网络中的故障函数定位可能会有独特的挑战,如可扩展性,这仍然是未来的工作。
我们提出了 CRADLE,这是一种新的方法,通过交叉检查多个后端来发现和定位 DL 模型实现中的 bug。我们在三个后端和 30 个预训练模型上评估 CRADLE,发现 28 个模型的后端有 12 个 bug 和 104 个特别的歧义。本文呼吁关注 DL 实现的测试,而不仅仅是 DL 模型。在未来,我们计划设计一些方法来识别 bug,即使它们不会在后端造成明显的差异。我们也设想用突变体来扩展 CRADLE 的训练模型集,以发现更多的 bug。
本文由南京大学软件学院 2021 级硕士颜昌粤翻译转述。