У меня есть реализация Julia (ниже) рандомизированного SVD из этой статьи, Поиск структуры со случайностью: вероятностные алгоритмы для построения приближенных матричных разложений . Если вам интересно, см. Алгоритм на стр. 9.
Я бы ожидал, что рандомизированный SVD будет более эффективным, чем SVD, для больших наборов данных, но он немного медленнее и использует способ больше памяти. Вот моя статистика эффективности от @time
:
SVD: 16.331761 seconds (17 allocations: 763.184 MiB, 0.82% gc time)
RSVD: 17.009699 seconds (38 allocations: 1.074 GiB, 0.83% gc time)
Обратите внимание, что мой рандомизированный SVD использует более 1 ГБ памяти. Я не уверен почему. Вот моя реализация:
using Distributions
using LinearAlgebra
# ------------------------------------------------------------------------------
function find_Q(A, l)
#=
Given an m × n matrix A, and an integer l, compute an m × l orthonormal
matrix Q whose range approximates the range of A.
=#
m, n = size(A)
Ω = rand(Normal(), n, l)
Y = A * Ω
Q, R = qr(Y)
return Q
end
# ------------------------------------------------------------------------------
function randomized_SVD(A, k)
#=
Given an m × n matrix A, a target number k of singular vectors, and an
exponent q (say q = 1 or q = 2), this procedure computes an approximate
rank-2k factorization UΣVt, where U and V are orthonormal and Σ is
nonnegative and diagonal.
=#
Q = find_Q(A, 2*k)
B = Q' * A
S, Σ, Vt = svd(B)
U = Q * S
return U, Σ, Vt
end
# ------------------------------------------------------------------------------
m = 2000
n = 20000
k = 10
# Construct low-rank matrix
A = rand(m, k) * rand(k, n)
println("Rank of A: ", rank(A))
println("Size of A: ", size(A))
println("Throwaway test:")
@time svd(A)
@time randomized_SVD(A, k)
println("Actual test:")
@time svd(A)
@time randomized_SVD(A, k)
println("Completed")
Обратите внимание, что я звоню @time
дважды по документации Джулии , которая гласит:
При первом вызове (@time sum_global ()) функция компилируется. (Если вы еще не использовали @time в этом сеансе, он также скомпилирует функции, необходимые для определения времени.) Вы не должны серьезно относиться к результатам этого запуска.