项目已交付

不训练也能预测

CatBoost 对阵 Kumo-Tabular,对象是西雅图建筑的能耗:一个表格基础模型似乎不用训练就做得更好,每次调用 25 秒。四个实验来验证,以及这对使用场景、成本,和留给本行的东西意味着什么。

· 时间:2026 年 10 月 8 日 → 18 日 · 阅读约 7 分钟

  • 机器学习
  • 表格基础模型
  • MLOps
  • CatBoost
  • 部署

为了我 AI Engineer 课程的第五个项目,我要把一个机器学习模型部署到生产环境:一个 API、测试、数据库、监控。模型预测西雅图非住宅建筑的能耗和 CO2 排放。我训练了一个 CatBoost,然后把它和 Kumo-Tabular 对比——后者是 NVIDIA 的表格基础模型,不训练:它靠每次调用时喂给它的示例来预测。在这个数据集上,它似乎做得更好,每次调用 25 秒。随后我做了四个实验来验证我的假设:它们明显修正了这个初步结论。下面是我测到的,以及我从中得到的。

Kumo-Tabular 在能耗上的 R²,未经训练,而 CatBoost 是 0.24
0.45
单单一栋建筑——一个数据中心——扛起了全部优势:去掉它,再去掉最大的工业场地,CatBoost 就反超了
1 / 310
Kumo 在 CPU(4 线程)上做一次预测,而 CatBoost 是 0.8 ms
25.5 s
Kumo 单次调用做 1,000 次预测:成本来自上下文,而不是行数
42.5 s
上下文构建不当时排放的误差:对 Kumo 来说,上下文扮演了模型的角色
× 528
行上下文:CatBoost 仍在进步,Kumo 触顶,且比 1,236 行时贵近 4 倍
4,700

交付的项目

场景:客户想让他的模型「可用于生产」。我交付了一个用 JWT 认证、以 PostgreSQL 为后端的 FastAPI。每次调用、每次预测都被记录,连同产出它的模型版本。训练在 MLflow 里被跟踪,两个 Grafana 看板读同一个数据库。一个 Gradio 界面用作演示。如果测试、安全性或模型性能相对基准版本出现回归,CI 会阻止合并。

CSV 2016 + open data 2017–2019 ─▶ ingestion (清洗、对齐、切分)
                                      │
                                      ▼
                                 PostgreSQL ◀── MLflow (runs、指标、制品)
                                 │   ▲   ▲
                       训练 ◀──────┘   │   └── Grafana (API、模型)
     CatBoost ×2 + Kumo 上下文          │
                    │                │ 可追溯性:请求、预测、版本
                    ▼                │
          FastAPI (JWT) ─────────────┘ ◀── Gradio (演示)
          /model/predict           CatBoost,几毫秒
          /model/predict/compare   CatBoost + Kumo-Tabular,约 25 s

代码在 GitHub 上,CatBoost 模型在 Hugging Face 上,还有一个 演示 在线运行。

两种预测方式

CatBoost 走的是经典路线。用 2016 年的 1,236 栋建筑训练(17 个变量:类型、街区、面积、建造年份、是否接入天然气或城市供暖管网),带交叉验证和超参数搜索。训练完成后,它装在两个 .cbm 文件里,不到一毫秒就能给出答案。

Kumo-Tabular 不训练。它被一次性预训练好,然后通过 in-context learning 预测:把带标签的行(上下文)和要预测的行一起传给它,它靠类比推理,不改变自己的权重。在这里,它的上下文恰好就是 CatBoost 的训练集。所以两个模型看到的是同样的数据,且不含任何测试建筑。

分数

  • CatBoost(已训练)
  • Kumo-Tabular(上下文)
在 310 栋测试建筑上的 R²00.10.20.30.40.5能耗0.240.45排放0.110.21在 310 栋测试建筑上的 R²00.10.20.30.40.5能耗0.240.45排放0.110.21
图 1 · 在 310 栋测试建筑(训练从未见过、也不在上下文中)上的 R²。项目公布的成绩;下一节说明它们值多少。
目标模型R²MAE相对误差中位数
能耗CatBoost0.245.17 M kBtu35.0%
能耗Kumo-Tabular0.454.71 M kBtu35.1%
排放CatBoost0.11145.9 t CO2e43.7%
排放Kumo-Tabular0.21136.6 t CO2e48.3%

纸面上,Kumo 在 R² 和绝对误差上明显胜出,而这两项指标被大建筑主导。在相对误差中位数上——它给一栋小建筑和一栋大建筑同等权重——它在能耗上打平,在排放上更差。我因此推断 Kumo 在分布尾部外推得更好。剩下的问题是:这个差距站得住吗?

