稀疏矩阵的单值分解
Single-value decomposition of a sparse matrix
我有一个比较大的矩阵,我想计算它的单值分解。不幸的是,使用 core.matrix 的直接 linear/svd
函数(使用 :vectorz
实现)会导致内存不足异常——我的机器对于开发机器来说内存相对较少( 8GB,Java 堆 space 设置为最大 5GB)。
矩阵的维度为 [422, 23069]
且相对稀疏(~1.74% 的值非零),因此我的下一次尝试是将矩阵转换为 sparse-matrix
:
(def sparse-fs (matrix/sparse-matrix fs))
Java 代码中的 ArrayOutOfBoundsException
出人意料地失败了。我可以通过先创建一个稀疏矩阵然后设置非零值来解决这个问题:
user> (def sparse-fs (matrix/sparse-matrix [422 23069]))
#'user/sfs
user> (count
(map-indexed
(fn [row line]
(map-indexed
(fn [col val]
(when (not (= val 0.0))
(matrix/mset! sparse-fs row col val)))))
fs))
422
然而,在这个稀疏矩阵上调用 linear/svd
也失败了,因为 svd 的协议显然没有实现:
user> (def svd-fs (linear/svd sparse-fs))
CompilerException java.lang.IllegalArgumentException: No implementation of method: :svd of protocol:
#'clojure.core.matrix.protocols/PSVDDecomposition found for class: mikera.vectorz.Vector2,
我目前对如何从这里取得进展一无所知,如果能就如何将我的矩阵(和 svd 计算)放入我相对较小的内存中提供任何意见,我将不胜感激。
更新:
协议问题来自我仍在尝试使用 clojure.core.matrix/sparse-matrix
,我显然不明白它的预期用途。相反,我可以使用 new-sparse-array
生成一个实现 AMatrix
的实例,为此实现了分解协议:
user> (def foo-sparse (matrix/sparse-matrix [422 23069]))
#'user/foo-sparse
user> (type foo-sparse)
mikera.vectorz.Vector2
user> (matrix/dimensionality foo-sparse)
1
user> (def foo-sparse (matrix/new-sparse-array [422 23069]))
#'user/foo-sparse
user> (matrix/dimensionality foo-sparse)
2
user> (type foo-sparse)
mikera.matrixx.impl.SparseRowMatrix
不幸的是,当我在此矩阵上调用 linear/svd
时,我又回到了内存不足错误:
1. Caused by java.lang.OutOfMemoryError
Java heap space
DoubleArrays.java: 724 mikera.vectorz.util.DoubleArrays/createStorage
Matrix.java: 45 mikera.matrixx.Matrix/<init>
Matrix.java: 56 mikera.matrixx.Matrix/create
Matrix.java: 653 mikera.matrixx.Matrix/createIdentity
BidiagonalRow.java: 174 mikera.matrixx.decompose.impl.bidiagonal.BidiagonalRow/handleU
BidiagonalRow.java: 155 mikera.matrixx.decompose.impl.bidiagonal.BidiagonalRow/getU
BidiagonalRow.java: 115 mikera.matrixx.decompose.impl.bidiagonal.BidiagonalRow/_decompose
BidiagonalRow.java: 78 mikera.matrixx.decompose.impl.bidiagonal.BidiagonalRow/decompose
Bidiagonal.java: 21 mikera.matrixx.decompose.Bidiagonal/decompose
SvdImplicitQr.java: 177 mikera.matrixx.decompose.impl.svd.SvdImplicitQr/bidiagonalization
SvdImplicitQr.java: 154 mikera.matrixx.decompose.impl.svd.SvdImplicitQr/_decompose
SvdImplicitQr.java: 89 mikera.matrixx.decompose.impl.svd.SvdImplicitQr/decompose
SVD.java: 31 mikera.matrixx.decompose.SVD/decompose
matrix_api.clj: 334 mikera.vectorz.matrix-api/eval26238/fn
protocols.cljc: 1150 clojure.core.matrix.protocols$eval21076$fn__21077$G__21067__21084/invoke
linear.cljc: 105 clojure.core.matrix.linear$svd/invoke
我怀疑这可能与 vectorz-clj 有关 issue 18 that operations on sparse matrices don't produce sparse results。
还有其他选择吗?
我可以通过使用 :clatrix
实现解决 svd
计算中的内存问题。 Clatrix 不支持稀疏矩阵,但似乎在 svd 计算上使用的内存较少。
我有一个比较大的矩阵,我想计算它的单值分解。不幸的是,使用 core.matrix 的直接 linear/svd
函数(使用 :vectorz
实现)会导致内存不足异常——我的机器对于开发机器来说内存相对较少( 8GB,Java 堆 space 设置为最大 5GB)。
矩阵的维度为 [422, 23069]
且相对稀疏(~1.74% 的值非零),因此我的下一次尝试是将矩阵转换为 sparse-matrix
:
(def sparse-fs (matrix/sparse-matrix fs))
Java 代码中的 ArrayOutOfBoundsException
出人意料地失败了。我可以通过先创建一个稀疏矩阵然后设置非零值来解决这个问题:
user> (def sparse-fs (matrix/sparse-matrix [422 23069]))
#'user/sfs
user> (count
(map-indexed
(fn [row line]
(map-indexed
(fn [col val]
(when (not (= val 0.0))
(matrix/mset! sparse-fs row col val)))))
fs))
422
然而,在这个稀疏矩阵上调用 linear/svd
也失败了,因为 svd 的协议显然没有实现:
user> (def svd-fs (linear/svd sparse-fs))
CompilerException java.lang.IllegalArgumentException: No implementation of method: :svd of protocol:
#'clojure.core.matrix.protocols/PSVDDecomposition found for class: mikera.vectorz.Vector2,
我目前对如何从这里取得进展一无所知,如果能就如何将我的矩阵(和 svd 计算)放入我相对较小的内存中提供任何意见,我将不胜感激。
更新:
协议问题来自我仍在尝试使用 clojure.core.matrix/sparse-matrix
,我显然不明白它的预期用途。相反,我可以使用 new-sparse-array
生成一个实现 AMatrix
的实例,为此实现了分解协议:
user> (def foo-sparse (matrix/sparse-matrix [422 23069]))
#'user/foo-sparse
user> (type foo-sparse)
mikera.vectorz.Vector2
user> (matrix/dimensionality foo-sparse)
1
user> (def foo-sparse (matrix/new-sparse-array [422 23069]))
#'user/foo-sparse
user> (matrix/dimensionality foo-sparse)
2
user> (type foo-sparse)
mikera.matrixx.impl.SparseRowMatrix
不幸的是,当我在此矩阵上调用 linear/svd
时,我又回到了内存不足错误:
1. Caused by java.lang.OutOfMemoryError
Java heap space
DoubleArrays.java: 724 mikera.vectorz.util.DoubleArrays/createStorage
Matrix.java: 45 mikera.matrixx.Matrix/<init>
Matrix.java: 56 mikera.matrixx.Matrix/create
Matrix.java: 653 mikera.matrixx.Matrix/createIdentity
BidiagonalRow.java: 174 mikera.matrixx.decompose.impl.bidiagonal.BidiagonalRow/handleU
BidiagonalRow.java: 155 mikera.matrixx.decompose.impl.bidiagonal.BidiagonalRow/getU
BidiagonalRow.java: 115 mikera.matrixx.decompose.impl.bidiagonal.BidiagonalRow/_decompose
BidiagonalRow.java: 78 mikera.matrixx.decompose.impl.bidiagonal.BidiagonalRow/decompose
Bidiagonal.java: 21 mikera.matrixx.decompose.Bidiagonal/decompose
SvdImplicitQr.java: 177 mikera.matrixx.decompose.impl.svd.SvdImplicitQr/bidiagonalization
SvdImplicitQr.java: 154 mikera.matrixx.decompose.impl.svd.SvdImplicitQr/_decompose
SvdImplicitQr.java: 89 mikera.matrixx.decompose.impl.svd.SvdImplicitQr/decompose
SVD.java: 31 mikera.matrixx.decompose.SVD/decompose
matrix_api.clj: 334 mikera.vectorz.matrix-api/eval26238/fn
protocols.cljc: 1150 clojure.core.matrix.protocols$eval21076$fn__21077$G__21067__21084/invoke
linear.cljc: 105 clojure.core.matrix.linear$svd/invoke
我怀疑这可能与 vectorz-clj 有关 issue 18 that operations on sparse matrices don't produce sparse results。
还有其他选择吗?
我可以通过使用 :clatrix
实现解决 svd
计算中的内存问题。 Clatrix 不支持稀疏矩阵,但似乎在 svd 计算上使用的内存较少。