在编译器的世界里,每个 AI 算子的运行方式都有成千上万种“做法”:分块取多大、循环怎么交换、向量化用多宽……这些调度参数一经组合,可能出现 \(10^{30}\) 种候选方案,比银河系恒星还多。想象一位叫安师傅的金牌主厨,要在一本厚到没边的“菜谱册”里找出做招牌菜最快的方法。他当然不傻:随手做 20 道菜试一圈,把好吃的两两合并、偶尔撒把盐当成新菜,再试一圈……几十轮下来,那道最好的菜就被“进化”了出来。这正是 Ansor 自动调优的核心——进化搜索(Evolution Search):用代价模型快速预估、用真实测量精准把关,通过选择、交叉、变异一代代逼近最优调度方案,而这一切都发生在有限的预算之内。它取代了传统“每页都试一遍”的网格搜索,成为 TVM 生态中让深度学习模型跑得更快的关键引擎。

岗位关联

AI 从业者一旦理解了进化搜索,就能看懂 Ansor 这类自动调优工具的核心原理,知道编译器如何自动为算子找到最优调度,从而在实际部署中摆脱手工调参的玄学。

目录
  1. 可视化演示
  2. 搜索空间:调度方案的“宇宙”
  3. 初始种群:从随机开始的第一代
  4. 适应度评估:老厨师的直觉与食客的舌头
  5. 进化算子:交叉、变异与选择
  6. 迭代收敛:有限预算内的逼近
  7. 对比优势:为何碾压网格搜索
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示Ansor进化搜索的种群迭代、交叉变异基因重组,以及代价模型预测与实测反馈机制,揭示自动调优算法核心原理。

本节配有交互动效(进入视口后自动加载,约 3KB)。

'+_captions.evolve+'

搜索空间:调度方案的“宇宙”

安师傅的厨房里挂着一本厚重的《招牌菜做法大全》,每一页都写着一种做法:第 37 页把肉切成 64 像素见方、大火爆炒 2 分钟、出锅前撒一把葱花;第 38 页则切成 128 见方、中火慢炖。食材、刀工、火候、下锅顺序,每一栏都有好几个选项,随意组合就能翻出天文数字的新页。安师傅咽了咽口水:“照我这本册子的厚度,一页页试根本不可能。”

这本“菜谱”在编译器世界里对应着调度方案的搜索空间。给定一个算子(比如矩阵乘法),编译器可以用多种方式生成目标代码:循环分块(tiling)、向量化(vectorization)、并行化(parallelization)、循环重排(reordering)等,每一种叫做一条调度原语(schedule primitive)。每条原语选取不同取值,就构成一个具体的调度方案,即一个程序变体(program variant)。所有变体的集合,就是搜索空间 S。在进化过程中,每个调度方案会被编码成一条紧凑的序列或向量(编码表示),交叉与变异就在这份“基因序列”上操作。

搜索空间的大小可以用简单的乘法估算。假设共有 k 种调度原语,第 i 种原语有 n_i 种可选取值,则总方案数为:

安师傅盯着菜谱册子叹气,但他转念一想:不需要翻完所有页,我只需要找到最优的那一两页——而“进化”能帮我快速逼近它。于是,他开始了第一批实验。

N=∏i=1kni=n1×n2×⋯×nk\displaystyle N = \prod_{i=1}^{k} n_i = n_1 \times n_2 \times \cdots \times n_k
调度空间的大小由所有调度原语可选值连乘得到。它是进化搜索要“逛”的宇宙,也是网格搜索望洋兴叹的根本原因。
  1. 原语种类 kk 表示调度原语的种类数,好比菜谱上有几列可调选项(分块、向量化、重排……)
    k=3k = 3
  2. 每种原语可选值 n_in_i 表示第 i 种原语有多少种合法取值,如分块大小可选 {16, 32, 64} 则 n₁ = 3
    n1=3, n2=4, n3=2n_1 = 3,\ n_2 = 4,\ n_3 = 2
  3. 连乘得到总数N 是所有可能的调度方案总数,因为每列选项彼此独立、自由组合,所以用乘法而非加法
    N=3×4×2=24N = 3 \times 4 \times 2 = 24
  4. 组合爆炸直觉即便每种原语只有五六种取值、共 30 种原语,N 也超过 10²⁰,远超任何穷举能力
    N=530≈9.3×1020N = 5^{30} \approx 9.3 \times 10^{20}

