想象一家餐厅的后厨。传统大厨手里有一本厚厚的祖传菜谱,每道菜都写好了固定刀工和火候——这些菜谱就是“模板”。AutoTVM 就像这位大厨,它把成功经验固化成模板,调优时挨个试菜谱。可菜谱再厚,也只能覆盖已知菜品;遇到从没见过的食材,大厨只能等老师傅来补写新条目。Ansor 完全不同:它不翻菜谱,而是像一位大胆的新主厨,先按一套自动规则把食材写成“烹饪草稿”,再通过随机改刀、换火候、调整摆盘生成大量候选菜,让经验丰富的“试吃员”快速估算哪一道更可能好吃,最后从优秀候选里一代代进化。整个过程不需要专家手工写模板,计算机自己就能发明新菜式。这篇讲解带你走一遍 Ansor 的探索流程,看看它是如何在抽象的调度空间中低成本、大范围地找到好调度。
对 AI 编译从业者而言,掌握 Ansor 的无模板调度搜索,是从“套模板调优”走向“自动化探索优化空间”的关键一步,能显著提升新算子在大规模模型中的部署效率。
可视化演示
展示Ansor无模板自动调度器的四阶段工作流、循环变换规则及进化搜索机制,交互切换查看调度搜索核心流程。
本节配有交互动效(进入视口后自动加载,约 3KB)。
工作流:四阶段无模板调度 分析计算图提取循环结构与依赖 自动生成调度草图并进化搜索 space=sketch+evolve 摆脱人工模板实现广覆盖
模板调优痛点
老主厨有一本祖传菜谱,里面写着每道菜的标准刀工和火候。AutoTVM 就像这位老主厨,把成功经验固化成模板,搜索调度就是打开菜谱一项项试。菜谱看似丰富,翻开却只有几十个固定条目:遇到新的食材组合,条目对不上,老主厨只能放下菜刀等专家来补写。越新的食材,菜谱越是一片空白。
在 AI 编译里,“食材”是算子(也就是一道待烹饪的计算任务),“菜谱条目”就是调度模板。调度(schedule)指循环如何切分、并行、展开等一系列操作顺序。AutoTVM 的模板会预留若干参数,比如循环展开因子、线程数,搜索器只负责填参数。填参数虽然快,但模板本身没有覆盖的算子,根本无法进入填参环节。模板漏掉一个结构,可能就错过最优性能。
假设一个算子的所有调度方案总数为 N,模板能表达的只有 M 种。当新算子不断出现,M 相对 N 会迅速变小。调优时间的大头,反而变成了专家为算子写模板的时间。
模板调优的痛点正像一本残缺菜谱:会做的菜很多,但不会做的更多。当新算子数量爆炸,等待专家补模板会把优化的希望寄托在人工经验上。Ansor 要做的第一件事,就是扔掉这本菜谱。
- 定义候选空间把对一个算子所有可行调度方式的总数记为 N,它通常随循环层数指数增长。
- 统计模板覆盖把每个模板能生成的参数组合累加起来,得到模板可覆盖的调度数 M。
- 计算覆盖率模板覆盖的调度数占总候选数的比例就是覆盖率 C,C 越接近 1 表示覆盖越全。
草图生成规则
Ansor 的新主厨不翻菜谱,而是先按一套“拆菜规则”写出烹饪草稿。所谓草稿,就是调度草图:它把一道菜切成几个阶段——备料、切配、下锅、摆盘,每个阶段都描述一层循环结构。主厨不用知道最终味道如何,只需要快速写出大量可行的草稿。
在实际调度中,Ansor 会对计算流程做分阶段生成。每个阶段对应一次计算产物的循环结构,比如矩阵乘法的累加循环或是卷积的输出通道循环。Ansor 有一组分派规则,根据算子的形状和访存特征,把不同结构匹配到不同的草图模板片段。这样生成的不是一个完整手工模板,而是许多随机初始草图。
因为草图来自规则,所以每条草图被生成的概率可以分解为各阶段概率的乘积。Ansor 正是利用这种概率分解,在生成阶段就鼓励多样化和覆盖度,避免所有草稿长得一模一样。
有了这套写草稿的规则,第一次把“无模板”落到了实处。不过草稿只是起点,真正让菜品千变万化的,是写完之后在菜谱边上加的“批注”。
- 划分阶段把调度草图拆成 k 个阶段,每个阶段对应一个循环计算块。
- 独立选择假定每个阶段的生成规则相互独立,则联合概率为各阶段概率的连乘。
- 指导采样Ansor 在高概率处多采样,同时保留随机性,保证覆盖不同结构。
注释变换机制
厨师写菜谱时,常会在旁边加一行小字:“蒜末爆香后改为小火慢煨。”这些批注不改变菜是什么,却会改变做菜的速度和口感。Ansor 的注释(annotation)也是如此:它不改变计算结果,只改变循环结构,比如把某个循环展开、绑定向量化宽度、绑定并行线程数。
循环展开是最典型的注释:原来一个循环每次只处理一个元素,现在改成一次处理 4 个元素,循环次数减少了,循环控制的开销也随之摊薄。向量化注释则是告诉编译器把多个数装进同一个寄存器并行计算;并行化注释则是让不同线程同时处理不同数据块。这些注释组合起来,可以在同一张草图上衍生出大量性能不同的变体。
如果把循环展开因子记为 u,原来需要 n 次迭代,展开后大约只需要 n/u 次迭代。迭代次数下降,开销自然下降,这正是注释最直接的价值。
注释像菜谱边上的小批注,同一个草稿能演出几十种变体。但光靠主厨手写批注不够,Ansor 还要让这些批注自动“变异”,从而进入进化搜索。
- 记录原迭代次数未展开的循环总迭代次数为 n。
- 应用展开因子展开因子 u 表示每次迭代同时处理 u 个原数据。
- 得到最终循环次数新循环只需执行 n' 次,循环条件判断和跳转开销也随之减少。
随机进化搜索
新主厨最擅长折腾:他会把上一轮的草稿随机改一刀,有时把展开因子从 2 改成 4,有时把并行线程从 1 改成 2,有时干脆交换两层循环的位置。这种随机微调就像做菜时随手换一种配料,有些改动会变难吃,有些却意外惊艳。Ansor 把这一过程叫随机变换。
随机变换不是乱改,它会严格遵守“上下文变换”规则:所有修改都保持计算结果等价,只改变执行方式。比如循环展开、拆分、重排序都属于上下文变换。Ansor 维护一个种群,里面保留多条候选调度,每次从中挑一些进行变异,再结合代价模型给出的分数淘汰较差个体,让种群整体不断进化。
用公式表示,从父代 S 生成子代 S′,子代被保留的概率与它的分数在所有候选分数之和中的占比成正比。分数越高,越容易被留下继续繁殖。
随机进化让 Ansor 能在草稿基础上源源不断地产出新方案。可问题是,每道菜都真做一遍太慢了,Ansor 需要一个能快速“试吃”的帮手。
- 随机变异对父代 S 施加一个随机上下文变换,得到子代 S′。
- 计算个体得分用代价模型给 S′ 一个分数,得分越高代表执行时间越短。
- 按比例保留把 S′ 的得分除以种群内所有个体的得分之和,得到保留概率。
代价模型引导
如果每道菜都要完整做一遍才能判断好不好吃,探索几十万种菜谱根本不现实。Ansor 的做法是请一位“试吃员”:他不用真正下厨,只要看看食材切法、火候标注、摆盘顺序,就能估算这道菜大概要花多久。这位试吃员就是代价模型。
代价模型会提取调度草图的特征,比如循环迭代次数、访存次数、并行度、向量化宽度等,然后通过学习历史数据预测执行延迟。Ansor 在搜索中用预测分数给所有候选草图排序,只把分数最高的几百个送入真实编译测量。这样大部分差方案在预测阶段就被筛掉了,大幅降低编译开销。
这很像用特征做加权打分:每个特征乘上一个权重,再加一个基准值,就得到预测耗时。权重来自训练数据,数据来自真实硬件上的测量结果。
试吃员虽然会偶尔看走眼,但在大规模筛选中足够可靠。有了它,Ansor 就能在有限时间里多看很多菜,但它仍需要聪明的“试菜顺序”。
- 提取特征从调度草图 s 中提取 d 个关键特征,如循环层数、展开因子。
- 赋予权重每个特征乘上学习到的权重 w_j,表示该特征对耗时的影响程度。
- 加上基准值再加上常数项 w0,得到最终预测执行时间。
搜索策略优化
有经验的试菜不会把每道菜平均用力:先快速尝一轮,锁定价位合适的几道,再对最有希望的反复精调。Ansor 的搜索策略也一样,它采用分层搜索:先粗粒度生成大量草图,划分出几个有潜力的区域,再在区域内细粒度微调。这样既覆盖大范围,又不会均匀撒网导致时间浪费。
搜索还有一个难点:是继续深挖当前最高分,还是去看看还没被评估过的冷门候选?Ansor 在代价模型和进化搜索中都会使用探索与利用平衡策略。公式里有两项:第一项代表当前已知的分数,第二项代表这个候选被评估的次数越少、越值得去探索。当采样总数增加,这个探索奖励还会自动变化。
有了这套试菜顺序,Ansor 能在大厨房里快速找到好菜,而不是漫无目的地乱试。那么,扔掉模板的最终收益到底有多大?
- 利用已知分数第一项 score(s) 是代价模型对调度 s 的当前预测,分数高就值得留下。
- 计算探索奖励第二项中 ln N 随总采样次数缓慢增长,除以 n_s 后开根号,评估少的候选会获得更大奖励。
- 综合排序两项相加后,搜索会优先选择综合分数最高的候选。
无模板收益分析
从祖传菜谱走到自动发明新菜,最大的变化不是做菜动作,而是后厨的运转方式。AutoTVM 像一位依赖菜谱的老主厨,每来一道新菜都要等专家来编写新条目;Ansor 则像一支自动研发团队,从草稿生成到试吃调整全部自动完成。结果就是覆盖率提升、新算子适配加快、调优周期缩短。
覆盖率提升来自草图生成规则:它不再限制于人工模板能表达的参数组合,而是直接生成循环结构与注释组合。自动化程度提高则来自整条流水线闭合:规则、变换、代价模型和进化搜索共同协作,人工只需要选择搜索时间和预算,不再需要手写调度模板。与 AutoTVM 相比,Ansor 在搜索空间广度上明显占优,但也仍然需要人工设计规则库和代价模型特征,并非完全零干预。
1. 统计总时长:记录完成一次调优所花费的全部时间 T_total。
2. 统计人工时长:其中专家写模板、调规则的时间记为 T_manual。
3. 计算自动化程度:用 1 减去人工占比,得到自动化程度。
无模板的收益,本质上是从“人力补全知识”变成“系统自动探索知识”。Ansor 没有让主厨失业,而是把主厨从重复写菜谱中解放出来,让他专注于设计更好的规则和模型。
AI 应用场景
新算子快速适配
阶段:模型部署与自动调优
解决的问题:当新模型结构(如视线Transformer、稀疏专家模型)不断出现,传统 AutoTVM 需要专家为每个新算子手写模板,可能要数天;Ansor 通过草图生成和进化搜索自动覆盖新算子,调优时间从数天压缩到数小时。
具体案例:某推理加速团队上线一个新型注意力算子,只提供算子定义和硬件平台。Ansor 自动生成上千个候选调度,用代价模型筛选后选出最优方案,全程无需人工编写调度模板。
异构硬件上的自动化适配
阶段:跨平台编译优化
解决的问题:同一模型要在 GPU、CPU、NPU 上部署时,各平台指令集和访存特征差异大,手工模板难以迁移;Ansor 的规则库按平台分别采样,配合代价模型学习各平台特点,自动适配不同硬件。
具体案例:云厂商将统一模型部署到三种硬件,Ansor 分别在每个平台上执行一次无模板搜索,自动生成平台特化调度,省去了三套专家模板的维护。
大规模模型编译流水线
阶段:端到端一键式模型编译
解决的问题:大模型拥有上万个算子,逐个调优不现实;Ansor 将搜索策略嵌入编译流程,只对热点算子做深度搜索,冷门算子用快速规则生成,在整体编译时间预算内取得最好性能。
具体案例:在基于 TVM 的推理引擎中,模型导入后 Ansor 自动识别热点算子并安排搜索预算,最终整网延迟下降 30%,编译时间仍在可控范围。
Python 演示
import random WORKLOAD = 10000.0 def generate_sketch(): stages = [] for i in range(3): stage = { "name": "conv" if i == 0 else "matmul", "unroll": random.randint(1, 4), "vector": random.randint(1, 4), "parallel": random.randint(1, 2) } stages.append(stage) return stages def mutate(stages): new_stages = [dict(st) for st in stages] idx = random.randrange(len(new_stages)) key = random.choice(["unroll", "vector", "parallel"]) delta = random.choice([-1, 1]) new_stages[idx][key] = max(1, new_stages[idx][key] + delta) if random.random() < 0.2: new_stages[idx]["name"] = random.choice(["matmul", "conv", "pool"]) return new_stages def cost_model(stages): cost = 0.0 for st in stages: ratio = st["unroll"] * st["vector"] * st["parallel"] cost += WORKLOAD / ratio return cost def evolutionary_search(iters=200, pop_size=12): pop = [generate_sketch() for _ in range(pop_size)] best = min(pop, key=cost_model) for _ in range(iters): child = mutate(best) pop.append(child) pop.sort(key=cost_model) pop = pop[:pop_size] best = pop[0] return best, cost_model(best) if __name__ == "__main__": best_schedule, best_cost = evolutionary_search() print("best schedule:", best_schedule) print("estimated cost:", best_cost)
def generate_sketch():随机生成初始调度草图,相当于主厨先写流程草稿。def mutate(stages):对某个阶段随机调整一个优化参数,模拟换火候或改刀法。def cost_model(stages):用简单除法公式估算执行时间,相当于试吃官快速评分。pop.sort(key=cost_model)每轮按评分排序并只保留前 pop_size 个,实现种群优胜劣汰。if __name__ == "__main__":以脚本方式运行时输出搜索到的最优调度,验证完整流程。
常见误区
误区Ansor 既然叫无模板,肯定就是像无头苍蝇一样随机乱试,没有任何章法。
正解Ansor 只是不依赖专家为每个算子写完整调度模板,但它仍然使用分派规则生成草图,用上下文变换和剪枝控制搜索范围。它更像按一套“自动写草稿规则”工作,规则照样是结构,只是不再落到某个具体算子头上。
为何常见:把“模板”理解成“规则”,看到无模板就以为连规则都不要了,忽略了规则库仍然存在。
误区代价模型只要预测不准,Ansor 就会把好方案筛掉,所以必须让预测误差尽量小。
正解Ansor 的代价模型只需要拥有不错的相对排序能力:让好方案整体排在前面、差方案集体靠后即可。搜索过程还会结合真实测量修正,少量误判不会致命,真正常见的问题是找错特征而不是模型不够复杂。
为何常见:习惯于把机器学习当作“精确预测器”,忘了在搜索场景里排序质量往往比绝对精度更重要。
误区Ansor 生成调度草图之后,只需要在这些草图中挑一个最快的执行,后面不再改变。
正解草图只是搜索的出发点。Ansor 还会对草图做循环展开、向量化、并行绑定等注释,再经过随机变换和进化搜索不断修改结构。一个初始草图可能最终演化成完全不同的高效调度。
为何常见:只盯着“草图生成”这个名词,忽略了后续变换、搜索、优化才是无模板方法的核心价值。
误区Ansor 既然能生成海量草图,那就把搜索空间无限扩大,一定可以找到全局最优调度。
正解搜索空间过大,评估数量不够时反而会漏掉好方案。Ansor 通过分层搜索、代价模型筛选、剪枝机制和进化保留策略,在有限时间预算内平衡广度和深度。扩大空间必须伴随更聪明的搜索,否则只会增加噪声。
为何常见:把“候选多”和“搜索能力强”混为一谈,忽略了时间预算和评估成本才是真实约束。
面试题
Q1. Ansor 与 AutoTVM 在调度搜索上的核心区别是什么?
- A.Ansor 不需要人工编写完整模板← 正确答案
- B.Ansor 只能搜索卷积算子
- C.AutoTVM 支持动态形状
- D.Ansor 不使用任何一种规则
答案:A。Ansor 的核心创新是摆脱人工模板,通过规则生成草图并进行进化搜索。它仍使用分派规则、变换规则等,所以 D 错误;Ansor 也不是只能处理卷积,B 错误;AutoTVM 在动态形状上并无显著优势,C 错误。
Q2. Ansor 中的“调度草图”最恰当的理解是什么?
- A.一张完整实现代码的缩略图
- B.包含多个阶段的循环计算流程草稿← 正确答案
- C.一个已经训练好的神经网络模型
- D.编译器输出二进制文件的注释
答案:B。调度草图由多个阶段组成,每个阶段描述循环结构和计算顺序,相当于菜谱初稿。它不是最终代码缩略图,也不是神经网络模型或二进制注释,因此 A、C、D 都不准确。
Q3. 下面哪个操作属于 Ansor 的“注释(annotation)”?
- A.修改算子数学定义
- B.把循环按因子 4 展开← 正确答案
- C.删除中间张量不计算
- D.改变卷积权重初始化
答案:B。注释包括循环展开、向量化绑定、并行绑定等,它们不改变数学语义,只改变执行方式。修改数学定义、删除中间张量或改变权重初始化都会破坏原算子语义,不属于注释。
Q4. 在循环展开公式 n'=ceil(n/u) 中,u 代表什么?
- A.总迭代次数
- B.循环展开因子← 正确答案
- C.向量寄存器数量
- D.线程块数量
答案:B。u 是循环展开因子,表示每次迭代同时处理 u 个原数据点。总迭代次数是 n,向量寄存器数量和线程块数量属于并行绑定的其他注释,不符合公式含义。
Q5. 代价模型在 Ansor 搜索中的主要作用是什么?
- A.完全替代真实硬件测量
- B.只评估最终选择的调度
- C.用预测分数快速排序候选草图← 正确答案
- D.生成新的算子表达式
答案:C。代价模型主要用来在搜索过程中快速筛选并排序大量候选草图,减少真实编译次数。它不能完全替代真实测量,也不只是评估最终结果,更不会生成算子表达式。
Q6. 关于随机变换与进化,哪种说法正确?
- A.每次只保留最好的一个个体
- B.通过变异和保留高分组维持种群多样性← 正确答案
- C.随机变换不会改变草图结构
- D.进化只会让搜索变得更慢
答案:B。Ansor 维护一个种群,随机变异后按代价模型排序,保留前若干名并淘汰尾部,既保留精华又维持多样性。只保留一个个体容易陷入局部最优;随机变换会改变结构;进化虽然增加计算,但整体收益更大,A、C、D 均错误。
Q7. 公式 U(s)=score(s)+λ√(lnN/n_s) 中,第二项主要起什么作用?
- A.增加人工反馈权重
- B.鼓励探索被评估次数较少的调度← 正确答案
- C.降低代码编译体积
- D.记录每个算子的日志
答案:B。第二项称为探索奖励,n_s 越小,这一项越大,从而让被评估次数少的候选也有机会被选中。它不涉及人工反馈、编译体积或日志记录,因此 A、C、D 错误。
Q8. Ansor 无模板方法主要提升了哪些方面?
- A.调度覆盖率← 正确答案
- B.调优自动化程度← 正确答案
- C.人工模板可读性
- D.新算子的适配速度← 正确答案
答案:ABD。无模板方法通过自动生成草图扩大覆盖率,也提升了自动化程度和新算子适配速度。人工模板可读性与 Ansor 的目标无关,C 错误。
Q9. 下列哪些属于 Ansor 草图生成阶段使用的机制?
- A.分派规则匹配← 正确答案
- B.分阶段构建循环结构← 正确答案
- C.手工指定所有循环次序
- D.初始草图采样← 正确答案
答案:ABD。Ansor 用分派规则匹配算子特征,分阶段构建循环结构,并采样多个初始草图。手工指定所有循环次序回到了模板方法,不是 Ansor 的做法。
Q10. 哪些措施帮助 Ansor 在更大搜索空间中保持高效?
- A.用代价模型快速筛选← 正确答案
- B.使用进化搜索保留优秀个体← 正确答案
- C.对候选进行剪枝← 正确答案
- D.放弃所有启发式规则
答案:ABC。代价模型快速排序、进化保留优秀个体、剪枝机制都能减少无效评估。Ansor 没有放弃启发式规则,规则库恰恰是草图生成的骨架,D 错误。