这些分数值多少

一栋建筑决定了结果。 在能耗上,五栋建筑集中了两个模型 96 到 97% 的平方误差,其中一栋就占了 65 到 76%。那是一个被归为「campus」的工业场地,带一座能源站和若干实验室:它消耗 448 M kBtu,CatBoost 预测 36 M,Kumo 63 M。两个都没猜中。第二栋是一个数据中心:实际 275 M kBtu,CatBoost 32 M,Kumo 175 M。这一栋,Kumo 靠得比较近。

从测试中移除的建筑(能耗)CatBoost R²Kumo R²
无0.240.43
工业场地0.390.69
数据中心0.250.32
两者0.580.53

310 栋里去掉了这两栋,CatBoost 就反超了。在排放上,去掉工业场地、数据中心和一家医院,就足以让两个模型打成平手(R² 处处 0.55,绝对误差 72 对 71 t CO2e)。所以 Kumo 的优势取决于它处理少数极端建筑的方式。这并非无关紧要:正是它们在城市能源账本里占了大头。但这是脆弱的证据。

bootstrap 证实了这一点。 对测试集做 2,000 次配对重采样,CatBoost 在能耗上 R² 的 95% 置信区间是 0.16 到 0.75,Kumo 是 0.26 到 0.81。两者的差距是 −0.23 到 +0.52:并不显著。在能耗上,90% 的抽取里 Kumo 的 R² 更好,排放上是 94%。趋势是一致的,但尚未确立。在排放的相对误差中位数上正好相反:92% 的抽取里 CatBoost 更好。

Kumo 不会两次给出同一个分数。 它的推理会随机抽样,而服务没有固定随机种子。用五个种子、同样的上下文,它在能耗上的 R² 在 0.42 到 0.46 之间波动。公布的 0.45 只是其中一次抽取。

注:两侧的 R² 都偏低:手上这 17 个变量对一栋建筑的真实能耗解释得很差。

上下文就是模型

对比的第一个版本用的是合成上下文:几行生成的数据,排放被固定为能耗的 0.1 倍。在西雅图,真实比值约为每 kBtu 0.00002 t CO2e。Kumo 会紧贴它在上下文里看到的值。于是它预测的排放高了约 500 倍,R² 为 −1,829。

Gradio 界面:对 Graham Hill 学校,CatBoost 预测每年 99.2 t CO2e,Kumo-Tabular 预测每年 52,417.3 t CO2e。
图 2 · 修复前的演示界面:同一所学校,CatBoost 预测每年 99.2 t CO2e,Kumo 52,417 t(× 528)。没有报错,没有警告:这个预测看上去完全有效。

修复没有碰模型,只改了数据:上下文变成了真实的训练集,由流水线导出,并随模型一起纳入版本管理。这是这个项目最具体的一课。对一个 in-context learning 模型,feature engineering 变成了 context engineering:给哪些行、代表性如何、避开哪种泄漏。而 MLOps 并没有消失,只是挪了位置:你不再对权重做版本管理,而是对一个数据集做版本管理。

一次预测的成本

我最初的直觉是:「数据集每次推理都要重新加载,所以成本会随数据量爆炸」。我用交付的模型测了它,CPU,4 线程。

  • CatBoost
  • Kumo-Tabular(1,236 行上下文)
一次调用的时长随预测建筑数的变化020,00040,00060,000 ms1 行0.8 ms25,490 ms10 行0.9 ms25,100 ms100 行1 ms26,700 ms1,000 行2 ms42,500 ms一次调用的时长随预测建筑数的变化020,00040,00060,000 ms1 行0.8 ms25,490 ms10 行0.9 ms25,100 ms100 行1 ms26,700 ms1,000 行2 ms42,500 ms
图 3 · 一次调用的时长随预测建筑数的变化,能耗目标。CatBoost 始终低于 2 ms(在这个尺度上柱子看不见)。Kumo 无论你让它做什么,都要约 25 s,之后缓慢上升。

我的直觉对了一半。Kumo 的成本主要取决于上下文的大小,而不是预测数量。一行要 25.5 s,一千行 42.5 s:批量下每栋建筑 42 ms。所以问题不是要预测的数据量,而是调用次数。批量使用摊薄了上下文的成本。实时使用——像我 API 里那样一次一个请求——每次都付这笔钱。而且一次调用的时长大致随上下文大小线性增长(见下一节)。

