NVIDIA Kumo Tabular:如何验证表格预测的准确率与效率新边界

2026-09-29 34 预计阅读时间: 1 分钟
来源: huggingface.co AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:10 分钟

表格数据仍然支撑着风控、推荐、需求预测、客户流失和运营决策等大量生产系统。NVIDIA 将 Kumo Tabular 描述为在表格预测准确率与效率之间建立了新的前沿,这个表述真正值得关注的地方,不是某个孤立的最高分,而是模型能否在同样的延迟、显存和成本预算下给出更好的预测。

由于给定来源没有提供具体数据集、硬件配置、模型接口或基准数字,下面不推测 Kumo Tabular 的内部架构,而是讨论团队应如何验证这一主张,并给出一套可直接运行、也可以接入实际产品输出的评测方法。

“准确率—效率前沿”不是一个指标

表格模型的比较经常被压缩成一列 AUC 或 RMSE,但生产环境中的最优模型通常位于一条 Pareto 前沿上:如果一个方案想继续提高准确率,就必须付出更多训练时间、推理延迟、内存或计算成本;如果 Kumo Tabular 能在不增加这些成本的情况下提高质量,它才真正推动了前沿。

对于二分类任务,可以至少记录以下指标:

  • 预测质量:ROC AUC、PR AUC、Log Loss,以及业务阈值下的召回率和精确率。
  • 校准能力:预测概率是否能直接解释为风险概率。信贷、流失预警等场景不能只看排序。
  • 训练效率:端到端训练耗时、峰值 CPU/GPU 内存和数据准备时间。
  • 在线效率:单条请求 P50/P95/P99 延迟,以及批量推理吞吐量。
  • 运行成本:完成一次训练或处理一百万行数据所需的实际成本。

回归任务则可以使用 MAE、RMSE 或业务加权误差。需要避免把不同硬件、不同数据切分或不同调参预算下的结果放在同一张表中直接比较。

基准设计比模型名称更重要

验证 Kumo Tabular 时,传统梯度提升树、当前生产模型和简单线性模型都应该保留。线性模型用于发现数据泄漏或任务过于简单的问题;成熟树模型提供强基线;生产模型则反映迁移是否真的值得。

数据切分也必须贴近业务过程:

  • 有时间顺序的数据采用时间切分,而不是随机打散。
  • 同一用户、设备或商家产生的记录应按实体分组,避免跨集合泄漏。
  • 特征只能使用预测时刻已经存在的信息。
  • 预处理、特征选择和超参数搜索只能在训练集内部完成。
  • 所有候选模型必须使用相同的测试集和指标实现。

还要分别测试冷启动、缺失值、类别漂移和长尾实体。一个模型在随机测试集上领先,并不意味着它在下个月的新客户上也能保持优势。

可运行的评测骨架

下面的示例建立一个本地 HistGradientBoostingClassifier 基线,并导出不含标签的验证输入。如果已经通过 Kumo Tabular 的正式接口生成预测,只需保存为 kumo_predictions.csv,脚本就会使用同一批标签计算指标。

这里没有假设任何未在来源中给出的 Kumo SDK 或 API。接入时应以实际产品文档为准。

先准备环境:

python -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install numpy pandas scikit-learn

将以下内容保存为 benchmark_tabular.py:

from pathlib import Path
from time import perf_counter

import numpy as np
import pandas as pd
from sklearn.datasets import make_classification
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.metrics import log_loss, roc_auc_score
from sklearn.model_selection import train_test_split

RANDOM_STATE = 42

# 用自己的 DataFrame 和标签替换这里,即可评测真实业务数据。
X_array, y = make_classification(
    n_samples=50_000,
    n_features=40,
    n_informative=18,
    n_redundant=8,
    weights=[0.82, 0.18],
    class_sep=1.0,
    random_state=RANDOM_STATE,
)
X = pd.DataFrame(
    X_array,
    columns=[f'feature_{i}' for i in range(X_array.shape[1])],
)

