模块 basalt¶
11 个公开类型 · 1 个包内可见类型
统一门面:一次创建上下文,取张量、模块、优化器,并转发经典模型入口。
类型概览
| 类型 | 种类 | 说明 |
|---|---|---|
Basalt | class | SDK 统一入口:持有单个原生上下文,集中提供张量、模块、优化器与估计器工厂 |
BasaltExceptionCode | enum | 跨 JNI 边界传递的标准化错误码枚举 |
BasaltMemoryException | class | 原生或堆外内存分配失败时抛出的异常 |
BasaltMetrics | class | 算子调用次数、延迟分位与内存占用的全局指标登记处 |
BasaltParameterException | class | 算子或估计器收到非法参数时抛出的异常 |
BasaltRuntimeException | class | SDK 统一非受检异常:封装原生 panic、形状拒绝与空参数 |
BasaltShapeException | class | 张量或矩阵维度不兼容时抛出的异常 |
BasaltUnsupportedOperationException | class | 请求的算子或配置不受支持时抛出的异常 |
BasaltMetrics.MemorySnapshot | record | 原生内存与 JVM 堆的即时占用快照 |
BasaltMetrics.MetricsSnapshot | record | 全部算子与单个上下文内存的一次性观测快照 |
BasaltMetrics.OperatorSummary | record | 单个算子的聚合统计快照 |
- final class Basalt implements AutoCloseable¶
SDK 统一入口:持有单个原生上下文,集中提供张量、模块、优化器与估计器工厂
门面把「一个原生上下文 + 一套张量工厂」绑定为单一对象。所有由它创建的张量、模块与图句柄都归属同一个 NativeContext,因此反向传播、清空计算图与内存统计天然共享同一份状态,不存在跨上下文混用的问题。
实例内部维护一个 AtomicLong 种子计数器,初值为黄金比例常数 0x9E3779B97F4A7C15。randn、linear、conv2d 每次都从计数器取一个新种子,因此同一实例内的随机初始化序列可复现,且不同层不会拿到相同权重。
经典估计器相关的 fit、predict、crossValidate 是静态方法,仅转发到 basalt.ml.Estimators,不读取实例上下文;同一套 API 因此同时覆盖 eager 张量编程与 sklearn 风格的估计器工作流。
示例try (Basalt jsl = Basalt.create(4)) { Tensor x = basalt.randn(32, 8); Tensor y = basalt.randn(32, 1); Linear hidden = basalt.linear(8, 16); Linear output = basalt.linear(16, 1); AdamW optimizer = basalt.adamw(output.parameters(), 1e-3f); Tensor loss = output.forward(hidden.forward(x).relu()).mse(y); loss.backward(); optimizer.step(); }注意
close() 会级联释放该上下文内的全部张量与图,关闭后任何张量操作都会快速失败而不是访问已释放内存。
注意
创建过程需要原生库可用;加载失败时构造函数路径抛出 BasaltRuntimeException,而非 UnsatisfiedLinkError。
注意
种子计数器为 AtomicLong,并发调用不会取到重复种子,但调用顺序决定种子分配顺序。
参见:basalt.nativebridge.NativeContext, basalt.torch.Tensor, basalt.torch.Graph, basalt.ml.Estimators
方法
- create() → Basaltstatic¶
以自动线程数创建门面实例
等价于 create(0):线程提示值 0 交由 Rust 侧按可用核数决定并行度,Java 层不做扩缩容。
注意
返回的实例必须关闭;未关闭时依赖 Cleaner 在回收时释放上下文。
- 返回
持有新建 NativeContext 的门面实例
- 抛出
BasaltRuntimeException – 原生张量运行时不可用,或原生上下文分配返回空指针
- create(int threads) → Basaltstatic¶
以指定线程提示值创建门面实例
线程数只是传给原生内核的提示值,不做线程池预创建。合法区间为 [0, 256],其中 0 表示自动。
- 参数
threads (int) – 原生内核并行度提示;0 表示交由 Rust 侧决定,合法区间 [0, 256]
- 返回
持有新建 NativeContext 的门面实例
- 抛出
IllegalArgumentException – threads 为负数或大于 256
BasaltRuntimeException – 原生张量运行时不可用,或原生上下文分配返回空指针
- context() → NativeContext¶
返回门面持有的原生上下文
用于直接调用上下文级能力,例如 guard()、graphSize() 或 clipGradNorm()。返回的引用与门面共享生命周期,门面关闭后该上下文随之失效。
- 返回
门面持有的 NativeContext 实例,永不为 null
- threads() → int¶
返回创建时传入的线程提示值
返回值原样透传上下文中的线程提示值,不会解析成实际核数;通过 create() 创建时得到 0。
- 返回
线程提示值,0 表示自动
- tensor(float[] data, int... shape) → Tensor¶
由数据构造不追踪梯度的张量
数据按行优先展平后写入原生缓冲区,requires_grad 固定为 false。元素总数必须与 data 长度严格相等,否则由上下文层拒绝。
- 参数
data (float[]) – 初始元素,按行优先解释;不能为 null
shape (int...) – 目标形状,各维必须为正;不能为空
- 返回
归属当前上下文的张量句柄
- 抛出
BasaltRuntimeException – data 为 null
IllegalArgumentException – data 长度与 shape 元素数不一致、shape 为空、某维非正,或元素总数超过 Integer.MAX_VALUE
- parameter(float[] data, int... shape) → Tensor¶
由数据构造可训练张量
与 tensor(float[], int...) 相同的数据校验,但 requires_grad 置为 true,可直接作为优化器的参数列表成员。
- 参数
data (float[]) – 初始元素,按行优先解释;不能为 null
shape (int...) – 目标形状,各维必须为正;不能为空
- 返回
requires_grad 为 true 的张量句柄
- 抛出
BasaltRuntimeException – data 为 null
IllegalArgumentException – data 长度与 shape 元素数不一致、shape 为空、某维非正,或元素总数超过 Integer.MAX_VALUE
- zeros(int... shape) → Tensor¶
创建全零且不追踪梯度的张量
常用于占位缓冲区或需要显式填充的累加器;需要参与训练时应改用 parameter(int...)。
- 参数
shape (int...) – 目标形状,各维必须为正;不能为空
- 返回
全零张量句柄,requires_grad 为 false
- 抛出
IllegalArgumentException – shape 为空、某维非正,或元素总数超过 Integer.MAX_VALUE
- randn(int... shape) → Tensor¶
创建标准正态随机张量
以缩放系数 1.0 从实例种子计数器取种子后调用原生随机初始化,requires_grad 为 false。同一实例中每次调用消耗一个新种子,序列可复现。
- 参数
shape (int...) – 目标形状,各维必须为正;不能为空
- 返回
标准正态初始化的张量句柄
- 抛出
IllegalArgumentException – shape 为空、某维非正,或元素总数超过 Integer.MAX_VALUE
- parameter(int... shape) → Tensor¶
创建全零的可训练张量
该重载是零初始化而非随机初始化:requires_grad 为 true,但所有元素为 0。需要随机初始化的参数应使用 parameter(float[], int...) 或模块构造器。
注意
零初始化会让对称权重在首步得到相同梯度;手工搭建网络时通常改用随机初始化。
- 参数
shape (int...) – 目标形状,各维必须为正;不能为空
- 返回
requires_grad 为 true 的全零张量句柄
- 抛出
IllegalArgumentException – shape 为空、某维非正,或元素总数超过 Integer.MAX_VALUE
- linear(int inputSize, int outputSize) → Linear¶
构造带偏置的全连接层
权重形状为 [inputSize, outputSize],按 sqrt(6 / (inputSize + outputSize)) 为界的均匀分布初始化;偏置形状为 [1, outputSize] 并置零。种子由实例计数器推进得到。
- 参数
inputSize (int) – 输入特征维,对应前向时最后一维的大小
outputSize (int) – 输出特征维,也是偏置的长度
- 返回
新建的 Linear 模块,requires_grad 参数已就绪
- 抛出
IllegalArgumentException – 形状校验失败时由张量创建路径抛出
- conv2d(int inputChannels, int outputChannels, int kernelSize) → Conv2d¶
构造默认步长与填充的二维卷积层
等价于 conv2d(inputChannels, outputChannels, kernelSize, 1, 0),即方形核、步长 1、无填充。
- 参数
inputChannels (int) – 输入通道数,必须为正
outputChannels (int) – 输出通道数,必须为正
kernelSize (int) – 方形卷积核边长,同时用于高与宽
- 返回
新建的 Conv2d 模块
- 抛出
IllegalArgumentException – 任一维参数非正
- conv2d(int inputChannels, int outputChannels, int kernelSize, int stride, int padding) → Conv2d¶
构造指定步长与填充的二维卷积层
stride 与 padding 同时作用于高度和宽度两个空间维,因此只支持对称配置。权重形状为 [outputChannels, inputChannels, kernelSize, kernelSize],按 sqrt(6 / (fanIn + fanOut)) 初始化,偏置形状为 [1, outputChannels, 1, 1] 并置零。
- 参数
inputChannels (int) – 输入通道数,必须为正
outputChannels (int) – 输出通道数,必须为正
kernelSize (int) – 方形卷积核边长,必须为正
stride (int) – 高宽共用步长
padding (int) – 高宽共用零填充宽度
- 返回
新建的 Conv2d 模块
- 抛出
IllegalArgumentException – 通道数或核尺寸非正
- conv2d(int inputChannels, int outputChannels, int kernelSize, int stride, int padding, int dilation, int groups) → Conv2d¶
构造支持膨胀与分组(含深度卷积)的二维卷积层
kernelSize、stride、padding、dilation 都同时作用于高与宽。groups 为 1 是普通卷积,等于 inputChannels 时退化为逐通道的深度卷积。
权重形状为 [outputChannels, inputChannels / groups, kernelSize, kernelSize],按 sqrt(6 / (fanIn + fanOut)) 的均匀分布初始化,偏置形状为 [1, outputChannels, 1, 1] 并置零。传给原生层的种子是实例计数器取值再混入 31 * inputChannels + outputChannels。
注意
分组卷积的参数量按组数成比例下降,groups 取 inputChannels 是逐通道卷积的极端情形。
- 参数
inputChannels (int) – 输入通道数,必须为正且能被 groups 整除
outputChannels (int) – 输出通道数,必须为正且能被 groups 整除
kernelSize (int) – 方形卷积核边长,必须为正
stride (int) – 高宽共用步长,必须为正
padding (int) – 高宽共用零填充宽度
dilation (int) – 高宽共用膨胀系数,必须为正
groups (int) – 输入与输出通道的分组数,必须为正
- 返回
新建的 Conv2d 模块
- 抛出
IllegalArgumentException – 任一维参数非正,或通道数不能被 groups 整除
- depthwiseSeparableConv2d(int inputChannels, int outputChannels, int kernelSize, int stride, int padding) → DepthwiseSeparableConv2d¶
构造深度可分离二维卷积层
内部串联两层卷积:第一层以 inputChannels 为分组数、不带偏置的逐通道卷积,负责空间滤波;第二层是 1×1、步长 1、无填充的逐点卷积,负责通道混合,偏置只存在于这一层。
stride 与 padding 仅作用于逐通道层。两层种子分别取实例计数器值偏移 17 与 53,因此同一层内不会与其它模块共用权重。
注意
参数量约为标准卷积的 1/outputChannels + 1/kernelSize²,代价是通道间信息只在 1×1 层交换。
- 参数
inputChannels (int) – 输入通道数,同时作为逐通道卷积的分组数
outputChannels (int) – 逐点卷积的输出通道数
kernelSize (int) – 逐通道卷积的方形核边长;逐点层固定为 1×1
stride (int) – 逐通道卷积的高宽共用步长
padding (int) – 逐通道卷积的高宽共用零填充宽度
- 返回
新建的 DepthwiseSeparableConv2d 模块
- 抛出
IllegalArgumentException – 通道数、核尺寸或步长非正
- <L extends Layout> groupNorm(int numGroups, int numChannels) → GroupNorm<L>¶
构造按通道分组的归一化层
通道被等分为 numGroups 组,归一化在每组内部进行,统计量不跨样本,因此结果与批量大小无关。epsilon 使用 GroupNorm 的默认值 1e-5。
可学习参数为长度 numChannels 的 gamma 与 beta,分别初始化为 1 与 0,两者 requires_grad 均为 true。
- 参数
numGroups (int) – 分组数,必须为正且整除 numChannels
numChannels (int) – 通道数,必须为正
- 返回
新建的 GroupNorm 模块
- 抛出
IllegalArgumentException – numChannels 非正,或不能被 numGroups 整除
- <L extends Layout> sequential() → Sequential<L, L>¶
创建空的顺序容器
返回 Sequential.start() 的空容器,布局类型参数在 add 时逐步推导。容器本身不持有上下文,其中模块的张量仍由调用方所属上下文创建。
- 返回
不含任何模块的顺序容器
- computationGraph() → ComputationGraph.Builder¶
创建计算图构建器
返回 ComputationGraph.builder() 的空构建器,用 addInputs、addLayer、addAddVertex、setOutputs 描述拓扑,build() 时校验输入与输出均非空、节点名唯一,并做拓扑排序得到执行顺序。
构建器是纯 Java 的图结构,不读取门面上下文;真正前向执行时才会用到模块所属的张量上下文。
注意
build() 失败时抛出 IllegalArgumentException,错误信息会指出缺失的输入或未知的输出节点。
- 返回
新的 ComputationGraph.Builder 实例
- <L extends Layout> activation(basalt.nn.Activation activation) → basalt.torch.Activation<L>¶
把激活枚举映射为可组合的激活模块
支持 RELU、GELU、SILU、SIGMOID、TANH 五种。NONE 与 SOFTMAX 没有对应的张量核:NONE 无意义,SOFTMAX 需沿指定维度归一化,应改用 Tensor.softmax(dimension)。
- 参数
activation (basalt.nn.Activation) – 激活函数枚举;不能为 null
- 返回
对应种类的 Activation 模块
- 抛出
BasaltRuntimeException – activation 为 null,或取值为 NONE、SOFTMAX
- optimizer(basalt.nn.Optimizer optimizer, List<Tensor> parameters, float learningRate) → basalt.torch.Optimizer¶
按枚举构造优化器实例
三种取值的超参数并不相同:SGD 映射为权重衰减 0 的 SGD;ADAM 映射为 AdamW(0.9, 0.999, 1e-8, 0.0),即不带解耦权重衰减的 Adam;ADAMW 映射为 AdamW 默认构造,权重衰减 0.01。
注意
ADAM 与 ADAMW 都实例化为 AdamW,区别仅在权重衰减系数;需要无衰减 Adam 时选 ADAM。
- 参数
optimizer (basalt.nn.Optimizer) – 优化算法枚举;不能为 null
parameters (List<Tensor>) – 待更新参数列表;不能为 null,元素通常来自模块的 parameters()
learningRate (float) – 学习率,原样传给所选优化器
- 返回
与枚举对应的优化器实例
- 抛出
BasaltRuntimeException – optimizer 或 parameters 为 null
- adamw(List<Tensor> parameters, float learningRate) → AdamW¶
构造使用默认超参数的 AdamW
使用 AdamW 的两参构造:beta1 = 0.9、beta2 = 0.999、epsilon = 1e-8、weightDecay = 0.01。需要自定义这些系数时应直接调用 AdamW 的六参构造。
- 参数
parameters (List<Tensor>) – 待更新参数列表,元素必须属于同一上下文
learningRate (float) – 学习率
- 返回
AdamW 优化器实例
- sgd(List<Tensor> parameters, float learningRate) → SGD¶
构造无权重衰减的随机梯度下降优化器
等价于 SGD(parameters, learningRate, 0.0f),权重衰减固定为 0;需要 L2 正则时应直接使用 SGD 的三参构造。
- 参数
parameters (List<Tensor>) – 待更新参数列表,元素必须属于同一上下文
learningRate (float) – 学习率
- 返回
SGD 优化器实例
- cosineAnnealingLR(basalt.torch.Optimizer optimizer, int tMax, float etaMin) → CosineAnnealingLR¶
构造余弦退火学习率调度器
构造时把优化器当前学习率记为基准,第 t 步的学习率为 etaMin + 0.5 × (基准 − etaMin) × (1 + cos(π × min(t, tMax) / tMax));迭代超过 tMax 后余弦项取 −1,学习率停在 etaMin。
注意
调度器只改动优化器的学习率,不修改优化器状态;同一步调用多次 step() 会连续推进计数。
- 参数
optimizer (basalt.torch.Optimizer) – 被调度的优化器,构造时读取其学习率作为基准
tMax (int) – 余弦周期的步数,必须为正
etaMin (float) – 学习率下限,必须有限且非负
- 返回
新建的 CosineAnnealingLR 实例
- 抛出
NullPointerException – optimizer 为 null
IllegalArgumentException – tMax 非正,或 etaMin 为负数或非有限值
- stepLR(basalt.torch.Optimizer optimizer, int stepSize, float gamma) → StepLR¶
构造按固定步数阶梯衰减的调度器
基准学习率在构造时锁定,第 t 步的学习率为 基准 × gamma^(t / stepSize),除法取整数商,因此每满 stepSize 步乘一次 gamma。
注意
基准学习率不会随外部 setLearningRate 更新,手动改动学习率后衰减仍按旧基准计算。
- 参数
optimizer (basalt.torch.Optimizer) – 被调度的优化器,构造时读取其学习率作为基准
stepSize (int) – 衰减间隔的步数,必须为正
gamma (float) – 每次衰减的乘数,必须为正且有限
- 返回
新建的 StepLR 实例
- 抛出
NullPointerException – optimizer 为 null
IllegalArgumentException – stepSize 非正,或 gamma 非正、非有限
- crossEntropy() → CrossEntropyLoss¶
创建交叉熵损失对象
每次调用返回新实例,损失对象本身无状态,可复用于多个前向过程。
- 返回
新的 CrossEntropyLoss 实例
- mse() → MSELoss¶
创建均方误差损失对象
每次调用返回新实例;单次调用也可直接用 Tensor.mse(Tensor) 这一便捷入口。
- 返回
新的 MSELoss 实例
- l1Loss() → L1Loss¶
创建 L1(平均绝对误差)损失对象
每次调用返回新实例;loss 直接转发到 Tensor.l1Loss,逐元素取绝对差后求均值。
- 返回
新的 L1Loss 实例
- smoothL1Loss(float beta) → SmoothL1Loss¶
创建带 beta 阈值的 Smooth L1 损失对象
误差绝对值小于 beta 时按二次项计算,否则按线性项计算,因此对离群点比纯 L1 更稳定;beta 由构造时固定,之后不可变。
- 参数
beta (float) – 二次段与线性段的分界阈值,必须非负
- 返回
新的 SmoothL1Loss 实例
- 抛出
IllegalArgumentException – beta 为负数
- bceWithLogitsLoss() → BCEWithLogitsLoss¶
创建带 logits 的二分类交叉熵损失对象
预测值直接接受未过 sigmoid 的 logits,sigmoid 与交叉熵在原生核内合并计算,避免概率接近 0 或 1 时的数值溢出。
注意
标签应为 0 或 1;损失对象本身无状态,可跨前向复用。
- 返回
新的 BCEWithLogitsLoss 实例
- graph() → Graph¶
包装当前上下文的计算图句柄
返回绑定同一 NativeContext 的新 Graph 包装对象,用于显式查看节点数、清空图或对指定根张量执行反向传播。
- 返回
绑定当前上下文的 Graph 句柄
- clearGraph()¶
清空计算图中记录的所有节点
在两次独立前向之间调用可避免图无限增长;张量本身不受影响,仅丢弃自动微分记录。
- 抛出
IllegalStateException – 上下文已关闭
- stats() → long[]¶
读取上下文的内存与图统计
返回长度固定为 3 的数组,依次为存活张量数、存活字节数、计算图节点数,由原生侧一次性填充。
- 返回
long[3],含义为 {liveTensors, liveBytes, graphNodes}
- 抛出
IllegalStateException – 上下文已关闭
- metrics() → BasaltMetrics.MetricsSnapshot¶
获取全局算子与本上下文内存的指标快照
等价于 BasaltMetrics.snapshot(context)。算子部分取自进程级静态登记表,涵盖所有实例记录过的算子,不按门面隔离;memory 部分读取本上下文的 stats(),即存活张量数、存活字节数与计算图节点数,再补上 JVM 已用堆与最大堆。
上下文已关闭时不会抛异常:原生三项计数直接记为 0,快照其余部分照常返回。
注意
算子统计只反映显式调用 recordOperator 或 time 的代码路径,未插桩的算子不会出现。
注意
需要清零累计值时调用 BasaltMetrics.reset(),它清空的是全局登记表。
- 返回
算子摘要映射与内存快照组成的 MetricsSnapshot
- fit(basalt.ml.Estimators.Algorithm algorithm, Matrix features, double[] targets) → Estimatorstatic¶
按算法枚举训练经典估计器
静态转发到 basalt.ml.Estimators.fit,使用各估计器的保守默认超参数并按任务类型选择训练路径;无监督算法忽略 targets。该调用不读取实例上下文,可在未创建门面时使用。
- 参数
algorithm (basalt.ml.Estimators.Algorithm) – 算法枚举,自带任务类型信息
features (Matrix) – 训练特征矩阵,行对应样本
targets (double[]) – 训练标签;有监督算法不能为 null,无监督算法可为 null
- 返回
已完成 fit 的估计器实例
- 抛出
IllegalArgumentException – 有监督算法的 targets 为 null
- predict(Estimator model, Matrix features) → double[]static¶
用已训练估计器输出预测值
静态转发到 basalt.ml.Estimators.predict,直接调用 model.predict(features),不做额外的形状或状态校验。
- 参数
model (Estimator) – 已训练好的估计器
features (Matrix) – 预测特征矩阵,列数需与训练时一致
- 返回
每个样本一个预测值,顺序与输入行一致
- crossValidate(basalt.ml.Estimators.Algorithm algorithm, Matrix features, double[] targets, int folds, basalt.ml.Estimators.Metric metric) → doublestatic¶
返回 K 折交叉验证的平均分数
静态转发到 basalt.ml.Estimators.crossValidate:按固定随机种子 42 打乱后切分,每折重新 fit 并在测试折上评估,最后对各折分数取算术平均。RMSE 取负值参与平均,因此所有指标都是越大越好。
- 参数
algorithm (basalt.ml.Estimators.Algorithm) – 算法枚举,必须是有监督任务
features (Matrix) – 特征矩阵
targets (double[]) – 标签数组,长度须与特征行数一致
folds (int) – 折数,合法区间为 [2, 特征行数]
metric (basalt.ml.Estimators.Metric) – 评估指标:ACCURACY、MACRO_F1、R2 或 RMSE
- 返回
各折指标的平均值;RMSE 已取负
- 抛出
IllegalArgumentException – 算法属于无监督任务,或 folds 超出 [2, 特征行数]
- close()¶
释放上下文及其全部张量与图
销毁原生上下文并注销 Cleaner 回调。重复调用是幂等的:句柄置零后不再重复销毁,后续张量操作会抛出 IllegalStateException。
注意
关闭会等待正在执行的 JNI 调用结束,因为上下文使用读写锁保护生命周期。
- enum BasaltExceptionCode¶
跨 JNI 边界传递的标准化错误码枚举
原生内核在每次 JNI 调用后返回一个 int 状态码,Java 层用 fromCode 还原成枚举,再由 BasaltRuntimeException.fromStatus 决定抛出哪个异常子类,因此两侧的失败分类始终对齐。
整数值 0 表示成功,负值表示失败类别;code() 暴露该整数,description() 暴露英文短句,后者用于调用方没有提供消息时的兜底文本。
枚举本身只做分类,不携带堆栈、句柄或形状信息,这些上下文由异常消息承担。
示例BasaltExceptionCode code = BasaltExceptionCode.fromCode(-2); if (code == BasaltExceptionCode.SHAPE_MISMATCH) { System.err.println(code.code() + ": " + code.description()); }注意
fromCode 对未登记的码返回 INVALID_PARAMETER,未知负码与 -1 无法区分。
注意
常量顺序即 values() 的顺序,序列化请使用 code() 而不是 ordinal()。
参见:basalt.BasaltRuntimeException, basalt.BasaltShapeException, basalt.BasaltMemoryException
枚举成员
- OK()¶
操作成功,状态码 0
唯一的非负状态码,表示 JNI 调用正常返回,不携带失败语义。
- INVALID_PARAMETER()¶
参数或实参非法,状态码 -1
覆盖空引用、越界取值与非法超参数;fromStatus 把它映射为 BasaltParameterException。
- SHAPE_MISMATCH()¶
张量或矩阵形状不兼容,状态码 -2
在形状推导或广播校验阶段由原生层返回,fromStatus 映射为 BasaltShapeException。
- UNKNOWN_HANDLE()¶
原生句柄未知、失效或已释放,状态码 -3
通常意味着张量或上下文句柄被提前释放,或指针来自另一进程;映射时不细分子类,直接使用 BasaltRuntimeException。
- CONTEXT_CLOSED()¶
原生上下文为空或已关闭,状态码 -4
门面关闭后继续调用张量操作会命中该状态;Java 层通常先抛出 IllegalStateException,只有原生侧检测才会带回此码。
- GRAPH_ERROR()¶
计算图拓扑或执行出错,状态码 -5
涵盖环检测失败、节点缺失与反向传播过程中的图不一致。
- NATIVE_PANIC()¶
在 JNI 边界捕获到原生 panic,状态码 -6
Rust 侧的 panic 被捕获后转成该码,进程不会终止,但相关句柄状态可能已不可用。
- OUT_OF_MEMORY()¶
原生内存分配失败,状态码 -7
覆盖堆外分配失败与超出可寻址上限两种情形;fromStatus 映射为 BasaltMemoryException。
- UNSUPPORTED_OPERATION()¶
不支持的算子或配置,状态码 -8
当请求的算子、数据类型或模块配置在当前原生构建中不存在时返回;fromStatus 映射为 BasaltUnsupportedOperationException。
方法
- code() → int¶
返回枚举对应的整数状态码
- 返回
0 表示成功,负值表示失败类别
- description() → String¶
返回与常量绑定的英文描述
- 返回
构造枚举时写入的英文短句,可直接拼进异常消息
- fromCode(int code) → BasaltExceptionCodestatic¶
按整数状态码查找枚举常量
线性扫描全部常量并按 code() 比较,找不到时返回 INVALID_PARAMETER 而不抛异常,因此未知状态码会被归入参数错误。
- 参数
code (int) – 原生层返回的状态码,可为任意 int
- 返回
匹配的常量;无匹配时为 INVALID_PARAMETER
- final class BasaltMemoryException extends BasaltRuntimeException¶
原生或堆外内存分配失败时抛出的异常
继承链为 BasaltMemoryException → BasaltRuntimeException → IllegalStateException,是异常层次的末级类型,修饰符为 final,因此不能继续扩展出更细的分类。
两个构造器都委托父类的带错误码构造,errorCode 固定为 OUT_OF_MEMORY(-7),statusCode() 恒返回 -7;cause 用来保留原生侧的原始失败对象。
除直接构造外,BasaltRuntimeException.fromStatus 在状态码为 -7 时也会选择该类型。
示例try (Basalt jsl = Basalt.create(4)) { basalt.zeros(4096, 4096); } catch (BasaltMemoryException failure) { System.err.println(failure.statusCode() + " " + failure.getMessage()); }注意
SDK 不在此类型中做任何内存回收;捕获后应先释放占用的张量再重试。
注意
可寻址上限超限与真实分配失败使用同一错误码,消息是唯一的区分依据。
参见:basalt.BasaltRuntimeException, basalt.BasaltExceptionCode
构造器
- BasaltMemoryException(String message)¶
以消息构造内存异常
错误码固定为 OUT_OF_MEMORY,不接受外部指定。
- 参数
message (String) – 异常消息,允许为 null
- BasaltMemoryException(String message, Throwable cause)¶
以消息与原因构造内存异常
错误码固定为 OUT_OF_MEMORY,cause 原样交给父类保存。
- 参数
message (String) – 异常消息,允许为 null
cause (Throwable) – 底层分配失败的原因,允许为 null
- final class BasaltMetrics¶
算子调用次数、延迟分位与内存占用的全局指标登记处
指标按算子名聚合。recordOperator 记录单次调用的纳秒耗时、元素数与字节数,time 则包住一段 Supplier 自动计时;每个算子维护调用计数、总耗时、总元素与总字节、最大值,以及 256 槽环形缓冲保存最近若干次耗时。均值按全部调用折算,p50/p95/p99 只基于缓冲内样本排序后取下标 floor(q × (n − 1)),单位为微秒;两个吞吐率都按累计耗时折算,分别为元素数与调用次数除以总秒数。
登记表是进程级静态 ConcurrentHashMap,跨上下文、跨门面共享;只有快照的 memory 部分与具体上下文绑定。recordOperator 在 operator 为 null 或空白时直接返回,不做任何登记,因此空名字的调用不会污染统计。
MetricsSnapshot 提供两种导出:toJson 输出 memory 与 operators 两段结构,toPrometheus 输出三个 gauge 以及按算子打标的累计值与时序行。采集本身没有全局开关,是否记录取决于调用方是否显式调用记录方法;JFR 事件则由 shouldCommit() 决定是否提交。
示例try (Basalt jsl = Basalt.create(4)) { Tensor y = BasaltMetrics.time("randn", 16, 64, () -> basalt.randn(4, 4)); BasaltMetrics.MetricsSnapshot snapshot = basalt.metrics(); System.out.println(snapshot.toJson()); System.out.println(snapshot.toPrometheus()); }注意
缓冲未填满时,分位统计只覆盖已记录的那部分调用,样本数不等于 calls。
注意
耗时按最小 1 纳秒记录,零耗时调用也会计入均值并拉低平均延迟。
注意
启用 JFR 时每次记录提交 OperatorExecutionEvent,快照提交 NativeMemoryEvent;未启用时这两类事件被跳过,指标本身照常累计。
注意
所有方法都是静态方法,且构造器为私有,不能创建实例。
参见:basalt.Basalt, basalt.BasaltMetrics.MetricsSnapshot, basalt.torch.OperatorExecutionEvent, basalt.torch.NativeMemoryEvent
方法
- recordOperator(String operator, long durationNanos, long elements, long bytesProcessed)static¶
登记一次算子调用的耗时与数据量
按算子名找到或新建计数器,累加调用次数、总耗时、元素数与字节数,更新最大值,并把耗时写入该算子的 256 槽环形缓冲。耗时小于 1 纳秒时按 1 纳秒记录,元素数与字节数为负时按 0 累加。
若 JFR 事件 OperatorExecutionEvent 已启用,同时提交一条同名事件。
- 参数
operator (String) – 算子名,作为聚合键;null 或空白时整次调用被忽略
durationNanos (long) – 本次耗时,单位纳秒
elements (long) – 本次处理的元素数,负值按 0 计
bytesProcessed (long) – 本次搬运的字节数,负值按 0 计
- recordOperator(String operator, String backend, long durationNanos, long elements, long bytesProcessed)static¶
带后端标签登记算子调用
直接转发到四参版本,backend 仅作为调用方标注,不进入聚合键,也不会出现在快照或导出结果中。
注意
同名算子即使来自不同后端也会汇总到同一条统计。
- 参数
operator (String) – 算子名,作为聚合键;null 或空白时整次调用被忽略
backend (String) – 后端标签,当前实现未使用
durationNanos (long) – 本次耗时,单位纳秒
elements (long) – 本次处理的元素数,负值按 0 计
bytesProcessed (long) – 本次搬运的字节数,负值按 0 计
- <T> time(String operator, long elements, long bytesProcessed, Supplier<T> block) → Tstatic¶
计时执行代码块并登记算子指标
以 System.nanoTime 取前后时间差,在 finally 中登记,因此 block 抛出异常时同样会记录一次调用,随后异常继续向外传播。
- 参数
operator (String) – 算子名,作为聚合键
elements (long) – 代码块处理的元素数
bytesProcessed (long) – 代码块搬运的字节数
block (Supplier<T>) – 被计时的代码块,不能为 null
- 返回
block.get() 的返回值,原样透传
- snapshot(NativeContext ctx) → MetricsSnapshotstatic¶
采集算子与指定上下文的内存快照
遍历全部登记项生成 OperatorSummary,按登记表迭代顺序放入 LinkedHashMap。内存部分:ctx 非空且处于打开状态时读取 stats() 的存活张量数、存活字节数与图节点数;ctx 为 null、已关闭或读取抛异常时这三项记为 0。JVM 侧取 Runtime 的已用堆(totalMemory − freeMemory)与最大堆。
若 JFR 事件 NativeMemoryEvent 已启用,同时提交一条包含原生三项计数与堆用量的记录。
注意
快照只读取计数,不清零;需要重新累计时调用 reset()。
- 参数
ctx (NativeContext) – 要读取原生内存统计的上下文,可为 null
- 返回
算子摘要映射与内存快照组成的新实例
- snapshot() → MetricsSnapshotstatic¶
只采集算子统计的快照
等价于 snapshot(null):原生三项计数固定为 0,只保留 JVM 堆用量与算子摘要。
- 返回
不含原生内存统计的 MetricsSnapshot
- reset()static¶
清空全部算子统计
直接清空静态登记表,之后各算子从零开始累计;已生成的历史快照不受影响。
注意
清空是全局的,会同时抹掉其它门面实例记录的数据。
- final class BasaltParameterException extends BasaltRuntimeException¶
算子或估计器收到非法参数时抛出的异常
继承链为 BasaltParameterException → BasaltRuntimeException → IllegalStateException,final 修饰,errorCode 固定为 INVALID_PARAMETER(-1),statusCode() 恒为 -1。
BasaltRuntimeException.requireNonNull 在引用为 null 时抛出的正是该类型,消息形如 "<name> must not be null";原生层返回 -1 时 fromStatus 也选择它。
它表达的是可编程的调用错误,与 BasaltShapeException 的形状类错误、BasaltMemoryException 的资源类错误并列。
示例try { BasaltRuntimeException.requireNonNull(null, "features"); } catch (BasaltParameterException failure) { System.err.println(failure.getMessage()); }注意
部分参数校验仍以 IllegalArgumentException 直接抛出,两者可能出现在同一调用路径上。
注意
捕获该类型通常意味着调用方代码需要修正,而不是重试。
参见:basalt.BasaltRuntimeException, basalt.BasaltShapeException
构造器
- BasaltParameterException(String message)¶
以消息构造参数异常
错误码固定为 INVALID_PARAMETER,不接受外部指定。
- 参数
message (String) – 异常消息,允许为 null
- BasaltParameterException(String message, Throwable cause)¶
以消息与原因构造参数异常
错误码固定为 INVALID_PARAMETER,cause 原样交给父类保存。
- 参数
message (String) – 异常消息,允许为 null
cause (Throwable) – 底层原因,允许为 null
- class BasaltRuntimeException extends IllegalStateException¶
SDK 统一非受检异常:封装原生 panic、形状拒绝与空参数
原生 Rust panic、JNI 层形状拒绝以及 null 参数都被翻译为该类型,调用方只需捕获一个 SDK 专属异常即可覆盖大多数失败场景。
继承 IllegalStateException 是为了兼容性:已有捕获 JDK 异常的代码无需修改,同时 SDK 用户可以精确区分 Basalt 自身的失败与其它状态错误。
requireNonNull 是配套的校验工具,失败时把参数名拼进消息,避免出现无上下文的 NullPointerException。
示例try (Basalt jsl = Basalt.create()) { basalt.activation(basalt.nn.Activation.NONE); } catch (BasaltRuntimeException failure) { System.err.println(failure.getMessage()); }注意
构造器不校验 message 与 cause,允许两者为 null,与父类行为一致。
注意
形状不匹配等可编程错误仍由 IllegalArgumentException 表达,本类型不替代它。
参见:basalt.Basalt,
java.lang.IllegalStateException构造器
- BasaltRuntimeException(String message)¶
以消息构造异常
- 参数
message (String) – 异常消息,允许为 null
- BasaltRuntimeException(BasaltExceptionCode errorCode, String message)¶
以错误码与消息构造异常
错误码为 null 时回落为 INVALID_PARAMETER,因此 errorCode() 永远不会返回 null。
- 参数
errorCode (BasaltExceptionCode) – 失败分类;null 视为 INVALID_PARAMETER
message (String) – 异常消息,允许为 null
- BasaltRuntimeException(String message, Throwable cause)¶
以消息与原因构造异常
用于在保留原始失败信息的前提下统一异常类型,例如把原生层返回的错误对象挂在 cause 上。
- 参数
message (String) – 异常消息,允许为 null
cause (Throwable) – 根因异常,允许为 null
- BasaltRuntimeException(BasaltExceptionCode errorCode, String message, Throwable cause)¶
以错误码、消息与原因构造异常
错误码为 null 时回落为 INVALID_PARAMETER;cause 原样传给 IllegalStateException。
- 参数
errorCode (BasaltExceptionCode) – 失败分类;null 视为 INVALID_PARAMETER
message (String) – 异常消息,允许为 null
cause (Throwable) – 根因异常,允许为 null
方法
- errorCode() → BasaltExceptionCode¶
返回异常携带的错误码
- 返回
构造时确定的枚举,永不为 null
- statusCode() → int¶
返回错误码对应的整数状态
- 返回
errorCode().code();失败为负值,0 仅出现在 OK
- fromStatus(int status, String message) → BasaltRuntimeExceptionstatic¶
按原生状态码构造对应子类异常
先用 BasaltExceptionCode.fromCode 还原分类,再做分派:INVALID_PARAMETER 得到 BasaltParameterException,SHAPE_MISMATCH 得到 BasaltShapeException,OUT_OF_MEMORY 得到 BasaltMemoryException,UNSUPPORTED_OPERATION 得到 BasaltUnsupportedOperationException,其余(含 OK、UNKNOWN_HANDLE、CONTEXT_CLOSED、GRAPH_ERROR、NATIVE_PANIC)得到携带原码的 BasaltRuntimeException。
message 为 null 或空白时,改用 "<description> (code <status>)" 作为消息;未登记的状态码会先被 fromCode 归为 INVALID_PARAMETER,随后按参数异常返回。
注意
返回的异常尚未抛出,调用方需要自行 throw。
- 参数
status (int) – 原生层返回的整数状态码
message (String) – 原生层附带的消息,可为 null 或空白
- 返回
按状态码分类的异常实例,方法本身不抛出
- <T> requireNonNull(T value, String name) → Tstatic¶
校验参数非空并原样返回
value 为 null 时抛出消息为 "<name> must not be null" 的异常,否则直接返回该值,便于写成内联表达式。
- 参数
value (T) – 待校验的引用
name (String) – 参数名,会被拼进异常消息
- 返回
非空的 value 本身
- 抛出
BasaltRuntimeException – value 为 null
- final class BasaltShapeException extends BasaltRuntimeException¶
张量或矩阵维度不兼容时抛出的异常
继承链为 BasaltShapeException → BasaltRuntimeException → IllegalStateException,final 修饰,errorCode 固定为 SHAPE_MISMATCH(-2),statusCode() 恒为 -2。
Java 层的多数形状校验发生在张量工厂与原生上下文之间,命中时直接抛 IllegalArgumentException;只有错误跨 JNI 边界带回 -2,或经 fromStatus 分派时才会得到本类型。
因此捕获它可以精准区分「形状不对」与「参数不对」「内存不足」三类失败。
示例try { basalt.tensor(new float[]{1f, 2f, 3f}, 2, 2); } catch (IllegalArgumentException | BasaltShapeException failure) { System.err.println(failure.getMessage()); }注意
异常本身不携带期望形状与实际形状字段,具体维度信息只存在于消息文本中。
注意
需要兼容既有代码时,捕获父类 BasaltRuntimeException 或 IllegalStateException 同样有效。
参见:basalt.BasaltRuntimeException, basalt.BasaltExceptionCode
构造器
- BasaltShapeException(String message)¶
以消息构造形状异常
错误码固定为 SHAPE_MISMATCH,不接受外部指定。
- 参数
message (String) – 异常消息,允许为 null
- BasaltShapeException(String message, Throwable cause)¶
以消息与原因构造形状异常
错误码固定为 SHAPE_MISMATCH,cause 原样交给父类保存。
- 参数
message (String) – 异常消息,允许为 null
cause (Throwable) – 底层原因,允许为 null
- final class BasaltUnsupportedOperationException extends BasaltRuntimeException¶
请求的算子或配置不受支持时抛出的异常
继承链为 BasaltUnsupportedOperationException → BasaltRuntimeException → IllegalStateException,final 修饰,errorCode 固定为 UNSUPPORTED_OPERATION(-8),statusCode() 恒为 -8。
适用于算子、opcode 或模块配置在当前原生构建中不存在的情形,例如缺少某种后端实现;BasaltRuntimeException.fromStatus 在收到 -8 时返回该类型。
与 BasaltParameterException 的区别在于:参数取值本身可能合法,只是运行时不提供对应能力,重试通常无效。
示例try (Basalt jsl = Basalt.create()) { basalt.activation(basalt.nn.Activation.SOFTMAX); } catch (BasaltRuntimeException failure) { System.err.println(failure.statusCode()); }注意
该类型不继承 java.lang.UnsupportedOperationException,唯一的共同祖先是 IllegalStateException。
注意
降级路径需要调用方自行选择,SDK 不会自动替换为等价算子。
参见:basalt.BasaltRuntimeException, basalt.BasaltExceptionCode
构造器
- BasaltUnsupportedOperationException(String message)¶
以消息构造不支持操作异常
错误码固定为 UNSUPPORTED_OPERATION,不接受外部指定。
- 参数
message (String) – 异常消息,允许为 null
- BasaltUnsupportedOperationException(String message, Throwable cause)¶
以消息与原因构造不支持操作异常
错误码固定为 UNSUPPORTED_OPERATION,cause 原样交给父类保存。
- 参数
message (String) – 异常消息,允许为 null
cause (Throwable) – 底层原因,允许为 null
- record BasaltMetrics.MemorySnapshot¶
原生内存与 JVM 堆的即时占用快照
记录五个计数字段:liveNativeTensors、liveNativeBytes、graphNodes 来自上下文 stats(),即存活张量数、存活字节数与计算图节点数;jvmHeapUsedBytes 与 jvmHeapMaxBytes 来自 Runtime,即已用堆与最大堆。
上下文缺失、已关闭或统计读取失败时,前三项固定为 0,后两项仍反映当前 JVM 状态。
示例BasaltMetrics.MemorySnapshot memory = BasaltMetrics.snapshot(basalt.context()).memory(); System.out.println(memory.liveNativeBytes() + " off-heap / " + memory.jvmHeapUsedBytes() + " heap");注意
liveNativeBytes 是堆外分配量,与 jvmHeapUsedBytes 不重叠,两者相加才是进程的总内存压力。
注意
最大堆可能为 Long.MAX_VALUE,表示未设置上限。
参见:basalt.BasaltMetrics, basalt.BasaltMetrics.MetricsSnapshot, basalt.nativebridge.NativeContext
- record BasaltMetrics.MetricsSnapshot¶
全部算子与单个上下文内存的一次性观测快照
由 BasaltMetrics.snapshot 生成,保存算子名到 OperatorSummary 的不可变有序映射,以及一份 MemorySnapshot。构造时复制映射,因此快照是时点值,不会随后续登记变化。
两种导出覆盖不同消费场景:toJson 适合日志与人工排查,字段名紧凑且包含全部十一项统计;toPrometheus 适合抓取,使用 gauge 与带标签的时序行,可直接拼进 /metrics 响应。
快照不持有上下文引用,也不负责释放资源,可以在关闭门面之后继续读取。
示例BasaltMetrics.MetricsSnapshot snapshot = BasaltMetrics.snapshot(basalt.context()); String json = snapshot.toJson(); String metrics = snapshot.toPrometheus();注意
数值格式化固定使用 Locale.US,跨区域部署时输出稳定。
注意
算子名为不可信输入时,导出前应自行过滤,否则可能产生非法 JSON 或指标行。
参见:basalt.BasaltMetrics, basalt.BasaltMetrics.OperatorSummary, basalt.BasaltMetrics.MemorySnapshot
构造器
- MetricsSnapshot(Map<String, OperatorSummary> operators, MemorySnapshot memory)¶
以算子摘要表与内存快照构造
显式声明的紧凑构造器把 operators 复制进不可变的 LinkedHashMap,保留传入顺序,因此后续对原映射的修改不会影响快照;memory 直接持有。
- 参数
operators (Map<String, OperatorSummary>) – 算子名到摘要的映射,构造时复制为不可变有序表;不能为 null
memory (MemorySnapshot) – 内存与计算图统计,原样持有;不能为 null
方法
- toJson() → String¶
导出两段式 JSON 文本
顶层固定为 memory 与 operators 两个对象。memory 下是五个计数字段;operators 下每个算子名对应 calls、elements、bytes、totalMs、meanUs、p50Us、p95Us、p99Us、maxUs、opsPerSec、elementsPerSec 十一个字段。
浮点统一按 Locale.US 格式化:毫秒 3 位小数、微秒 2 位、吞吐 1 位,因此小数点不会随系统区域设置变化。
注意
算子名直接作为键拼接,未做转义;含引号或反斜杠的名字会破坏 JSON 结构。
注意
空算子表输出为空的 operators 对象,仍是合法 JSON。
- 返回
缩进两空格的多行 JSON 字符串
- toPrometheus() → String¶
导出 Prometheus 文本格式指标
先输出三个 gauge 并附 HELP 与 TYPE 注释:basalt_native_live_tensors、basalt_native_live_bytes、jsl_jvm_heap_used_bytes。随后为每个算子输出 jsl_operator_calls_total,以及带 quantile 标签(0.5、0.95、0.99)的 jsl_operator_latency_micros 和 jsl_operator_throughput_elements_per_sec。
注意
graphNodes 与 JVM 最大堆没有对应的指标行,需要时请读取 toJson。
注意
所有时序都带 op 标签,标签值同样未做转义。
- 返回
以换行分隔的文本,行数随算子数量线性增长
- record BasaltMetrics.OperatorSummary¶
单个算子的聚合统计快照
包含算子名 operator、调用次数 calls、累计元素数 totalElements、累计字节数 totalBytes,以及以毫秒计的 totalMillis、以微秒计的 meanMicros、p50Micros、p95Micros、p99Micros、maxMicros。
最后两个字段是以累计耗时折算的吞吐率:throughputElementsPerSec 为元素数除以总秒数,throughputOpsPerSec 为调用次数除以总秒数;总耗时为 0 时按 1 纳秒下限处理,避免除零。
分位值只来自 256 槽环形缓冲内最近记录的那部分样本,未填满时样本数等于 calls。
示例BasaltMetrics.OperatorSummary summary = BasaltMetrics.snapshot(basalt.context()).operators().get("randn"); if (summary != null) { System.out.println(summary.calls() + " calls, p95 = " + summary.p95Micros() + " us"); }注意
totalMillis 与微秒字段单位不同,混用时需要先换算。
注意
样本被环形缓冲覆盖后,分位统计只反映最近 256 次调用,而 calls 与均值仍是全量累计。
参见:basalt.BasaltMetrics, basalt.BasaltMetrics.MetricsSnapshot
包内可见类型
以下类型没有 public 修饰符,但出现在公开签名中,因此一并列出。它们不是稳定 API,跨版本可能变化。
- private static final class BasaltMetrics.OperatorTracker¶
按算子名分桶的调用量与延迟累加器
recordOperator 通过 ConcurrentHashMap.computeIfAbsent 在某个算子名首次出现时创建实例,之后同名算子的所有调用都累加到这一份计数器上,因此它是 BasaltMetrics 内部唯一的可变指标载体。
调用次数、总纳秒、元素数与字节数用 LongAdder 累加,最大耗时用 AtomicLong 的 accumulateAndGet 维护;延迟样本写入长度 256 的环形数组,snapshot() 按键值拷贝当前已填充部分并排序取 p50、p95、p99。
snapshot() 产出的 OperatorSummary 会进入公开的 MetricsSnapshot,并被 toPrometheus() 渲染成带 op 标签的指标行,所以这一类型虽然包内可见,仍决定了调用方读到的分位数口径。
注意
分位数只覆盖环形数组内的样本,采样数超过 256 后早期样本会被覆盖。