эквивалент pdist2 в версии 7 MATLAB
Мне нужно вычислить евклидово расстояние между 2 матрицами в matlab. В настоящее время я использую bsxfun и вычисляю расстояние, как показано ниже( я прикрепляю фрагмент кода):
for i=1:4754
test_data=fea_test(i,:);
d=sqrt(sum(bsxfun(@minus, test_data, fea_train).^2, 2));
end
размер fea_test составляет 4754x1024, а fea_train-6800x1024, использование его цикла for вызывает выполнение for примерно за 12 минут, которые я думаю, слишком высоки. Есть ли способ быстрее вычислить евклидово расстояние между обеими матрицами?
I было сказано, что путем удаления ненужных для циклов я могу сократить время выполнения. Я также знаю, что pdist2 может помочь сократить время для расчета, но так как я использую версию 7. из matlab у меня нет функции pdist2. Обновление не является вариантом.
любая помощь.
С уважением,
Bhavya
3 ответов
вы можете полностью векторизовать расчет, повторяя строки fea_test
6800 раз, а fea_train
4754 раза, вот так:
rA = size(fea_test,1);
rB = size(fea_train,1);
[I,J]=ndgrid(1:rA,1:rB);
d = zeros(rA,rB);
d(:) = sqrt(sum(fea_test(J(:),:)-fea_train(I(:),:)).^2,2));
однако это приведет к промежуточным массивам размером 6800x4754x1024 (*8 байт для двойников), которые займут ~250 ГБ ОЗУ. Таким образом, полная векторизация не будет работать.
вы можете, однако, уменьшить время расчета расстояния путем предварительного распределения и не вычисляя квадратный корень, прежде чем он необходимо:
rA = size(fea_test,1);
rB = size(fea_train,1);
d = zeros(rA,rB);
for i = 1:rA
test_data=fea_test(i,:);
d(i,:)=sum( (test_data(ones(nB,1),:) - fea_train).^2, 2))';
end
d = sqrt(d);
вот векторизованная реализация для вычисления евклидова расстояния, которое намного быстрее, чем то, что у вас есть (даже значительно быстрее, чем PDIST2 на моей машине):
D = sqrt( bsxfun(@plus,sum(A.^2,2),sum(B.^2,2)') - 2*(A*B') );
он основан на том, что: ||u-v||^2 = ||u||^2 + ||v||^2 - 2*u.v
рассмотрим ниже грубое сравнение между двумя методами:
A = rand(4754,1024);
B = rand(6800,1024);
tic
D = pdist2(A,B,'euclidean');
toc
tic
DD = sqrt( bsxfun(@plus,sum(A.^2,2),sum(B.^2,2)') - 2*(A*B') );
toc
на моем ноутбуке WinXP под управлением R2011b мы можем увидеть улучшение в 10 раз во времени:
Elapsed time is 70.939146 seconds. %# PDIST2
Elapsed time is 7.879438 seconds. %# vectorized solution
вы должны знать что он не дает ровно те же результаты, что и PDIST2, вплоть до наименьшей точности.. Сравнивая результаты, вы увидите небольшие различия (обычно близкие к eps
с плавающей запятой, относительная точность):
>> max( abs(D(:)-DD(:)) )
ans =
1.0658e-013
на боковой ноте я собрал около 10 различных реализаций (некоторые из них просто небольшие вариации друг друга) для этого вычисления расстояния и сравнивал их. Вы были бы удивлены, как быстро простые петли могут быть (благодаря JIT), по сравнению с другими векторизованными решениями...
попробуйте эту векторизованную версию, она должна быть довольно эффективным. Edit: просто заметил, что мой ответ похож на @Amro.
function K = calculateEuclideanDist(P,Q)
% Vectorized method to compute pairwise Euclidean distance
% Returns K(i,j) = sqrt((P(i,:) - Q(j,:))'*(P(i,:) - Q(j,:)))
[nP, d] = size(P);
[nQ, d] = size(Q);
pmag = sum(P .* P, 2);
qmag = sum(Q .* Q, 2);
K = sqrt(ones(nP,1)*qmag' + pmag*ones(1,nQ) - 2*P*Q');
end