Basalt»3.4.0»API 参考»basalt.io
模块 索引 GitHub

模块 basalt.io

7 个公开类型 · 3 个包内可见类型

模型持久化:.bsl v2 容器(magic + kind + 长度 + CRC32C)。

类型概览

类型种类说明
ModelCodecclass带版本与 CRC32C 校验的 .bsl 模型容器读写器。
OnnxConverterclassONNX 导入导出门面:把 Basalt 估计器与模块翻译成 .onnx。
OnnxModelclassONNX ModelProto 的内存表示与原生推理引擎,零依赖编解码。
OnnxModel.AttributerecordONNX 节点属性的不可变记录,涵盖标量与数组两类载荷。
OnnxModel.NoderecordONNX 计算图节点:算子类型、输入输出值名与属性表。
OnnxModel.TensorDatarecordONNX 常量张量:名字、维度与 float32 载荷。
OnnxModel.ValueInforecordONNX 值声明:名字、元素类型与形状。
final class ModelCodec

带版本与 CRC32C 校验的 .bsl 模型容器读写器。

容器由 24 字节头与载荷组成,字段依次为 int magic = 0x42534C54("BasaltM")、int version = 2、int kind(ModelKind 编码)、int length(载荷字节数)、long crc32c,随后是 length 字节的模型载荷,均按大端序。

save() 让模型把状态写进内存 ModelWriter,再分配整文件缓冲、填头并循环写出;load() 只读映射整个文件,依次比对 magic、version、长度与文件大小,再在映射区原地计算 CRC32C,通过后把偏移 24 起的零拷贝切片交给按 ModelKind 分发的读取器。

载荷解码完成后要求被完整消费,残留字节视为格式错误。所有失败以未检查异常抛出:结构性问题用 ModelFormatException,I/O 问题包装为 UncheckedIOException。

示例
Matrix features = Matrix.fromRows(new double[][]{
        {0.0, 1.0}, {1.0, 1.5}, {9.0, 8.5}, {8.5, 9.0}});
KMeans model = KMeans.builder().clusters(2).build().fit(features);

Path file = Path.of("kmeans.bsl");
ModelCodec.save(file, model);
KMeans restored = ModelCodec.load(file, KMeans.class);
long bytes = ModelCodec.fileSize(file);

注意

save 会截断已存在的目标文件,且不写临时文件,写入中途失败会留下不完整文件。

注意

load 依赖内存映射,解码期间文件须保持不变;文件被替换或截断时映射区内容不再可信。

注意

版本不匹配直接拒绝,不做向后兼容解析;ModelFormatException 为 RuntimeException。

注意

类为静态工具,无实例(构造器私有),无可变状态,可并发调用。

参见:basalt.core.Persistable, basalt.core.ModelKind, basalt.core.ModelFormatException

方法

save(Path target, Persistable model)static

把模型序列化为 .bsl 文件。

先创建初始容量 4096 的 ModelWriter,调用 model.write 得到载荷字节,据此计算 CRC32C,再组装 24 字节头与载荷,以 CREATE、WRITE、TRUNCATE_EXISTING 打开通道循环写出。

target 或 model 为 null 时抛 NullPointerException;载荷长度超过 Integer.MAX_VALUE - 24 时抛 ModelFormatException;打开或写入失败抛 UncheckedIOException。模型的 write 实现自身抛出的异常会原样传播。

注意

载荷完整驻留内存,大模型峰值内存约为文件大小的两倍

注意

校验和在写入前一次算完,写出过程不再重新计算

参数
  • target (Path) – 输出路径,父目录须已存在,已存在文件会被截断

  • model (Persistable) – 待保存的模型,提供 kind() 与 write(ModelWriter)

load(Path source) → Persistablestatic

读取并校验 .bsl 文件,返回模型。

映射文件后依次校验:长度不小于 24 字节、magic 匹配、version 为 2、kind 编码可识别、声明长度等于文件大小减 24、CRC32C 与头部记录一致;随后按 ModelKind 分发到对应模型的 read 方法,并要求载荷被完整消费。

任一校验失败抛 ModelFormatException(截断、魔数错误、版本不支持、长度不符、校验和不匹配、载荷有残留字节);文件打开或映射失败抛 UncheckedIOException。

注意

校验在映射区上原地进行,不复制载荷

注意

返回类型取决于文件内容,需要具体类型时用 load(Path, Class)

参数
  • source (Path) – 输入路径,须为 save 写出的 .bsl 文件

返回

按文件内 kind 构造的模型实例,静态类型为 Persistable

<T extends Persistable> load(Path source, Class<T> type) → Tstatic

读取并校验类型后返回模型。