另一个杠杆是缩小上下文。项目文档声称用 300 行样本能到 R² 0.49,比用整个数据集还好。那是一次有利的抽取:另外三次抽取,我得到 0.31 到 0.37。我还试过「表格 RAG」的想法:对每一栋要预测的建筑,把它在训练集里最近的 300 个邻居给 Kumo。

Kumo 的上下文能耗 R²能耗误差中位数排放 R²排放误差中位数
300 随机行(3 次抽取)0.31 到 0.3742%0.17 到 0.2654%
300 个最近邻0.3838%0.2149%
1,236 行(全部训练集)0.42 到 0.4634%0.20 到 0.2149%

在相同规模下,邻居在所有指标上都胜过随机,但在能耗上仍追不上完整上下文。取舍取决于用途。对单次请求,300 个邻居约需 6 s 而不是 25 s。批量下正好相反:每栋建筑一个上下文就无法复用,预测 310 栋建筑要半小时而不是一分钟。

即便优化后,差距依然巨大:单次调用约为 CatBoost 延迟的 30,000 倍。对一个每秒服务数千请求的 API,这个问题根本不用考虑。

数据更多会怎样?

表格基础模型以在小数据集上表现强著称。所以要找的是 CatBoost 反超的那个点。我把训练集大小——它同时也充当 Kumo 的上下文——从 100 行变到 4,700 行。在 2016 年的 1,236 栋建筑之外,我加入了 2017 到 2019 年,始终不包含任何测试建筑。测试仍是同样的 310 栋。每个点是三次抽取的平均。

  • CatBoost
  • Kumo-Tabular
能耗 R² 随训练集或上下文规模的变化00.10.20.30.40.5100 行0.090.25300 行0.190.33600 行0.210.351,236 行0.250.442,500 行0.270.414,700 行0.290.44能耗 R² 随训练集或上下文规模的变化00.10.20.30.40.5100 行0.090.25300 行0.190.33600 行0.210.351,236 行0.250.442,500 行0.270.414,700 行0.290.44
图 4 · 能耗 R² 随训练行数(CatBoost)或上下文行数(Kumo)的变化,三次抽取的平均。直到 4,700 行都没有交叉:CatBoost 缓慢进步,Kumo 从 1,236 行起就触顶。
行数能耗误差中位数(CatBoost / Kumo)排放误差中位数(CatBoost / Kumo)Kumo 一次调用时长
10047% / 54%55% / 71%16 s
30039% / 42%49% / 54%20 s
60037% / 37%46% / 51%30 s
1,23634% / 34%44% / 49%59 s
2,50034% / 34%44% / 47%117 s
4,70034% / 37%45% / 48%225 s

我找不到 R² 上的交叉:Kumo 在所有规模上都领先。但这个 R² 依赖前面看到的少数极端建筑。在误差中位数上,表格说的是另一回事。数据少时,反而是 CatBoost 做出更好的典型预测:100 行时,它在排放上的误差中位数是 55%,而 Kumo 是 71%。Kumo 在数据少时占优这个说法,只对极端情况成立。

超过 1,236 行,Kumo 再也挣不到好处,而一次调用的时长仍在近乎线性地增长,每行上下文约 48 ms。注意:新增的行大多是同一批建筑的其他年份,所以新信息很少。而且 CatBoost 沿用为 1,236 行调好的超参数,没有按规模重新调参。

那么,像 Kumo 这样的模型有什么用?

这才是我的真问题。搭一条 XGBoost 或 CatBoost 的训练链已经变得很容易,一个代码智能体几分钟就能搞定。如果 Kumo 唯一的优势只是省掉训练,那它分量不重。

但训练只是成本的一部分。这个项目让我看到了:MLflow、CI 里的性能门禁、数据库里的模型版本、重训后重启 API。一个模型的真实成本是它的生命周期。当生命周期比推理更贵时,in-context learning 模型就变得有吸引力:

场景为什么 in-context learning 站得住
冷启动:几百个带标签的示例在这里它能更好地抓住极端情况,但它的典型预测不如 CatBoost
大量小问题:每个客户、站点或地区一个模型一个服务加若干上下文,而不是几百条要重训、要监控的流水线
标签持续到来新增一行上下文在下次调用就生效,无需重训
被遗忘权从上下文里删掉一行就够了,而训练过的模型必须重训
稀疏、批量、高价值的预测25 s 对年度能源审计不算什么。这个数据集正是这种情况
在刚整理好的数据上做基线几分钟得到一个质量参照,用来判断专用流水线值不值得投入

反过来,在请求量高、数据稳定、标签充足的情况下,训练过的模型在各方面都胜出。正确的标准不是抽象地问「Kumo 还是 XGBoost」,而是每次调用的成本乘以调用次数,对比一条训练流水线的持有成本。

