opentuner论文翻译

opentuner:一种可扩展的程序自动调谐框架

摘要

OpenTuner用于构建领域特定的多目标程序自动调谐程序,OpenTuner内部的一个关键功能是同时使用各种不同的搜索技术

介绍

自动调谐还提供了性能可移植性

多目标自动调谐可用于在性能和准确性或其他标准(如能耗和内存使用)之间进行权衡,并提供满足给定性能或服务质量目标的程序

自动调谐的三个挑战:第一个挑战是对问题使用正确的配置表示,第二个挑战是有效配置空间的大小,需要使用智能机器学习技术,通过少量的实验来寻求良好的结果。第三个挑战是配置空间的景观,如果搜索空间不连续且随机,则进化算法的性能可能会更好,还需要机器学习专业知识来构建系统的自动调谐。

OpenTuner具有可扩展的配置和技术表示,能够支持复杂的用户定义数据类型和自定义搜索启发式。它包含一个预定义数据类型和搜索技术的库,可以轻松地设置新项目。因此,OpenTuner解决了自定义配置问题,它不仅提供了一个足以支持大多数项目的数据类型库,而且还提供了可扩展的数据类型,可以在需要时用于支持更复杂的特定于域的表示。

OpenTuner的一个核心概念是使用各种搜索技术。许多搜索技术(内置和用户定义)同时运行,每个都测试候选配置。

通过找到更好的配置而表现良好的技术将分配更大的测试预算来运行,而表现不佳的技术将分配更少的测试或完全禁用。这些技术能够使用公共结果数据库共享结果,以建设性地相互帮助找到最佳解决方案。算法将其他技术的结果添加为其群体的新成员。为了在技术之间分配测试,我们使用曲线下面积信用分配的multi-armed bandit问题的最优解决方案。通过为多种类型的大型搜索空间提供稳健的解决方案,以及无缝结合特定领域的搜索技术,技术集成解决了大型复杂的搜索空间问题。

opeentuner 框架

我们的术语(opentuner)反映了自动调谐问题被转换为搜索问题。

搜索空间由配置组成,这些配置是一组参数的具体分配。参数可以是整数等基本参数,也可以是列表置换等复杂参数。

搜索技术是探索搜索空间并提出测量要求的方法,称为期望结果。搜索技术可以使用用户定义的配置操纵器更改配置,该操纵器还包括与配置中的参数直接对应的参数。一些参数包括操纵器,它们是不透明的函数,可以对配置中的特定参数进行随机更改。

OpenTuner中的主要组件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4tn2S5Ex-1656862060630)(C:\Users\83989\AppData\Roaming\Typora\typora-user-images\image-20220522121221396.png)]

opentuner的使用

要使用OpenTuner实现自动调谐,首先,用户必须通过创建配置操纵器来定义搜索空间。此配置操纵器包括一组OpenTuner将搜索的参数对象。其次,用户必须定义一个运行函数,该函数评估搜索空间中给定配置的适合性,以生成结果。

一个例子:

import opentuner
from opentuner import ConfigurationManipulator
from opentuner import EnumParameter
from opentuner import IntegerParameter
from opentuner import MeasurementInterface
from opentuner import Result

GCC_FLAGS = [
    'align-functions', 'align-jumps', 'align-labels',
    'align-loops', 'asynchronous-unwind-tables',
    'branch-count-reg', 'branch-probabilities',
    # ... (176 total)
]

# (name, min, max)
GCC_PARAMS = [
    ('early-inlining-insns', 0, 1000),
    ('gcse-cost-distance-ratio', 0, 100),
    ('iv-max-considered-uses', 0, 1000),
    # ... (145 total)
]