委托 load(Path) 完成全部结构校验与解码,再用 type.isInstance 检查结果;不匹配时抛 ModelFormatException,信息中同时给出期望类型与文件中实际的 ModelKind。

注意

类型不符时载荷已被解码,异常前不会泄漏句柄,但已付出解码开销

参数
  • source (Path) – 输入路径

  • type (Class<T>) – 期望的模型类型,例如 KMeans.class

返回

已转换为 T 的实例,可直接使用具体类型的访问器

readPayload(ModelKind kind, ModelReader reader) → Persistablestatic

按模型种类分派载荷解码。

load 完成头部与 CRC32C 校验后调用该方法:对 ModelKind 的每个常量用 switch 调用对应模型的静态 read(如 KMeans.read、Pipeline.read、ModelSerializer.readCNN),返回新实例;随后由调用方执行 requireFullyConsumed 检查残留字节。

switch 为穷尽式,新增 ModelKind 常量时必须补分支,否则编译失败。各模型的 read 在头部字段非法或载荷截断时抛 ModelFormatException。

注意

公开的扩展点,可脱离 load 直接对任意 ModelReader 使用,此时头部校验与 CRC32C 都不参与

注意

方法本身不校验 reader 是否被读完,残留字节由调用方用 requireFullyConsumed 判定

注意

不修改 reader 的所有权,两次调用之间需要自行重置位置

参数
  • kind (ModelKind) – 头部记录的模型种类,通常来自 ModelKind.fromCode 或 peekKind

  • reader (ModelReader) – 位于载荷起点(偏移 24)的读取器,可映射在文件上;位置由各 read 自行推进

返回

对应 kinds 的新实例,静态类型为 Persistable

抛出
  • ModelFormatException – kind 对应的 read 判定载荷头部非法或数据不足

peekKind(Path source) → ModelKindstatic

只读文件头,返回模型种类。

打开通道读取前 12 字节,校验 magic 与 version 后用第三个 int 调 ModelKind.fromCode。头部截断、魔数或版本不符、编码未知时抛 ModelFormatException;打开或读取失败抛 UncheckedIOException。

不映射载荷,也不校验长度与 CRC32C,因此开销恒定且与文件大小无关。

注意

适合在加载前按种类分派或做工具统计,结果不代表载荷完整

参数
  • source (Path) – 输入路径

返回

文件头 kind 字段对应的 ModelKind 常量

fileSize(Path source) → longstatic

返回 .bsl 文件的总字节数。

直接委托 Files.size,不解析头部也不校验内容;文件不存在、不可读或路径指向目录时抛 UncheckedIOException。

注意

载荷大小等于返回值减 24

注意

可对任意文件使用,不要求是 .bsl 容器

参数
  • source (Path) – 输入路径

返回

文件长度(字节),包含 24 字节头

字段

MAGIC()static

容器魔数 0x42534C54,即 ASCII "BasaltM"。

位于文件前 4 字节,save 写入,load 与 peekKind 校验;不匹配时抛 ModelFormatException("Invalid .bsl magic")。

注意

注意与 BasaltD 数据格式的魔数 0x4A534C44 不同

VERSION()static

当前容器版本号,值为 2。

紧随 magic 之后写入。load 与 peekKind 要求完全相等,其他版本一律抛 ModelFormatException("Unsupported .bsl version"),不尝试降级解析。

注意

版本只描述容器布局,载荷格式由各模型自行定义

final class OnnxConverter

ONNX 导入导出门面:把 Basalt 估计器与模块翻译成 .onnx。

导入侧只有 load,直接转调 OnnxModel.load。导出侧把两类对象翻译成节点与常量张量:估计器方向接受 Pipeline、StandardScaler、MinMaxScaler、PCA、LinearRegression、Ridge、Lasso、LogisticRegression、LinearSVM;模块方向接受 Sequential、Linear、Conv2d、DepthwiseSeparableConv2d、Activation、MaxPool2d、Flatten、BatchNorm2d、LayerNorm、Dropout 与 ComputationGraph。产物统一声明 IR v8、Opset 17。

翻译是结构性的:线性模型展开为 MatMul + Add,标准化器展开为 Sub/Mul(StandardScaler 的尺度取倒数预先算好),PCA 展开为 Sub + MatMul(主成分先转置),Pipeline 按步骤串联并以 step0、step1、est 等前缀命名中间值;LogisticRegression 在回归输出后再接 Sigmoid。类型不在支持列表内时在翻译阶段抛 BasaltUnsupportedOperationException,此时不会写出任何文件。

输入输出声明:估计器导出固定为 input 形状 [-1, inputFeatures] 与输出形状 [-1, outDim],-1 表示动态批;模块导出把调用方给的 inputShape 原样写进第一输入声明,输出形状留空(未知);ComputationGraph 导出中每个图输入都套用同一 inputShape。生成的算子集合限定在 OnnxModel 执行器的白名单内,因此导出的模型也能被重新加载执行。