初始种群:从随机开始的第一代

安师傅没有继续对着菜谱空想,而是挽起袖子,闭着眼从册子里随机抽了 20 页,照着做了 20 道菜,一字排开。有的切块大得离谱,有的火候忽大忽小,卖相难看,但安师傅很满意:“这才叫广撒网,哪个方向都别漏。”

进化搜索的第一步,就是生成这样的“第一批试验品”,称为初始种群(population)。种群中的每个方案是一个个体(individual),它们从搜索空间中随机采样(random sampling)得到。为了保证不遗漏任何可能有希望的区域,采样还要尽量均匀,避免 20 道菜全挤在同一种口味上——这就是多样性(diversity)。

假设种群规模为 P,第 0 代种群写作:

“第一批 20 道菜虽然大多难以下咽,但重要的是它们长满了整个口味地图。”安师傅把试吃结果记在本子上,心里已有了下一锅的灵感——好的方向,慢慢浮出水面。

P0={x1, x2, …, xP},xi∼Uniform(S)\displaystyle \mathcal{P}_0 = \{ x_1,\, x_2,\, \dots,\, x_P \}, \qquad x_i \sim \mathrm{Uniform}(\mathcal{S})
初始种群由 P 个从搜索空间均匀随机采样得到的调度方案组成。种群的“杂”是后续进化的资本。
  1. 种群记号\(\mathcal{P}_0\) 表示进化的第 0 代种群,也就是安师傅的第一批实验菜
    P0\mathcal{P}_0
  2. 个体与空间\(x_i\) 是第 i 个调度方案个体,它属于整个搜索空间 \(\mathcal{S}\)
    xi∈Sx_i \in \mathcal{S}
  3. 均匀随机采样\(x_i \sim \mathrm{Uniform}(\mathcal{S})\) 表示每个个体独立、均匀地从搜索空间抽取,保证初始覆盖
    xi∼Uniform(S)x_i \sim \mathrm{Uniform}(\mathcal{S})
  4. 种群规模 PP 是每代保留的个体总数,太小探索不足、太大每代评估开销高,Ansor 中通常取几十到几百
    P=40P = 40

适应度评估:老厨师的直觉与食客的舌头

试菜是有成本的。安师傅的招牌菜工序复杂,一道菜从备料到出锅要 5 分钟,20 道就是 100 分钟,这还不算顾客等菜的不耐烦。聪明的安师傅想了个办法:先凭自己几十年的经验(直觉)快速扫一眼,把明显不行的菜直接划掉;只有少数看着有潜力的菜,才真正做给食客们试吃(实测)。食客的反馈,又反过来修正他的直觉。

这就是代价模型(cost model)与实际测量(measurement)的双轨评估。Ansor 训练一个代价模型 \(f_\theta(x)\) 来预测调度方案 x 的运行性能,用它给种群中所有个体打分排序;排名前 k 的候选才上真机实测。实测获得的真实性能数据会加入训练集,微调模型参数 θ,让“老厨师的直觉”越来越准。

评估流程可以表示为:

“光靠直觉会看走眼,光靠试吃要等到天黑。”安师傅的双轨策略,让每次试吃都花在刀刃上,而他的经验也在一次次反馈中进化——这正是 Ansor 能快速锁定好方案的关键。

f^(x)=fθ(x),Mt={x∈Pt∣rank(f^(x))≤k}\displaystyle \hat{f}(x) = f_{\theta}(x), \qquad\mathcal{M}_t = \left\{ x \in \mathcal{P}_t \mid \mathrm{rank}\big(\hat{f}(x)\big) \le k \right\}
代价模型为每个方案预测性能分,按分排序后只取前 k 名进行真实测量,实测数据再反馈更新模型。
  1. 模型打分\(\hat{f}(x)\) 是代价模型对调度方案 x 的预估性能,θ 为模型参数,训练数据来自历史实测记录
    f^(x)=fθ(x)\hat{f}(x) = f_{\theta}(x)
  2. 排名预筛对种群内所有个体按预测分排序,rank 函数给出每个个体在种群中的名次
    rank(f^(x))\mathrm{rank}\big(\hat{f}(x)\big)
  3. 选取实测集\(\mathcal{M}_t\) 是第 t 代被选中实测的个体集合,只保留预测排名前 k 的候选,其余不下锅
    Mt={x∈Pt∣rank(f^(x))≤k}\mathcal{M}_t = \{ x \in \mathcal{P}_t \mid \mathrm{rank}(\hat{f}(x)) \le k \}
  4. 反馈修正实测得到的真实耗时 \(y_{\mathrm{meas}}(x)\) 会用于更新模型参数 θ,使预测逐步逼近真实性能
    θ←θ−η∇θL(fθ(x), ymeas(x))\theta \leftarrow \theta - \eta \nabla_\theta L\big(f_\theta(x),\, y_{\mathrm{meas}}(x)\big)