class GccFlagsTuner(MeasurementInterface):

    def manipulator(self):
        """
        Define the search space by creating a
        ConfigurationManipulator
        """
        manipulator = ConfigurationManipulator()
        manipulator.add_parameter(
            IntegerParameter('opt_level', 0, 3))
        for flag in GCC_FLAGS:
            manipulator.add_parameter(
                EnumParameter(flag,
                              ['on', 'off', 'default']))
        for param, min, max in GCC_PARAMS:
            manipulator.add_parameter(
                IntegerParameter(param, min, max))
        return manipulator

    def compile(self, cfg, id):
        """
        Compile a given configuration in parallel
        """
        gcc_cmd = 'g++ apps/raytracer.cpp -o ./tmp{0}.bin'.format(id)
        gcc_cmd += ' -O{0}'.format(cfg['opt_level'])
        for flag in GCC_FLAGS:
            if cfg[flag] == 'on':
                gcc_cmd += ' -f{0}'.format(flag)
            elif cfg[flag] == 'off':
                gcc_cmd += ' -fno-{0}'.format(flag)
        for param, min, max in GCC_PARAMS:
            gcc_cmd += ' --param {0}={1}'.format(
                param, cfg[param])
        return self.call_program(gcc_cmd)

    def run_precompiled(self, desired_result, input, limit, compile_result, id):
        """
        Run a compile_result from compile() sequentially and return performance
        """
        assert compile_result['returncode'] == 0

        try:
            run_result = self.call_program('./tmp{0}.bin'.format(id))
            assert run_result['returncode'] == 0
        finally:
            self.call_program('rm ./tmp{0}.bin'.format(id))

        return Result(time=run_result['time'])

    def compile_and_run(self, desired_result, input, limit):
        """
        Compile and run a given configuration then
        return performance
        """
        cfg = desired_result.configuration.data
        compile_result = self.compile(cfg, 0)
        return self.run_precompiled(desired_result, input, limit, compile_result, 0)


if __name__ == '__main__':
    argparser = opentuner.default_argparser()
    GccFlagsTuner.main(argparser.parse_args())

此示例将三种类型的标志调谐到GCC。首先,它在四个优化级别之间进行选择-O0、-O1、O2、-O3。其次,对于第8行列出的176个标志,它决定是打开标志(使用-fFLAG)、关闭标志(使用-fnoFLAG)还是忽略标志以允许默认值优先。将默认值作为选项并不是完整性所必需的,但会加快收敛速度并缩短命令行。最后,它使用–param NAME=value命令行选项为第15行上的145个参数指定一个有界整数值。

manipulator方法在启动时调用一次,并创建一个ConfigurationManipulator对象,该对象定义GCC标志的搜索空间。通过搜索技术对配置的所有访问都是通过配置操纵器完成的。对于优化级别,将创建一个介于0和3之间的整型参数。对于每个标志,都会创建一个EnumParameter,它可以启用、禁用和默认值。最后,对于剩余的有界GCC参数,将创建一个具有适当范围的整型参数。

搜索技术

OpenTuner包括可以处理多种类型的搜索空间的技术,并同时运行一系列搜索技术。性能好的技术分配更多的测试,而性能差的技术分配更少的测试。技术通过结果数据库共享结果,因此一种技术所做的改进可以使其他技术受益。这种共享以特定于技术的方式发生;例如,进化技术将其他技术发现的结果添加为其群体的成员。OpenTuner技术需要扩展。用户可以定义实现特定领域启发式的定制技术,并将其添加到预定义技术的集合中。

技术集合是通过实例化meta technique(元技术)创建的,元技术是由其他技术集合组成的技术。OpenTuner搜索驱动程序与单个根技术交互,这通常是一种元技术。当元技术得到分配的测试时,它会以增量的方式决定如何在其子技术中划分这些测试。OpenTuner包含技术和元技术的可扩展类层次结构,这些技术和元技术可以组合在一起并用于自动调谐。

AUC Bandit Meta Technique

除了一些简单的元技术,如round robin,结果中使用的OpenTuner的核心元技术是multi-armed bandit with sliding window, area under the curve credit assignment(AUC Bandit) meta technique(AUC Bandit 下带滑动窗口的multi-armed bandit)

