0

我有幾個高斯分佈,我想同時從它們中繪製不同的值。由於這基本上是GMM所做的,所以我研究了Matlab GMM實現(gmrnd),並且我已經看到它對所有組件執行簡單的循環。Matlab中的低通高斯混合模型

我想以更快的方式實現它,但問題是涉及到3d矩陣。一個簡單的代碼(帶循環)將是

n = 10; % number of Gaussians 
d = 2; % dimension of each Gaussian 
mu = rand(d,n); % init some means 
U = rand(d,d,n); % init some covariances with their Cholesky decomposition (Cov = U'*U) 
I = repmat(triu(true(d,d)),1,1,n); 
U(~I) = 0; 
r = randn(d,n); % random values for drawing samples 

samples = zeros(d,n); 
for i = 1 : n 
    samples(:,i) = U(:,:,i)' * r(:,i) + mu(:,i); 
end 

它可以加快它?我不知道如何處理3d協方差矩陣(不使用cellfun,這比較慢)。

回答

1

一些改進(希望是提高)可以在這裏建議。與bsxfun(@times,..)

I = repmat(triu(true(d,d)),[1,1,n]); 
U(~I) = 0; 

單行 - -

PARTE#1可以替換下面的代碼片

U = bsxfun(@times,triu(true(d,d)),U) 

PARTE#2可以的多圈部分代碼再次與bsxfun(@times,..)一樣 -

samples = squeeze(sum(bsxfun(@times,U,permute(r,[1 3 2])),2)) + mu 
+0

謝謝!不過,總和必須沿着第一個維度來完成。加快速度顯着提高'n'(在我的計算機內存耗盡之前可高達10倍),但如果我還增加'd',則反過來也是如此。如何在循環和'bsxfun'之間進行選擇似乎取決於情況,我不認爲有一個通用規則。儘管如此,再次感謝!我認爲除了你的建議之外,還有其他方法可以殺死這個循環。 – Simon

0

我不完全相信這是更快,但它擺脫了循環。如果可以的話,看到基準測試結果會很有趣。我也認爲這段代碼的內容相當醜陋,並且推導出發生的事情有點難,但我會讓你在可讀性和性能之間做出決定。

無論如何,我決定定義一個大的n*d維高斯,其中每個變量塊d是彼此獨立的(如原來的)。這允許將協方差定義爲塊對角矩陣,爲此我使用blkdiag。從那裏,應用bsxfun來消除循環的需要。

使用相同的隨機種子,我可以恢復同一樣品爲您的代碼:

%// sampling with block diagonal covariance matrix 
rng(1) %// set random seed 
Ub = mat2cell(U, d, d, ones(n,1)); %// 1-by-1-by-10 cell of 2-by-2 matrices 
C = blkdiag(Ub{:}); 
Ns = 1; %// number of samples 
joint_samples = bsxfun(@plus, C'*randn(d*n, Ns), mu(:)); 
new_samples = reshape(joint_samples, [d n]); %// or [d n Ns] if Ns > 1 

%//Compare to original 
rng(1) %// set same seed for repeatability 
r = randn(d,n); % random values for drawing samples 
samples = zeros(d,n); 
for i = 1 : n 
    samples(:,i) = U(:,:,i)' * r(:,i) + mu(:,i); 
end 

isequal(samples, new_samples) %// true 
+0

感謝您的回覆!不幸的是,你的解決方案比較慢(至少是10倍,甚至更多'n'和'm'),並且比循環更快地耗盡內存(因爲由'零(...)'預分配)。 – Simon