示例
Matrix x = Matrix.fromRows(new double[][]{
        {0.0, 1.0}, {1.0, 1.5}, {9.0, 8.5}, {8.5, 9.0}});
double[] y = {0.0, 0.0, 1.0, 1.0};
LinearRegression model = LinearRegression.builder().build().fit(x, y);

Path file = Path.of("linear.onnx");
OnnxConverter.export(model, 2, file);

OnnxModel onnx = OnnxConverter.load(file);
int features = onnx.inputs().get(0).shape()[1];
Matrix scores = onnx.predictMatrix(x);

注意

全部数值以 float32 写入,Basalt 侧的 double 权重在导出时降精度;往返一次会引入 float32 舍入误差。

注意

只表达前向推理:Dropout 写成 Identity,BatchNorm2d 使用 runningMean/runningVar 与 epsilon,training_mode 不写。

注意

输出 shape 不写入具体维度,下游工具无法据文件做静态形状校验。

注意

导出不做算子集裁剪,也不检查目标机器上的 onnxruntime 版本是否支持 Opset 17。

注意

类为静态工具,无实例(构造器私有),无可变状态。

参见:basalt.io.OnnxModel, basalt.ml.Pipeline, basalt.torch.Sequential, basalt.torch.ComputationGraph

方法

load(Path path) → OnnxModelstatic

加载 .onnx 文件。

等价于 OnnxModel.load(path):整文件读入后按 proto3 线格式解析,不额外校验算子集合或 IR 版本。

注意

返回的模型可直接用于推断,遇到不支持的算子时在 run 阶段才报错

参数
  • path (Path) – 标准 .onnx 文件路径,须为可读普通文件

返回

解析出的 OnnxModel,图结构与元数据均来自文件

抛出
  • UncheckedIOException – 文件不存在、不可读或读取失败

export(Estimator estimator, int inputFeatures, Path target)static

把估计器导出为 .onnx 文件。

先调用 toOnnx(Estimator, int) 在内存中完成翻译,再 save(target) 写出。转换阶段的异常不会留下文件;写出失败时目标可能已被截断。

注意

null 参数与 inputFeatures 的非正校验由 toOnnx 完成,先于任何 I/O

注意

同一估计器可重复导出,翻译过程不修改原模型

参数
  • estimator (Estimator) – 待导出的估计器,须已完成 fit 以具备权重;Pipeline 会连同其末端估计器一起翻译

  • inputFeatures (int) – 输入特征数,决定 input 声明第二维与常量张量形状;须为正数

  • target (Path) – 输出路径,父目录须已存在,已存在文件被覆盖

抛出
  • BasaltUnsupportedOperationException – 估计器类型或 Pipeline 中某一步骤不受支持

  • UncheckedIOException – 目标路径不可写或写入失败

export(Module<?, ?> module, int[] inputShape, Path target)static

把深度学习模块导出为 .onnx 文件。

先调用 toOnnx(Module, int[]) 完成翻译,再 save(target)。Sequential 与 DepthwiseSeparableConv2d 会递归展开成等价的多节点链。

注意

inputShape 只记录在声明里,不做形状推断或校验

注意

ComputationGraph 的多个输入共用同一 inputShape

参数
  • module (Module<?, ?>) – 待导出的模块,权重取自其当前状态

  • inputShape (int[]) – 第一输入的完整形状(含批维),例如 {1, 3, 32, 32};原样写入 input 声明

  • target (Path) – 输出路径,父目录须已存在

抛出
  • BasaltUnsupportedOperationException – 模块链中出现不受支持的类型

  • UncheckedIOException – 目标路径不可写或写入失败

toOnnx(Estimator estimator, int inputFeatures) → OnnxModelstatic

把估计器翻译成内存中的 ONNX 模型。

按类型分流:Pipeline 遍历 steps() 逐个追加变换步骤(前缀 step0、step1…),若末端估计器非 null 再以 est 前缀追加;单独的 Transformer 走 tr0 前缀;其他估计器走 est0 前缀。追加过程中生成的权重、均值、尺度等以 TensorData 放入 initializers,节点名与值名由前缀派生。

返回的模型固定为 irVersion 8、opsetVersion 17、producerName "Basalt"、graphName "jsl_ml_graph";input 声明为 elemType 1、shape [-1, inputFeatures],output 声明为 elemType 1、shape [-1, outDim],其中 outDim 由最后一步决定(线性与逻辑回归为 1,PCA 为主成分个数,标准化器沿用输入维数)。

注意

