Skip to content

Basalt 3.5.0 — 三层 API:一行建模、拼装训练、手写一切

Choose a tag to compare

@github-actions github-actions released this 30 Oct 11:46
· 14 commits to main since this release

Basalt 3.5.0

同一个库,三种介入深度。三层共用同一套张量与同一张计算图,所以上一层不会限制下一层。

  • 坐标 — io.github.9178nekomc:basalt:3.5.0
  • 在线文档 — https://9178nekomc.github.io/basalt/
  • 运行要求 — Java 21,启动加 --add-modules jdk.incubator.vector
  • 规模 — 235 个公开类型 / 1510 个公开成员,全部带逐参数说明

第一层:一行跑起来

AutoModel model = Auto.quickstart(features, labels);
System.out.println(model.summary());
double[] prediction = model.predict(unseen);

它自己判断这是分类还是回归:目标全为整数且不同取值不多时按分类处理,否则按回归。
然后按该任务把注册过的算法全部用分层 K 折交叉验证跑一遍,取最优者在全量数据上重训,
最后在 25% 留出集上报分——留出集没有参与拟合,也没有参与筛选。

细节可以调:

AutoModel model = Auto.builder(features, labels)
        .folds(10)
        .testFraction(0.2)
        .candidates("random_forest", "gradient_boosting")
        .metric(Estimators.Metric.MACRO_F1)
        .fit();

筛选表按分数排序,summary() 直接打印成表。RMSE 这类越小越好的指标在写入前取负,
所以「分数越高越好」在所有指标上一致成立。

第二层:拼装与训练

try (Basalt engine = Basalt.create()) {
    Sequential<BC, BC> net = Zoo.tabularClassifier(engine, 4, 3);
    History history = Trainer.of(engine.context(), net,
                    engine.adamw(net.parameters(), 1e-2f), engine.crossEntropy())
            .epochs(50)
            .batchSize(16)
            .earlyStopping(5)
            .fit(engine.tensor(features, rows, 4), engine.tensor(labels, rows));
}
  • Zoo 提供 mlp、tabularClassifier、cnnClassifier,返回的都是普通 Sequential,可以继续 add
  • Trainer 是手写循环的封装:前向、损失、反向、更新、清梯度、清图,一步不省
  • 早停带 1e-12 容差,浮点抖动不会被当成进步
  • 某轮损失变成非有限值时直接抛异常,而不是继续训出一个坏模型

批次是把行复制进新张量,不是在原张量上切片——每个批次多一次数组拷贝,换来计算图里没有视图、没有隐藏别名。

第三层:手写一切

一个层只需要两个方法:

final class MyLayer extends Module<BC, BC> {
    private final Tensor weight = Tensor.parameter(context, 128, 64);

    @Override public Tensor forward(Tensor input) { return input.matMul(weight).tanh(); }
    @Override public List<Tensor> parameters() { return List.of(weight); }
}

Trainer 只认 Module,所以手写层和库里的层走完全相同的训练路径。

算法层面用注册表扩展:

Registry.register("my_regressor", Task.REGRESSION, MyRegressor::new);
Auto.quickstart(features, targets);   // 新算法与 23 个内置算法同台竞争

重复注册会被拒绝而不是静默替换——筛选顺序和报告标签都依赖名字唯一。

本版还修了什么

  • verify.sh 仍在找 jsl/tests 下的 Phase 1–3 类,改名后这三套测试一直被静默跳过。现已恢复,
    三套共 27 组用例重新纳入验证。
  • 新的 JUnit 测试被误纳入 legacy javac 路径(没有 JUnit classpath),已排除。

产物

文件 说明
basalt-3.5.0.jar 标准 jar,含四个平台原生库
basalt-3.5.0-all.jar Fat jar,无外部依赖
basalt-3.5.0-sources.jar 源码

验证

  • ./verify.sh:Rust 单测、javac -Xlint:all 零告警、6 套 legacy 测试、Phase 1–3、JUnit 5、6 个编译期拒绝用例
  • AdvancedApiTest 9 项:三层 API 各 3 项,含自定义层与自定义算法
  • 冒烟测试:对打包后的 all-jar 编译运行,三层各自跑通