Матричное умножение MATLAB против цикла для каждого столбца - PullRequest
2 голосов
/ 06 февраля 2011

При умножении двух матриц я пробовал следующие два варианта:

1)

res = X*A;

2)

for i = 1:size(A,2)
    res(:,i) = X*A(:,i);
end

Я предварительно выделил память для res в обоих,И что удивительно, я обнаружил, что вариант 2 работает быстрее.

Может кто-нибудь объяснить, как это так?

редактировать: я пытался

K=10000;
clear t1 t2
t1=zeros(K,1);
t2=zeros(K,1);

for k=1:K
    clear res
    x = rand(100,100);
    a = rand(100,100);
    tic
    res = x*a;
    t1(k) = toc;
end

for k=1:K
    clear res2
    res2 = zeros(100,100);
    x = rand(100,100);
    a = rand(100,100);
    tic
    for i = 1:100
        res2(:,i) = x*a(:,i);
    end
    t2(k) = toc;
end

Ответы [ 4 ]

3 голосов
/ 07 февраля 2011

Я запускаю оба кода в цикле 1000 раз.В среднем (но не всегда) первый векторизованный код был в 3-4 раза быстрее.Я очистил результирующие переменные и предварительно выделил их перед запуском таймера.

x = rand(100,100);
a = rand(100,100);

K=1000;
clear t1 t2
t1=zeros(K,1);
t2=zeros(K,1);

for k=1:K
    clear res
    tic
    res = x*a;
    t1(k) = toc;
end

for k=1:K
    clear res2
    res2 = zeros(100,100);
    tic
    for i = 1:100
        res2(:,i) = x*a(:,i);
    end
    t2(k) = toc;
end

Поэтому никогда не делайте вывод о времени на основе одного прогона.

2 голосов
/ 07 февраля 2011

Я полагаю, что могу понять разницу во времени между этими двумя методами, а также почему люди получают разные относительные скорости.

До версии Matlab 2008a (или версии, близкой к этой версии), дляВ любом коде Matlab основные циклы получили главный удар, потому что интерпретатор (слой между очень читаемым скриптом и реализацией кода более низкого уровня) должен был бы каждый раз заново интерпретировать код через цикл for.

После этого релиза интерпретатор становился все лучше и лучше, поэтому при запуске современной версии Matlab интерпретатор может посмотреть на ваш код и сказать: «Ага! Я знаю, что он делает, позвольте мне немного его оптимизировать» и избегатьудар, который в противном случае потребовался бы при повторной интерпретации кода.

Я ожидал бы, что два способа выполнения умножения матриц будут оцениваться в одно и то же время, поэтому реализация цикла for выполняется быстрее из-за некоторых деталей воптимизация интерпретатора, что мы простые смертные нехочу знать.

Один большой урок, который мы должны извлечь из этого, не все версии равны.Я работаю над несколькими передовыми случаями, используя два дополнения Matlab, SimBiology и Parallel Computing Toolbox, оба из которых (особенно если вы хотите, чтобы они работали вместе) зависят от версии в зависимости от скорости выполнения и время от времени.другие проблемы со стабильностью.Таким образом, я сохраняю три последних выпуска Matlab, проверю, получаю ли я одинаковые ответы для каждой версии, и иногда буду откатываться на более раннюю версию, если обнаружу проблемы с некоторыми функциями.Это, вероятно, излишне для большинства людей, но дает представление о различиях версий.

Надеюсь, это поможет.

Правки:

Чтобы уточнить, векторизация кода по-прежнему важна.Но с учетом сценария, подобного следующему:

x_slow = zeros(1,1e5);
x_fast = zeros(1,1e5);


tic;
for i=1:1e5
    x_slow(i) = log(i);
end
time_slow = toc; % evaluates for me in .0132 seconds

tic;
x_fast = log(1:1e5);
time_fast = toc; % evaluates for me in .0055 seconds

Несоответствие между time_slow и time_fast уменьшилось в последних нескольких версиях на основе улучшений в интерпретаторе.Я видел пример, который, как мне кажется, был 2000a против 2008b, но это мое воспоминание.

Возможно, есть еще кое-что, о чем говорили Оли и Юк.Часто существует разница между time_1 и time_2 в:

tic; x = log(1:1e5); time_1 = toc
tic; x = log(1:1e5); time_2 = toc

Таким образом, проверка миллиона оценок против одной оценки полезна, в зависимости от того, где в памяти находится x (в кеше или нет).

Надеюсь, это поможет снова.

2 голосов
/ 07 февраля 2011

Это вполне может быть эффектом кеширования.a уже находится в кеше, когда вы делаете вторую версию, так что это имеет преимущество.Попробуйте создать независимый набор входных данных, чтобы сделать его справедливым.Кроме того, вероятно, лучше измерить время, например, 1 миллион итераций, чтобы исключить типичные изменения из-за внешних эффектов.

0 голосов
/ 07 февраля 2011

Мне кажется, что вы не умножаете матрицу должным образом, вам нужно сложить все произведения из i-й строки матрицы X и j-го столбца матрицы A, что может быть причиной. Посмотрите здесь , чтобы увидеть, как это делается.

...