所有常量都以 float32 副本写入,与 Basalt 侧的原数组不共享存储

注意

输出维度信息只在 ValueInfo 中体现,节点本身不携带 shape

注意

只翻译结构与数值,不写出 sklearn 的类名、参数列表等元数据

参数
  • estimator (Estimator) – 待翻译的估计器,其权重、均值、标准差等在调用时读取

  • inputFeatures (int) – 输入特征数,须大于 0;决定权重常量形状 [inputFeatures, 1] 以及 [1, inputFeatures] 的偏置/尺度张量

返回

新构造的 OnnxModel,节点顺序即 Pipeline 的步骤顺序

抛出
  • NullPointerException – estimator 为 null

  • IllegalArgumentException – inputFeatures 小于等于 0("inputFeatures must be positive")

  • BasaltUnsupportedOperationException – 估计器类型或 Pipeline 中某一步骤不受支持

toOnnx(Module<?, ?> module, int[] inputShape) → OnnxModelstatic

把模块翻译成内存中的 ONNX 模型。

ComputationGraph 走整图分支:按 executionOrder() 逐顶点翻译,MODULE 顶点递归展开为算子节点,ADD/SUB/MUL 顶点直接成同名节点;输入名取自 inputNames()、输出名取自 outputNames(),图名 jsl_dag_graph,输出声明 shape 为 null。

其他模块包成单链:输入名固定 "input",输出名由 appendModule 返回,图名 jsl_torch_graph。两种分支都使用 irVersion 8、opsetVersion 17、producerName "Basalt",每个输入声明都套用传入的 inputShape。

注意

Flatten 固定写 axis = 1,Conv 的 pads 按上下左右对称写出

注意

Dropout 写成 Identity 节点,不做率值编码

注意

输出声明省略 shape,多输出计算图的每个输出名都逐个声明

注意

5 维及以上的卷积、转置卷积、注意力类模块均不支持

参数
  • module (Module<?, ?>) – 待翻译的模块,权重取自 weight()、bias()、gamma()、beta()、runningMean()、runningVar() 等访问器

  • inputShape (int[]) – 第一输入的完整形状,写入每个输入声明的 shape;不做元素类型推断

返回

新构造的 OnnxModel,常量以 float32 保存

抛出
  • NullPointerException – module 或 inputShape 为 null

  • BasaltUnsupportedOperationException – 模块类型不在支持列表内("ONNX export does not yet support module type")

final class OnnxModel

ONNX ModelProto 的内存表示与原生推理引擎,零依赖编解码。

解码不依赖 protobuf 运行时:load 读入整个文件后按 proto3 线格式逐字段解释 ir_version、opset_import、producer_name 与 graph(node、initializer、input、output),未知字段按线类型跳过,因此 doc_string、metadata_props、training_info 等无关段不会导致失败。缺失字段走缺省值:IR 8、Opset 17、producer "Basalt"、图名 "jsl_graph"。

计算图执行由 run 完成:先为每个 initializer 建张量放进按名字索引的环境表,再用 feed 覆盖同名条目,然后按 nodes 的列表顺序逐节点求值,中间结果写回同一张表;最后按 outputs 声明的名字从表中取值。单输入重载取 inputs 第一个作为输入名、outputs 第一个作为返回项。

支持算子为固定白名单:MatMul、Gemm、Add、Sub、Mul、Div、Relu、Sigmoid、Tanh、Gelu、Silu、LeakyRelu、Elu、Softmax、Identity、Dropout、Flatten、Reshape、Transpose、Conv、MaxPool、BatchNormalization、LayerNormalization、GreaterOrEqual、Where。执行到白名单外的节点时抛 BasaltUnsupportedOperationException,报错信息带算子名,图不会部分产出。

示例
Path file = Path.of("model.onnx");
OnnxModel model = OnnxModel.load(file);

for (OnnxModel.ValueInfo in : model.inputs()) {
    System.out.println(in.name() + " " + java.util.Arrays.toString(in.shape()));
}
System.out.println(model.opsetVersion() + " / " + model.nodes().size());

Matrix features = Matrix.fromRows(new double[][]{{
        1.0, 2.0}, {3.0, 4.0}});
Matrix scores = model.predictMatrix(features);

byte[] encoded = model.toBytes();
model.save(Path.of("copy.onnx"));

注意

张量类型映射:TensorData 只存 float32。解码时 raw_data 按 data_type 转换——INT64(7) 与 DOUBLE(11) 逐元素转 float,其余一律按 FLOAT 解释;raw_data 缺失时回退 float_data 或 int64_data。编码恒写 DataType.FLOAT(1) 与 little-endian raw_data。

注意

