ND4J执行SVD时触发运行时错误,请求解决方法
ND4J奇异值分解(SVD)报错修复方案
环境信息
- 运行环境:Macbook Pro
- ND4J依赖:nd4j-api、nd4j-native 1.0.0-M2.1
- JDK版本:Open JDK 17
- 开发语言:Kotlin 1.7.20
- IDE:IntelliJ 2022.2.2旗舰版
问题背景
学习ND4J线性代数运算时,已完成矩阵与标量的加减乘除、矩阵间加减乘、LU/QR分解的JUnit 5测试且全部通过,但执行SVD测试时触发ND4JIllegalStateException,提示"Op name svd - no output arrays were provided and calculateOutputShape failed to execute"。
测试代码
@Test fun `singular value decomposition`() { // setup val a = Nd4j.create(doubleArrayOf( 0.0, 1.0, -2.0, 3.0, 5.0, -3.0, 1.0, -2.0, 5.0, -2.0, -1.0, 1.0 ), intArrayOf(3, 4)) val b = Nd4j.create(doubleArrayOf(-17.0, 28.0, 11.0), intArrayOf(3, 1)) val u = Nd4j.create(doubleArrayOf( -0.1295469, -0.8061540, 0.5773503, 0.7629233, 0.2908861, 0.5773503, 0.6333764, -0.5152679, -0.5773503 ), intArrayOf(3, 3)) val v = Nd4j.create(doubleArrayOf( 0.87191556, -0.2515803, -0.1764323, -0.46022634, -0.1453716, -0.4694190, 0.04853711, 0.5423235, 0.6394484, -0.15999723, -0.7883272, 0.5827720 ), intArrayOf(3, 4)) val d = Nd4j.create(doubleArrayOf( 8.007081e+00, 4.459446e+00, 4.022656e-16 ), intArrayOf(3)) // exercise val actual = NDLinalg().svd(a, true, true) // assert Assertions.assertTrue(true) }
错误日志
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. org.nd4j.linalg.exception.ND4JIllegalStateException: Op name svd - no output arrays were provided and calculateOutputShape failed to execute at org.nd4j.linalg.cpu.nativecpu.ops.NativeOpExecutioner.exec(NativeOpExecutioner.java:1513) at org.nd4j.linalg.factory.Nd4j.exec(Nd4j.java:6545) at org.nd4j.linalg.factory.ops.NDLinalg.svd(NDLinalg.java:309) at ie.duffymo.fea.MatrixTest.singular value decomposition(MatrixTest.kt:353) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) Process finished with exit code 255
修复方案
改用显式指定输出数组的SVD调用方式
1.0.0-M2.1版本的NDLinalg.svd方法存在自动输出数组生成的兼容性问题,可直接使用SVD操作类并显式执行来规避:// 替代原有的NDLinalg().svd调用 val svdOp = SVD() svdOp.setComputeU(true) // 对应原参数的computeU svdOp.setComputeV(true) // 对应原参数的computeV val outputs = Nd4j.exec(svdOp, a) // 输出结果依次为U矩阵、奇异值数组、V矩阵 val uActual = outputs[0] val sActual = outputs[1] val vActual = outputs[2]验证矩阵形状与参数合理性
- 确认输入矩阵
a的形状(3x4)符合SVD运算要求,非空且元素类型正确 computeU和computeV参数设为true时,会生成对应的左/右奇异矩阵,若不需要可设为false以减少计算开销
- 确认输入矩阵
考虑升级ND4J版本
1.0.0-M2.1为较早的里程碑版本,后续稳定版本(如1.0.0-M3及以上)已修复多个线性代数运算的兼容性问题,升级后可直接使用NDLinalg.svd的原有调用方式。
内容的提问来源于stack exchange,提问作者duffymo
相关产品推荐
相关产品推荐

