Tôi đã triển khai SVD ngẫu nhiên như được đưa ra trong "Halko, N., Martinsson, PG, Shkolnisky, Y., & Tygert, M. (2010). Một thuật toán để phân tích thành phần chính của các tập dữ liệu lớn. Arxiv in sẵn arXiv: 1007.5510, 0526. Truy xuất ngày 1 tháng 4 năm 2011, từ http://arxiv.org/abs/1007.5510 . ". Nếu bạn muốn rút ngắn SVD, nó thực sự hoạt động nhanh hơn nhiều so với các biến thể svd trong MATLAB. Bạn có thể lấy nó ở đây:
function [U,S,V] = fsvd(A, k, i, usePowerMethod)
% FSVD Fast Singular Value Decomposition
%
% [U,S,V] = FSVD(A,k,i,usePowerMethod) computes the truncated singular
% value decomposition of the input matrix A upto rank k using i levels of
% Krylov method as given in [1], p. 3.
%
% If usePowerMethod is given as true, then only exponent i is used (i.e.
% as power method). See [2] p.9, Randomized PCA algorithm for details.
%
% [1] Halko, N., Martinsson, P. G., Shkolnisky, Y., & Tygert, M. (2010).
% An algorithm for the principal component analysis of large data sets.
% Arxiv preprint arXiv:1007.5510, 0526. Retrieved April 1, 2011, from
% http://arxiv.org/abs/1007.5510.
%
% [2] Halko, N., Martinsson, P. G., & Tropp, J. A. (2009). Finding
% structure with randomness: Probabilistic algorithms for constructing
% approximate matrix decompositions. Arxiv preprint arXiv:0909.4061.
% Retrieved April 1, 2011, from http://arxiv.org/abs/0909.4061.
%
% See also SVD.
%
% Copyright 2011 Ismail Ari, http://ismailari.com.
if nargin < 3
i = 1;
end
% Take (conjugate) transpose if necessary. It makes H smaller thus
% leading the computations to be faster
if size(A,1) < size(A,2)
A = A';
isTransposed = true;
else
isTransposed = false;
end
n = size(A,2);
l = k + 2;
% Form a real n×l matrix G whose entries are iid Gaussian r.v.s of zero
% mean and unit variance
G = randn(n,l);
if nargin >= 4 && usePowerMethod
% Use only the given exponent
H = A*G;
for j = 2:i+1
H = A * (A'*H);
end
else
% Compute the m×l matrices H^{(0)}, ..., H^{(i)}
% Note that this is done implicitly in each iteration below.
H = cell(1,i+1);
H{1} = A*G;
for j = 2:i+1
H{j} = A * (A'*H{j-1});
end
% Form the m×((i+1)l) matrix H
H = cell2mat(H);
end
% Using the pivoted QR-decomposiion, form a real m×((i+1)l) matrix Q
% whose columns are orthonormal, s.t. there exists a real
% ((i+1)l)×((i+1)l) matrix R for which H = QR.
% XXX: Buradaki column pivoting ile yapılmayan hali.
[Q,~] = qr(H,0);
% Compute the n×((i+1)l) product matrix T = A^T Q
T = A'*Q;
% Form an SVD of T
[Vt, St, W] = svd(T,'econ');
% Compute the m×((i+1)l) product matrix
Ut = Q*W;
% Retrieve the leftmost m×k block U of Ut, the leftmost n×k block V of
% Vt, and the leftmost uppermost k×k block S of St. The product U S V^T
% then approxiamtes A.
if isTransposed
V = Ut(:,1:k);
U = Vt(:,1:k);
else
U = Ut(:,1:k);
V = Vt(:,1:k);
end
S = St(1:k,1:k);
end
Để kiểm tra nó, chỉ cần tạo một hình ảnh trong cùng một thư mục (giống như một ma trận lớn, bạn có thể tự tạo ma trận)
% Example code for fast SVD.
clc, clear
%% TRY ME
k = 10; % # dims
i = 2; % # power
COMPUTE_SVD0 = true; % Comment out if you do not want to spend time with builtin SVD.
% A is the m×n matrix we want to decompose
A = im2double(rgb2gray(imread('test_image.jpg')))';
%% DO NOT MODIFY
if COMPUTE_SVD0
tic
% Compute SVD of A directly
[U0, S0, V0] = svd(A,'econ');
A0 = U0(:,1:k) * S0(1:k,1:k) * V0(:,1:k)';
toc
display(['SVD Error: ' num2str(compute_error(A,A0))])
clear U0 S0 V0
end
% FSVD without power method
tic
[U1, S1, V1] = fsvd(A, k, i);
toc
A1 = U1 * S1 * V1';
display(['FSVD HYBRID Error: ' num2str(compute_error(A,A1))])
clear U1 S1 V1
% FSVD with power method
tic
[U2, S2, V2] = fsvd(A, k, i, true);
toc
A2 = U2 * S2 * V2';
display(['FSVD POWER Error: ' num2str(compute_error(A,A2))])
clear U2 S2 V2
subplot(2,2,1), imshow(A'), title('A (orig)')
if COMPUTE_SVD0, subplot(2,2,2), imshow(A0'), title('A0 (svd)'), end
subplot(2,2,3), imshow(A1'), title('A1 (fsvd hybrid)')
subplot(2,2,4), imshow(A2'), title('A2 (fsvd power)')
Khi tôi chạy nó trên máy tính để bàn của mình cho một hình ảnh có kích thước 635 * 483, tôi nhận được
Elapsed time is 0.110510 seconds.
SVD Error: 0.19132
Elapsed time is 0.017286 seconds.
FSVD HYBRID Error: 0.19142
Elapsed time is 0.006496 seconds.
FSVD POWER Error: 0.19206
Như bạn có thể thấy, đối với các giá trị thấp k
, nó nhanh hơn 10 lần so với sử dụng Matlab SVD. Nhân tiện, bạn có thể cần chức năng đơn giản sau cho chức năng kiểm tra:
function e = compute_error(A, B)
% COMPUTE_ERROR Compute relative error between two arrays
e = norm(A(:)-B(:)) / norm(A(:));
end
Tôi đã không thêm phương thức PCA vì nó đơn giản để thực hiện bằng cách sử dụng SVD. Bạn có thể kiểm tra liên kết này để xem mối quan hệ của họ.