输入形状对加载的模型不是固定的:执行器不读取、也不校验 ValueInfo.shape,形状完全由传入张量决定,仅各算子自身的形状约束生效。导出模型时批维写成 -1(dim_param "N"),特征维为具体值。

注意

图按 nodes 列表顺序执行,不做拓扑排序;节点顺序必须与数据依赖一致,否则取不到输入。

注意

不支持子图(If/Loop/Scan)、external_data 外部权重与稀疏初始化器;遇到时对应字段被跳过,结果是这些节点缺席而非显式报错。

注意

所有计算在 float32 上进行,Matrix 入口的 double 数据会先降精度,往返存在舍入误差。

参见:basalt.io.OnnxConverter, basalt.io.ModelCodec, basalt.torch.Tensor, basalt.nativebridge.NativeContext

构造器

OnnxModel(long irVersion, long opsetVersion, String producerName, String graphName, List<ValueInfo> inputs, List<ValueInfo> outputs, Map<String, TensorData> initializers, List<Node> nodes)

用图元数据与节点表构造模型,不做语义校验。

列表参数经 List.copyOf 复制为不可变列表,initializers 先复制进 LinkedHashMap 再包装为不可变视图,因此迭代顺序(也是写回时的编码顺序)与传入顺序一致。

注意

不校验 irVersion/opsetVersion 范围,也不检查节点引用的名字是否闭合,错误延迟到 run 时才暴露

注意

null 参数在 List.copyOf 或 LinkedHashMap 构造时抛 NullPointerException;元素内容不做判空

注意

TensorData 与 ValueInfo 以引用保存,其内部数组由各自构造器克隆

参数
  • irVersion (long) – IR 版本号,写入 ir_version 字段;导出路径固定传 8

  • opsetVersion (long) – 算子集版本,写入 opset_import.version;导出路径固定传 17

  • producerName (String) – 生成工具名,写入 producer_name;文件缺该字段时解码回落 "Basalt"

  • graphName (String) – 计算图名,写入 graph.name;缺省为 "jsl_graph"

  • inputs (List<ValueInfo>) – 图输入声明,run 用第一个的名字作为单输入入口

  • outputs (List<ValueInfo>) – 图输出声明,run 按此顺序收集返回项

  • initializers (Map<String, TensorData>) – 名字到常量张量的映射,run 会为每项建张量

  • nodes (List<Node>) – 节点列表,保存顺序即执行顺序

方法

load(Path path) → OnnxModelstatic

读取 .onnx 文件并解析为模型。

Files.readAllBytes 一次性读入后交 parseModelProto 解析;graph 段内的 node、name、initializer、input、output 逐项收集,opset_import 只取 version 字段(多个导入以最后一个为准),其余字段忽略。

注意

ONNX 没有魔数,非 ONNX 文件可能被解析成空图而不报错

注意

不解析 external_data,权重指向外部文件时数据为空

注意

整文件驻留堆内存,大模型(数百 MB)需相应堆空间

参数
  • path (Path) – 标准 .onnx 文件路径,须为可读普通文件

返回

解析出的 OnnxModel,缺失字段按缺省值填充

抛出
  • UncheckedIOException – 文件不存在、不可读或读取失败

  • IllegalStateException – 线格式损坏,例如 varint 在缓冲区末尾被截断或出现未知线类型

save(Path path)

把模型编码为 .onnx 文件并写出。

先用 toBytes() 得到完整 ModelProto 编码,再以 Files.write 覆盖写出;父目录不存在时不创建,直接失败。

注意

编码整体持有一个 byte[],写入期间峰值内存约为文件大小加编码缓冲

注意

producer_version 恒写 2.4.0,不从原文件保留

参数
  • path (Path) – 输出文件路径,已存在时被截断覆盖

抛出
  • UncheckedIOException – 路径不可写、父目录不存在或写入失败

irVersion() → long

返回 IR 版本号。

返回

ir_version 字段值;文件未写该字段时为 8

opsetVersion() → long

返回算子集版本。

返回

opset_import.version;缺省 17,文件含多项导入时取最后解析到的值

producerName() → String

返回生成工具名。

返回

producer_name;缺省为 "Basalt",Basalt 自身导出的模型即为该值

graphName() → String

返回计算图名。

返回

graph.name;缺省为 "jsl_graph",导出路径按来源写成 jsl_ml_graph、jsl_torch_graph 或 jsl_dag_graph

inputs() → List<ValueInfo>

返回图输入声明。

注意

只含声明,不含形状推断结果;形状可能为 null 或带 -1 维

返回

不可变列表,顺序与文件中的 input 字段一致;首元素的名字被单输入 run 采用

outputs() → List<ValueInfo>

返回图输出声明。

注意

声明名必须在执行环境中存在,否则 run 抛 IllegalStateException