接下来论文引出了一个多臂老虎机的案例,可以看一下这篇文章(52条消息) 专治选择困难症——bandit算法_CrissChan的博客-CSDN博客

滑动窗口使该技术在做出决策时只考虑历史的子集(窗口的长度)。这种元技术封装了开发(使用最著名的技术)和探索(评估所有技术的性能)之间的基本权衡

之后介绍了AUC Bandit meta公式

其他技术

opentuner包括以下技术的实现

techniquename
differential evolution差分进化
Nelder-Mead search and Torczon hillclimbers内尔德·米德搜索和托尔松·希尔克林伯斯的许多变体
a number of evolutionary mutation techniques许多突变技术
pattern search模式搜索
particle swarm optimization粒子群优化算法
random search随机搜索
bandit mutation techniquebandit变异技术,该技术使用相同的AUC bandit方法来决定在所有参数中调用最知名配置的操纵器功能。

这些技术跨越了一系列策略,每一种都倾向于在不同类型的搜索空间中表现最好。它们还包含许多可以配置为更改其行为的设置。每种技术都经过了修改,因此,如果其他技术发现了更好的配置,它将以一定的概率使用其他技术发现的信息。

本文结果中使用的默认元技术是稳健的,它使用AUC Bandit元技术结合贪婪突变、差异进化和两个爬山者实例(AUC Bandit meta technique
to combine greedy mutation, differential evolution, and two hill climber instances.)

Configuration Manipulator

配置操纵器在搜索技术和原始配置结构之间提供了一个抽象层。它主要负责管理参数对象列表,搜索技术可以使用每个参数对象来读取和写入底层配置的部分。

配置操纵器的默认实现使用固定的参数列表,并将配置存储为从参数名称到参数相关数据类型的字典。用户可以扩展配置操纵器,以更改用于配置的底层数据结构,或支持依赖于配置实例的动态参数列表。

参数类型

内置参数类型的层次结构。用户定义的类型可以添加到树中基元或复杂下面的任意点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3gWEpNLv-1656862060632)(C:\Users\83989\AppData\Roaming\Typora\typora-user-images\image-20220522130747962.png)]

从搜索技术的角度来看,有两种主要类型的参数:基本参数和复杂参数,每种参数都为搜索技术提供了不同的抽象:

基本参数

基本参数用于搜索具有上限和下限的数值搜索

内置参数类型Float和LogFloat(以及类似的Integer和LogInteger)在配置中都有相同的表示,但为搜索技术提供了不同的底层值视图。Float直接呈现给搜索技术,而LogFloat呈现给搜索技术的底层参数的对数比例视图。对于搜索技术来说,对数比例参数的减半和加倍是同等大小的变化。参数的对数缩放变量通常更适用于块大小等参数,其中值的固定变化会产生递减效应,参数越大。

复杂参数

复杂的参数为搜索技术提供了一个更加不透明的视图。复杂参数有一组可变的操纵操作符(操纵器),这些操作符对基础参数进行随机更改。这些操纵器是在参数上定义的任意函数,可以进行与类型相关的高级更改。复杂的参数易于扩展,以便向搜索空间添加特定于域的结构。新的复杂参数定义了供配置操纵器使用的自定义操纵操作符。

派生方法

除了这些主要的原始和复杂的参数类型抽象之外,还有许多派生的方法,搜索技术将与参数交互,以便更精确地传达意图。这些是关于参数的附加方法,其中包含基本参数和复杂参数类型的默认实现。可以选择为特定参数类型重写这些方法,以改进搜索技术。参数类型将在不重写这些方法的情况下工作,但实现它们可以改善结果。

