生成、筛选、评判、选择
要在巨大的空间里找出少量优秀设计,就先造远超需要的候选,用最便宜的测试先刷掉大多数,只把活下来的给人看。这篇方法论文把六个阶段各自的数学写清楚:怎么排阶段顺序、造多少候选、怎么定阈值。
中文
复制

生成、过滤、评判、选择
摘要
要在巨大的设计空间里找到少数几个优秀方案,就造出远超所需的候选,先用最廉价的检验淘汰大部分,只把幸存者摆到人面前。
方法分六个阶段。生成器造出候选。代码里的精确检查删掉不合法的。距离度量删掉近似重复的。廉价模型删掉明显差的。强模型给剩下的打分排序。选择规则挑出一份简短、多样的清单交给人。
本文定义每个阶段并给出其数学形式:如何构建生成器,如何按成本排列各阶段,该造多少候选,如何设定廉价模型的阈值使其极少误删好设计,如何用有噪声的评判者排序,如何选出有保证的多样最终集合,以及如何把结果反馈回去让生成器变好。文中还列出该方法会怎样失败,以及如何针对每种失败做检验。
主要结果是一个公式(第 1 节)。在简单假设下,所选设计的期望质量与评判者的准确度成正比,而只与候选数量的对数的平方根成正比。超过一定规模后,更好的评判比更多的候选更值钱。
1. 问题
一个人坐下来大约能看 20 个设计,但好设计可能千里挑一。目标是把那一个摆到人面前,又不让人去看另外 999 个。
手工做设计很慢,因为每一个都要占用作者的全部注意力。评判一个做完的设计只需扫一眼。本方法把力气从制作挪到评判,并把大部分评判交给机器。
为什么规模有用。 独立地造出 N 个设计。设 q 为所有设计中属于你所关注的那一档的比例。至少命中一个的概率是
令 qN = 3,即可得到 95%。因此,大约 N ≈ 3/q 个设计,就能有 95% 的概率至少命中一次。当 q = 1/1,000 时,也就是 3,000 个设计。
为什么单靠数量不再划算。 设每个设计的真实质量为 f,呈钟形分布,均值为 μ,标准差为 σ。N 个设计中最佳者的期望值为
Z_N 是 N 个标准正态抽样中最大值的期望。平方根公式算出的结果略偏高。精确值是:N = 1,000 时 Z = 3.3,100,000 时 Z = 4.4,1,000,000 时 Z = 4.9。样本量增加一百倍,大约只多换来一个 σ。
为什么评判准确度更重要。 实践中我们按分数 u 排序,而不是按 f 排序。设 r 为分数与 f 之间的相关系数。这就是评判的准确度,从 0(毫无用处)到 1(完全准确)。如果 u 和 f 服从联合钟形分布,那么得分最高的设计的期望质量为
原因在于:对于联合钟形变量,给定分数 u 时 f 的期望为 μ + rσ 乘以 u 高出其均值多少个标准差。N 个分数中的最高分大约高出 Z_N。
比较两种投入方式,从 N = 100,000、r = 0.5 出发。N 翻倍使 Z 从 4.40 升到 4.55,质量提升 0.5 × 0.15σ ≈ 0.07σ。r 从 0.5 升到 0.6,质量提升 0.1 × 4.40σ ≈ 0.44σ。准确率提高 0.1,约等于把规模翻六倍。
两点提醒。钟形只是一个假设,真实的尾部并非如此,所以这些公式用来判断量级如何缩放,而不是用来做预测。另外,多个评审组成的漏斗,其行为等同于一个合并后的评审,其准确率 r 可以测量(第 13 节)。
对当事人来说,变化是什么。 你不再是每个设计的作者。你写 brief,然后对一份短名单说 yes 或 no。
2. 定义
下文每个术语在本文余下部分都严格按此含义使用。
- 设计(x)。 一个完整候选,以程序可读取、可检查的数据形式存储。
- 空间(X)。 生成器可能产出的全部设计。
- Brief(b)。 你想要什么的陈述。它分三层:规则(必须)、目标(偏好)、品味(感觉)。见第 7 节。
- 生成器(G)。 一个程序,给定参数 θ 和种子 s,返回设计 x = G(θ, s)。相同输入永远给出相同设计。
- 检查(e_j)。 一个返回 1(通过)或 0(失败)的测试。当设计通过所有检查时,它是有效的:V(x) = e_1(x) × e_2(x) × … × e_J(x)。
- 余量(ξ_j)。 设计距离未通过检查 j 还有多远。为正表示它通过且尚有余地。为负表示它以该幅度未通过。
- 质量(f)。 写 brief 的人会觉得设计 x 有多好。只有那个人能说,而问他需要花他的时间。
- 好。 若 f(x) ≥ g,则设计是好的,其中门槛 g 在看任何结果之前就已固定。
- 分数(u)。 由模型或公式给出的对 f 的更廉价估计。它有误差。其准确率(r)是分数与 f 之间的相关性。
- 阶段。 一个步骤,接收一批设计并放行其中一部分。阶段 i 有每个设计的成本 c_i 和通过率 p_i,即它放行的设计占比。
- 召回率(R_i)。 进入阶段 i 的好设计中,它放行的占比。召回率低意味着好设计正在被丢掉。
- 精确率。 一个阶段放行的设计中,好的占比。
- 特征(φ)。 一组描述设计 x 是什么样子的数字,例如尺寸、对称性、所用部件。它们不说明它是否好。
- 距离(d)。 一个数 d(x, y),表示两个设计有多不同,由其特征算出。见第 6 节。
- 档案。 目前保留的设计。新设计与之比较以检测重复。
- 短名单。 最终展示给当事人的 k 个设计。
- 审计。 把某阶段拒绝的设计随机抽样后照样送下去,以测量该阶段错误丢弃了什么。
3. 总览:漏斗
共六个阶段,每个阶段处理单个设计的成本都低于后一阶段,从而将 100,000 个候选方案缩减为一份 12 个方案的候选清单。
[embedded content: illustrative run · 100,000 designs generated, 12 shown to the person]
前三个阶段由代码执行,结果是精确的。剩余的一批先交给一个廉价模型,再交给一个强模型来评判。一条筛选规则将 40 个设计收窄至 12 个,你从中做出选择。结果会回流到生成器(第 12 节)。
| 阶段 | 它回答的问题 | 章节 |
|---|---|---|
| 1 生成 | 我们能造出一个候选方案吗? | 4 |
| 2 校验 | 它违反规则吗? | 5 |
| 3 描述与去重 | 它是新的吗? | 6 |
| 4 廉价评判 | 有明确的理由把它丢掉吗? | 9 |
| 5 强模型评判 | 它有多好,排序如何? | 10 |
| 6 筛选 | 哪几个、分布如何,交给用户? | 11 |
第 7 节和第 8 节穿插在阶段之间。第 7 节将需求说明转化为规则和目标,第 8 节确定预算。
4. 阶段 1:生成
生成器决定了后续所有环节的上限,因为任何后续阶段都无法挑出一个从未被造出来的设计。它必须满足五项要求。
- 在成本允许的范围内,构造即合法。 它造出的非法设计越少,浪费的工作就越少。
- 覆盖广。 它能触及你会接受的每一种设计。
- 可控。 它有几个旋钮,每个都有可见的效果。
- 可复现。 相同的参数和种子总是给出相同的设计。
- 快。 单核每分钟数千个设计。
单元格与域模型(波函数坍缩)。 将设计铺成网格上的单元格。每个单元格 c 有一个域 D_c,即该处仍然可能的选项集合。开始时,每个选项在每个单元格里都可能。生成过程不断收缩这些域,直到每个域只剩一个选项。
兼容性只需写一次。对于选项 t 和方向 d,A_d(t) 是在方向 d 上与 t 相邻时被允许的选项集合。当 D_c 收缩时,方向 d 上的每个邻居 n 都会被剪枝:
不断重复,直到不再发生变化。这个过程称为传播。如果某个域变为空集,说明该设计遇到了矛盾。
下一步是决定哪个单元格。 为每个选项 t 赋予权重 w_t。在单元格 c 中,令 W_c 为 D_c 上所有 w_t 之和,并令 p_t = w_t / W_c。该单元格的熵为
优先确定熵最低的未定格子,再掺入一点随机抖动,让每次运行时打平的结果有所不同。熵低意味着现实可选值少,因此这个格子最有可能在之后引发矛盾。早点定下来,就能早点发现问题。
选哪个选项。 在格子 c 中采样选项 t,概率正比于
这里 n 遍历已经确定下来的邻居,t_n 是那里选中的选项,N(t, t') 统计在你的示例设计中 t' 紧挨着 t 出现的次数。偏置 β ≥ 0 决定输出在多大程度上照搬示例。β = 0 时完全忽略示例。上限 3 防止某一对过于常见的组合占据主导。对选项在物理上会连接的每个邻居,可以再加一个内聚因子 (1 + γ),它偏向连通的方案。
密度。 添加一个名为 empty 的选项,权重为 w_0。设 W_real 为所有非空选项的权重之和。在无约束的格子里,empty 的概率是 w_0 / (w_0 + W_real)。若要让填充格子的期望占比等于选定的密度 ρ,则令
检查:空着的概率是 1 − ρ,所以填满的概率是 ρ。
全局限制。 诸如部件 k 最多 N_k 个副本这样的限制不是邻居规则,传播看不到它。维护一个实时计数。当部件 k 的计数达到 N_k 时,从每个未定单元格中移除 k 并传播。这仍可能在后期失败。一旦出现矛盾,撤销上一次选择,在该单元格中禁用该选项,再试另一个。这就是回溯。最多允许 B 次回溯,然后放弃本轮,用新种子重新开始。如果一轮在预算内成功的概率为 q_s,那么每次成功所需的期望轮数是 1/q_s。
两层随机性。 一轮内部的差异来自种子 s,改变的是细节。轮与轮之间的差异来自参数 θ,它从先验 π_0(θ) 中抽取,应当改变的是整体特征:密度、偏置、整体形状。每一轮都要随机抽取 θ,而不只是抽取种子,否则所有设计看起来都像是同一个设计的重复。
输出的多样性有多大? 生成器是一个有偏采样器。它的输出概率 p(x) 没有闭式解,所以只能去测量。定义设计的有效数量
如果所有 M 个设计出现的概率相同,这个值就等于 M。要估计它,可以生成 N 个设计,然后数出其中距离小于某个小 ε 的重复对数量 C。每一对发生碰撞的概率是 Σ p² = 1/N_eff,因此期望数量为 C = N(N−1)/2 × 1/N_eff,而
示例:N = 2,000 个设计、C = 40 对重复,得到 N_eff ≈ 50,000。如果 C = 0,你只能知道 N_eff 大于约 N(N−1)/2。N_eff 小,说明生成器在自我重复,需要更大的旋钮范围。
其他生成器同样适用。 任何满足这五项要求的采样器都能填进这个位置:从语法中采样、带修复的随机游走、对种子设计做变异、物理模拟器,或非零温度的 language model。无论选哪个,本节之后的内容都一样。
旋钮设计。 每个旋钮应当只改变一个你能看见、能叫出名字的属性。你描述不出来的旋钮,学习循环(第 12 节)也用不上。
5. 阶段 2:验证
用代码写成的检查是精确的、廉价的,而且从不会累,所以在任何模型看到设计之前先跑它们。一个设计通过所有检查,才算有效:
检查长什么样。 常见的有六种:
- 几何。 任意两个实体部分不共享空间。检验:重叠体积 ≤ 一个小容差。
- 连通。 零件及其连接的图是一个连通整体。
- 物理。 质心落在支撑区域之上。
- 可装配。 存在某种顺序,使每个零件都能沿一条无阻挡路径到达其位置。
- 库存。 零件 k 最多使用 N_k 次。
- 语法。 设计中的每个关节都在允许关节列表上。
裕度。 对每项检查记录一个有符号裕度 ξ_j(x),即使设计通过也要记录。几何检查中,ξ 是重叠体积的相反数。物理检查中,ξ 是质心到支撑区域边缘的距离。裕度免费带来三样东西。它标出值得再看一眼的擦边情况。它是后续学习的特征。它还说明容差是否合适:如果测量上的微小变化就能让检查结果翻转,容差就太紧了。只有当 |ξ| 大于你的测量误差时,才该相信一次通过或失败。
检查说的是绝不允许,不是最好别。 过严的检查会悄悄删掉好设计,后面的阶段再也找不回来。只有违反它绝不可接受的东西,才该做成检查。其余一切都是目标(第 7 节)。
修复而不是丢弃。 有时小修一下胜过直接扔掉,比如移除那个造成重叠的零件。修复能提高产出率,但会让设计池偏向修复过的形态。统计有多少设计需要修复,并保存一个修复标记,这样效果可以被审计。
有效指的是通过我们写下的规则。 检查的好坏取决于写检查的人。每一个漏过去的无效设计,都会变成一条新检查和一项永久测试。宽泛的生成器就是这样同时充当规则的 fuzzer:它找出你没想到的情况。
为什么用代码而不是模型。 模型更慢、更不精确,而且会以你无法预测的方式出错。如果一条规则能写成测试,就写成测试。
通过率。 生成的设计中有效的比例是 p_V = Pr(V = 1)。用样本估计它,区间见第 8 节。如果 p_V 低于几个百分点,该改的是生成器而不是检查,因为你的算力大部分都花在了夭折的设计上。
6. 阶段三:描述与去重
大多数生成器都会重复自己,所以在模型上花钱之前,先从每一组近似副本中保留一个设计。这需要一种能说明两个设计有多大差异的方法。
特征。 为每个有效设计计算一组数值 φ(x)。低成本的例子包括:整体尺寸、包围盒的填充比例、平衡点、各类零件的数量、对称性得分、颜色直方图,以及从正面、侧面和顶面看的轮廓。特征描述的是种类,不是好坏。对称性得分是指镜像后依然存在的零件所占的比例:
这里 n 是部件数量,方括号内的值在条件成立时为 1,否则为 0。
距离。 对每个特征重新缩放,以免某一维占据主导:φ'_j = (φ_j − μ_j) / σ_j,其中均值和标准差均在有效池上计算。然后
权重 ω_j ≥ 0 表示各特征对人眼的重要程度,初始时全部相等。把人最先注意到的特征权重调高,比如轮廓。
轮廓距离。 将每个轮廓渲染为二值网格 M。两个轮廓之间的差异由
Γ 是一组不应算作不同改动的变换,例如将设计旋转 180° 或做镜像。该分数为交并比。
新颖性门槛。 只有当设计 x 与所有已保留的设计都相距足够远时,才保留它:
A 是档案,δ 是最小距离。与 A 中所有条目逐一比对需要 |A| 次比较,所以一旦 A 超过几千,就该用空间索引,比如 k-d tree。δ 的选取标准是:低于它的样本对在人看来是一样的——把若干不同距离的样本对拿给人看,记下他们从哪里开始说「一样」。退而求其次,可以取随机样本对距离的第 10 百分位数。
饱和。 统计最近几百个设计的接受率 a = 接受数 / 尝试数。当 a 接近零,说明在这个 δ 下生成器已经造不出新设计了。此时的档案大小就是覆盖度:生成器能造出多少个 δ 分离的设计。应对办法是放宽 θ 上的先验,或者停下来。
质量-多样性(MAP-Elites)。 想看到整个空间而不只是顶部,就选两三个行为特征 b(x),比如长度、高度、对称性。把每个特征切成若干区间,组成一张格子 κ。每个格子里只保留得分最高的设计:
这里需要一个分数 u,所以它排在 Section 9 和 Section 10 的评判器之后运行。两个汇总数字:coverage = 已填充单元格 / 总单元格,QD = 保留设计的分数之和。结果是一张映射表:每一种设计,对应找到的最好的那一个。Section 11 给出了挑选多样化集合的另一种方式。
7. 让任务书可计算
任务书里凡是程序能测量的东西都应该测量,因为测量既精确又免费。把任务书的每一行归入三层中的一层。
| 层 | 它回答的问题 | 由谁处理 | 例子 |
|---|---|---|---|
| 规则 | 什么永远不可接受? | 检查(Stage 2) | 必须能独立站立 |
| 目标 | 我偏好什么,偏好多少? | 一个公式 | 偏好紧凑的形状 |
| 品味 | 它感觉对吗? | 模型,然后是人 | 它看起来有目的性 |
把模糊的词变成度量。 问自己:要裁决一场关于这个词的争论,你会测量什么。Balanced 变成质心相对底面中心点的偏移量。Compact 变成包围盒中被填充的比例。Symmetric 变成 Section 6 里的 S(x)。一个度量只要排序结果和你的排序一致,就值得保留。自己给 20 个设计排序,对它们计算该度量,再用 Spearman 秩相关衡量一致性:
d_i 是设计 i 的两个排名之差,n 是设计的数量。取值为 1 表示顺序完全一致,0 表示毫无关系,−1 表示顺序完全相反。当 n = 20 时,低于约 0.45 的值可能只是偶然。
目标作为平滑门限。 指标 y_j 的目标有一个目标值 y*_j 和一个宽度 h_j,宽度表示偏离多少仍然可以接受。对于接近目标的情况:
至少就目标而言:
两者均返回一个 0 到 1 之间的数值,其中 1 表示最佳。
组合目标。 为每个目标分配一个权重 ν_j ≥ 0,且所有权重之和为 1。组合方式有两种:
求和让一个强目标可以掩盖一个弱目标。乘积——加权几何平均——则不行:只要任何一个 u_j 接近 0,u_0 就接近 0。每个目标都不可或缺时用乘积,目标之间可以互相权衡时用求和。
u_0 这个分数几乎不花什么代价,所以在 Stage 3 用它来决定一组近似重复的设计里保留哪一份。
晋升规则。 能往上提一层就往上提。当你找到一个能反映品味的指标时,品味就变成目标,因为公式胜过模型。只有当违反某条规则永远不可接受时,目标才变成规则,而且要先查清这条规则会删掉多少好设计(第 14 节)。
8. 预算:做多少个,按什么顺序做
成本主要由那个仍然要处理大量设计的最贵阶段决定,所以阶段的顺序和各自的通过率决定了这套方法是否负担得起。
成本与存活数。 设 N_0 为生成的设计数量。阶段 i 的通过率为 p_i,每个设计的成本为 c_i。进入阶段 i 的数量是 N_(i−1) = N_0 × p_1 × … × p_(i−1)。总成本和存活数量为
按每次淘汰的成本给阶段排序。 取两个可以互换顺序的阶段。若先跑阶段 1,每个设计的成本是 c_1 + p_1 c_2;若先跑阶段 2,成本则是 c_2 + p_2 c_1。阶段 1 应排在前面,当且仅当
证明:c_1 + p_1 c_2 < c_2 + p_2 c_1 等价于 c_1 (1 − p_2) < c_2 (1 − p_1)。比值 c / (1 − p) 是每剔除一个设计所付出的成本。按该比值递增的顺序执行各阶段。只要相邻两阶段的顺序颠倒,交换两者就能省成本,因此在各阶段相互独立时,按此排序最优。若各阶段不独立,就把这条规则当作参考,并实测。
召回率可组合。 生成、检查与去重剔除的是无效或重复的设计,而不是好的设计,所以只要检查本身正确,它们对好设计的召回率就是 1。只有评判阶段会损失好设计。如果廉价评判器和强评判器各自独立出错,那么最终走到末尾的好设计占比约为
要让 n_J 个评审员达到目标召回率 R*,就给每位评审员分配 (R*)^(1/n_J) 的召回率。当 R* = 0.8、评审员为两人时,每人需达到 0.89。如果评审员容易漏掉同一批设计,真实召回率会高于乘积,因此用乘积来估算是稳妥的。
该生成多少。 设 q 为一个生成的设计既有效又优秀的概率。要最终得到至少 m 个优秀设计,可用这条经验法则
好设计的数量近似服从均值为 N_0 q R_total 的泊松分布,其离散程度等于均值的平方根。2√m 这一项额外留出了两个离散度的安全余量。当 m = 1、R_total = 1 时,结果为 3/q,与第 1 节一致。
用区间估计一个比率。 要估计 q、p_V 或任何其他比率,就评判 n 个设计并数出 k 次命中。于是 p̂ = k/n,Wilson 95% 区间为
与教科书中的区间不同,它在 n 较小、p̂ 接近 0 或 1 时表现良好。要在最坏情况下把比率控制在 ±h 以内,需要 n ≈ 0.96 / h²。±0.05 约需 385 个设计,±0.10 约需 96 个。如果 q 很小,n 个随机样本中大约只有 nq 个合格设计。第 9 节介绍如何巧妙地打标签。
一次示例运行。 下面的成本和通过率是编出来的,只为演示算术。请替换成你实测的数值。
| 阶段 | 输入设计数 | 每个设计的成本 | 阶段成本 |
|---|---|---|---|
| 1 生成 | 100,000 | $0.00001 | $1.00 |
| 2 验证 | 100,000 | $0.00005 | $5.00 |
| 3 去重 | 40,000 | $0.000001 | $0.04 |
| 4 廉价评判 | 4,000 | $0.0005 | $2.00 |
| 5 强力评判 | 400 | $0.02 | $8.00 |
| 6 筛选 | 40 | 可忽略 | $0.00 |
| 合计 | $16.04 |
把 100,000 个设计直接送去强力评判要花 $2,000,贵出约 125 倍。按比率规则,去重应排在验证之前,因为它每次剔除的成本更低。但去重必须排在验证之后,因为归档里可能只保留有效设计。该规则假设各阶段相互独立,而这两个阶段并不独立。
额外预算该花在哪。 第 1 节已经说明,超过大约 100,000 个设计之后,评判准确率提升一点,抵得上把规模翻好几倍。在把预算花在更多设计上之前,先花在提高每个设计的重复次数、更好的评分标准和校准上(第 10 节和第 13 节)。
9. 阶段 4:廉价评判
廉价评判应当调到几乎不放过任何好设计。它不需要在其余部分判断正确,因为后面的强力评判负责精确率。
它看到什么、返回什么。 给廉价模型一个设计的渲染结果、阶段 2 和阶段 3 的指标文本,以及一个范围很窄的问题。它返回一个 0 到 1 之间的分数 u(x)。一个有用的技巧是问它是否存在明确的理由丢弃这个设计,而不是让它评价质量。这样就把模型变成了一个高召回率的过滤器。
通过阈值。 若 u(x) ≥ τ,设计通过。在已知好坏的设
提高 τ 会降低通过率,从而省钱,但也会降低召回率,从而漏掉好设计。
付费规则。 放行一个设计必然要付出 c_next,也就是强评判器的价格。丢掉它,如果它是好设计,就会损失 V_g,其中 V_g 是一个好设计对你而言的价值,单位与 c_next 相同,也就是你愿意为找到一个好设计付出的价格。当丢掉它的期望损失超过放行它的成本时,就放行:
示例:c_next = 2。只要好东西的概率不低于 1%,就放行。这正是廉价评判器阈值定得低的原因。
把分数变成概率。 在有标注的设计上(好则 y = 1),通过选取 a 和 b 来最大化对数似然,从而拟合出一条 logistic 曲线:
优质设计稀少时的标注。 标签来自强评判者或人工。如果 q = 2%,随机抽样中每 50 个设计才有一个优质设计。不如按分数区间来标注。以概率 π_i 标注每个设计,在优质设计可能出现、阈值将要落位的区间里调高概率。然后给每个标签加权 1/π_i,这样一个被标注的设计就代表它所能代表的那么多个设计(Horvitz–Thompson 估计量):
你需要多少个好标签。 如果评判器通过了样本中全部 n_g 个好设计,那么其漏检率的 95% 上界约为 3/n_g。这就是三倍法则,来自 (1 − miss)^n_g = 0.05。要认证召回率至少达到 R*:
对于 R* = 0.9,标注集中大约需要 30 个合格设计。选择 τ 为满足召回率置信下界仍不低于 R* 的最大阈值。
审计。 生成器变化时阈值会漂移,所以要持续检查。将随机比例 α 的被拒设计(比如 1% 到 5%)照常送去强评判。在 n_a 个被审计的拒绝样本中,有 K 个实际合格,因此拒绝样本中的漏检率为 û = K/n_a,其 Wilson 区间见第 8 节。设 N_rej 为被拒绝的数量,G_pass 为通过样本中发现的合格设计数量。该阶段的估计召回率为
审计成本为 α × N_rej × c_next。在第 8 节的运行中,对 3,600 个被拒设计中的 2% 进行审计,即 72 个设计,花费 $1.44。如果 n_a = 72 中 K = 0,漏检率仍可能接近 3/72 ≈ 4%。审计是监控,不是证明。要证明每 1,000 个被拒设计中不良品少于 1 个,需要 n_a ≈ 3,000。
选哪个模型。 选择在选定 τ 下实测召回率满足 R* 的最便宜模型。要在标注集上测试,而不是凭印象。对几何理解差的模型,应把指标以文本形式提供。强评判模型应来自与廉价评判模型不同的模型家族,这样两者的错误才会不同(第 14 节)。
10. 阶段 5:强评判
强评判对剩下的几百个设计打分并排序,它主要的敌人是噪声和偏差。
评分标准。 写一份包含若干条标准的评分细则。评判对每条标准打 1 到 5 分,并给出一句话的理由。一次遍历 ℓ 得到
这里的 a_j 是准则得分,v_j 是它的权重。
让权重贴合你自己的偏好。 自己给 30 个设计打分。设 h_i 是你对设计 i 的评分,ā_ij 是评审在准则 j 上的平均分。用普通最小二乘法来选取权重:
拟合出的权重反映的是你真正看重的东西,而它往往并非你写下的那些。
重复以削减噪声。 对每个设计评判 m 次,打乱视图顺序、变换措辞,然后取平均:
σ_w 是同一设计重复测量之间的离散度。将单次运行的可靠性定义为 rel_1 = σ_b² / (σ_b² + σ_w²),其中 σ_b² 是不同设计之间的方差。它衡量的是可见变异中有多少是真实信号。Spearman–Brown 公式给出了 m 次运行均值的可靠性:
例如:rel_1 = 0.5,目标 rel_m = 0.9,则需要 m = 9 轮。用 20 个设计、每个设计评判 3 次的预实验来估计 σ_w 和 σ_b。
成对排序。 模型与人比较时,比打分更可靠。在 Bradley–Terry 模型中,每个设计有一个强度 a_i,i 胜过 j 的概率是
为拟合该模型,设 w_ij 为 i 战胜 j 的次数,n_ij 为两者之间的比较次数,W_i 为 i 的总胜场数。令 π_i = e^(a_i),并重复
每轮比较结束后重新缩放,使 π 的几何平均数为 1。当数值不再变化时停止,通常几十轮之后就会稳定。每一步都会提高似然。当某个设计在所有比较中全胜或全败时,为了让强度保持有限,对 a_i 加一个小的岭惩罚。
比较 M 个设计的所有配对需要 M(M−1)/2 次比较,M = 40 时是 780 次。可以改为分轮进行。每轮结束后按当前强度排序,让相邻的设计互相比拼,就像瑞士制赛制那样。大约 M log₂ M 次比较就能得到不错的排序:M = 40 时是 213 次。
消除位置偏差。 每一对都评判两次,两种顺序各一次,每个结果按半胜计入。
偏差检查清单。
- 位置。 随机化顺序并交换配对,如上所述。
- 长度。 固定理由的长度,忽略设计自身描述中的任何主张。
- 自我偏好。 不要告诉评判者某个设计来自哪个生成器或哪次运行。
- 整洁度。 评判者偏爱整洁、对称的设计。与自己的评分对比,看看自己是否也有这种倾向。
- 锚定。 在比较之前先单独评判每个设计,不要展示之前的分数。
- 共同盲区。 使用与廉价评判者不同的模型家族。
以自己为基准进行校准。 至少给 30 个设计评分,覆盖评判者分数范围的各个区间,评分时不要看它的分数。用 Spearman 的 r_s(第 7 节)和 Kendall 的 tau 衡量一致性:
C 是你们俩排序一致的配对数量,D 是排序相反的配对数量。还要统计 top-10 重合度:评委的 top 10 中有多少个也在你的 top 10 里。要得到 r_s 的区间,对设计做 1,000 次有放回重采样,取结果的中间 95%。
一致性的上限是你自己的稳定性。一周后再给同一批设计打分。评委与你的吻合度不可能超过你与自己的吻合度。你自己与自己的吻合度是 0.75,评委达到 0.7,就很出色;只有 0.4,就偏弱。不存在通用的及格线。
第 1 节中的准确度 r 就是这个相关系数,测量对象是分布在整个设计池中的设计。只在头部设计上测量会让 r 显得比实际低,因为取值范围被截短了。
11. 第 6 阶段:选出候选名单
候选名单里应该是得分高、彼此有差异的设计,每一个入选者代表一组相似的设计。
从 M 个已打分候选开始。候选 i 的平均分 s̄_i 介于 0 和 1 之间。把距离转成相似度:
相似度在完全相同的设计中为 1,在距第 6 节所述新颖性距离 δ 处为 0.5。
目标。 选择由 k 个设计组成的集合 S,以最大化
第一项是奖励质量。第二项是奖励覆盖度:每个候选都由与其最相似的选择来代表,当每个候选都有足够接近的代表时,总和就高。介于 0 和 1 之间的数 ψ 在两者之间权衡。
贪心选择,附带保证。 从空集 S 开始。反复加入增益最大的设计,到 k 就停止:
F 是单调的,因为加入一个设计绝不会让它降低;它也是次模的,因为每多加入一个设计,带来的增益都比前一个更小。非负分数之和加上一个设施选址项,同时具备这两种性质。对于这类函数,贪心选出的集合至少能达到最优集合的 1 − 1/e ≈ 63%(Nemhauser、Wolsey 和 Fisher,1978)。实际使用中,贪心通常远好于此。
一个更简单的近亲:MMR。 挑选下一个设计的方式是
λ 是你为了避开近似复制品而愿意牺牲的分数。它没有保证,但胜在容易解释,且在 k 约为 12 时表现良好。
行列式选择(可选)。 定义 Pr(S) 正比于 det(L_S),其中 L_ij = q_i q_j sim(i, j),q_i = exp(β s̄_i)。行列式等于所选设计张成体积的平方,因此当设计质量高且彼此不相似时,行列式就大。贪心选择每次加入能让行列式增幅最大的设计,借助增量 Cholesky 更新,每个候选的开销约为 k² 次运算。相比 F,它更倾向于把选择分散开,但没有 63% 的保证。
说明每个入选者代表谁。 选定 S 之后,把每个候选分配给与它最相似的入选者。分组大小反映了这类设计在这个人身上有多常见。只代表自己的入选者就是独一份。
外卡。 在 k 个名额中预留 e 个,比如 12 个里留 2 个,只按新颖度挑选:选离已选集合最远的候选,无论分数高低。外卡能让评委可能低估的设计浮现出来。
每个入选者呈现给这个人的内容。 一张渲染图、各项指标、评委的理由、最近的邻居以及分组大小。他的时间应该花在比较设计上,而不是解读设计上。
12. 学习循环
纯过滤器会浪费它学到的东西。每一份入围名单都展示了好的设计长什么样,生成器应该利用这一点。
基本设定。 生成器的选择,也就是旋钮 θ 和选项权重 w_t,服从分布 π_φ。每一轮从 π_φ 中抽取 P 次运行 θ_1, …, θ_P。每次运行生成的设计都会经过漏斗。用每次运行的产出 y_p 给它打分:进入入围名单的设计占比,或者进入第 5 阶段的设计的平均强分数。
交叉熵更新。 保留精英运行 E,即产出最高的前 10% 到 20%。让分布向它们靠拢。对于均值为 μ、方差为 σ² 的连续旋钮:
对于一个取值为离散值 c 的旋钮,其中 n_c(E) 表示精英运行中使用取值 c 的次数:
步长 η 介于 0 和 1 之间,通常取 0.1 到 0.3。下限 σ²_min 可防止分布坍缩为零。这是采样器对优胜者的平滑最大似然拟合。同样的更新也适用于选项权重 w_t:用 w_t / W 代替 π_c,用精英设计中选中 t 的比例代替 n_c(E) / |E|。
一条缰绳。 针对评判者做优化,可能会偏离你真正想要的东西(第 14 节)。通过给学习到的采样器与原始先验之间的 KL 散度设上限,让它保持接近:
如果一次更新会超过 κ,就减小 η,直到不超过为止。θ 连续时,把求和换成积分。
探索下限。以概率 ε(介于 0.1 和 0.2 之间)改为从原始先验中抽取 θ。没有这一步,循环会收窄到某一个家族上,永远学不到其他家族的情况。这些探索轮次同时充当第 13 节的对照组。
在少数几个设置之间做选择时,用 bandit。把每个设置——比如整体形状或创造力档位——当作一个臂 a。统计成功次数 s_a(进入候选名单的设计)和失败次数 f_a。对每个臂从 Beta(1 + s_a, 1 + f_a) 中抽一个数,选抽出的数最大的臂执行。这就是 Thompson sampling。它在尝试新臂和使用最佳臂之间取得平衡。
把廉价评判器换成学习出来的评判器。来自强评判器或人工的每一个标注都是一个训练样本。在归一化特征 φ' 上拟合一个 logistic 模型:
它的评分几乎不费什么成本。当它在选定阈值上测得的召回率与廉价模型持平或更高时,就用它替换廉价模型(第 9 节)。
接下来该标注哪些设计。 标注那些模型最没把握、且与已标注过的任何设计都不相似的设计。一个简单的优先级是
这样选出的每个标签,教给模型的东西都比随机选一个更多。
你自己的选择也是标签。 当你从候选清单中挑中或否掉某个设计时,把每次结果记成一次两两胜负,并以更高的权重加入 Bradley–Terry 数据(第 10 节)。你的选择比评委的判断更可信。
生成器一变,就要重新校准。 第 9 节的阈值是在旧的设计分布上测出来的。经过几次更新之后,重新标注一批分层样本并重算 τ。否则你的召回率估计已经过时。
13. 衡量它是否有效
没有度量,这套方法可能看起来很忙,实际却在变差,所以在第一次运行之前就把度量定下来。
先定死标准。 在看到任何结果之前,先设定质量标准 g 和候选清单长度 k。事后改动 g 会让所有数字失去意义。
留出集。 在评委和去重介入之前,从生成器中随机抽取 n_h 个有效设计。让人给它们全部打分,或者让强评委打分再与人的评分对照。绝不要在这个集合上训练。下面所有指标都在它上面测量。当 n_h = 200、q = 5% 时,其中大约有 10 个好的设计。如果好的设计更稀少,就用第 9 节的分层标注。
| 指标 | 定义 | 怎么读 |
|---|---|---|
| 命中率 | 人评为好的候选设计数除以 k,附 Wilson 区间 | 最重要的数字 |
| 端到端召回率 | 通过每一阶段的留出好设计数除以全部留出好设计数 | 偏低说明好设计正在被丢掉 |
| 评委准确度 r | 评委打分与人在留出集上评分的相关性 | 与你自己的自洽度比较(第 10 节) |
| 多样性 | N_eff(第 4 节)与覆盖率(第 6 节) | 数值下降说明生成器在重复自己 |
| 候选清单分散度 | 各选中项两两之间的平均距离 | 接近 0 说明选出来的都是复制品 |
| 每次命中的成本 | 总成本除以好设计被选中的次数 | 逐轮跟踪 |
| 学习增益 | 学习型运行的命中率减去探索型运行的命中率,附 bootstrap 区间 | 区间包含 0 就说明这个循环没起作用 |
何时停止。 假设设计方案以任意顺序到达——在探索阶段确实如此,但一旦学习开始便不再成立。那么第 n + 1 个方案进入当前前 k 名的概率为 k/(n + 1)。对接下来 n 个方案求和,新进入者的期望数量约为 k ln 2:
当 k = 12 时,体积翻倍大约会带来 8 个新进入者,但每一个相比它所取代的设计都只强一点点。把第 k 名的分数 T 对 ln N_0 作图。一次翻倍带来的增益就是斜率乘以 ln 2。当这个增益低于你能察觉到的最小改进,或者一次翻倍的成本(等于 C_tot)超过增益的价值时,就停下来。
为每个设计保留记录。 存下代码版本、θ、随机种子、每个阶段的结果、margin 和 judge 的理由。这样任何人都能重新生成任意设计,并追溯它为什么被保留或淘汰。如果代码变了,旧分数就不再可比,所以给每个结果打上产生它的版本标签。
14. 失效模式
每种失效都有一个能看到的迹象和一个能确认它的测试。
| 失效 | 迹象 | 测试 | 修复 |
|---|---|---|---|
| 代理漂移 | judge 分数上升,但你自己的评分没有 | 每一轮在留出集上的命中率 | KL 约束、探索下限 ε、重新校准 |
| 生成器自我重复 | N_eff 下降;去重接受率接近 0 | 碰撞估计(第 4 节) | 放宽 θ 上的先验,增加可调参数 |
| 生成器太窄 | 你不停地说:我想要类似这样的,但要不一样 | 画出你想要的东西,看生成器能不能做出来 | 增加选项;变异你的草图 |
| 检查太严 | 通过的设计很少;好的从不出现 | 在样本上依次放宽每项检查,看好的比例是否上升 | 把检查降级为目标 |
| 检查太松 | 不可能的设计进入候选名单 | 抽查 50 个随机通过的设计 | 加上检查;把坏设计留作测试 |
| judge 偏差 | 候选名单全是整齐的或全是对称的;结果随顺序变化 | 交换顺序;与你的评分比较 | 两种顺序都评,隐藏来源,使用评分标准 |
| judge 相关 | 便宜和强的 judge 在所有事上都一致,但命中率很低 | 它们在标注集上误差的相关性 | 使用不同的模型家族和不同的证据 |
| 阈值过时 | 审计发现的漏检比以前更多 | 审计漏检率 û 随时间的变化 | 重新标注分层样本;重新计算 τ |
| 好的标签太少 | 召回区间非常宽 | n_g 低于 3/(1 − R*) | 分层标注;降低门槛 g |
| 人工疲劳 | 列表靠后的条目得到更低的评分 | 按列表位置比较评分 | k 保持在 15 或更少;打乱顺序;拆分场次 |
| 静默变更 | 同一个设计在不同周得分不同 | 重新给 20 个旧设计打分 | 给一切打版本;代码变更后重跑旧设计 |
最危险的是代理指标漂移。一旦分数本身成了目标,它就不再衡量它原本要衡量的东西。留出集、探索性运行和 KL 约束的存在就是为了这个。如果要省力气砍掉点什么,别砍这些。
15. 什么时候用,以及完整流程
当有效设计做起来便宜、无效设计容易识别、评判一个成品设计的成本远低于亲手做一个时,就用这套方法。需要同时满足五个条件。
- 生成器能廉价、广泛地产出候选。
- 硬性规则可以写成测试。
- 评判者——模型或人——能把候选看作图像、文本或测量数据。
- 评判一个设计的成本远低于手工做一个。
- 把好设计摆在那个人面前,他能认出来,哪怕他说不清好在哪里。
不要用在体量上不可能做量的单件高风险设计上。不要用在有效性本身模糊、无法测试的场合,因为那样第 2 阶段就塌缩成评判,成本优势也就没了。不要用在空间小到可以完整列举的场合。也不要用在人即便看着也分不出好坏的时候。
适用范围。 平面图、包装、电路与板级布局、排班表、游戏关卡、图案与纺织品设计、以仿真作为硬性校验的分子与材料,以及代码——代码里测试和类型检查就是硬性校验,语言模型就是生成器。
流程。 准备阶段,只做一次:
- 写任务书。把每一行归入规则、目标或品味(第 7 节)。
- 搭好生成器和校验。让校验记录余量(第 4、5 节)。
- 选特征和距离。在人的帮助下设定 δ(第 6 节)。
- 抽 500 个设计。测出 p_V 和 N_eff(第 4、5、8 节)。
- 定下门槛 g 和入围数量 k。对分层样本打标,拟合概率曲线,按召回目标 R* 选 τ(第 9 节)。
- 建立评分量表。自己给 30 个设计打分,拟合权重,测量评判者一致性(第 10 节)。
- 建留出集(第 13 节)。
反复运行:
- 以概率 1 − ε 从学习到的采样器中抽取 θ,以概率 ε 从先验中抽取。生成、验证并去重。
- 以阈值 τ 运行廉价评判器。对 α 比例的拒绝样本进行审计。
- 运行强评判器,重复 m 次,并用成对比较进行排序。
- 通过贪心 F(S) 选出候选名单,外加外卡。
- 在 KL 约束内,用交叉熵步骤更新采样器。
- 重新计算指标,并按第 13 节的规则停止。
审查,由你完成:
- 查看候选名单。挑选和拒绝,并为每个给出一个句子的理由。你的挑选和拒绝会作为标签反馈回去。
机器负责生成和缩小范围。你做只有你能做的事:在看到想要的东西时说出你想要什么。
符号表
每一行标明该符号定义所在的章节。
| 符号 | 含义 | 章节 |
|---|---|---|
| N, q | 设计数量;一个设计进入顶层的概率 | 1 |
| f, μ, σ | 真实质量;其均值和标准差 | 1 |
| Z_N | N 个标准正态抽样中期望的最大值 | 1 |
| u, r | 评判器分数;评判器准确率(分数与 f 的相关性) | 1 |
| x, X | 一个设计;所有设计的空间 | 2 |
| b | 任务简报 | 2 |
| G, θ, s | 生成器;其参数;种子 | 2 |
| e_j, V | 检查 j(0 或 1);有效 = 所有检查通过 | 2, 5 |
| ξ_j | 检查 j 的余量 | 2, 5 |
| g | 质量门槛;若 f ≥ g,则设计为好 | 2 |
| c_i, p_i, R_i | 阶段 i 的成本、通过率和召回率 | 2, 8 |
| φ, φ' | 特征;重新缩放至均值 0、离散度 1 的特征 | 6 |
| d, δ, A | 距离;新颖性的最小距离;存档 | 6 |
| D_c, A_d(t) | 单元格 c 中剩余的选项;在方向 d 上允许与 t 相邻的选项 | 4 |
| w_t, H_c | 选项 t 的权重;单元格 c 的熵 | 4 |
| β, γ, ρ | 示例偏差;内聚性;密度 | 4 |
| π_0 | 生成器参数上的先验 | 4 |
| N_eff | 有效设计数量 | 4 |
| u_j, y_j, h_j, ν_j | 目标门、指标、宽度和权重 | 7 |
| N_0, N_i, C_tot | 生成的设计数量;进入阶段 i + 1 的设计数量;总成本 | 8 |
| m, k | 评判器重复次数;候选名单大小 | 10, 11 |
| τ | 廉价评判器阈值 | 9 |
| α | 审计比例 | 9 |
| V_g, c_next | 一个好设计的价值;下一阶段的成本 | 9 |
| n_g | 标注集中的好设计数量 | 9 |
| v_j | 评分标准权重 | 10 |
| rel_1, rel_m | 单次通过的可靠性;m 次通过均值的可靠性 | 10 |
| a_i, π_i | Bradley–Terry 强度;其指数 | 10 |
| sim, ψ, λ | 相似度;质量与覆盖率的权重;MMR 惩罚 | 11 |
| F(S) | 候选名单目标 | 11 |
| η, ε, κ, E | 更新步长;探索概率;KL 上限;精英运行次数 | 12 |
| n_h | 留出集的大小 | 13 |