返回

不可变列表,run 按其中的名字与顺序收集结果

initializers() → Map<String, TensorData>

返回常量张量表。

注意

run 每次调用都会为表中每一项新建张量,不做缓存

注意

权重按名字与节点 inputs 中的字符串匹配,键须与训练侧导出的一致

返回

名字到 TensorData 的不可变映射,迭代顺序即构造或解码顺序

nodes() → List<Node>

返回计算图节点。

返回

不可变列表,按文件中的出现顺序排列,该顺序就是执行顺序

predictMatrix(Matrix features) → Matrix

以二维 Matrix 为输入做一次性推理。

创建线程数为 1 的 NativeContext,把 double 特征逐元素转成 float 并按 rows×cols 构造 rank 2 张量,走单输入 run 取回输出,再把 float 结果转回 double 构造 Matrix。输出列数取输出张量形状的第 1 维,输出秩小于 2 时按 1 列处理。上下文在方法内用 try-with-resources 关闭,所有中间张量随之释放。

注意

只使用第一个输入与第一个输出,多输入模型须改用 run(NativeContext, Map)

注意

每次调用独立建上下文,循环推理时建议直接用 run 复用上下文

注意

输入输出都是 float32,double 往返存在舍入误差

注意

不检查特征列数与模型声明是否一致,形状不匹配由算子内部报错

参数
  • features (Matrix) – 二维特征矩阵,行数为样本数,列数须与模型期望的每样本元素数一致

返回

rows × outCols 的预测结果矩阵,元素为 double

抛出
  • IllegalStateException – 模型未声明输入("ONNX graph has no declared inputs"),或输出名未被任何节点产生

  • BasaltUnsupportedOperationException – 图中出现白名单外的算子

run(NativeContext context, Tensor input) → Tensor

单输入单输出的推理入口。

要求模型至少声明一个输入,用 inputs.get(0).name() 作为键构造单元素 feed,委托 Map 版本执行整图,再按 outputs.get(0).name() 从结果中取回张量。

注意

context 为 null 时由 Map 版本抛 NullPointerException

注意

忽略 outputs 中除第一个以外的其余输出

注意

不做形状与元素类型校验,张量须属于同一 context

参数
  • context (NativeContext) – 活跃的 NativeContext,常量与中间张量都在其中分配,由调用方负责关闭

  • input (Tensor) – 与第一输入对应的张量,元素为 float32,形状由模型第一输入的实际约束决定

返回

第一个输出名对应的张量

抛出
  • IllegalStateException – inputs 为空,或第一个输出名未被执行环境产生

  • BasaltUnsupportedOperationException – 图中出现白名单外的算子

run(NativeContext context, Map<String, Tensor> feed) → Map<String, Tensor>

按名字喂入张量,执行整图并返回全部输出。

先为 initializers 的每一项创建张量(dims 长度为 0 时按形状 {1} 处理),再以 feed 覆盖同名条目,然后按 nodes 顺序逐个执行节点,中间结果以输出名写入同一张环境表;最后按 outputs 的声明顺序取值,装入 LinkedHashMap 返回。

注意

每次调用都重新为 initializers 建张量,重复推理时这部分开销固定存在

注意

环境表在方法返回后丢弃,输出张量之外不再保留引用

注意

不校验 feed 覆盖了全部输入,缺失输入会在使用该名字的节点上以空张量失败

参数
  • context (NativeContext) – 活跃上下文,常量、中间张量与输出张量都在其中分配

  • feed (Map<String, Tensor>) – 输入名到张量的映射,键须与 inputs 中声明的 name 完全一致;与常量同名时覆盖常量

返回

保持 outputs 声明顺序的映射,值为对应名字的张量,同样属于 context

抛出
  • NullPointerException – context 或 feed 为 null

  • IllegalStateException – 某个输出名在执行环境中不存在("ONNX execution did not produce output")

  • BasaltUnsupportedOperationException – 节点算子不在支持集合内

toBytes() → byte[]

把模型编码为标准 ONNX 字节。

按 onnx.proto3 的字段号手写线格式:ir_version(1)、opset_import(8,domain 写空串)、producer_name(2)、producer_version(3,固定 "2.4.0")、graph(7);图内依次写 node(1)、name(2)、initializer(5)、input(11)、output(12)。张量恒写 data_type = FLOAT(1) 与 little-endian raw_data(9);ValueInfo 写 elem_type(1) 与 shape(2),维度值大于 0 写 dim_value,否则写 dim_param "N"。

注意

不写 doc_string、metadata_props、value_info 与 training_info,往返一次这些信息即丢失

注意

属性只编码 FLOAT、INT、STRING、FLOATS、INTS 五种,其余类型(TENSOR、GRAPH 等)被省略

