讲义定位
到第六课,我们已经有从 context/query 到 prediction 的完整计算图(cell → column → row → ICL → head)。 但它还没有回答:共享参数 \(\theta\) 从哪里来?
PFN 的核心训练观念不是在一张固定表上拟合一个长期模型,而是在许多由 task prior 生成的 episode 上做 outer-loop training,让 \(\theta\) 学习一套可迁移的 task-conditioned prediction procedure。测试时通常 不更新 \(\theta\),而是在 forward 中读取当前 context(第 5 课的 ICL)。
本讲义解释 synthetic prior、meta-learning 两层时间尺度、简化 SCM generator、seed hierarchy、 query-only loss 和 OOD prior split。它也明确说明:synthetic SCM 是可控的数据生成工具,不自动证明 模型恢复了真实因果结构或具备 intervention / counterfactual ability。
Mini 简化:课程用可配置、可 replay 的小 prior 做端到端训练。官方 TabPFN-3(02_tabpfn3 §Synthetic Prior) 在更大、更丰富的 SCM prior 上预训练(报告称超过 8 trillion tokens);课程不复现该规模与完整 recipe。
1. 学习目标与先修知识
学完后你应该能够:
- 区分固定数据集训练、task-distribution training 和单个 episode 的 inner computation;
- 用 outer loop 描述 PFN 风格预训练,并写出 canon §3.8 / §3.1 的 loss 边界;
- 设计可 replay 的 synthetic prior 与
run/task/episode/modelseed hierarchy; - 解释为什么 query-only loss 是 prediction boundary 的一部分(衔接第 1、5 课);
- 对照官方 prior 扩展维,并设计课程版 in-distribution / OOD prior split;
- 把 train loss、checkpoint 与 held-out / OOD task 泛化分开报告。
先修:第 1–6 课的 episode 契约、ICL mask、classification/regression head。本课不改模型内部公式, 只把它们接到可采样的任务分布上。
2. 什么是 prior?
在这里,prior 不是一张固定训练表,而是生成 task 的分布(canon §3.8):
task_spec 可包含特征数 \(P\)、context/query 大小 \(N_c,N_q\)、函数族、噪声、类别数 \(C\) 和 生成机制。每次 outer-loop step 先从 prior 采样一个或一批 task,再生成 context/query,最后只用 query target 计算 loss。
普通监督学习通常优化:
PFN 风格训练更接近:
参数要学的是跨 task 的预测策略,而不只是某张表的固定决策边界。这与第 1 课的 “学程序,不是学一张表”同一条主线。
3. Meta-learning 的两层时间尺度
Outer loop
更新共享参数 \(\theta\):
合法的 outer-loop 目标(与 canon §3.1 一致)是:
Inner computation
测试时模型通常不更新 \(\theta\),而是在 forward 中把 context evidence 读入 row-level ICL,形成对 当前 task 的条件预测(第 5 课)。这就是 in-context adaptation:适应发生在输入与激活路径中,而不是 为每个 task 重新训练一套参数。
4. 官方 prior 维对照与 Mini 实现范围
官方 TabPFN-3 在 Synthetic Prior 中强调最大化数据广度,并列出若干扩展维。课程讲义应列名对齐、 不声称实现全部:
官方 prior 维(02_tabpfn3) | 直觉 | Mini 课程 |
|---|---|---|
| Graph generation | 更丰富的 DAG / 结构多样性 | 实现:chain / star / sparse random DAG |
| Combiner mechanisms | 父节点 → 子节点的多种函数合成 | 实现:linear / threshold / sinusoid / interaction |
| Categorical variables | 更表达力的类别生成 | 可选简化;默认数值为主 |
| High-frequency oscillators | 全频谱正弦结构 | 用 sinusoid family 近似,不追求官方频谱覆盖 |
| Spatial prior | 空间相关协变量 | 不实现;可作 OOD 叙事 |
| Many-class prior | 与 \(C_{\max}=160\) 解码器匹配 | 课程限制较小 \(C\);提醒官方 ceiling |
| Temporal prior (DSCM) | 离散时间动态 SCM | 不实现;列为论文扩展 |
| Out-of-distribution prior | 分布偏移与外推 | 必须在 task 生成层做 OOD split |
官方流程图(Step 1–5)可记为:采样超参 → 采样 DAG → 计算 SCM → 抽取数据集 → 后处理。课程至少要覆盖 前四步的可审计简化版。
5. 一个简化 synthetic prior
课程从一个小而透明的 task family 开始:
对每个 task 先采样 latent state,再生成一张 episode。将 TaskSpec 与 Episode 分开很重要:
TaskSpec描述出题配置与 provenance(含prior_split);Episode是模型实际允许看到的 tensor 与合法 metadata;- 未观察的 latent state(真 DAG、父节点集合)不能通过 shortcut 进入 model input。
6. SCM 的最小基础
一个简化 structural causal model 可写成一组结构方程:
其中 \(U\) 是噪声或 exogenous variables,\(f\) 是生成函数。它提供可控的相关结构、非线性与噪声机制, 适合作为 synthetic task prior 的一个 family。
按拓扑序生成特征时,也可写成:
但要保持边界:
- 生成器有已知 DAG,不代表模型能从 observational episode 恢复 DAG;
- 在 synthetic SCM 上 prediction 变好,不代表现实世界 causal identification 成立;
- 变量名或结构方程是 generator provenance,不是模型输入中的“真相标签”;
- counterfactual 能力需要单独定义 intervention、潜在结果与评估 protocol(本课不做)。
7. Seed hierarchy:可复现不是只记一个 seed
至少区分(canon §3.8):
如果所有随机过程共用一个隐式 global seed,出现差异时无法判断是 task 变了、batch 变了还是模型初始化 变了。seed hierarchy 让 same-seed replay 和 controlled intervention 成为可能。
8. Query-only loss
合法形式:
不能这样做:
也不能把 \(Y_{\mathrm{query}}\) 放进 batch normalization、统一 label tensor、padding statistics 或 cache。query target 只能作为 prediction 之后的监督信号。这与第 5 课的 leakage hard gate 同一条边界: 训练监督与 prediction input 必须分离。
9. Trainer 的最小契约
for step in range(num_steps):
batch = prior.sample_batch(generator)
pred = model(
batch.x_context,
batch.y_context,
batch.x_query,
context_mask=batch.context_mask,
query_mask=batch.query_mask,
)
loss = criterion(pred, batch.y_query)
optimizer.zero_grad(set_to_none=True)
loss.backward()
optimizer.step()
训练记录至少包括:run/task/episode seed、prior configuration、checkpoint step、train query loss、 validation held-out task loss、资源信息与 wall-clock。只有 loss、没有 seed/split/prior 版本,实验 不可复盘。
10. OOD prior split
如果 train 和 test 使用完全相同的 task family、feature width、noise 和 context size,结果只能说明 in-distribution generalization。OOD 必须在 task generation 层定义,而不是生成全部数据后随机切 row。一个合法例子:
报告中要写清楚 OOD 改变了哪些 prior dimension,不能只说“测试集更难”。官方也单独加入 out-of-distribution prior;课程用更小的可控轴变化即可,但语义必须是 task-level。
11. Loss、泛化与 checkpoint 的关系
训练 loss 下降说明模型在当前采样分布的 query targets 上优化成功;它不自动说明:
- held-out task 表现更好;
- OOD prior 上仍然有效;
- 输出概率校准;
- 模型使用了 context,而不是 shortcut;
- 架构组件的解释与论文一致。
因此每个 checkpoint 都应在固定 validation episodes 和 held-out task episodes 上评估,避免只挑最好看的 train curve。第 8 课会把这些数字挂到明确的 claim 上。
12. 计算预算与 prior 设计
扩大 prior 的 family、\(N_c\) 和 \(P\) 会提升覆盖范围,也会增加计算量。合理的课程实验先固定一个小 prior,建立端到端证据,再一次只改变一个维度:
- 增加 task family;
- 增加 context size;
- 增加 feature width;
- 增加 noise 或 missingness;
- 增加 OOD distance。
否则一次改太多,loss 变化没有可解释归因。
13. 四个必做实验
实验 A:same-seed replay
同一个 task/episode seed 产生逐元素相同的 tensor、label 和 mask。
实验 B:query-only loss audit
用不同 \(Y_{\mathrm{query}}\) 的 evaluation copy 进行 prediction,输出必须相同;用真实 target 计算 loss 后,loss 才可以不同。
实验 C:OOD prior split
固定训练 budget,比较 IID 与 OOD task performance,并描述 prior 改变的维度。
实验 D:loss vs generalization
画 train query loss、validation task loss、OOD loss 三条曲线,说明它们何时分叉。
14. 知识检查
- prior 生成的对象是 row、dataset 还是 task?为什么?
- outer loop 与 inner computation 的时间尺度有什么区别?
- 为什么 synthetic SCM 不能自动支持 causal claim?
- 为什么需要多个 seed,而不是只保存一个 global seed?
- query-only loss 如何同时做到训练监督与 prediction boundary 分离?
- OOD split 为什么必须在 task generation 层定义?
- 官方 prior 的哪几维是课程明确“列名对齐、不实现”的?
15. 本课的硬结论
Synthetic prior training 的目标是让共享参数跨 episode 学习一种预测程序。它的可信度依赖 prior 定义、 seed hierarchy、query-only loss、held-out task / OOD split 和 checkpoint evidence;synthetic generator 本身不是现实因果能力的证明。官方 prior 维可作为对照地图;课程只对已实现轴负责。
第 7 课:Synthetic Prior 与预训练
项目问题
PFN 不在一张固定表上把参数拟合到终点,而是在不断生成的新任务上训练一个跨任务预测算法。本课把 “生成任务”和“训练模型”接起来,并与官方 TabPFN-3 synthetic prior 维做对照(实现范围见下)。
简化 SCM prior
每个 episode 随机化特征数 \(P\)、样本数 \(N_c,N_q\)、图结构、线性/非线性关系、交互、噪声、目标类型 和类别数 \(C\)。
官方 prior 维(列名对齐)
| 官方维 | Mini 是否实现 |
|---|---|
| Graph generation | 是(简化族) |
| Combiner mechanisms | 是(简化函数族) |
| Categorical / oscillators / spatial / temporal | 否或极简;报告中标明 |
| Many-class prior | 小 \(C\);提醒官方 \(C_{\max}=160\) |
| OOD prior | 是(task 生成层 split) |
实现任务
data/scm.py;data/functions.py:线性、阈值、周期、异方差函数;data/prior_sampler.py;training/trainer.py、losses.py、checkpoint.py;- 分类与回归统一 episode API。
验证实验
- 每个 seed 能重放同一批任务;
- 训练 loss 下降不等于新任务能力,必须保留 held-out task;
- 记录任务分布、模型配置、环境和 checkpoint;
- 对 prior 中未出现的组合做一轮 OOD 任务测试。
边界
synthetic SCM prior 是任务生成器与 inductive bias,不是现实数据上的因果识别证明;课程也不声称复现 官方 TabPFN-3 的完整训练 recipe 或 8T-token 规模。
交付
scm.py、prior_sampler.py、训练脚本、checkpoint、held-out task report。
本课的具体教学包
本课把 task generator 接到 end-to-end trainer。重点不是造一个“看起来像真实数据”的随机表,而是 定义一个可记录、可重放、可做 OOD split 的 task distribution。
| 时间 | 内容 | 证据 |
|---|---|---|
| 00:00–00:25 | prior 是 task distribution,不是数据增强 | 画出 outer/inner loop |
| 00:25–00:55 | DAG/SCM 与 function family;官方维对照表 | 采样一张小图 |
| 00:55–01:30 | prior sampler implementation | task manifest |
| 01:30–01:45 | 休息 | 检查 seed hierarchy |
| 01:45–02:20 | query-only loss trainer | loss trace + checkpoint |
| 02:20–02:50 | held-out/OOD task evaluation | train vs held-out 曲线 |
| 02:50–03:00 | review | prior boundary 与交付 |
1. Prior 的对象和 outer loop
PFN 训练的抽象形式(对齐 canon §3.8 / §3.1)是:
p(task_spec) 是课程的 synthetic prior。每个 task 可以改变 \(P\)、\(N_c\)、噪声、函数族、图结构和 target kind。训练 loss 只使用 query labels;context labels 作为输入条件。不能把全表 target 先喂给 encoder 再称为 ICL。
2. 简化 SCM prior 的实现拆解
先采样有向无环图,再按 topological order 生成 feature:
课程需要至少支持以下离散选择:
graph: chain / star / sparse random DAG
function: linear / threshold / sinusoid / pairwise interaction
noise: gaussian / laplace / heteroskedastic
target: binary / multiclass / scalar regression
推荐的 TaskSpec:
@dataclass(frozen=True)
class TaskSpec:
task_id: int
kind: Literal["classification", "regression"]
n_features: int
n_classes: int | None
n_context: int
n_query: int
graph_family: str
function_family: str
noise_family: str
prior_split: Literal["train", "heldout", "ood"]
TaskSpec 是 provenance metadata;模型不应收到 graph_family、latent adjacency 或 true parents。
3. 采样器与 seed hierarchy
把一个 global seed 拆成可定位的子 seed(canon §3.8):
并与讲义中的 episode_seed / model_seed 一并写入 manifest。当一个 episode 失败时,可以用 task_id 和 seed 逐项 replay,而不需要保存完整 tensor。每个 checkpoint 必须保存:
model_config, optimizer_config, run_seed, prior_config,
git/source identifier, torch version, device, global_step
不要只保存 model.state_dict();否则无法判断某个结果来自哪一种 task distribution。
4. Trainer 的 exact contract
class EpisodeTrainer:
def train_step(self, batch: list[Episode]) -> dict[str, float]:
self.optimizer.zero_grad(set_to_none=True)
losses = []
for episode in batch:
pred = self.model(
episode.x_context, episode.y_context, episode.x_query
)
losses.append(self.loss_fn(pred, episode.y_query, episode.task_kind))
loss = torch.stack(losses).mean()
loss.backward()
torch.nn.utils.clip_grad_norm_(self.model.parameters(), 1.0)
self.optimizer.step()
return {"loss": float(loss.detach())}
真实实现可以 vectorize;课堂先要求读清楚“每个 episode 的 query-only loss”,再做 batch 优化。 classification 与 regression 若共享模型,head dispatch 必须由 task_kind 控制,不能让 target dtype 暗示任务类型。
5. Reference training run
为了让第 8 课有稳定输入,课程参考 run 可以先用一个小预算:
train tasks sampled on the fly: 2,000 episodes
batch size: 8 episodes
optimizer: AdamW, lr=3e-4
gradient clip: 1.0
validation: every 100 steps, 100 fresh held-out tasks
checkpoint: best validation + final step
这些数是课程 smoke run,不是官方 TabPFN-3 recipe,也不构成性能承诺。若设备不足,减少 steps,但 必须保留完整 manifest 和 held-out evaluation。
6. 必做验证
实验 A:same-seed replay
同一 TaskSpec/task_seed 必须生成相同的 X/Y。如果使用 nondeterministic GPU kernel,记录这一事实, 并在 CPU smoke test 上完成逐元素 replay。
实验 B:query-only loss audit
在 trainer 中临时把 y_query 替换为随机值,确认只有 loss/metrics 改变,model input、context hidden 和 prediction 不应因 evaluation-only label 改变。这个审计要和第 5 课的 forward leakage test 区分开: 第 5 课查 ICL 输入路径;本课查 trainer / collate / loss 路径。
实验 C:OOD prior split
训练只使用 linear + chain,held-out 至少包含:
nonlinear + chain
linear + sparse random DAG
heteroskedastic regression
OOD 任务结果可以变差;课程要报告变化而不是挑最好的一组。
实验 D:loss vs generalization
同时画 train episode loss、held-out task loss、classification calibration 或 regression coverage。 训练 loss 下降不是“学会跨任务算法”的充分证据。
常见失败
- 先生成一张固定 synthetic table,再反复 shuffle rows;
- 每个 task 都使用同一 graph/function/noise,prior 实际没有 task diversity;
- query labels 在
collate阶段进入 model input; - checkpoint 没有 prior/config/seed,结果无法 replay;
- 把 synthetic SCM 的生成结构写成模型已经识别现实因果结构;
- 只看 train loss,不做 fresh held-out tasks;
- 把官方 prior 的未实现维写成“课程已覆盖”。
退出条件与评分
通过条件:
- 至少 4 个 prior axes 可配置并记录;
- 同一 seed 可以 replay task;
- trainer 的 loss 只在 query target 上计算;
- checkpoint 能恢复 model、optimizer、prior config 和 step;
- 至少一组 OOD prior split 有独立报告;
- 明确 synthetic prior 是 inductive bias,不是 causal identification evidence;
- 报告中有官方 prior 维对照表(实现 / 未实现)。
评分建议:prior design 25%,trainer/loss 30%,replay/checkpoint 20%,OOD evidence 15%,边界 10%。
课后作业
加入一个新 function family,但先写 task-level test 证明它真的改变了生成分布,再把它加入 train 或 OOD split。不能只改函数名而不改变 episode statistics。