例如,许多搜索技术中的一个常见操作是将配置a和B之间的差异添加到配置C中。这在差异进化和许多爬山者中都使用。复杂参数具有此缩进的默认实现,该缩进比较3种配置中参数的值:如果a=B,则没有差异,结果为C;类似地,如果B=C,则返回A;否则,应进行更改,以便调用随机操纵器。这在一般情况下有效,但对于个别参数类型,通常有更好的解释。例如,使用排列可以计算列表中每个项目的位置移动,并通过再次应用这些移动计算新的排列。

目标

OpenTuner支持多个用户定义的目标。结果记录有时间、准确性、能量、大小、置信度和用户定义的数据字段。默认目标是最小化时间。支持许多其他目标,例如:最大限度地提高准确性;阈值精度,同时最小化时间;最大化精度,然后最小化尺寸。用户可以通过在objective的子类上定义比较运算符和显示方法,轻松定义自己的目标。

Search Driver and Measurement

OpenTuner分为搜索和测量两个子模块。每个模块中的搜索驱动程序和度量驱动程序协调了搜索过程的大部分框架。这两个模块仅通过结果数据库进行通信。度量模块在设计上是最小的,主要是围绕用户定义的度量函数的包装,该函数创建配置的结果。

搜索和测量之间的这种划分是由许多不同的因素推动的:

并行性、测量模块的分离、需要一个最小的测量模块

结果数据库

结果数据库是一个功能齐全的SQL数据库。支持所有主要的数据库类型,如果用户没有配置数据库类型,因此不需要进行设置,则使用SQLite。它允许不同的技术以各种方式查询和共享结果,并有助于在自动调谐程序的大量运行中反思技术的性能。

案例结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4ALuqnLb-1656862060632)(C:\Users\83989\AppData\Roaming\Typora\typora-user-images\image-20220522132329806.png)]

我们通过使用OpenTuner为七个不同的项目实现自动调谐来验证OpenTuner。本节描述了这七个项目、我们实现的自动调谐,并给出了与每个项目中先前实践相比的结果。

对于每个基准,我们尽可能保持环境不变,但由于每个基准都有特定的要求,并且其中一个(模具基准)是基于我们无法控制的环境中的数据,因此不会对所有基准使用相同的环境。

GCC/G++ Flags

我们的完全自动调谐程序来自

在linux下输入:

g++ --help=optimizers

参数和合法范围自动从GCC的源代码:params.def中提取

在四个示例程序:fft.c,matrixmultiply.cpp,raytracer.cpp,tes_ga.cpp下进行测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jjz2jnEq-1656862060633)(C:\Users\83989\AppData\Roaming\Typora\typora-user-images\image-20220522133554245.png)]

随着自动调谐时间的增长,程序的执行时间越来越短

下图显示了一个单独的实验,试图了解哪些标志对获得的加速贡献最大。发现完整的GCC命令行包含250多个选项,很难手动理解。为了估计每个标志的重要性,我们测量了从自动调谐GCC命令中删除它所导致的速度减慢。我们将所有减速标准化为100%。该实验是在自动调谐装置的单次运行上进行的。这种重要性度量是不完美的,因为标志可以以复杂的方式交互,并且不是独立的。我们注意到,单独删除每个标志的总速度比删除所有标志的速度慢得多。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c1d2mMjW-1656862060634)(C:\Users\83989\AppData\Roaming\Typora\typora-user-images\image-20220522133814114.png)]

基准测试显示了有趣的行为和不同的最佳标志集。矩阵乘法基准通过几个大步骤达到最佳性能,其加速比由3个标志决定:-fno-exceptions, -fwrapv, and -funsafe-math-optimizations. 另一方面,TSP需要许多小的、递增的步骤,它的加速速度分布在大量的标志上,影响较小。FFT基准是经过大量手工优化的,在-O3下的性能比在-O2下的性能差;它的标志主要是禁用而不是启用各种编译器优化,这些优化与它的手写优化之间的交互很差。虽然有一些模式,但每个基准都需要一组不同的标志来获得最佳性能。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值