原文名称:Fuzzing Deep Learning Compilers with HirGen
原文作者:Haoyang Ma; Qingchao Shen; Yongqiang Tian; Junjie Chen; Shing-Chi Cheung*
原文链接:https://dl.acm.org/doi/pdf/10.1145/
3597926.3598053
发表期刊:International Symposium on Software Testing and Analysis, 2023
开源代码:https://github.com/haoyang9804/HirGen/
深度学习(Deep Learning,DL)编译器被广泛用于优化先进的DL模型使其可以在不同硬件上高效部署。他们的质量对编译的DL模型的质量产生了深远影响。最近的bug研究表明,高层中间表示优化是最容易出错的编译阶段,这个阶段的bug占整个编译过程收集到的bug的44.92%。然而,现存的测试技术都没有考虑到高级优化相关的特征,因此在高级优化阶段发现bug的效果很差。为了应对这一问题,我们提出了Hirgen,一种可以有效地检测高层中间表示优化中的错误的自动测试工具。Hirgen的设计包括:1.生成多样化且有效的计算图的三个覆盖标准;2.使用高层中间表示的语言特征生成不同的中间表示;3.三种测试判定方法,其中两种分别基于变形测试和差分测试的理念。Hirgen已经成功检测出TVM中的21个bug,其中17个被确认并且有12个已经被修复。DL编译器是针对DL模型优化和部署的工具,TVM、Glow、XLA和nGraph等编译器已经展现出了良好的效果。但是和传统编译器一样,DL编译器也容易出现错误,这些错误可能会导致非预期的行为,导致DL模型出现崩溃、错误或者性能下降等情况,对自动驾驶、飞机避碰等DL模型应用程序产生严重影响。目前已经提出了一些针对DL编译器错误的技术,例如TZER、TVMFuzz、MT-DLComp和NNSmith,并且已经取得一些成果,但是这些技术在测试用例生成和测试判断标准的设计没有考虑DL模型生成中高层IR的语言特性,也未在测试判定设计中考虑高级优化,因此检测高级优化错误的效率低下甚至完全无法检测这一阶段的错误,而高级优化错误在DL编译器产生的错误中占比很大。为了解决这一问题,本文提出了HirGen,一种专注于DL编译器在高级优化阶段的fuzz技术,其设计实现了以下四个方面:(1)HirGen在每次插入算子节点时,通过利用现有节点的信息(包括类型、形状和连接关系)执行类型检查和形状检查,以满足完整性约束(数据类型匹配和向量维度匹配)来控制高级IR,从而避免在DL编译器调用优化之前发生崩溃。(2)HirGen通过输入空间的覆盖引导探索多样的算子节点、算子边和算子类型和数据类型的结合,以生成多样化的计算图。(3)HirGen能够从单个计算图构建多样化的高级IR,从而充分利用IR的语言特性。(4)HirGen集成了三种测试判定方法,其中两种是专门为DL编译器设计的,以使其具备检测多种高级优化错误的能力除了功能正确性外,HirGen还能测试DL编译器的鲁棒性。具体来说,HirGen提供了生成无效计算图(违反类型约束和形状约束)的选项,测试DL编译器是否能够捕获这些无效的计算图并抛出预期的异常。通过这种方式,HirGen 还能检测因异常处理错误而导致的Bug。HirGen的workflow如图1所示,其维护了一个包含58个算子的算子池,这些算子可以通过流行的高层框架(例如Relay 、ONNX )的高层IR表达。HirGen首先加载现有的覆盖信息,根据覆盖信息生成一个计算图,并从最新生成的图中更新覆盖信息。随后,HirGen利用高层框架(如Relay或ONNX)将计算图转换为高层IR,并将其输入到DL编译器中。为了高效捕获目标DL编译器中的缺陷,除了常用的崩溃测试判定(oracle crash)外,HirGen还基于变异测试(metamorphic testing)和差分测试(differential testing)的理念,构建了两种测试判定方法。任何违反这些判定条件的测试用例都会被视为编译器Bug的证据,并报告给开发者。(1)计算图生成(Computational Graph Generation)HirGen采用两种严格生成和扰动生成两种生成模式,使用算子-数据类型,算子-向量形状 、算子-算子边三种覆盖引导多样化的计算图生成。(2)高级IR生成(High-Level IR Generation)HirGen使用Relay、ONNX等框架将计算图中每个节点转换为相应的高级表达式并组装成高级IR。除开这种普通转换,还充分利用了这些框架的原始特性,从生成的计算图中提取一个子图将其封装为函数,从而增加生成测试用例的多样性,还能更有针对性地测试编译器在复杂场景下的表现。(3)测试判定方法(Test Oracles)HirGen采用三种测试判定方法,在常用的crash判定之外,还针对DL编译器设计了两种判定方法。(Computational Graph Generation)HirGen将计算图的生成过程认为是向空计算图中插入算子节点直到节点数量达到阈值。在每次迭代中,HirGen从算子池中选择一个算子,将其加载到计算图中作为节点并与其他节点建立连接。同时,HirGen维护每个节点的信息,包括数据类型、张量形状和连接信息。此外,HirGen还利用三个覆盖标准来提高图的多样性。基于这些前提条件,HirGen提供了两种生成模式。其一是在计算图生成时进行严格的类型检查和形状检查,保证生成的计算图的有效性;另一种则是故意破坏类型约束和形状约束,生成错误的计算图来测试 DL 编译器的异常处理能力。节点信息:向计算图中插入节点需要图中所有节点的信息做类型检查和形状检查,节点信息描述了节点的典型特征,每种类型的节点都有自己的节点信息,如表1所示。Node Type | Node Information |
Variable | dataType,tensorShape |
Constant | dataType,tensorShape,value |
Operator | dataType,parentNodes,tensorShape=INFERENCE(parentNodes) |
表1 节点信息
(1)变量节点:包括数据类型dataType和张量形状tensorShape,用于描述此节点中封装张量的详细信息。dataType对应张量中所有元素的数据类型,例如float64和float32,tensorShape是一个向量,表示张量所有维度的尺寸。(2)常量节点:在dataType和tensorShape,常量节点还使用张量的值value作为节点信息的一部分。(3)算子节点:算子需要参数,因此算子节点都与图中其他节点相连接,为了记录每个算子节点的连接信息,除了数据类型,HirGen还记录该节点连接的父节点 parentNodes,以及从父节点推断出的张量形状。覆盖引导:为了保证计算图生成过程中数据类型、张量形状和算子的多样性,HirGen采用了三种覆盖引导标准。(1)算子-数据类型覆盖:opi是算子池中的第i个算子,dtypej是数据类型集合中的第j个数据类型,如果计算图中已经包含数据类型为dtypej的opi算子节点,则不会继续插入此类节点。通过算子-张量形状覆盖,HirGen引导在计算图生成时引入不同的算子并使用多样化的数据类型,从而更好地检测数据类型问题。(2)算子-张量形状覆盖:设opi为算子池中的第i个算子,设shape为该算子节点插入计算图后输出张量的形状,如果计算图中已经包含输出张量形状为dtypej的opi算子节点,则不会继续插入此类节点。通过算子-张量形状覆盖,HirGen尝试使用多样化的张量形状进行各种计算,从而增加发现计算问题的可能性,例如某些算子在特定形状下的实现不佳,或在不同平台上的计算结果不一致。(3)算子-算子边覆盖:opi和opj是算子池中的第i个和第j个算子,如果存在从opi类型节点向opj类型节点的连接,则不再将opi类型节点插入到opj类型节点之后。这样,生成的计算图包含更复杂,更深层的数据流,而不是几个简单数据流的并行连接。其中前两种覆盖引导策略的基于DL编译器中类型问题和维度问题设计的。第三种覆盖引导策略使计算图的数据流复杂化,引导在计算图中交错使用不同的算子。通过这三种覆盖引导策略,能够避免计算图生成过程中产生重复的子图(由于高层优化通常涉及识别、注释、重构和缩减可优化子图,重复的子图只能发现重复的Bug。)。约束感知的计算图生成:算法1展示了HirGen用于生成严格遵循高层 IR 类型和形状约束的计算图的两个过程,分别是主要函数generation和辅助函数preinsert。(1)初始化阶段:初始化在算法的第2行到第5行执行,其创建一个空的计算图并将节点数量设置为0,同时初始化算子池和数据类型集合。(2)循环生成阶段:在每次迭代中(6-17行),HirGen创建一个算子节点,更新其节点信息,并在该节点产生一种新覆盖时将其插入到计算图中。具体来讲,HirGen在算子池和数据类型集合中随机选择(第7、8行),然后从计算图中查找合适的连接并推断新生成的算子节点的张量形状(第9行),接着,HirGen检查覆盖,并在检查新的覆盖时(即三项覆盖指标任意一项有增加)执行更新和插入操作(10-16行)。每次更新信息时都将节点数量加1,直到达到阈值终止迭代并返回计算图。preinsert中展示了建立连接和张量形状推断的具体细节,HirGen使用目标DL编译器的类型约束、形状约束进行类型、形状检查(第21、22行),避免类型和张量形状的不匹配,并将已有节点分组,使每一组中的节点都是张量形状兼容且与新插入节点类型兼容发的。HirGen会随机选择一组节点作为参数节点(第23行)。每一种算子节点所需要的参数数量都是固定的,如果选择的参数节点数量不足,则会创建变量或常量节点作为参数节点,将其添加到计算图中并更新节点信息(24-28行)。最后,HirGen创建连接信息(29-31行),推断新节点张量形状(第32行),返回给主函数generation。扰动生成模式:扰动生成模式与常规的计算图生成很相似,其需要覆盖信息来记录哪些约束已经被打破,也需要节点信息用于插入打破约束的节点。扰动生成模式以两种方法打破约束:(1)将算子节点连接到DL编译器不接受的数据类型的节点(例如将add算子节点与数据类型为bool的节点连接)(High-Level IR Generation)通过relay、ONNX等框架,高级IR的生成非常简单。算法2展示了将计算图转化为高级IR表示方式的方法,利用了relay提供的将子图包装为函数的功能特性,可以使用同一个计算图生成多样化的高级IR。Conversation函数是利用计算图生成高级IR的主要函数,其在初始化阶段(第2、3行)生成Functions和Expressions两个集合,用于存储生成的函数和高级IR。在循环中(4-12行),HirGen遍历整个计算图,将每一个节点载入为高级IR表达式,并更新Expressions集合(第5行)。在遍历计算图的过程中,HirGen随机选择一组高级IR表达式,分析这一部分子图的输入节点和输出节点(第7行),使用这些节点构成一个函数(第8行),然后更新Functions和Expressions集合(第9、10行),最终将这两个集合的并集返回,作为计算图的高级IR表示。Load函数展示了将计算图节点转化为高级IR表达式的过程,其在将节点加载为高级IR表达式后,会考虑其是否连接到某个已包装为函数的节点,如果是,则查找对应的函数并创建调用表达式,保证函数的封装性不被破坏。最后将调用表达式和构造的IR表示加入到Expressions集合并返回。测试判定方法决定了一次测试是否通过。因此为了检测不同类型的错误,本文设计了三种测试判定方法。Oracle1:Crash。Crash常用于构建测试判定方法,而且根据编译器bug研究的统计数据,收集到的603个bug中,导致Crash发生的bug占据了59.37%。在严格生成模式下,HirGen会报告发生的一切Crash事件,此时生成的计算图遵守所有约束,发生的Crash事件归因于编译器在实现上的缺陷。而在关闭类型检查和维度检查时(即扰动生成模式下),只有当检测到的Crash是segmentation fault时报告错误,其他带有详细错误追踪信息的Crash主要是由于生成的计算图显式地违反约束引起的。Oracle2:原始高级IR、优化的高级IR和突变的高级IR的结果不一致。在正常情况下,高级优化只会优化模型的性能,不会改变计算结果。因此优化的高级IR如果和原始高级IR结果不一致,认为编译器发生错误。本文还设计了一种突变策略,其通过重写原始高级IR中的函数,使突变的高级IR接收相同的输入时,与原始高级IR的结果一致。函数的重写方法如下:(1)将全局函数f变为新建立的全局函数g的闭包,g接收与f相同的参数,返回值是用这些参数调用f的返回值(2)使用空函数g包装函数f,直接返回函数f的返回值基于此突变策略,突变的高级IR只在函数调用链上与原始高级IR有差别,结果仍是相同的。另外,如果原始高级IR能够通过编译并运行,优化、突变的高级IR在编译某个阶段失败,也认为结果不一致。Oracle3:不同硬件设备上的结果不一致。DL编译器的目标是将优化模型并高效部署到多种硬件设备上,因此在接收相同输入时,模型在不同设备上的运行结果应该是相同的。在这一测试判定方法中也考虑了模型在不同设备上的执行状态的不一致,例如,如果一个模型在CPU上崩溃而在GPU上运行良好,也认为这是一种结果不一致。1.研究问题
RQ1:HirGen检测TVM的bug的有效性如何?RQ2:是否所有的测试判定方法在检测bug时是有效的?RQ3:HirGen发现的所有bug是否都与高级优化阶段高度相关?RQ4:扰动生成模式在发现DL编译器的异常处理bug方面是否有效?RQ5:覆盖引导的计算图生成方法是否有益于生成计算图的多样性?2.实现
算子:HirGen维护了一个包括58个算子的算子池,其中23个一元算子,35个二元算子,可以很好地扩展到复杂运算。优化和编译方法:HirGen选用了TVM支持的25种优化方法,因为生成的计算图可以触发这些优化方法,除了这些方法,也可以很容易地将HirGen扩展到其他优化方法。Hirgen还选择了TVM支持的4种编译方法,每种方法适用于不同的场景并包含不同的优化序列。四种编译方法如下:(2)relay.build_module.create_executor('debug')(3)relay.build_module.create_executor('graph')(4)relay.build_module.create_executor('vm')3.基准方法选择
TVMfuzz:TVMfuzz是一个用于TVM模糊测试的概念验证应用。其从单元测试脚本中学习 TVM API 调用链,然后对其进行重新排序和变异。使用高级IR和优化相关的单元测试脚本,TVMfuzz可以测试DL编译器的高级优化阶段。MT-DLComp:MT-DLComp是一个DL编译器的自动测试框架。它通过突变现有的DL模型来生成等价的模型并使用三个判定方法测试DL编译器。尽管该技术不是专门用于检测高级优化中的bug的,其仍然能够覆盖这个容易出错的阶段。因此,本文选择该技术作为基准方法。LEMON:LEMON是一种深度学习框架测试技术。其通过现有模型突变生成Keras模型。通过设置不同Keras后端,LEMON可以检测这些后端引起的预测差异。尽管LEMON不是用于测试DL编译器的,我们可以对其进行改造,以勉强实现这一目标。简而言之,我们保留了变异部分,用于生成新模型,并通过两种测试判定方法来测试DL编译器:1.崩溃;2.原始Keras模型和编译后的Keras模型之间的预测差异超过阈值。NNSmith:NNSmith是一个基于生成的DL编译器fuzzer。其生成多样化的计算图,将其转换为使用不同DL框架的模型,并使用梯度引导的搜索来生成输入。在测试阶段,它在多个深度学习编译器之间进行差异测试。在该过程中,NNSmith捕捉所有的预测差异和崩溃情况。度量:采用了错误计数来评估HirGen和其他基准方法。超时设置:针对所有技术的研究发现,在执行26小时后没有发现新类型的Crash/不一致,设置超时时间为两天。平台:在CPU为Intel Xeon,GPU为NVIDIA Geforce GTX1080Ti和128G内存的64位ubuntu16.04服务器上进行试验。在严格生成模式下运行三个月并在扰动生成模式下运行一周,HirGen共计发现了21个bug,其中17个已经被确认,12个被修复。另外,21个bug中有10个是以前未知的。表2种展示了HirGen发现且已被确认的所有bug的详细信息,包括bug的类型,根本原因,检测到该bug的判定方法,修复状态,先前是否未知,在哪种生成模式下被检测到,是否被其他基准技术检测到以及是否与高级优化相关。bug类型包括崩溃和不一致两种,前者对应TVM非预期的终止,后者表示测试时获得不一致的结果或状态。此外还将这些bug与收集到的历史bug仔细比较,为每一个bug分配一个根本原因。类型问题:此类bug通过数据类型问题触发,包括类型推断错误,算子在某种数据类型上实现不完整等。不正确的异常处理:这类bug发生在TVM没有给出详细的警告信息甚至在极端情况下没有处理异常时,与TVM的鲁棒性相关。不正确的数值计算:包括不正确的数值计算、不正确的值和不正确的数值使用内部API不兼容:此类bug是由于TVM无法正确处理某些API的组合而引发的。例如,多个高级优化方法的组合被DL编译器非预期的拒绝。内存分配问题:这个根本原因指糟糕的或不正确的内存分配。HirGen在十次测试中平均检测出11.8个不同的崩溃/不一致,十次实验的结果方差为0.36,并且与高级优化相关的bug平均数为8.8。TVMfuzz平均检测出3.7个不同的崩溃/不一致,其中1.4个与高级优化相关。而MT-DLComp和LEMON没有检测任何崩溃/不一致。至于NNSmith,其平均检测出10个不同的崩溃/不一致。其中数据布局问题和数据类型问题居多,占比为52.2%,通常是通过bug信息捕获的,例如“WCHN layout is not supported”和“TVM cannot support type matching between int32 and int64”。非数据布局问题和数据类型问题的崩溃和不一致中,平均只有3.5个崩溃/不一致与高级优化相关,方差为1.45,表明NNSmith在检测高级优化错误时不稳定。在手动检查过程中,我们只发现一个崩溃是HirGen和NNSmith都检测到的,这表明这两种技术在错误检测能力上几乎是互补的。为了证明测试判定方法的有效性,本文对于每个测试判定方法检测到的几个代表性的bug进行了案例研究。(1)Oracle1:Crash。该方法检测到了最多的bug,共计8个源自3种根本原因的bug,包括不正确的数值计算、 不正确的异常处理和内存分配问题。不正确的数值计算:以bug1为例,在触发该bug的计算图中,一个除法算子首先计算常量除以变量的结果,然后将计算结果R作为被除数传递给floor_mod算子。所有相关的变量节点和常量节点的数据类型都是uint,并最终以该类型流入floor_mod。然而,TVM预先计算了R的可能值范围,并检测到其可能为0。因此,TVM错误地抛出了异常并终止了程序,甚至在我们为变量var1和var2赋值之前。这一错误仅在数据类型为uint时发生,其原因是错误的值范围估计。不正确的异常处理:bug11、bug12和bug13是三种不正确的异常处理bug,是在扰动生成过程中被检测到的。在bug11中,触发错误的计算图包括一个类型为int16的常量节点、一个tan算子节点以及这两个节点之间的连接。在这个图中,HirGen故意破坏了tan算子只能接受TVM中定义的float数据类型的约束,并在编译过程中引发了segmentation fault。这是因为TVM没有针对该算子及其不接受的数据类型的异常处理机制。内存分配问题:bug14是此根本原因下的唯一错误,当HirGen利用relay.shape_of推断具有静态张量形状(1, 2)的变量节点的张量形状时,发生了意外的崩溃,并出现警告信息“Cannot allocate memory symbolic tensor shape [?, ?]”。(2)Oracle2:原始高级IR、优化的高级IR和突变的高级IR的结果不一致。该方法共计检测到了6个已确认的bug,由三个不同的根本原因引起,包括不正确的异常处理、类型问题和内部API不兼容。不正确的异常处理:以bug 10为例。HirGen捕捉到这个错误是因为它发现一个高级IR通过了编译,但优化版本失败了。HirGen在优化序列中将FirstOrderGradient放在FuseOps之前,检测到TVM无法成功处理这个优化序列,其原因是异常处理过于严格,TVM在FirstOrderGradient之后对高级IR进行遍历以执行FuseOps,当访问到常量节点时,TVM发现该节点不是标量类型,因为FirstOrderGradient已经重写了该属性,TVM抛出异常,编译终止。类型问题:以bug 8为例。此错误是通过函数重写变异检测到的,具体来说,将一个全局函数f更改为另一个空的全局函数g的局部闭包,并在g中返回f后,TVM无法推断g的类型。这是因为在成功推断出f的类型后,当TVM开始推断g的类型时,该类型信息丢失了。内部API不兼容:bug 9被检测到是因为relay.build_module.create_executor('vm')失败,但其他编译方式运行顺利。在HirGen将高级IR转换为A范式后,使用虚拟机进行编译时无法确定x91与全局函数之间的绑定关系,而其他编译方式没有遇到这个问题。(3)Oracle3:不同硬件设备上的结果不一致。Oracle3检测到了3个bug。CPU和GPU上的计算结果之间的差异是由特定于平台的差异引起的,更进一步说就是LLVM和CUDA具有相同的算子实现,但TVM缺乏对该算子的完整规范,或是缺少有关使用此类算子的警告信息。以bug 15为例。HirGen创建了一个简单的计算图,其中包含一个right_shift算子节点,以两个其他变量节点作为输入。随后,HirGen首先生成相应的高级IR,然后使用relay.build编译IR生成运行时模型,最后创建输入并在CPU和GPU上运行该运行时模型,得到两个计算结果。当第二个变量大于第一个变量时,结果不一致。因为这种情况会导致LLVM中的poison value,而在right_shift算子中使用poison value是会导致未定义行为。Bug2、Bug8、Bug9、Bug10是都是由于在高级优化后违反Oracle2而被检测到的bug,这些bug显示出几个高级优化应优化的结构未能优化,且多个优化之间存在不兼容性。修复这些错误直接提高了优化性能,并促进了多种优化组合的可能性。HirGen发现的八个具有崩溃症状的错误中,Bug3和Bug14与高级优化直接相关。为了提高效率,TVM在编译期间调用OptimizeImpl并隐式地执行11个高级优化,通过在高级IR上执行一个或多个传递进行工作,在任何可优化的表达式上进行重写。在此过程中出现的错误可能会导致高级优化无法顺利执行,甚至可能导致崩溃从而停止优化。修复这些错误间接改善了高级优化所需的IR传递过程。此外,Bug11、Bug12和Bug13出现在高级IR构建阶段。由于构建发生在优化之前,这些错误也会阻碍高级优化的执行。尽管HirGen是针对高级优化提出的,但生成的测试用例也可以执行低级优化和可部署的代码生成,因此也可以测试编译的其他阶段。Bug15、Bug16和Bug17都与TVM的低级部分和代码生成相关,由于在不同后端硬件设备上对相同输入的计算结果不一致而被检测到。Bug1和Bug5是低级的算术问题,HirGen能够检测到它们,因为生成的计算图包含了错误触发的计算逻辑。在实验过程中,HirGen生成了170个计算图,这些图包含了不同的触发错误的算子、数据类型和张量形状组合。所有这些计算图都会导致TVM崩溃,并只显示‘segmentation fault’信息,显示出异常处理能力的不足。在最新版本的TVM中,所有这些错误已经被修复。现在,这些明显违反约束的情况会触发崩溃,并提供详细的错误信息。通过比较最新版本TVM的错误信息,170个计算图总共触发了三个错误。序列生成策略的研究:作者从IR-Fuzz中删除了序列生成策略,替换为随机序列构造方法,变体表示为IR-Fuzz-WSG。定量结果汇总见表4,IR-Fuzz的性能明显优于IR-FuzzWSG。Oracle3的优点和局限性:实验中oracle3的效果不如另外两个,仅检测到三个已确认但未修复的错误,其发现的bug的修复优先级较低。这一现象的原因在于,不同平台之间的浮点精度设置存在差异。开发者很难判断这些差异是由错误引起的,还是由精度设置不一致造成的。尽管存在这一限制,oracle3仍然可以帮助发现容易混淆的场景,并为对底层平台中特殊错误触发算子缺乏足够了解的用户提供经验。有效性的威胁:内部有效性威胁主要在于HirGen的实现,本文的两个作者仔细检查并测试了HirGen的所有组件的功能。外部有效性威胁主要来源于研究中选择的DL编译器。虽然HirGen目前主要支持将其生成的计算图转换为TVM的高级IR(使用Relay),但这种技术方法也适用于ONNX,未来的工作也包括增加对ONNX的支持,以便测试更多的DL编译器。构造有效性威胁主要来源于随机性和设置,为了减少随机性带来的负面影响,本文复了所有涉及随机性的实验10次,并使用平均值、方差和Mann-Whitney U检验来确保结果具有统计显著性。不同平台上浮点精度设置的差异也可能导致错误的缺陷检测结果,因此将阈值设置为一个非常小的浮动值 10−3,以确保不遗漏任何细微差异,从而不会错过任何新的缺陷。高级优化是DL编译器工作流中最容易出错的阶段。然而,目前还没有针对这一阶段的系统性测试研究。为了填补这一空白,本文提出了HirGen,这是一种基于生成的模糊测试工具,具有有效的计算图生成方法和三个测试预言器。与现有的工作不同,HirGen能够探索更复杂且有效的高级IR,从而检测到更深层次的错误。此外,HirGen中的三个测试预言器还提高了它在检测各种根本原因的错误方面的能力。HirGen提升了高级优化的鲁棒性和功能正确性,并得到了TVM社区的认可。
文章来源: https://mp.weixin.qq.com/s?__biz=MzU1NTEzODc3MQ==&mid=2247486850&idx=1&sn=dced461f84a7bc0c0fce0bc7d690ea72&chksm=fbd9a63eccae2f28d233d59f36d0bbff14a8c6daae02b28bae378464ea8a92da71dc90e8cde1&scene=58&subscene=0#rd
如有侵权请联系:admin#unsafe.sh