想象一家新开的餐厅后厨,主厨端来一道从未做过的新菜:一个卷积算子。它对学徒厨师说:“这道菜,你必须在今天之内做到又快又好。”学徒面前有几十个旋钮——切法怎么切、火候用多大、摆盘怎么摆、配菜放多少。每一个旋钮有几十种选择,全部组合起来比天上星星还多。学徒不可能一道菜做几十亿次让客人试吃,那该怎么办?他想到一个办法:每做一次菜就记笔记,记下当时看到了什么、做了哪些操作、客人打了多少分,然后慢慢摸索出“哪种做法最受欢迎”的规律。这个“边做菜、边记笔记、边改进”的循环,就是强化学习调优的核心思路。AutoTVM 和 Ansor 这类工具,正是把“给算子找最优调度”变成一场有章法的厨房修行,让计算机自己学会如何把代码调得飞快。
掌握强化学习调优的思路,你就能从“手写手工优化经验”进阶到“让编译器自动从千万种方案里学习最优调度”,在模型上线、跨硬件移植时省下数周人力。
目录
可视化演示
展示强化学习调优机制:状态-动作-环境-奖励循环、策略动作搜索与最优动作选择、RL调优相对基线的训练效果,通过交互理解AutoTVM/Ansor的RL调度搜索原理。
本节配有交互动效(进入视口后自动加载,约 3KB)。
RL循环:状态-动作-奖励 调度搜索建模为序列决策问题 RL代理自动探索高效调度策略 S → A → Env → R 奖励驱动策略迭代优化
调优困境:组合爆炸的厨房
学徒厨师第一天上班就傻了眼。主厨给的那道菜,光可调的旋钮就有七八个:块的大小、循环的顺序、向量化的宽度、数据摆放的方式……每个旋钮还有十几个档位。他随手算了一下:几千万种组合。就算十秒钟试一次,也要连续试好几年。这还没算上每次试菜都要重新切菜、热锅、摆盘——在真实的调优任务里,每试一种调度方案,都要重新编译一次算子再跑一遍,单次试验往往要花几秒甚至几分钟。
这道菜的困境,本质是“组合爆炸”:每个旋钮的档位数相乘,会得到一个天文数字。传统做法靠资深工程师写启发式规则,比如“在 GPU 上优先用某某分块大小”。但规则是针对某个硬件手工调出来的,换一块新芯片、换一个输入尺寸,规则立刻失效。而且规则本身也不覆盖所有算子结构,很多形状复杂的算子根本套不上现成模板。
学徒垂头丧气地放下菜刀,意识到自己缺的不是力气,而是一套“边做边学”的方法。他决定从明天起,每次做菜都认真记笔记,看看能不能从几千次尝试里总结出规律——这就是强化学习登场的原因。
- 旋钮档位设第 \(i\) 个可调旋钮有 \(c_i\) 种档位,比如“分块大小”有 8 档。
- 连乘取积把所有旋钮的档位数相乘,得到总组合数。
- 爆炸含义只要 \(k\) 稍大或单个档位稍多,总数便超过手工可枚举的范围。
强化学习框架:试菜记笔记的循环
从第二天开始,学徒换了一种干活方式。他每做一次菜,就掏出一个小本子:第一行写“我看到了什么”——食材种类、切菜台的状态、灶台的型号;第二行写“我做了什么”——选了哪种切法、哪个火候;第三行写“客人打了几分”——这道菜上桌后比正常慢了还是快了。试的次数多了,他慢慢发现:某些动作组合总是拿高分,于是他在本子上把这些动作偷偷圈起来,下次多做。
这就是强化学习调优的完整骨架。在 AutoTVM/Ansor 的场景里,学徒是“策略网络”,厨房是“编译器 + 真实硬件”,本子上的“看到什么”叫状态(state),“做了什么”叫动作(action),“客人打分”叫奖励(reward)。一次完整的做菜过程叫一条轨迹,包含多步“状态→动作→奖励”的交替。调度搜索因此被建模成一个序列决策问题:代理一步一步地选择调度变换,最终拼出一个完整的 schedule。
收集了一堆轨迹之后,怎么用?核心思想是:凡是带来高奖励的动作,就提高它下次被选中的概率;凡是低奖励的动作,就降低概率。这个“提优降劣”的数学操作,叫策略梯度。
学徒的本子越记越厚,动作也从盲目乱试变成了“优先尝试划圈的做法”。接下来他要解决三个更细的问题:如何把厨房的状态记清楚?如何保证动作合法?客人打分怎么打才公平?下面四节逐一拆解。
- 策略参数\(\theta\) 是代理脑中的“做菜经验”权重,也就是策略网络的参数。
- 对数概率梯度\(\nabla_\theta \ln \pi_\theta(a_t \mid s_t)\) 告诉我们在状态 \(s_t\) 下,往哪个方向调整参数能明显提高选中动作 \(a_t\) 的概率。
- 奖励加权把梯度乘以 \(R_t\),让高奖励的动作被大幅强化,低奖励的动作被压低。
状态空间设计:给后厨拍一张结构化快照
学徒发现,光记“食材很多、锅很热”这种模糊描述没用,他需要一张标准化的表:菜品是什么类型、食材有多少块、每一块大概多大、灶台是明火还是电磁炉、锅的容量多少。换句话说,不能把厨房的乱象全拍下来,而要抽出影响做菜结果的关键信息。
在算子调优中,状态就是对“当前这个算子和硬件”的结构化描述。它要编码算子的计算图结构:算子类型(卷积、矩阵乘、池化……)、输入张量的形状、循环嵌套的层数与层次关系、当前已选择的部分调度。同时还要融入硬件特征:目标芯片是 CPU 还是 GPU 或 NPU、缓存多大、向量寄存器多宽、核数多少。这些特征共同决定哪个调度方案跑得快。
但原始特征有个麻烦:有的特征数值很大(比如张量长度上万),有的很小(比如向量宽度只有几十)。直接把它们塞给神经网络,大数值会淹没小数值,训练很不稳定。所以要先做归一化,把每个维度的特征压到相近的尺度上,再通过嵌入层把离散结构(比如算子类型)转成稠密向量。
有了这张“结构化快照”,学徒每次进后厨都能一眼看清关键信息。但他还缺一样东西:一份明确的“可以做什么”的清单,不然他可能会把菜扔到天花板上。
- 原始特征\(s_i\) 是某个维度的原始值,比如循环层数或向量宽度。
- 中心化减去该维度在所有样本上的均值 \(\mu_i\),让特征围绕 0 分布。
- 标准化缩放除以标准差 \(\sigma_i\),把不同量纲统一成“单位尺度”。
- 防除零加上极小常数 \(\epsilon\),避免标准差恰好为 0 时算出无穷大。
动作空间设计:合法做菜手法清单
后厨贴着一张规定:学徒只能使用五种手法——切块、焯水、爆炒、摆盘、换锅,而且使用顺序不能颠倒到离谱。比如不能先摆盘再切块。这张清单既保护了菜品的可行性,也大幅缩小了学徒需要尝试的范围。
对应到调优,动作就是“调度变换原语”。AutoTVM/Ansor 里常见的原语有:split(把循环分块)、reorder(交换循环顺序)、vectorize(向量化)、parallel(并行化)、compute_at(把某段计算挪到另一层循环内)等等。一个完整的调度方案,就是这些原语按某种顺序拼成的动作序列。代理的策略,本质上是在为“下一步该用哪个原语、参数选多少”打分。
但并不是所有动作拼接都合法。例如对已经展开的循环再做 split 可能破坏语义,某些变换顺序在不同算子结构下会生成错误代码。假如代理乱试这些非法动作,轻则编译失败浪费试验次数,重则得到错误结果。解决办法是“合法动作掩码”:每一步先把当前状态允许的动作列出来,把非法动作的概率直接置零,再在合法集合上做 softmax。
学徒终于拥有了“合法手法清单”。但他很快发现一个新问题:客人打分必须公平,否则一次手抖就会误导他好几天。
- 动作打分\(z_a\) 是策略网络针对动作 \(a\) 打出的分数,分数越高越倾向选择。
- 指数化对分数取自然指数,把任意实数变成正数,且保持大小顺序。
- 归一化除以合法动作集合 \(\mathcal{A}\) 中所有动作分数之和,变成总和为 1 的概率。
- 合法动作集合\(\mathcal{A}\) 是经过掩码过滤后的合法动作集合,非法动作已被剔除。
奖励函数设计:客人的评分标准
学徒一开始让客人随便打分,结果有的客人心情好给满分,有的客人挑剔给零分,他完全学不到规律。后来主厨定了规矩:打分只看一道硬指标——上菜时间。先用最普通的做法做一版,记下耗时作为基准;之后每道菜的分数,就是基准耗时除以这道菜的实际耗时。上菜比基准快一倍,分数就是 2;比基准慢一半,分数就是 0.5。
在调优任务里,这个“客人评分”就是奖励函数。首先用一张默认 schedule 编译并运行算子,测出基线耗时 \(T_{\text{baseline}}\);然后对候选 schedule 同样编译运行,测出 \(T_{\text{candidate}}\)。奖励取两者的比值:
不过比值奖励也有隐患:运行时间受系统噪声影响,同一个方案测两次可能相差 10%。更麻烦的是“奖励稀疏”问题——在组合空间里,绝大多数随机方案性能都差不多,奖励几乎没有区分度,代理像个没有方向的学徒,试了很多次也学不到东西。工程上常用 log 加速比压缩极端值、对同一方案多次测量取中位数、或者先用粗粒度方法筛掉明显差劲的区域,再让 RL 精调。这样才能让客人的评分既稳定又有信息量。
- 基线耗时默认调度方案在目标硬件上的实测耗时,作为比较的“原味配方”。
- 候选耗时当前策略选出的新调度方案的实测耗时。
- 比值奖励比值大于 1 表示方案变快,奖励为正反馈。
学习探索策略:守成与尝新
学徒现在面临一个经典的矛盾:已知“爆炒拿高分”,他应该每道菜都爆炒吗?如果永远只做拿手菜,他就永远发现不了可能更好的“低温慢煮”。但若是每道菜都乱试新花样,客人又会纷纷给差评。成熟的学徒会定下规矩:大部分时候按已知好做法来,留一小部分次数尝试新配方,并且每次试新风波不能太大,免得把学过的经验全搞砸。
这个矛盾在强化学习里叫“探索与利用的权衡”。对应策略包括:\(\epsilon\)-greedy(以 \(\epsilon\) 概率随机探索,否则选当前最优)、在损失函数里加熵正则项鼓励多样化动作、以及把采集到的轨迹放进经验池打乱顺序再学习(经验回放,减少相邻轨迹的关联性)。AutoTVM/Ansor 这类框架接入 RL 时,常用 PPO 优化器来更新策略,因为它有一个特别务实的机制:限制单次更新的幅度。
学徒带着“大部分守成、小部分尝新、每次小步改进”的纪律,手艺稳步上涨。现在该跟其他后厨的效率比一比了。
- 概率比\(\rho_t\) 是旧策略与当前策略在状态 \(s_t\) 下选择动作 \(a_t\) 的概率之比,衡量策略变化的幅度。
- 优势函数\(\hat{A}_t = R_t - V(s_t)\) 表示这一步的实际收获比期望好多少。
- 截断操作\(\mathrm{clip}(\rho_t, 1-\varepsilon, 1+\varepsilon)\) 把概率比强制限制在安全区间内。
- 保守取小\(\min\) 取原始项与截断项的较小值,保证超范围的部分不再贡献梯度。
效果对比分析:学徒对决掷骰子
餐厅老板想验证学徒的方法值不值得培养,于是请来两组对照组:一组是“掷骰子厨师”,每次做菜完全随机选配方,从不记笔记;另一组是“进化厨师”,同时养着几十个配方,每轮留好的、杂交差的,像自然选择一样迭代。老板给三组同样的预算——各做 200 次试验,看谁先找到满足加速目标的最佳配方。
结果通常很明显:随机搜索完全没有记忆,这次试了高分区域,下次照样可能在低分区域打转,达成目标需要的试验次数非常多。进化算法靠种群并行,能找到不错的解,但每个“个体”都从零开始,缺乏对“一个算子的调度长什么样”的全局理解。RL 代理则把历史试验全部压缩进策略参数里,随着试验次数增加,采样越来越集中在高奖励区域。量化这个差距的指标叫“样本利用率”:
当然,样本效率高不等于永远赢。当搜索空间很小、几十次试验就能穷举完时,随机搜索连训练成本都不用付,反而更干脆;进化算法天然适合并行,多台机器同时跑能摊薄时间。学徒的胜利是有条件的:空间足够大、每次试验成本足够高、并且有足够的历史经验可以积累时,他的“记笔记式学习”才真正划算。
- 随机搜索试错数\(N_{\text{random}}\) 是随机搜索达到目标加速比所需的试验次数。
- RL 试错数\(N_{\text{RL}}\) 是 RL 代理达到同等水平所需的试验次数。
- 效率比值\(\eta\) 越大,说明 RL 用越少的试验达到同样效果,样本效率越高。
工程选型建议:何时启用学徒制
餐厅老板最后算了一笔账:培养一个学徒有固定成本——要花时间教他记笔记、训练他的判断力。如果餐厅只有一道凉菜,随便让切菜工试几下就行,没必要上学徒制;但如果要应对几十道硬菜、还要长期经营同一间厨房,学徒制就非常值。
调优工作的工程选型也是同样逻辑。先看三个因素:待调算子的数量 \(n_{\text{op}}\)、每个算子需要的平均试验次数 \(N_{\text{trial}}\)、能并行跑试验的设备数 \(p_{\text{device}}\)。三者决定总调优成本:
实际的工程选型还有几条经验法则:搜索空间小(比如旋钮少于四五个)直接用随机或网格搜索;空间中等用进化算法或模拟退火;空间大且硬件会长期服役,才投入 RL。冷启动阶段可以先加载一个预训练策略(从相似算子迁移经验)再微调,避开几百次“从头学起”的浪费。AutoTVM/Ansor 本身也提供了多种搜索器接口,RL 代理并非要替代一切,而是作为可插拔的“精调专家”,与启发式粗筛、进化并行形成混合策略。学徒制的精髓不在于每道菜都从零教,而在于把经验沉淀下来,让下一道菜学得更快。
- 算子总数\(n_{\text{op}}\) 是模型里需要调优的算子数量,几十个还是上千个。
- 单算子试验数\(N_{\text{trial}}\) 是每个算子平均要编译运行的试验次数。
- 并行设备数\(p_{\text{device}}\) 是同时能跑试验的机器数,设备越多调得越快。
- 总代价分子越大成本越高,分母越大成本越低,据此判断 RL 是否值得。
AI 应用场景
新硬件的算子移植加速
阶段:编译优化与算子自动调优
解决的问题:传统方式把算子调度移植到新 NPU 时,需要工程师逐硬件手写优化规则,一个卷积算子往往要调数天甚至数周。强化学习调优把“做菜经验”沉淀为策略网络,新硬件上的算子直接交给 RL 代理探索,省去大量人工。
具体案例:某推理引擎团队在接入一颗新 NPU 时,用 Ansor 为每个卷积算子生成大量 sketch(调度草图),再用 RL 代理在百万级配置空间中搜索。同一个算子,手工调优需要 3 天的任务,RL 加并行采样把时间压缩到 3 小时,最终加速比达到手工方案的 1.2 倍。
动态 shape 模型的在线服务
阶段:推理服务冷启动与动态 shape 适配
解决的问题:线上视频模型的输入分辨率经常变化(720p、1080p、4K),每换一个新 shape 就要重新调优,传统方式会带来分钟级卡顿。用训练好的 RL 策略做 warm start,可以继承相似 shape 的调度经验,把重调优时间压到秒级。
具体案例:一个视频超分服务在分辨率切换时,用历史 RL 策略作为初始参数,只做少量微调就让新 shape 的算子达到 95% 的峰值性能,用户无感切换。
云端批量调优平台
阶段:模型仓库批量调优的基建调度
解决的问题:云上要为整个模型仓库(成百上千个算子)批量调优,试验成本直接决定账单金额。奖励用稳定加速比,策略用 PPO 更新,多台设备共享一个经验池,让所有算子的探索经验互相复用。
具体案例:某云厂商的编译服务把 RL + 并行采样结合,数百个算子的调优任务共享经验回放池,相比各算子独立随机搜索,总机器小时节省约 60%,用户拿到的时间预算从“天”变成“小时”。
Python 演示
import numpy as np class TuningEnv: """模拟一个算子调优环境: 5 个调度旋钮, 存在隐藏最优组合""" def __init__(self, seed=0): rng = np.random.default_rng(seed) self.knob_sizes = [4, 4, 8, 3, 8] self.optimal = [int(rng.integers(n)) for n in self.knob_sizes] self.baseline_ms = 10.0 def reward(self, schedule): # 离最优越远, 耗时越长, 加速比越小 dist = sum(s != o for s, o in zip(schedule, self.optimal)) time_ms = self.baseline_ms * (0.7 + 0.3 * dist) return self.baseline_ms / max(time_ms, 1e-3) class PolicyAgent: """用策略梯度(REINFORCE)学习每个旋钮各档位的选择概率""" def __init__(self, knob_sizes, lr=0.1): self.theta = [np.zeros(int(n)) for n in knob_sizes] self.lr = lr self.reward_mean = 1.0 def softmax(self, logits): e = np.exp(logits - logits.max()) return e / e.sum() def sample(self): # 按当前策略选一个完整调度, 同时计算对数概率 schedule = [] log_prob = 0.0 for j, logits in enumerate(self.theta): p = self.softmax(logits) a = int(np.random.choice(len(p), p=p)) schedule.append(a) log_prob += np.log(p[a] + 1e-12) return schedule, log_prob def update(self, schedule, log_prob, reward): # 优势 = 奖励 - 平均奖励, 降低方差 advantage = reward - self.reward_mean self.reward_mean = 0.9 * self.reward_mean + 0.1 * reward for j, a in enumerate(schedule): p = self.softmax(self.theta[j]) grad = np.zeros_like(p) grad[a] += 1.0 grad -= p self.theta[j] += self.lr * advantage * grad return advantage def main(): env = TuningEnv(seed=0) agent = PolicyAgent(env.knob_sizes, lr=0.1) print("真实最优旋钮组合:", env.optimal) best_schedule, best_reward = None, 0.0 rewards_history = [] for step in range(400): schedule, log_prob = agent.sample() reward = env.reward(schedule) if reward > best_reward: best_reward, best_schedule = reward, schedule agent.update(schedule, log_prob, reward) rewards_history.append(reward) if (step + 1) % 80 == 0: avg = round(float(np.mean(rewards_history[-80:])), 4) print("步数:", step + 1, "最近80步平均奖励:", avg) print("最优发现:", best_schedule, "加速比:", round(float(best_reward), 4)) print("模拟最佳加速比: %.2fx" % best_reward) if __name__ == "__main__": main()
self.optimal = [int(rng.integers(n)) for n in self.knob_sizes]环境随机生成隐藏的最优旋钮组合,模拟真实硬件上“某个调度最快”这个未知事实。time_ms = self.baseline_ms * (0.7 + 0.3 * dist)离最优越远的调度耗时越长,把抽象的性能关系简化成可计算的奖励。def softmax(self, logits)把策略分数变成概率分布,是动作选择的数学基础。a = int(np.random.choice(len(p), p=p))按当前策略概率采样,高概率动作更常被选中,同时保留探索机会。log_prob += np.log(p[a] + 1e-12)记录被选动作的对数概率,供策略梯度计算使用。advantage = reward - self.reward_mean减去历史平均奖励得到优势,让梯度更新更有针对性、方差更小。grad[a] += 1.0; grad -= p计算 softmax 交叉熵梯度:推高被选动作的概率,压低其他动作。self.theta[j] += self.lr * advantage * grad策略梯度更新:高优势时加强这次选择,低优势时反向修正。
常见误区
误区我以为是让代理不停随机试配置,试得多了自然能找到好的,本质和随机搜索没区别。
正解随机搜索每次试验相互独立、毫无记忆;RL 代理每次试验后会用奖励更新策略,下一次采样会偏向高分区域。好比学徒会记笔记并调整手法,而掷骰子的人永远靠运气。两者虽然都在“反复试”,但一个在积累经验,一个在重复抛硬币。
为何常见:从外部看,两者都表现为“不断尝试+测量耗时”,表象太像,容易忽略内部是否有“学习”这个关键环节。
误区想当然地认为把算子源码全文、全部硬件参数一股脑塞给代理,信息全了策略自然更准。
正解高维冗余特征会增加策略网络的训练难度,噪声维度还会干扰梯度。关键是提取真正影响性能的核心结构:循环嵌套、数据布局、硬件带宽与缓存。特征要结构化、归一化,而非单纯堆料。
为何常见:人们默认“信息越多决策越准”,却忽略了机器学习中特征工程的重要性,以及高维空间带来的稀疏与过拟合风险。
误区奖励就是实测加速比,数值越大训练越快,不用做任何加工。
正解原始加速比受测量噪声影响大,极端值会拉偏梯度方向。工程上常取 log 压缩极端值、多次测量取中位数、或用相对基线比值得分。奖励追求的是“稳定、有区分度”,而不是单纯的“大”。
为何常见:奖励定义看起来简单,但编译环境的时钟波动、降频、缓存状态都会污染单次测量,初学容易忽视这些工程细节。
误区既然论文里说 RL 样本效率高,那任何场景下都用 RL 就能最快找到最优调度。
正解搜索空间很小或测量噪声很大时,启发式规则、随机搜索、进化算法往往更简单稳定,还没有训练 RL 的额外成本。RL 的优势集中在“空间够大、经验能积累、试验代价高”的场景,选型要看具体约束。
为何常见:把论文中特定条件下的优势,错误推广到所有算子、所有硬件、所有预算。
误区把策略模型当成一个一次性的宝贝,调完一个模型后任何新算子都能直接用。
正解状态中包含算子结构、输入 shape 和硬件特征,模型结构一换、输入分辨率一变、目标芯片一换,状态分布就漂移,旧策略效果大打折扣。需要在新分布上重训或迁移微调,这也正是“冷启动策略”要解决的问题。
为何常见:把离线优化当成一次性工程交付,忽略了部署环境与模型迭代带来的分布变化。
面试题
Q1. 在强化学习调优中,RL 代理最直接利用的“奖励”信号来自哪里?
- A.编译报错次数
- B.实测运行加速比← 正确答案
- C.生成代码的行数
- D.模型参数量大小
答案:B。奖励反映调度方案的好坏,最直接信号就是真实运行的加速比(基线耗时/候选耗时)。编译报错属于约束而非奖励,代码行数和参数量与性能没有直接正比关系。就像客人打分只看上菜快不快,而不是看厨师切了几刀。
Q2. 为什么强化学习调优通常比随机搜索更高效?
- A.它每次都是随机试验
- B.它用历史奖励指导探索← 正确答案
- C.它不测量真实运行时间
- D.它完全依赖手工规则
答案:B。RL 代理每轮试验后会用奖励更新策略,使后续采样偏向高奖励区域,这是“经验积累”;随机搜索没有记忆,每次独立,试验分布不随历史改变。比喻上学徒会记笔记改进手法,掷骰子的人不会。
Q3. 状态特征归一化的主要作用是什么?
- A.让不同特征尺度一致← 正确答案
- B.直接删除部分特征
- C.把所有特征全部置零
- D.减少状态空间的维度
答案:A。归一化把各维度特征缩放到相近尺度,避免大数值特征淹没小数值特征,让策略网络训练更稳定。它不删除特征、不置零,也不负责降维,而是让每个特征在梯度计算中有公平的话语权。
Q4. 动作空间中“合法动作掩码”要解决什么问题?
- A.加快编译器的速度
- B.屏蔽非法调度变换← 正确答案
- C.让奖励值变得更大
- D.缩小状态特征数量
答案:B。某些调度变换在当前算子结构下非法或会破坏语义,掩码把这些动作的概率置零,代理就不会浪费试验次数去试注定失败的方案。好比后厨规定不能先摆盘再切菜,避免无效劳动。
Q5. “奖励稀疏”问题指的是什么?
- A.每次获得的奖励都很大
- B.大多数动作奖励难区分← 正确答案
- C.奖励函数总是返回负数
- D.奖励来自单一测量指标
答案:B。当组合空间极大而大部分随机方案的性能都差不多时,奖励几乎没有区分度,代理难以从反馈中学习。解决思路包括 log 加速比、基线比值、多次测量取中位数和先粗筛后精调,类比客人打分全打 6 分时,学徒根本分不清哪个手法更好。
Q6. PPO 中 clip 操作的核心作用是什么?
- A.将奖励数值整体放大
- B.限制新旧策略更新幅度← 正确答案
- C.裁剪掉无用的状态特征
- D.直接丢弃历史经验轨迹
答案:B。clip 把新旧策略的概率比限制在 \(1 \pm \varepsilon\) 区间内,任何超出该幅度的更新都不再获得额外鼓励,从而防止单次更新破坏已有经验。这是 PPO 相比朴素策略梯度更稳定的关键,类似给学徒的“小步改进纪律”。
Q7. 在“学徒厨师”这个比喻里,AutoTVM/Ansor 中的“算子”最像什么?
- A.一份标准的做菜原料
- B.一道等待端出的新菜← 正确答案
- C.一间拥挤的厨房环境
- D.一位挑剔的试菜客人
答案:B。一个算子是一个待优化目标,对应一道需要做好的新菜;厨房对应编译器+硬件环境,动作是调度变换,奖励是实测加速比。选 B 是因为“给算子找最优调度”就像“把这盘菜做到最好”。
Q8. 以下哪些属于调度变换原语?
- A.分块变换 tile← 正确答案
- B.向量化 vectorize← 正确答案
- C.循环重排序 reorder← 正确答案
- D.随机梯度下降 sgd
答案:ABC。tile、vectorize、reorder 都是 TVM 调度原语,用来调整循环结构和计算方式;sgd 是训练神经网络的优化器,与调度变换无关。原语就像后厨的切块、焯水、摆盘,是构成完整调度动作序列的基本单元。
Q9. 相比进化算法,强化学习调优的潜在优势包括哪些?
- A.能感知调度状态特征← 正确答案
- B.样本利用率通常更高← 正确答案
- C.完全不需要真实测量
- D.可复用相似算子经验← 正确答案
答案:ABD。RL 策略网络以状态为输入,能利用算子结构特征;通过历史奖励更新策略,样本利用率往往更高;相似算子的经验可以通过预训练策略迁移。但 RL 仍然必须做真实运行测量来获得奖励,C 的说法错误。
Q10. 工程选型判断“是否值得用强化学习调优”时,需要考虑哪些因素?
- A.待调算子的数量规模← 正确答案
- B.可用的算力时间预算← 正确答案
- C.目标硬件服役周期长短← 正确答案
- D.算子源码注释的多少
答案:ABC。算子越多、空间越大、硬件服役越久,RL 的学习成本越能被摊薄;算力预算决定能承受多少次试验。注释多少与性能无关,不构成选型依据。类比餐厅只有一道凉菜时不必培养学徒,若长期经营几十道硬菜则很值得。