X_train, X_valid, y_train, y_valid = train_test_split(
    X,
    y,
    test_size=0.2,
    stratify=y,
    random_state=RANDOM_STATE,
)
X_train = X_train.reset_index(drop=True)
X_valid = X_valid.reset_index(drop=True)
y_train = np.asarray(y_train)
y_valid = np.asarray(y_valid)

# 导出给外部候选模型的输入,故意不包含标签。
validation_input = X_valid.copy()
validation_input.insert(0, 'row_id', np.arange(len(validation_input)))
validation_input.to_csv('validation_input.csv', index=False)

baseline = HistGradientBoostingClassifier(
    learning_rate=0.08,
    max_iter=200,
    l2_regularization=1.0,
    random_state=RANDOM_STATE,
)

started = perf_counter()
baseline.fit(X_train, y_train)
fit_seconds = perf_counter() - started

# 预热后重复批量推理,避免只测一次造成较大抖动。
baseline.predict_proba(X_valid.iloc[:100])
repeats = 30
started = perf_counter()
for _ in range(repeats):
    baseline_probability = baseline.predict_proba(X_valid)[:, 1]
elapsed = perf_counter() - started
milliseconds_per_1000_rows = (
    elapsed / repeats / len(X_valid) * 1_000_000
)


def evaluate(name, probability):
    probability = np.asarray(probability, dtype=float)
    probability = np.clip(probability, 1e-7, 1 - 1e-7)
    return {
        'model': name,
        'roc_auc': round(roc_auc_score(y_valid, probability), 6),
        'log_loss': round(log_loss(y_valid, probability), 6),
    }


results = [evaluate('hist_gradient_boosting', baseline_probability)]
results[0]['fit_seconds'] = round(fit_seconds, 3)
results[0]['batch_ms_per_1000_rows'] = round(
    milliseconds_per_1000_rows, 3
)

# 可选文件格式:row_id,probability
candidate_path = Path('kumo_predictions.csv')
if candidate_path.exists():
    candidate = pd.read_csv(candidate_path).sort_values('row_id')
    expected_ids = np.arange(len(y_valid))

    if not {'row_id', 'probability'}.issubset(candidate.columns):
        raise ValueError(
            'kumo_predictions.csv must contain row_id and probability'
        )
    if not np.array_equal(candidate['row_id'].to_numpy(), expected_ids):
        raise ValueError('row_id must cover every validation row exactly once')

    # 外部服务的训练和推理耗时应在相同硬件及批量条件下另行记录。
    results.append(evaluate('kumo_tabular', candidate['probability']))

print(pd.DataFrame(results).to_string(index=False))
print('\nExternal validation features: validation_input.csv')

运行基线:

python benchmark_tabular.py

如果实际接口返回了每行属于正类的概率,可以整理成下面的文件后再次运行:

row_id,probability
0,0.0812
1,0.7734
2,0.1941

这套脚本只演示最小闭环。真实评测还应使用独立测试集,重复多个随机种子,并分别测量单条请求和典型批量大小。若 Kumo Tabular 运行在 GPU 或远程服务上,网络往返、序列化和数据上传时间也应该计入端到端延迟。

从试验结果走向生产决策

不要因为候选模型提高了几个小数点就立即替换现有系统。更稳妥的采用路径是:

  1. 离线复现:固定数据快照、切分规则、随机种子、依赖版本和硬件型号。
  2. 构建 Pareto 图:横轴放成本或延迟,纵轴放核心质量指标,同时标出内存占用。
  3. 检查分群表现:比较新老客户、地区、设备、长尾类别和缺失值比例不同的样本。
  4. 验证概率校准:如果下游按概率定价或触发人工审核,应增加 Brier Score 和校准曲线。
  5. 影子运行:让候选模型读取线上流量但不参与决策,观察延迟、漂移和失败率。
  6. 保留回退方案:明确超时、服务不可用、特征缺失和版本回滚时使用的基线模型。

NVIDIA Kumo Tabular 是否真的建立了新的准确率—效率前沿,最终应由团队自己的数据、硬件和服务等级目标决定。值得寻找的并不是“所有数据集上都最强”的模型,而是在你的约束下不被其他方案同时从准确率和成本两方面击败的方案。


相关推荐