静态缓存页面 · 查看动态版本 · 登录
智柴网 登录 | 注册
← 返回话题
✨步子哥 @steper · 2026-06-13 07:54

Born 集成架构分析

1. 完整文件清单

直接依赖 github.com/born-ml/born(4 个源文件)

文件角色
c:\GitHub\leaves\tree\born_engine.goBorn 推理引擎入口,borncpu.New() + 调用 tree/born
c:\GitHub\leaves\tree\born\tensors.goBackend 类型别名 + tensor.FromSlice 辅助
c:\GitHub\leaves\tree\born\forest.goGBDT 张量算法:WalkTreeBatchForestMarginsDense
c:\GitHub\leaves\treebuilder\hist_accel_born.go训练直方图增益扫描(//go:build born_train),绕过 tree/born

tree/born 子包(3 个源文件,无 born-ml import 的 IR 层)

文件角色
c:\GitHub\leaves\tree\born\ir.goTreeData / ForestData / DecisionFunc
c:\GitHub\leaves\tree\born\forest.go见上
c:\GitHub\leaves\tree\born\tensors.go见上

Born 桥接 / 转换 / 选型(无 born-ml import)

文件角色
c:\GitHub\leaves\tree\born_convert.goForestIRborn.ForestData 深拷贝 + MakeDecisionFn
c:\GitHub\leaves\tree\decision.goTreeDecision — Born 标量回退路径的 categorical 逻辑
c:\GitHub\leaves\tree\backend_select.goBackend* 常量、SelectBackendBornSupports
c:\GitHub\leaves\tree\engine.goEngine 接口、Backend 枚举
c:\GitHub\leaves\tree\forest_predict.goNative 路径 margin 聚合(与 born/forest.go 逻辑平行)

引擎工厂 / API 层

文件角色
c:\GitHub\leaves\model\build.goBackendBornCPU/GPUNewBornEngine,否则 NewNativeEngine
c:\GitHub\leaves\model\backend.goModelIRModelCapstree.ResolveBackend
c:\GitHub\leaves\bridge.goEngineOptions{Backend, Workload}model.NewEngineWithHint
c:\GitHub\leaves\io\io.go / load.go重导出 Backend* 常量
c:\GitHub\leaves\predict\engine.go统一 predict.Engine 接口

Native 对照路径(golden,非 Born 但架构对称)

文件角色
c:\GitHub\leaves\tree\native.goNativeEngine,调用 ForestMargins
c:\GitHub\leaves\tree\ir.goForestIR / TreeIR 领域 IR

训练 Born 桩 / 测试

文件角色
c:\GitHub\leaves\treebuilder\hist_accel_stub.go!born_train 时回退 CPU
c:\GitHub\leaves\treebuilder\hist.go调用 scanHistGains
c:\GitHub\leaves\tree\born_test.goBorn vs Native smoke/parity
c:\GitHub\leaves\born_parity_test.go全库 parity 门禁
c:\GitHub\leaves\tree\backend_select_test.go后端选型测试
c:\GitHub\leaves\treebuilder\t4_born_test.gohist Born 增益测试
c:\GitHub\leaves\backend_bench_test.goNative/BornCPU/BornGPU benchmark
c:\GitHub\leaves\delegation_test.goNative vs BornCPU 委托对比
c:\GitHub\leaves\io\backend_test.goBackendAuto 加载测试

配置 / 文档

文件角色
c:\GitHub\leaves\go.modreplace github.com/born-ml/born => C:/GitHub/born
c:\GitHub\leaves\AGENTS.md, NOTES.md, README.md, 演进计划.md架构决策文档

未接线 / 遗留

  • BornConfig.UseGPUborn_engine.go 中被 _ = cfg.UseGPU 丢弃,始终 borncpu.New()BackendBornGPU 选型存在但 GPU 未实现
  • tree/born/forest.goHasNaN 无调用方(死代码)
  • glob 显示 tree/gomlx_engine.go 存在但当前环境读不到(可能未跟踪);AGENTS 已声明 GoMLX 废弃
---

2. Import 依赖图

github.com/born-ml/born
├── backend/cpu  ─────────────────────────────────────────┐
└── tensor       ─────────────────────────────────────────┤
                                                          │
    tree/born/tensors.go  ◄───────────────────────────────┤
    tree/born/forest.go   ◄───────────────────────────────┤
    tree/born_engine.go   ◄───────────────────────────────┤
    treebuilder/hist_accel_born.go  (born_train tag) ◄────┘

github.com/dmitryikh/leaves/tree/born
    tree/born/ir.go          (无 born-ml import)
    tree/born_convert.go  ◄── tree/born
    tree/born_engine.go   ◄── tree/born + born-ml

github.com/dmitryikh/leaves/tree  (领域 IR + 双引擎)
    ir.go, decision.go, forest_predict.go, native.go
    born_convert.go, born_engine.go, backend_select.go, engine.go
         │
         ├── model/build.go ──► predict.Engine
         ├── bridge.go (EngineOptions)
         └── io/load.go (Backend 重导出)

treebuilder/hist_accel_born.go  ──► born-ml 直接(不经 tree/born)
treebuilder/hist.go             ──► scanHistGains() 抽象

关键边界tree/ 不依赖 train/tree/born/ 不 import tree(避免循环),因此需要 TreeData/ForestData 快照 + DecisionFunc 回调注入 categorical 逻辑。

---

3. 各层抽象:leaves ↔ born-ml/born

抽象作用
L0 领域 IRForestIR / TreeIR (tree/ir.go)框架无关 GBDT 中间表示(LGB/XGB/sklearn 加载目标)
L1 快照 IRborn.TreeData / born.ForestData (tree/born/ir.go)TreeIR/ForestIR 字段镜像,解 import cycle
L2 转换ForestToBorn / TreeToBorn (tree/born_convert.go)引擎构造时 深拷贝 全部 slice
L3 决策注入DecisionFunc + MakeDecisionFnTreeDecisionCatSmall / 大 bitset 分类分裂回退到 tree/decision.go
L4 GBDT 算法tree/born/forest.go在 Born 张量上做 batch 树遍历、margin 聚合(非 born-ml 内置能力)
L5 张量辅助tree/born/tensors.goBackend = borncpu.Backend 别名 + FromSlice/Gather 封装
L6 引擎BornEngine vs NativeEngine同构 tree.Engine 接口;构造时二选一,非运行时互调
L7 选型Backend + SelectBackend + BornSupportsworkload 驱动的引擎选择
L8 训练hist_accel_born.go独立使用 born-ml 做 hist 增益向量化,与推理 tree/born 无关
born-ml/born 本身:通用张量库(tensor.TensorGatherMulDiv 等),无 GBDT / 树遍历抽象。leaves 在 tree/born/ 自行实现 GBDT 所需原语。

---

4. tree/born/ 子包:是 facade 吗?

不完全是。 三层混合:

1. 薄 facadetensors.go):type Backend = borncpu.BackendmustFromF64 等 — 可合并进 born_engine.go。 2. 适配器 IRir.go):TreeData/ForestDataTreeIR/ForestIR 的平行 struct — 为解循环,不是 born-ml API 的 facade。 3. 算法层forest.go,~487 行):WalkTreeBatchForestMarginsDense、叶值 gather — 核心业务逻辑,不应称为 facade。

