
JNum 发布:基于 Project Panama 的纯 Java 25 NumPy/BLAS 库
来源标题:Show HN: JNum – Pure Java 25 NumPy/BLAS via Project Panama FFM and Vector API
JNum 是一个面向 Java 25+ 和 Kotlin 的高性能数值计算库,通过 Project Panama 的 FFM 和 Vector API 实现原生 BLAS 性能,无需 C++ 构建工具链或 JNI。它提供类似 NumPy 的 API,支持 64 字节对齐的堆外张量、硬件 SIMD 矩阵乘法和零拷贝切片。该库旨在替代依赖 JNI 和 sun.misc.Unsafe 的传统 JVM 张量库。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
为现代 Java(JDK 25+)和 Kotlin 打造的高性能、硬件加速数值计算库,由 Project Panama(Foreign Function & Memory API 和 Vector API)驱动。
JNum 将 NumPy 和 PyTorch 的易用性带到 JVM 上,同时具备原生 BLAS 性能——无需原生 C++ 构建工具链、无需跨越 JNI 边界、也没有垃圾回收开销。
传统的 JVM 数值与张量库(如 ND4J 或 Deeplearning4j)依赖原生 C++ 后端。它们使用已弃用的 sun.misc.Unsafe 操作内存,并通过 JNI(Java Native Interface)跨越原生边界。
现代 Java 25
import jnum.DType; import jnum.JNum; import jnum.NDArray; import jnum.Slice;
void main() { // 1. 分配 64 字节对齐的堆外张量 NDArray a = JNum.rand(1024, 512); NDArray b = JNum.rand(512, 256);
// 2. 硬件 SIMD 矩阵乘法(4 层 BLIS 引擎)
NDArray c = a.matmul(b); // 形状:[1024, 256]
// 3. 零拷贝子视图与 Python 风格切片
NDArray slice = c.slice("0:10, 0:5");
// 4. 原地零分配修改
slice.muli(2.0f);
IO.println("左上角区块:\n" + slice);
}
地道的 Kotlin DSL
import jnum.*
fun main() { val x = JNum.rand(128, 64) val w = JNum.rand(64, 10) val b = JNum.zeros(10)
// 自然的运算符重载与中缀线性代数
val logits = (x matmul w) + b
// Python 风格的多维范围切片
val topScores = logits[0 until 5, all]
println("最高分:\n$topScores")
}
功能亮点
硬件 SIMD 向量通道:自动探测你的 CPU,通过 Vector API 调度 AVX-512(16 通道)、AVX2(8 通道)或 ARM NEON(4 通道)指令。
4 层 GEMM 引擎:硬件自适应矩阵乘法路由,覆盖 Nano 标量、Direct 寄存器分块、单线程 BLIS 和并行 ForkJoin 宏内核。
零拷贝布局与切片:转置、重塑、子视图和跨步子切片都是常数时间 $O(1)$ 操作,且零内存拷贝。
符号表达式求值:将 JNum.eval("$0 * $1 + $2", a, b, c) 或 JNum.eval("x * w + b", map) 这样的公式编译为硬件 FMA 指令,并自动回收缓冲区。
现代 AI 检查点 I/O:对 Hugging Face Safetensors(.safetensors)和 NumPy 二进制(.npy、.npz)提供直接零拷贝内存映射,另支持高吞吐 CSV/TSV 解析。
纯 Java 神经网络推理:内置 jnum.nn 模块(保留序列秩的 Linear、ReLU、Sigmoid、Tanh、Softmax 和 Sequential)。
实测基准与性能
所有基准均通过 OpenJDK JMH 1.37 在 Java 25 LTS 上测量(-Xms8g -Xmx8g -XX:+AlwaysPreTouch -XX:+UseParallelGC --add-modules jdk.incubator.vector),将 JNum 与 NumPy 2.4(OpenBLAS/C 后端)以及标准 JVM 数值引擎(EJML 0.44、ojAlgo 55.0 和带原生 OpenBLAS 后端的 ND4J 1.0.0-M2.1)进行对比。
矩阵维度 JNum(纯 Java 25) NumPy(C / OpenBLAS) ND4J(OpenBLAS C++) EJML(纯 Java) 性能亮点 $4 \times 4$ 0.0002 ms 0.0023 ms 0.020 ms ≈ 0.0001 ms 比 NumPy 快 11 倍,比 ND4J 快 100 倍 $16 \times 16$ 0.0004 ms 0.0028 ms 0.019 ms 0.003 ms 比 NumPy 快 7 倍,比 ND4J 快 47 倍 $64 \times 64$ 0.015 ms 0.013 ms 0.190 ms 0.140 ms 与 NumPy 持平,比 EJML 快 9.3 倍 $128 \times 128$ 0.138 ms 0.254 ms 0.499 ms 1.028 ms 比 NumPy 快 1.8 倍,比 EJML 快 7.4 倍 $512 \times 512$ 2.50 ms 1.86 ms 2.67 ms 27.16 ms 与 C++ BLAS 相当,比 EJML 快 10.8 倍 $1024 \times 1024$ 13.85 ms 8.98 ms 12.18 ms 216.56 ms 接近原生速度,比 EJML 快 15.6 倍 $2048 \times 2048$ 94.62 ms 62.99 ms 85.29 ms 2,049.86 ms 纯 Java 可与 C BLAS 竞争,比 EJML 快 21.6 倍 $4096 \times 4096$ 942.38 ms 487.92 ms 857.41 ms 17,419.52 ms 与 ND4J C++ 相当,比 EJML 快 18.4 倍 $8192 \times 8192$ 6,784.15 ms 5,967.30 ms 6,317.97 ms 141,500.0 ms 约为 NumPy C BLAS 的 88%,比 EJML 快 20.8 倍
说明
为什么 JNum 在中小矩阵上胜出:传统 C++ 封装(ND4J)和 Python C-API 绑定(NumPy)会带来调度和 JNI 调用边界开销。JNum 的 Tier 0 纳米标量和 Tier 1 直接 SIMD 内核在 CPU 向量寄存器内执行,不跨越原生边界,也不调度线程池。
向量数学运算 JNum(纯 Java 25) NumPy EJML ojAlgo ND4J(原生 C++) JNum 优势 sin(x) 151.59 ms 154.87 ms 1,334.80 ms 1,338.30 ms 1,693.35 ms 与 NumPy 持平,比 JVM 同类快 8.8–11.2 倍 cos(x) 170.91 ms 151.35 ms 1,077.31 ms 1,542.43 ms 1,979.36 ms 比 JVM 同类快 6.3–11.6 倍 exp(x) 111.49 ms 122.10 ms 804.97 ms 913.84 ms 1,988.33 ms 比 NumPy 快 1.1 倍,比 JVM 同类快 7.2–17.8 倍 log(x) 121.47 ms 164.22 ms 844.08 ms 1,062.01 ms 1,243.39 ms 比 NumPy 快 1.35 倍,比 JVM 同类快 6.9–10.2 倍 sigmoid(x) 115.01 ms 440.49 ms 973.74 ms 1,033.69 ms 1,843.23 ms 比 NumPy 快 3.8 倍,比 JVM 同类快 8.5–16.0 倍 tanh(x) 301.43 ms 197.38 ms 1,493.26 ms 1,602.51 ms 3,130.68 ms 比 JVM 同类快 5.0–10.4 倍
提示
为什么 JNum 在超越函数上胜出:EJML 和 ojAlgo 在单线程循环中通过标量 Math.* 调用逐元素处理。JNum 使用向量化的 minimax Chebyshev 多项式,在 AVX2/AVX-512 通道上调度,每个 CPU 时钟周期计算 8 或 16 个超越函数运算。
运算 JNum(纯 Java 25) NumPy EJML ND4J JNum 优势 矩阵求逆 7.271 ms 10.680 ms 18.122 ms 1,224.654 ms 比 NumPy 快 1.47 倍,比 EJML 快 2.5 倍,比 ND4J 快 168 倍 线性求解($Ax=b$) 1.976 ms 1.003 ms 5.331 ms 37.278 ms 接近原生速度,比 EJML 快 2.7 倍,比 ND4J 快 18.8 倍 行列式 1.839 ms 5.735 ms 5.380 ms 399.752 ms 比 NumPy 快 3.1 倍,比 EJML 快 2.9 倍 Cholesky 分解 1.261 ms 2.328 ms 3.545 ms — 比 NumPy 快 1.8 倍,比 EJML 快 2.8 倍 QR 分解 46.170 ms 12.622 ms 7.447 ms 586.330 ms 比 ND4J 快 12.7 倍
快速安装
将 JNum 添加到你的项目(选择 Java 或 Kotlin):
<dependency> <groupId>io.github.ch-abhinav</groupId> <artifactId>jnum</artifactId> <version>0.2.0</version> </dependency>(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。