注意

每次调用重新编码,无缓存;大模型的返回值占满一段连续堆内存

返回

完整 ModelProto 编码,可被 onnxruntime 等标准实现读取

record OnnxModel.Attribute

ONNX 节点属性的不可变记录,涵盖标量与数组两类载荷。

对应 AttributeProto 的常用子集:name、type 与五个按类型取用的载荷字段 intVal、floatVal、stringVal、intsVal、floatsVal;当前类型未使用的字段保持 0、空串或空数组。

type 取 FLOAT=1、INT=2、STRING=3、FLOATS=6、INTS=7,与官方 AttributeType 编号一致,写回时以字段 20 记录,读取方据此决定取哪个载荷。

静态工厂 ofInt、ofFloat、ofInts、ofFloats 用于构造标量与数组属性,数组入参在构造时克隆。

注意

数组分量在构造时克隆,后续修改入参不会影响已建属性;但访问器返回内部数组引用,不要就地改写

注意

STRING 类型没有工厂方法,需要直接构造:new Attribute(name, Attribute.STRING, 0L, 0.0f, text, new long[0], new float[0])

注意

只覆盖这五种类型;TENSOR、GRAPH、SPARSE_TENSOR 等属性解码时 type 保留但载荷为空,再编码时被丢弃

注意

记录本身不做 name 判空与载荷一致性校验

方法

ofInt(String name, long value) → Attributestatic

构造 INT 型属性。

参数
  • name (String) – 属性名,写回时作为 AttributeProto.name,节点内须唯一

  • value (long) – 属性值,存入 intVal

返回

type 为 INT 的新属性,其余载荷为空值

ofFloat(String name, float value) → Attributestatic

构造 FLOAT 型属性。

参数
  • name (String) – 属性名,例如 LeakyRelu 的 alpha、BatchNormalization 的 epsilon

  • value (float) – 属性值,存入 floatVal

返回

type 为 FLOAT 的新属性,其余载荷为空值

ofInts(String name, long... values) → Attributestatic

构造 INTS 型属性。

参数
  • name (String) – 属性名,例如 Conv 的 strides、pads、kernel_shape

  • values (long...) – 属性值数组,构造时克隆;传空表示空列表

返回

type 为 INTS 的新属性,intsVal 为入参副本

ofFloats(String name, float... values) → Attributestatic

构造 FLOATS 型属性。

参数
  • name (String) – 属性名,例如 Clip 的边界值

  • values (float...) – 属性值数组,构造时克隆;传空表示空列表

返回

type 为 FLOATS 的新属性,floatsVal 为入参副本

字段

FLOAT()static

类型码 1,单精度标量属性。

载荷在 floatVal;Node.attrFloat 只接受 type 等于该值的属性。

INT()static

类型码 2,int64 标量属性。

载荷在 intVal;Node.attrInt 只接受 type 等于该值的属性。

STRING()static

类型码 3,UTF-8 字符串属性。

载荷在 stringVal;Node 没有对应的读取方法,需要自行访问 stringVal。

FLOATS()static

类型码 6,float 数组属性。

载荷在 floatsVal;编码时按重复的 float 字段写出,解码同时接受打包与非打包两种线格式。

INTS()static

类型码 7,int64 数组属性。

载荷在 intsVal;Node.attrInts 读取该类型并逐项窄化为 int。

record OnnxModel.Node

ONNX 计算图节点:算子类型、输入输出值名与属性表。

inputs 与 outputs 是值名字符串而非张量,执行时按名字在同一张环境表中查找与写入;空串表示该位置的可选参数缺省,例如 Conv 的 bias、Gemm 的 C。执行器只写 outputs 的第一个名字。

attributes 以属性名为键,值为 Attribute;attrInt、attrFloat、attrInts 在属性缺失或类型不符时返回调用方给的默认值,不抛异常,因此算子缺省参数就靠这里的默认值表达。

节点不携带形状信息,元素类型与维度都由执行期张量决定,这与 ONNX 把 shape 推断交给运行时的设计一致。

注意

按列表顺序执行,不做拓扑排序;节点顺序须与数据依赖一致

注意

属性类型不匹配时静默回落到默认值,语义可能与训练侧产生差异且不报警

注意

多输出节点(如 LayerNormalization 的 mean、var)只保留第一个输出名对应的结果

方法

attrInt(String key, long defaultVal) → long

读取整数属性,缺失时取默认值。

注意

只认 Attribute.INT;属性存在但类型不符同样返回 defaultVal,不报错

参数
  • key (String) – 属性名,例如 axis、group、transA

  • defaultVal (long) – 属性缺失或类型不是 INT 时返回的值

返回