设计意图(见 ir.go 注释):*「与 tree.TreeIR 解耦,避免 import cycle」*。

---

5. BornEngine vs NativeEngine 委托模式

引擎级:互斥,非委托

model/build.go 在构造时按 Backend 选择 一个 引擎:

``34:38:c:\GitHub\leaves\model\build.go case tree.BackendBornCPU, tree.BackendBornGPU: cfg := &tree.BornConfig{UseGPU: backend == tree.BackendBornGPU} return tree.NewBornEngine(ir.Forest, transform, outputType, ir.NOutputGroups, cfg) default: return tree.NewNativeEngine(ir.Forest, transform, outputType, ir.NOutputGroups), nil

两者平行实现同一 `tree.Engine` / `predict.Engine` 接口;`NativeEngine` 是 golden,`BornEngine` 是加速路径。

### Born 路径内部:张量 + Native 混合

`ForestMarginsDense` 对每棵树分支:

- **张量 batch**:数值分裂 + CatOneHot(`TreeNeedsNativeWalk == false`)→ `WalkTreeBatch` + Born `Gather`
- **标量回退**:CatSmall / 大 bitset → 逐行 `WalkTreeScalar(t, fvals, decide)`,`decide` 来自 `TreeDecision(t.TreeIR, ...)`

Leaf index 预测(`TransformLeafIndex`)在 `BornEngine` 中逐树、逐样本混合上述两路。

