跳转至

模块设计:输入与分箱

1. 职责

把用户数值矩阵转换为稳定、紧凑的分箱表示,并定义所有权、缺失值、边界和序列化语义。分箱结果是 CPU oracle 与 MPS 后端的共同输入。

2. 输入不变量

  • rows > 0features > 0
  • rows × features × itemsize 使用检查过的 64 位算术;
  • 0.2.0 输入全部有限;
  • 不支持的 dtype 在分配大内存前拒绝;
  • 行数和特征数不得超过内部索引类型上限。

3. 分箱算法

0.2.0 使用确定性分位数边界:

  1. 按特征读取有限值;
  2. 以稳定规则生成最多 max_bins - 1 个切分边界;
  3. 去除相同边界,常量特征只产生一个有效 bin;
  4. 使用固定的 upper_bound/lower_bound 语义映射值;
  5. 相同输入、参数和版本必须产生相同边界与 bin。

算法只实现一次。并行化可以改变执行顺序,但不能改变边界规则。

4. 内部表示

  • max_bins <= 256 使用 uint8_t
  • 257..65536 使用 uint16_t
  • 超过范围在 0.2.0 拒绝;
  • 边界使用连续 float32 或冻结后的精度;
  • 特征元数据记录 offset 和有效 bin 数。

训练布局默认 feature-major,以连续读取单特征样本;最终决定需通过布局基准。模型格式只保存边界,不保存训练布局。

5. 数据所有权

  • Python 输入只在同步验证与转换期间借用;
  • BinnedDataset 拥有其分箱内存;
  • 不得保存用户临时 buffer 的裸指针;
  • 若零复制条件不满足,必须明确复制并可诊断;
  • 上传设备后,host 数据的释放时机由训练会话统一管理。

6. 缓存

0.2.0 首先支持进程内复用。磁盘分箱缓存只有完成以下条件后才能启用:

  • fingerprint 覆盖数据内容、形状、dtype、分箱参数和格式版本;
  • 原子写入与校验;
  • 不缓存标签;
  • 用户可查询和清理;
  • 损坏或不匹配时重建。

7. 错误与安全

  • 所有 offset 和 stride 运算检查溢出;
  • 不允许 NaN 在不同平台被映射到不同 bin;
  • 分配前估算 host 与 device 峰值;
  • 错误消息说明数据形状、所需类型与限制,不打印原始数据。

8. 验收

  • 手算边界、常量、重复值、极端偏斜、最大 bin 和非连续输入测试;
  • 同一数据重复执行得到完全一致的 bin;
  • CPU oracle 与 MPS 使用相同只读视图;
  • 无越界、悬空指针或隐藏的多份全量复制。