属性的 intVal,或 defaultVal

attrFloat(String key, float defaultVal) → float

读取浮点属性,缺失时取默认值。

注意

与 ONNX 规范一致,缺省值由调用方给出,记录本身不存规范默认值

参数
  • key (String) – 属性名,例如 alpha、epsilon、momentum

  • defaultVal (float) – 属性缺失或类型不是 FLOAT 时返回的值

返回

属性的 floatVal,或 defaultVal

attrInts(String key, int[] defaultVal) → int[]

读取整数数组属性,缺失时取默认值。

注意

走默认值分支时直接返回传入的引用,不克隆,调用方不要就地修改

注意

窄化不做范围检查,超出 int 范围的值被截断

注意

属性为 INTS 但数组为空时返回空数组,不会回落到默认值

参数
  • key (String) – 属性名,例如 strides、pads、dilations、perm

  • defaultVal (int[]) – 属性缺失或类型不是 INTS 时原样返回的数组

返回

由 intsVal 逐项窄化得到的新 int 数组,或 defaultVal 本身

record OnnxModel.TensorData

ONNX 常量张量:名字、维度与 float32 载荷。

对应 GraphProto.initializer(TensorProto)中执行器实际用到的部分:name 是图中引用该常量的键,dims 是形状,floatData 是按行优先排列的元素,长度应与 dims 的乘积一致。

紧凑构造器要求 name 非空(否则抛 NullPointerException),并克隆 dims 与 floatData 两个数组;不校验 floatData 长度与形状是否匹配。

执行时 dims 长度为 0 的常量按形状 {1} 建张量,因此标量初始化器也能参与逐元素运算。

注意

解码时 raw_data 按 data_type 转换:INT64 与 DOUBLE 逐元素转 float,其余类型按 FLOAT 解释;raw_data 缺失时回退 float_data,再回退 int64_data

注意

编码恒写 DataType.FLOAT 与 little-endian raw_data,原始元素类型在往返中丢失

注意

名字必须与节点 inputs 中的字符串逐字一致,否则执行时取不到张量

注意

只承载 float32,float64 与 int 权重在加载时即已降精度

record OnnxModel.ValueInfo

ONNX 值声明:名字、元素类型与形状。

对应 ValueInfoProto,用于 graph.input 与 graph.output。elemType 取 TensorProto.DataType 编码,1 表示 float32,执行器不据此转换数据类型。

shape 为维度数组,元素来自文件中的 dim_value;为 null 表示形状未知(写回时整个 shape 段省略),元素小于等于 0 的维按下标写成 dim_param "N"。

解码遇到 dim_param 的维度记为 -1,符号名本身不保存。

注意

没有紧凑构造器,字段不做校验,shape 可为 null、可为空数组

注意

执行器完全不使用 shape 与 elemType,仅作元数据;实际形状由传入张量决定

注意

Basalt 导出时 elemType 恒为 1,批维写 -1,因此同一模型可接受任意批大小

包内可见类型

以下类型没有 public 修饰符,但出现在公开签名中,因此一并列出。它们不是稳定 API,跨版本可能变化。

private record OnnxConverter.StepResult

一段导出片段的输出值名与输出维度

appendLinearModel、appendTransformer、appendEstimator 每向计算图追加一段就返回该记录,上层据此把下一段的输入接到上一段的 outputName 上;Pipeline 的逐级串联就是靠这两个字段推进的。

outputDim 只用于构造 graph output 的 ValueInfo 形状 [-1, outputDim]:线性模型与二分类固定为 1,PCA 为所取主成分数,标准化等逐元素变换沿用输入维度。

private static final class OnnxModel.ProtoReader

protobuf 解码游标,供加载路径逐层读取字段

parseModelProto 为每个嵌套消息新建一个 ProtoReader 包住对应的字节片段,hasMore() 控制读取循环,skip() 按 wire type 跳过当前版本不认识的字段,使解析器可以容忍模型文件中的新增字段。

load(Path) 读入整个文件后即由这组游标完成解析;readVarint 在字节耗尽时抛 IllegalStateException,skip 遇到 0、1、2、5 之外的 wire type 抛同一异常,对应被截断或损坏的文件。

private static final class OnnxModel.ProtoWriter

生成 .onnx 字节的 protobuf 编码缓冲区

公开的 toBytes() 用它逐字段拼装 ModelProto:writeTag 与 writeVarint 写键和变长整数,writeFloatField 写 5 号 wire type 的定长浮点,writeBytesField 与 writeStringField 写 2 号 wire type 的长度前缀块。

缓冲区从 256 字节起按需倍增,toByteArray() 截取到实际写入位置,因此保存出的文件不含未使用的尾部空间;save(Path) 直接落盘这份字节。