CSR 输入:`BornEngine.PredictCSR` 先 **densify** 再 `PredictDense`(无 Born 稀疏路径)。

### 选型级:`BornSupports` 整森林 gate

含 `CatSmall` 时 `BackendBornCPU` 自动选型返回 false;但 **显式** 指定 `BackendBornCPU` 仍可创建 `BornEngine`(per-tree 标量回退),见 `born_parity_test.go` KDDCup99 注释。

---

## 6. ForestData/TreeData vs ForestIR/TreeIR

| 维度 | `ForestIR` / `TreeIR` | `born.ForestData` / `born.TreeData` |
|------|----------------------|-------------------------------------|
| 位置 | `tree/ir.go` | `tree/born/ir.go` |
| 额外字段 | `Name`, `NumParallelTree`, `SplitGain`, `SumHess`, `NumLeaves` | 无(仅 Born 推理所需子集) |
| 生命周期 | 加载/训练全程 | `NewBornEngine` 时深拷贝,引擎内只读 |
| 用途 | 领域 IR、Native、explain、io | Born 张量图输入 |

转换在 `born_convert.go` 逐字段 `append([]T(nil), ...)` — **O(n) 内存复制**,引擎持有双份树数据(`BornEngine.forest` + `BornEngine.bornForest`)。

---

## 7. 冗余转换 / 包装类型

### 明确冗余

| 冗余 | 位置 A | 位置 B | 说明 |
|------|--------|--------|------|
| **Margin 聚合** | `tree/forest_predict.go` `ForestMargins` | `tree/born/forest.go` `ForestMarginsDense` | `adjustNEstimators`、`classBaseScore`、`forestTreeClassIndex`、`scaleExceptBase` 几乎同构 |
| **树遍历** | `forest_predict.go` `walkTree` | `born/forest.go` `WalkTreeScalar` | 相同 DFS 逻辑 |
| **叶值读取** | `treeLeafScalar/Vector` (两处) | 同上 | 重复 |
| **零值判定** | `decision.go` `isZeroFval` | `born/forest.go` `isZeroFval` | 第三份在 `explain/treeutil.go` |
| **IR 快照** | `TreeIR`/`ForestIR` | `TreeData`/`ForestData` + `ForestToBorn` | 字段镜像 + 深拷贝 |
| **引擎状态** | `BornEngine.forest *ForestIR` | `BornEngine.bornForest ForestData` | 双份持有;leaf index 路径仍读 `forest.Trees` |
| **Decision 闭包** | `[]born.DecisionFunc` 每棵树一个 | 闭包捕获 `*TreeIR` | 与 `bornForest` 中 `TreeData` 并行存在 |
| **Backend 包装** | `born.Backend = borncpu.Backend` | 可直接用 borncpu | 一行别名 |
| **GPU 占位** | `BackendBornGPU` / `BornConfig.UseGPU` | 实际只用 CPU | 虚假抽象层 |

### 非冗余(应保留)

- **`ForestIR` / `TreeIR`**:框架无关领域 IR,加载、explain、训练、Native golden 共用
- **`tree.Engine` / `predict.Engine`**:可插拔后端契约
- **`NativeEngine`**:正确性基准与 categorical 完整实现
- **`DecisionFunc` 注入模式**:在 Born 未实现 CatSmall/bitset 张量化前必要
- **`backend_select.go`**:部署/workload 策略
- **`tree/born/forest.go` 算法本身**:born-ml 不提供 GBDT,此层不可删,只能合并位置

---

## 8. 「完全拥抱 Born、去掉中间层」建议

### 可移除 / 合并

1. **`TreeData` / `ForestData` + `born_convert.go`**  
   - 方案:把 `tree/born/*.go` 移入 `tree` 包(如 `tree/born_forest.go`),直接读 `*ForestIR`/`*TreeIR`  
   - 前提:接受 `tree` 包 import `born-ml`(已有 `born_engine.go` 先例)  
   - 收益:消除深拷贝、双份 IR、转换维护成本

