📑 本页目录(点开跳转)
08 · 数据、实验、模型的飞轮
⏱ 24 分钟 | ⭐ 贪心挑候选 8 次只成功 2 次,UCB 8 次全中
🎯 一句话
这里的数据不是给定的,是你决定去生产的。 所以模型的价值不在指标好看,在于它让下一批实验少做多少次 —— ⭐ 而「下一批做什么」这个问题,答案不是挑预测分最高的那些。
🔄 一、闭环才是这件事的形态
普通 ML 的数据集是给定的:拿到、切分、训练、评估,结束。 AI4S 不是。它是一个环,而且环上每一步都要花真钱:
训模型 → 挑候选 → 做实验 → 拿到新数据 → 回去训模型
⭐⭐ 这个环改变了「好模型」的定义。 一个 R² 0.9 但只会推荐你已经做过的东西的模型,价值是零; 一个 R² 0.6 但每次都能指出「这个方向你没试过、而且可能有戏」的模型,能省掉几个月。
⭐ 判据一句话:别问模型多准,问它让你少做了多少次实验。
🎯 二、为什么不能挑分数最高的
这是全章的题眼。直觉是「挑模型觉得最好的」—— ⚠️ 这会让你一直在已知区域打转: 模型对熟悉的区域预测得准、给分高;对没探过的区域没把握,于是给不出高分。 于是你永远不去那里,于是模型永远学不会那里。这个循环自己会锁死。
⭐ 解法是在打分里明确地给不确定性付钱:
采集分数 = 预测值 + κ × 不确定性
κ = 0 就是纯贪心;κ 越大越倾向于去没探过的地方。
这个式子叫 UCB(置信上界),⭐ 和强化学习里的探索与利用是同一件事,
站内有一整章:强化学习基础 07 · 探索与利用。
🧪 三、把差别跑出来
一个一维的目标函数,右边有个高的全局最优,左边有个诱人的局部最优。 两种策略从完全相同的三个初始点出发,各跑 25 轮:
import numpy as np
def f(x):
"""多峰目标函数:全局最优在右侧,左侧有个诱人的局部最优。"""
return np.sin(3 * x) * np.exp(-0.3 * (x - 2) ** 2) + 1.6 * np.exp(-2.5 * (x - 7.2) ** 2)
grid = np.linspace(0, 10, 400)
best_x = grid[np.argmax(f(grid))]
def gp(Xtr, ytr, Xte, ls=0.6, noise=1e-4):
"""最小版高斯过程:RBF 核,返回后验均值和标准差。"""
k = lambda a, b: np.exp(-0.5 * ((a[:, None] - b[None, :]) / ls) ** 2)
K = k(Xtr, Xtr) + noise * np.eye(len(Xtr))
Ki = np.linalg.inv(K)
mu = k(Xte, Xtr) @ Ki @ ytr
var = 1.0 - np.einsum("ij,jk,ik->i", k(Xte, Xtr), Ki, k(Xte, Xtr))
return mu, np.sqrt(np.maximum(var, 1e-12))
def run(kappa, rounds=25, seed=0):
r = np.random.default_rng(seed)
X = r.uniform(0, 10, 3) # 三个初始点,两种策略完全相同
y = f(X)
for t in range(rounds):
mu, sd = gp(X, y, grid)
nxt = grid[np.argmax(mu + kappa * sd)] # ⭐ kappa=0 就是纯贪心
X, y = np.append(X, nxt), np.append(y, f(nxt))
if abs(nxt - best_x) < 0.15:
return t + 1
return None
print("目标函数全局最优在 x = %.2f,f = %.3f" % (best_x, f(best_x)))
print()
print("%-22s %s" % ("策略", "第几轮找到全局最优(25 轮内)"))
for name, kap in [("greedy (kappa=0)", 0.0), ("UCB (kappa=2)", 2.0)]:
res = [run(kap, seed=s) for s in range(8)]
ok = [r for r in res if r is not None]
print("%-22s %s" % (name, " ".join("%2s" % (r if r else "--") for r in res)))
print("%-22s found %d/8, avg round %.1f" % ("", len(ok), np.mean(ok) if ok else float("nan")))
真实输出:
目标函数全局最优在 x = 7.19,f = 1.600
策略 第几轮找到全局最优(25 轮内)
greedy (kappa=0) -- -- -- -- -- 2 -- 2
found 2/8, avg round 2.0
UCB (kappa=2) 5 7 8 7 9 7 8 5
found 8/8, avg round 7.0
⭐⭐ 这张表要横着读,不要只看平均轮数:
- 贪心 8 次里只成功 2 次 —— 而且那两次是初始点碰巧就撞在全局最优附近(第 2 轮就中)。 ⚠️ 其余 6 次它 25 轮全部耗光,一直在左边那个局部最优上反复采样。
- UCB 8 次全中,平均第 7 轮。
⚠️ 别被「贪心平均 2.0 轮」骗了 —— 那是只统计成功的那 2 次算出来的。 ⭐ 把失败的 6 次算进去,贪心的期望代价是无穷 —— 它根本到不了。 💀 这正是真实项目里最贵的失败模式:指标一直在缓慢改善,而你一直在错的区域里。
📦 四、一次挑一批的坑
实验很少一次做一个 —— 一块 96 孔板就是 96 个。 ⚠️ 直接取采集分数最高的 96 个是错的:它们会挤在同一个小区域里, 彼此几乎一样,你花了 96 次实验只买到 1 条信息。
⭐ 两个能直接用的办法:
- 挑一个就假装拿到了结果(用模型预测值代替),更新不确定性再挑下一个 —— 这样后选的点自然会避开已选的点。
- 加一个多样性下限:候选之间的距离/相似度不得超过某个阈值。
⭐ 站内已经有一整章讲这个问题的近亲: 数据这一关 12 · 标注预算与主动学习。 ⚠️ 两者的区别值得记:那一章是「标注一个已经存在的样本要花钱」, 候选池是给定的、有限的;⭐ 这一章是「做一次实验要花钱,而样本是你造出来的、 原本不存在」—— 搜索空间是开放的,这让「挑哪个」变得难得多。
⚠️ 五、实验结果回来之后,你的数据分布已经变了
💀 这一条最容易被忽略,而它会毁掉你的评估。
你专门挑了模型认为好的、或者不确定的那些去做实验。 于是新数据根本不是从原分布里随机抽的 —— 它是被你的模型筛过的。
后果有两个:
① 用新旧数据混在一起做的评估会失真。 测试集里塞满了「模型觉得有戏」的样本, 它在这些样本上的表现不代表它在全空间上的表现。
② 每一轮的指标不可比。 第 3 轮的测试集和第 1 轮的分布不同, ⚠️ 「R² 从 0.6 涨到 0.7」可能只是因为后来的候选更好预测。
⭐ 对策:留一个从原始分布随机抽的、从不参与挑选的固定测试集。 它是你唯一一把不会随着飞轮转动而变形的尺子。 ⚠️ 而它同样必须按同源家族划分 —— 见 07 章。
🏁 六、什么时候停
三个信号,⚠️ 但它们都不干净:
| 信号 | ⚠️ 但是 |
|---|---|
| 预算用完了 | 最诚实的一个,也是最常见的真实原因 |
| 连续几轮没有改善 | 可能是收敛了,⭐ 也可能是 κ 太小、根本没在探索 |
| 模型说没有更好的了 | 💀 这句话不可信 —— 它只覆盖你定义的搜索空间 |
⭐⭐ 第三条要特别当心:「模型找不到更好的」和「更好的东西不在你的搜索空间里」 在数据上完全无法区分。第 3 节那个实验就是缩微版 —— 贪心那 6 次失败里,模型每一轮都很自信,而它从没去过右边。
🔗 这一章连到哪里
| 去哪 | 为什么 |
|---|---|
| 强化学习基础 07 · 探索与利用 | ⭐ 第 2 节那个 预测值 + κ × 不确定性 就是 UCB,那一章讲它的完整形态和为什么这样配 |
| 数据这一关 12 · 标注预算与主动学习 | ⭐ 同一个问题的近亲。区别:那边候选池是给定的(标注已有样本),这边样本是你造出来的、搜索空间开放 |
| 07 · 评测的坑 | ⚠️ 第五节说的固定测试集,同样必须按同源家族划分,否则它也是虚的 |
| 06 · 小数据这一关 | 飞轮的第一圈就是小数据 —— 那一章讲头几十条标签怎么用 |
| 模型上线之后 · 附录A 速查 | ⭐ 第五节那个「分布变了」在部署语境里叫数据漂移,那边有完整的检测方法清单 |
✅ 检查点
- 闭环怎么改变了「好模型」的定义?判据是什么?
- 为什么挑预测分最高的候选会锁死?说清那个循环。
- 实验里贪心和 UCB 各成功几次?「贪心平均 2.0 轮」为什么是个误导性的数字?
- 一次挑 96 个的坑是什么?两个解法各是什么?
- 实验结果回来后为什么数据分布变了?会造成哪两个后果?对策是什么?
- 「模型说没有更好的了」为什么不可信?
👀 答案
- 因为数据不是给定的,是你决定去生产的。⭐ 好模型 = 让你少做实验的模型,不是指标高的模型。一个 R² 0.9 但只推荐你做过的东西的模型价值是零。判据:别问模型多准,问它让你少做了多少次实验。
- 模型对熟悉区域预测准、给分高;对没探过的区域没把握所以给不出高分 → 你永远不去那里 → 模型永远学不会那里 → 继续给不出高分。这个循环自己会锁死。
- 贪心 2/8,UCB 8/8。 ⚠️「贪心平均 2.0 轮」只统计了成功的那 2 次,而那 2 次是初始点碰巧撞上;其余 6 次 25 轮全耗光。⭐ 把失败算进去,贪心的期望代价是无穷。
- 取分数最高的 96 个会挤在同一小区域、彼此几乎一样,96 次实验只买到 1 条信息。解法:①挑一个就用预测值假装拿到结果、更新不确定性再挑下一个 ②加多样性下限。
- 因为你专门挑了模型觉得好或不确定的去做实验,新数据不是从原分布随机抽的。后果:①混合数据的评估失真 ②每轮指标不可比(涨了可能只是因为后来的候选更好预测)。⭐ 对策:留一个从原始分布随机抽、从不参与挑选的固定测试集(且同样要按家族划分)。
- 因为它只覆盖你定义的搜索空间。💀「模型找不到更好的」和「更好的不在搜索空间里」在数据上无法区分 —— 第 3 节贪心失败的那 6 次里,模型每轮都很自信,而它从没去过右边。
🛑 可以停在这里
这是正文最后一章。⭐ 你现在有一条完整的链: 把科学问题变成建模问题 → 表示 → 结构与对称性 → 小数据 → 正确评估 → 决定下一批实验做什么。
⚠️ 什么时候回来:真正开始转飞轮的时候。第五节那条「分布已经变了」 在纸上看很显然,⭐ 在项目第三轮时几乎所有人都会忘。
⚡ 走神救援
先记住这几件事
- 模型参与选择下一批实验,数据和策略会随反馈不断变化。
- 只挑预测最高分容易反复停在熟悉区域,要明确考虑不确定性与批次多样性。
- 保留不参与候选挑选的评估数据,区分模型改进与采样分布改变。
- 用实验成本和实际发现衡量价值,并预先说明预算与停止条件。
下一节 👉 附录A-速查.md