进化算子:交叉、变异与选择

第一轮试吃结束,安师傅对着成绩单琢磨:第 3 道菜的火候堪称完美,第 11 道菜的刀工让人惊艳,可惜它们各自都有短板。他灵机一动,把第 3 道的火候和第 11 道的刀工拼到一道新菜里——这就是“交叉”。偶尔,他还会故意手一抖多撒一把盐,给新菜加点“意外”——这就是“变异”。

进化算子(evolution operator)是驱动种群升级的引擎。选择(selection)负责决定谁有资格当父母:锦标赛选择(tournament selection)从种群中随机抽出几个个体“比武”,适应度最高的胜出。交叉(crossover)把两个父代方案的调度特征拼接成子代。变异(mutation)以一定概率随机扰动某个参数,比如把分块大小从 64 改成 128。精英保留(elitism)则把每代最优个体原封不动地放进下一代,防止好方案失传。子代生成规则可写成:

安师傅的新菜一批批出锅:火候基因、刀工基因在种群中像口碑一样传开,偶尔的“手抖”又带来惊喜。好味道在一代代进化中不断叠加,离那道完美招牌菜越来越近。

xchild={crossover(xa, xb)概率为 pcmutate(xa)概率为 pmxa概率为 1−pc−pm\displaystyle x_{\mathrm{child}} = \begin{cases}\mathrm{crossover}(x_a,\, x_b) & \text{概率为 } p_c \\\mathrm{mutate}(x_a) & \text{概率为 } p_m \\x_a & \text{概率为 } 1 - p_c - p_m\end{cases}
子代有大概率由两个父代交叉生成,小概率发生变异,极小概率原样保留父代。三段概率之和为 1。
  1. 父代挑选\(x_a\)、\(x_b\) 是经过锦标赛选择选出的优秀父代,它们带着被验证过的“好基因”
    xa, xb∈Ptx_a,\, x_b \in \mathcal{P}_t
  2. 交叉分支以概率 \(p_c\) 将两个父代的调度片段(如分块大小、向量宽度)重组生成新个体
    xchild=crossover(xa,xb)x_{\mathrm{child}} = \mathrm{crossover}(x_a, x_b)
  3. 变异分支以概率 \(p_m\) 对单个父代做小幅随机扰动,产生父代没有的新参数组合
    xchild=mutate(xa)x_{\mathrm{child}} = \mathrm{mutate}(x_a)
  4. 概率归一\(p_c + p_m < 1\),余下概率直接继承父代,保证种群不会因剧烈变化而失稳
    pc+pm<1p_c + p_m < 1

迭代收敛:有限预算内的逼近

安师傅给自己立下规矩:最多试 50 锅,每锅 20 道,预算用光就收工。另外,如果连续几锅都没能做出比之前更好的菜,说明已经接近这道菜的“天花板”,再耗下去也是浪费。他把规则贴在厨房墙上,提醒自己:进化的目的是在有限时间内端出最好的菜,而不是永远试下去。

迭代(iteration)是进化搜索的主循环:评估当前种群 → 选择父代 → 交叉变异生成下一代 → 再评估,如此循环 T 代。整个过程中,算法始终记录着历史最优个体。收敛判定通常看相邻两代最优适应度的提升量 \(\Delta f_t\) 是否跌破阈值 ε,若长期无改善则提前终止。Ansor 的实际运行也受总时长、总测量次数预算约束。最终返回的最优方案为:

50 锅很快用完,安师傅端出那盘集大成之作。它不是菜谱册子里每一页都试过的“理论最好”,却是试过的几千道菜里最棒的一盘——这正是工程世界的聪明活法。

x∗=arg⁡max⁡x∈⋃t=0TPtfmeas(x),Δft=fbest(Pt+1)−fbest(Pt)≤ε\displaystyle x^{*} = \arg\max_{x \in \bigcup_{t=0}^{T} \mathcal{P}_t} f_{\mathrm{meas}}(x), \qquad\Delta f_t = f_{\mathrm{best}}(\mathcal{P}_{t+1}) - f_{\mathrm{best}}(\mathcal{P}_t) \le \varepsilon
最优调度是历次迭代中真实测量性能最好的个体;当相邻两代最优性能提升小于阈值时,判定收敛并停止。
  1. 历史最优\(x^{*}\) 是所有世代里实测性能最佳的个体,用 arg max 选出这个“历代最强者”
    x∗=arg⁡max⁡xfmeas(x)x^{*} = \arg\max_{x} f_{\mathrm{meas}}(x)
  2. 世代并集将第 0 代到第 T 代种群合并成一个集合,最优者就藏在这个大集合里
    ⋃t=0TPt\bigcup_{t=0}^{T} \mathcal{P}_t
  3. 收敛判据\(\Delta f_t\) 是相邻两代最优适应度之差,当它小于阈值 ε 时认为搜索趋于饱和,可以收工
    Δft≤ε\Delta f_t \le \varepsilon
  4. 预算上限T 是最大进化代数,对应编译时的总时间预算,防止搜索无限进行下去
    T=30T = 30

对比优势:为何碾压网格搜索

如果安师傅是个死心眼的“网格搜索”厨师,他会怎么做?把菜谱册子从第 1 页开始,一页一页全部做一遍。以每道 5 分钟算,做完 \(10^{20}\) 道菜需要千亿年。如果是个“随机搜索”厨师,他每天随机抽几页做,做完就忘,永远不知道哪道更好——没有记忆,就没有进步。

网格搜索(grid search)枚举搜索空间中所有组合,开销为完整空间大小;随机搜索(random search)虽然能覆盖一些点,但每轮彼此独立,没有利用已发现的好区域。进化搜索通过选择压力把算力集中在有希望的区域,同时保留一定探索能力,实际评估次数只是种群规模 P 与代数 T 的乘积:

安师傅的进化菜谱最终成了餐厅招牌。同样的思路,在 Ansor 中对 ResNet、BERT 等真实模型做了验证,开发者们发现:曾经需要手工调好几天的算子,进化搜索自动跑几十分钟就能逼近甚至超越人工调优的性能。这就是“聪明试错”对“笨拙穷举”的全面碾压。

Nevo=P×T≪Ngrid=∏i=1kni\displaystyle N_{\mathrm{evo}} = P \times T \ll N_{\mathrm{grid}} = \prod_{i=1}^{k} n_i
进化搜索的评估次数等于种群规模乘以进化代数,通常只有几千次,远小于网格搜索所需的枚举总量。
  1. 进化开销\(N_{\mathrm{evo}}\) 是进化搜索实测/评估的个体总数,等于种群规模 P 乘代数 T
    Nevo=P×TN_{\mathrm{evo}} = P \times T
  2. 网格开销\(N_{\mathrm{grid}}\) 是网格搜索需要枚举的全部组合数,即整个搜索空间的大小
    Ngrid=∏i=1kniN_{\mathrm{grid}} = \prod_{i=1}^{k} n_i
  3. 差距悬殊当搜索空间有 \(10^{20}\) 种方案时,网格搜索要试 \(10^{20}\) 次,而进化搜索可能只要 \(40 \times 30 = 1200\) 次
    1020≫1.2×10310^{20} \gg 1.2 \times 10^{3}
  4. 性价比根源进化搜索不做无用功——每代淘汰劣质方案、繁殖优质方案,评估预算花在最值得探索的地方

AI 应用场景

深度学习编译器的算子自动调优

阶段:模型部署优化 / 推理性能调优

解决的问题:手工调优依赖资深工程师的直觉和经验,能覆盖的调度组合极其有限;传统网格搜索面对 \(10^{20}\) 以上的搜索空间完全不可行。进化搜索自动在调度空间中寻找最优方案,把“老师傅经验”变成“算法自动探索”。

具体案例:TVM 编译器对 ResNet-50 的卷积算子做自动调优时,先用代价模型对随机采样的几十个候选打分排序,挑出 top-k 到真实 GPU 上测量,再用实测数据微调模型。经过约 30 轮进化,在十几分钟内找到了比默认实现快 2~3 倍的调度方案,且全程无需人工干预。

数据库查询计划自动优化

阶段:数据查询优化

解决的问题:查询优化器面对表连接顺序、索引选择、并行度设置等参数,同样存在组合爆炸。传统规则优化器依赖手工编写的启发式规则,容易错过反直觉的最优计划。

具体案例:借鉴进化搜索思想,优化器将一条 SQL 查询的执行计划编码为“基因”,随机生成一批候选计划,用统计信息代价模型预筛、抽样执行少量计划得到真实延迟,再交叉、变异产生下一代。数轮迭代后,自动找到比默认优化器快数倍的执行计划,尤其在多表 Join 场景收益显著。

Python 演示

python74 行
import random # 搜索空间: 每种调度参数的可选值TILE = [16, 32, 64, 128, 256]     # 分块大小VEC = [2, 4, 8, 16]               # 向量化宽度STAGE = [1, 2, 3, 4]              # 流水级数POP_SIZE = 12GENERATIONS = 20MUT_RATE = 0.2CACHE = {}                        # 测量缓存, 同一方案只实测一次 def random_sample():    # 从搜索空间均匀随机采样一个调度方案    return (random.choice(TILE), random.choice(VEC), random.choice(STAGE)) def cost_model(s):    # 模拟代价模型: 预估运行耗时, 越小越好    t, v, st = s    return 4000.0 / t + v * 2.0 + st * 3.0 + random.uniform(0, 5) def real_measure(s):    # 模拟真实测量: 在预估基础上加噪声波动, 并缓存结果    if s not in CACHE:        CACHE[s] = cost_model(s) + random.gauss(0, 3)    return CACHE[s] def fitness(s):    # 耗时越小适应度越高, 进化搜索按适应度最大化来排    return -real_measure(s) def crossover(a, b):    # 均匀交叉: 每个维度随机取自一个父代    return tuple(a[i] if random.random() < 0.5 else b[i] for i in range(3)) def mutate(s):    # 变异: 以一定概率扰动每个维度    t, v, st = s    if random.random() < MUT_RATE:        t = random.choice(TILE)    if random.random() < MUT_RATE:        v = random.choice(VEC)    if random.random() < MUT_RATE:        st = random.choice(STAGE)    return (t, v, st) def tournament_select(pop, k=3):    # 锦标赛选择: 随机挑 k 个, 取适应度最高者    best = None    for _ in range(k):        ind = random.choice(pop)        if best is None or fitness(ind) > fitness(best):            best = ind    return best def evolve():    # 初始化种群    pop = [random_sample() for _ in range(POP_SIZE)]    for gen in range(GENERATIONS):        pop.sort(key=fitness, reverse=True)        elites = pop[:2]                    # 精英保留        next_gen = elites[:]        while len(next_gen) < POP_SIZE:            p1 = tournament_select(pop)            p2 = tournament_select(pop)            child = mutate(crossover(p1, p2))            next_gen.append(child)        pop = next_gen        best = max(pop, key=fitness)        print('gen', gen, 'best cost %.1f' % -fitness(best), best)    return max(pop, key=fitness) if __name__ == '__main__':    best = evolve()    print('best schedule:', best, 'cost %.1f' % -fitness(best))
目的:用 20 行核心逻辑演示进化搜索四大组件——初始种群、适应度评估、交叉变异、精英保留,运行后观察最优耗时代代下降。
  1. CACHE = {}测量缓存池,模拟 Ansor 中“同一调度方案只实测一次”的工程约束,避免重复测量浪费预算
  2. pop = [random_sample() for _ in range(POP_SIZE)]初始化种群,从搜索空间均匀随机采样 12 个候选调度
  3. pop.sort(key=fitness, reverse=True)按适应度从高到低排序,让优秀方案排在最前
  4. elites = pop[:2]精英保留:最优秀的 2 个方案原样进入下一代,防止好基因丢失
  5. child = mutate(crossover(p1, p2))先交叉再变异,把两个父代的调度特征重组并引入随机扰动
  6. if s not in CACHE:实测前先查缓存,命中则直接返回已测结果,节省昂贵测量开销

常见误区

误区进化搜索本质上是随机瞎试,和随机搜索没区别,试的次数多了总能蒙到一个好方案。

正解随机搜索每轮彼此独立,没有任何记忆;进化搜索每一代都根据适应度筛选父代,优秀方案的特征通过交叉、变异逐代累积,越试越有方向。就像安师傅不是闭眼做菜,而是把上一轮的好火候、好刀工“遗传”给下一代,这是有方向的搜索。用一句话区分:随机搜索是蒙着眼扔飞镖,进化搜索是每次看上一镖落点再调整姿势。

为何常见:变异和随机采样都带有随机性,初学者容易把“用了随机数”和“纯随机搜索”混为一谈,忽略了选择压力这个核心差异。

误区代价模型预测肯定有误差,既然要追求最优性能,那每个候选调度都应该实际运行一遍,以实测为准。

正解实测一次可能需要几秒甚至几分钟,而搜索空间有 \(10^{20}\) 个候选,全测等于没测。Ansor 的做法是:先用代价模型给全部候选打分排序,只把排名前 k 的少数个体送上真机,实测数据再反哺模型,让预测越来越准。这就像主厨不可能让每道菜都经食客全流程品鉴,先用经验筛出有希望的那几道,品鉴才有意义。

为何常见:直觉上“实测=真理”没有错,但忽略了实测的时间成本恰恰是自动调优要解决的核心瓶颈,预算有限才是工程常态。

误区既然一直在进化,多跑几代肯定能找到理论最快的那个调度方案。

正解进化搜索是启发式算法,在有限预算内逼近最优而非保证全局最优。它需要在“探索新区域”和“利用已发现的好区域”之间做折中,可能陷入局部最优。Ansor 的收敛判据和预算控制,本质上是接受“够好”的工程现实——就像安师傅 50 锅预算用完就收工,端出的是“试过的所有菜里最好的一盘”,而不是“全宇宙理论最优的一盘”。

为何常见:受生物进化“适者生存”叙事的影响,人们误以为自然选择也有完美终点,忽略了进化本身是受环境资源约束的不断适应过程。

误区多变异就能多尝试新方案,变异率设得越高,搜索覆盖越广,效率自然越高。

正解变异率过高会破坏已被验证的优秀方案,种群退化成随机游走;过低则种群固化、容易早熟陷入局部最优。工程中一般把变异率设在 0.1~0.3,并配合精英保留维持稳定性。这就像做菜:每次多撒一撮盐是新尝试,但把整罐盐倒进去,连前几代积累的好味道也一并毁掉了。进化搜索要的是“在稳定中探索”,而不是“为了探索而自毁”。

为何常见:把“探索”理解成越多越好,忽略了探索与利用之间的平衡——有效的搜索既要敢尝试新路,也要守住已验证的好成果。

面试题

Q1. 进化搜索中“适应度函数”的作用是?

单选题 · easy

  • A.衡量调度方案的性能优劣← 正确答案
  • B.控制在变异时的随机概率
  • C.计算搜索空间的大小范围
  • D.将调度方案编码为二进制

答案:A。适应度函数是进化搜索的“评分标准”,用来衡量每个调度方案的好坏,数值越高代表性能越好。选项 B 是变异率做的事,C 是搜索空间分析的范畴,D 是编码表示的工作,均与适应度函数无关。好比安师傅试吃后的打分,决定了哪道菜值得“繁殖后代”。

Q2. Ansor 采用代价模型预筛候选的主要作用是?

单选题 · mid

  • A.完全替代真实测量的结果
  • B.减少昂贵耗时的实测次数← 正确答案
  • C.增大搜索空间的覆盖范围
  • D.消除进化过程的所有随机性

答案:B。代价模型用预测分给所有候选排序,只挑排名前 k 的个体去实测,从而把昂贵的真机测量次数压到最小。它不能完全替代实测(预测有误差),也不会改变搜索空间或消除随机性。就像安师傅先用经验筛菜,而不是让每道菜都下锅。

Q3. 交叉操作在进化搜索中的含义是?

单选题 · mid

  • A.随机丢弃种群里的劣质个体
  • B.组合两个父代的调度方案片段← 正确答案
  • C.对单个方案做小幅随机参数扰动
  • D.让最优个体直接原样进入下一代

答案:B。交叉是把两个父代方案的调度特征(如分块大小、向量宽度)重新组合生成子代,相当于把第 3 道菜的火候和第 11 道菜的刀工拼到一盘。A 是淘汰策略,C 是变异,D 是精英保留,三者都不是交叉。

Q4. 精英保留策略的核心思想是?

单选题 · easy

  • A.将最优个体无修改地传给下一代← 正确答案
  • B.只用精英个体参与交叉繁殖
  • C.淘汰所有新生成的子代个体
  • D.实时增大种群的个体数量

答案:A。精英保留保证每代最优的个体原封不动进入下一代,防止交叉变异等操作把好方案破坏掉。它只是“保底”,不是让精英独占繁殖权,更不是淘汰子代或扩大种群。就像安师傅每锅必定留一盘上一轮最受欢迎的菜,不会因为做新菜就把老招牌丢了。

Q5. 为什么网格搜索在 Ansor 的调度空间中不可行?

单选题 · hard

  • A.调度空间中的方案都是相同的
  • B.组合数量随参数增加呈指数爆炸← 正确答案
  • C.性能测量结果没有任何误差
  • D.编译器根本不支持批量测试

答案:B。调度空间的大小是各调度原语可选值的连乘,随参数种类增加呈指数爆炸,常见规模超过 \(10^{20}\)。网格搜索要枚举全部组合,时间上完全不可行。A、C、D 都与事实相反:方案各不相同、测量有噪声、编译器完全支持批量测试。

Q6. 关于变异率设置的正确理解是?

单选题 · mid

  • A.变异率设置得越高搜索效果越好
  • B.变异率必须设为零才能保持稳定
  • C.过高会破坏优秀解需要折中设置← 正确答案
  • D.变异率与最终搜索效率完全无关

答案:C。变异率过高会破坏已被验证的优秀方案,种群退化为随机游走;过低则种群固化、易早熟。工程上通常取 0.1~0.3 的折中值,配合精英保留维持稳定,所以 C 正确。A 忽略了过度变异的破坏性,B 走向另一个极端,D 否认了变异的作用。

Q7. 进化搜索中的“个体”在 Ansor 中指?

单选题 · easy

  • A.一套具体的算子调度方案← 正确答案
  • B.一个完整的神经网络模型
  • C.一台用于测试的物理机器
  • D.一组用于训练的数据样本

答案:A。在 Ansor 的进化搜索里,一个个体就是一份具体的调度方案,包含分块大小、向量宽度等一系列参数取值。种群就是这些调度方案的集合,而不是神经网络模型、测试机器或数据集。好比一道具体的菜,而不是整个餐厅。

Q8. 以下属于进化搜索核心操作的有?

多选题 · mid

  • A.交叉重组两个父代的调度方案← 正确答案
  • B.变异扰动单个方案的调度参数← 正确答案
  • C.用梯度下降更新整个种群的权重
  • D.锦标赛选择出优质的父代个体← 正确答案

答案:ABD。进化搜索的三大核心操作是选择(锦标赛选择)、交叉(重组父代方案)、变异(扰动参数),所以 A、B、D 正确。梯度下降是训练神经网络代价模型时可能用到的优化器,不是进化搜索本身的算子。

Q9. 关于代价模型与实际测量的关系,正确的是?

多选题 · hard

  • A.模型预测用于排序并筛选候测个体← 正确答案
  • B.实测数据反馈用于更新模型参数← 正确答案
  • C.实测结果完全不存在任何测量噪声
  • D.两者结合可压缩高开销的实测次数← 正确答案

答案:ABD。Ansor 用代价模型预测性能并排序,只选前 k 名实测(A),实测数据反哺模型让预测更准(B),两者结合把实测次数从天文数字压缩到几千(D)。实测必然受硬件波动、频率变化等影响而有噪声,C 错误。这就像安师傅的经验筛选 + 食客真实反馈互相促进。

Q10. 哪些手段可以平衡进化搜索的“探索”与“利用”?

多选题 · hard

  • A.设置适当的变异率避免种群固化← 正确答案
  • B.精英保留确保已发现优解不丢失← 正确答案
  • C.锦标赛选择给优秀个体更多繁殖机会← 正确答案
  • D.每代全部重新随机生成种群个体

答案:ABC。适当变异率让种群保持探索新区域的能力(A),精英保留守住已发现的优解、保证利用(B),锦标赛选择把繁殖机会倾斜给优秀个体、强化利用(C)。D 每代全部重新随机生成等于抛弃了所有进化积累,完全退化为随机搜索,谈不上平衡。