2. **`ForestMargins` vs `ForestMarginsDense` 重复**  
   - 方案:提取共享 `forestMarginsCore`(接受 interface 或函数参数),Native 单样本 / Born batch 共用迭代逻辑  
   - 或:Native 小 batch 也走 Born(仅保留 Native 作 golden 测试对照)

3. **`born.Backend` 类型别名 + `tensors.go` 小 helper**  
   - 可内联到 `born_engine.go` / `forest.go`,减文件数

4. **`BornEngine.forest` 冗余引用**  
   - leaf index 改为只用 `bornForest` + `decisions`,或统一 IR 后只保留一份

5. **`BackendBornGPU` / `UseGPU` 占位**  
   - 未实现前应删除或明确 stub,避免误导(当前 `backend_test` 期望 GPU 选型但引擎不接线)

6. **`HasNaN`(born/forest.go)**  
   - 未使用,可删

7. **训练路径统一**  
   - `hist_accel_born.go` 直接 import born-ml,与 `tree/born` 分裂;可共用 `tree/born/tensors.go` 的 helper(若保留子包)

### 应保留

| 组件 | 理由 |
|------|------|
| **`ForestIR` / `TreeIR`** | 领域 IR;Born 只是执行后端 |
| **`NativeEngine`** | Golden、完整 categorical、零 Born 依赖部署 |
| **`BornEngine` 作为 `Engine` 实现** | 接口清晰,benchmark/parity 可切换 |
| **`tree/born/` 算法层(或合并后的等价代码)** | born-ml 无 GBDT;必须在 leaves 实现 batch 树遍历 |
| **`DecisionFunc` + `TreeDecision`(至 CatSmall 张量化完成)** | 分类特征正确性 |
| **`backend_select.go`** | Auto/WASM/GPU batch 策略 |
| **`born_train` build tag** | 可选训练加速,默认零依赖 |
| **`model/build.go` 工厂** | 统一入口 |

### 「完全拥抱」的 realistic 终点

不是删掉所有 wrapper 直接用 born-ml API(born 没有树模型),而是:

ForestIR (保留) ↓ 无拷贝指针 Born GBDT kernels (合并进 tree 或保留 tree/born) ↓ born-ml tensor (Gather/Mul/…) + NativeEngine (golden + categorical fallback,长期可仅测试用)
---

## 9. 架构示意

mermaid flowchart TB subgraph domain ["领域层 (保留)"] IR["ForestIR / TreeIR"] Native["NativeEngine\nforest_predict.go"] end

subgraph born_layer ["Born 集成层 (可瘦身)"] Conv["born_convert.go\nForestToBorn 深拷贝"] Snap["TreeData / ForestData"] Algo["tree/born/forest.go\nWalkTreeBatch / ForestMarginsDense"] Eng["BornEngine"] end

subgraph external ["github.com/born-ml/born"] CPU["backend/cpu"] T["tensor"] end

subgraph train ["训练 (独立)"] Hist["hist_accel_born.go\nborn_train tag"] end

IR --> Native IR --> Conv --> Snap --> Algo IR --> Eng Snap --> Eng Eng --> Algo Algo --> T Algo --> CPU Eng --> CPU Hist --> T Hist --> CPU decision["tree/decision.go\nTreeDecision"] -.->|DecisionFunc 回调| Algo `

---

10. 要点总结

  • Born 集成是 四层:born-ml 张量 → tree/born GBDT 算法 → born_convert/born_enginemodel/io 选型。
  • tree/born/ 不是 born-ml 的 facade,而是 GBDT-on-tensor 算法包 + 解循环 IR 快照;仅 tensors.go 偏 facade。
  • BornEngineNativeEngine 构造期互斥;Born 内部对复杂 categorical per-tree/per-row 回退 Native 决策
  • 最大冗余:双份 IR(ForestIR + ForestData)双份 margin 逻辑(forest_predict vs born/forest)
  • BackendBornGPU 已选型但未实现;BornConfig.UseGPU 被忽略。
  • 训练加速 (hist_accel_born.go) 与推理 (tree/born`) 共享 born-ml 依赖但代码路径分离

👍 1