这张表是推理,不是测量。这里只有第一行经过了测试,而它证明比预想的更微妙。

留给本行的东西

如果训练变成一种商品,那么还有两件事,CatBoost 和 Kumo 都不会替我们做。

了解数据。 合成上下文的 bug 就是例子。那不是模型问题,而是一个物理比值错了。2017–2019 年的对齐是另一个例子。西雅图的开放数据没有 2016 年 CSV 的 schema:我得靠 3,194 栋共同建筑来重建列,然后过滤掉那些虽然被标为合规、实则可疑的申报(有一栋建筑申报的能耗是上一年的 278 倍)。没有这份工作,整整一年的 R² 会崩掉。

模型的 Grafana 看板:按模型和来源的预测、预测能耗的分布、按年份的真实误差,以及对数刻度上预测对真实的散点。
图 5 · 模型的 Grafana 看板,直接读 PostgreSQL:按模型和来源的量、预测分布、按年份的真实误差,以及预测对真实(对数刻度)。

解读结果。 CatBoost 因为树结构,天然提供变量重要性和精确的 SHAP 值。Kumo 什么都没有。需要一种与模型无关的方法:置换重要性。把某个变量在测试建筑之间打乱,测量误差涨了多少。借助批量处理,这可行:17 个变量、3 次置换、2 个目标,大约一小时计算。

  • CatBoost
  • Kumo-Tabular
能耗上的置换重要性010203040 pts建筑面积34.9 pts32.7 pts主要用途2.1 pts24.2 pts物业类型14.3 pts14.9 pts第二用途面积2 pts12 pts第二用途0.9 pts7.6 pts停车1.9 pts7.2 pts能耗上的置换重要性010203040 pts建筑面积34.9 pts32.7 pts主要用途2.1 pts24.2 pts物业类型14.3 pts14.9 pts第二用途面积2 pts12 pts第二用途0.9 pts7.6 pts停车1.9 pts7.2 pts
图 6 · 能耗:打乱变量时相对误差中位数的上升,单位点(3 次置换的平均,Kumo 用完整上下文)。低于 2 个点就是噪声。
  • CatBoost
  • Kumo-Tabular
排放上的置换重要性0102030 pts建筑面积26.2 pts22.4 pts天然气23 pts19.9 pts主要用途6.3 pts14.4 pts物业类型6.4 pts4.2 pts城市蒸汽6.2 pts3.2 pts排放上的置换重要性0102030 pts建筑面积26.2 pts22.4 pts天然气23 pts19.9 pts主要用途6.3 pts14.4 pts物业类型6.4 pts4.2 pts城市蒸汽6.2 pts3.2 pts
图 7 · 排放:同样的测量。两个模型都依赖建筑面积和天然气接入。

两个模型在要点上一致:先是面积,然后是建筑的用途。它们在描述用途的那个变量上出现了分歧。CatBoost 依赖物业类型,Kumo 依赖主要用途。这两列基本重合,除了某些建筑。测试里的数据中心,在物业类型上是「Other」,在主要用途上是「Data Center」。CatBoost 把它看成一个「其他」,Kumo 把它看成数据中心,而 Kumo 的优势正是出在这栋建筑上。Kumo 还把重要性分摊到更多变量上:第二用途的面积、停车、楼层数。

在排放上,天然气接入在两个模型里都紧随面积之后。对 CatBoost 来说,按 SHAP 它甚至是第一变量(占重要性 28%,面积 27%)。城市蒸汽也有分量。这与问题的物理相符:西雅图的电力以水电为主,因此碳排低。排放主要来自燃烧,天然气在现场烧,蒸汽则在管网的锅炉房里烧。模型重新发现了能源工程师本就熟悉的东西。这让人安心,也是这项练习的局限:它们只看得见变量所描述的东西。

基于上下文的模型或许能提供另一种解释:「这栋建筑像那几栋」。我没找到 Kumo-Tabular 会如何把这些有影响的示例暴露出来。

我从中得到什么

仍然开放的问题

  • 更大的测试集,或者按建筑做交叉验证,让三栋建筑不再决定排名。
  • 在每个数据集规模上重新调 CatBoost,而不是沿用为 1,236 行调好的超参数。
  • 真正的新建筑,而不是超过 1,236 行后同一批建筑的其他年份。
  • 按相似度共享的上下文,在相近建筑之间复用,既保留邻居带来的增益又不失批量处理。

链接

地图位置

图 8 · 本条目及其邻居
  1. LLM Summarizer Trainer项目
  2. OC-Ai-Engineer-P3项目
  3. Fashion Trend Intelligence项目