Как умножить тензоры в MATLAB без цикла?
предположим, что я:
A = rand(1,10,3);
B = rand(10,16);
и я хочу к вам:
C(:,1) = A(:,:,1)*B;
C(:,2) = A(:,:,2)*B;
C(:,3) = A(:,:,3)*B;
могу ли я как-то умножить это в одной строке, чтобы это было быстрее?
Что делать, если я создам новый тензор b, как это
for i = 1:3
b(:,:,i) = B;
end
могу ли я умножить A и b, чтобы получить тот же C, но быстрее? Время, затраченное на создание B циклом выше, не имеет значения, так как мне понадобится C для многих разных A-s, в то время как B остается тем же.
4 ответов
если A
это правда 3D массив, что-то вроде A = rand(4,10,3)
и предполагая, что B
остается в виде 2D-массива, затем каждый A(:,:,1)*B
даст 2D-массив.
Итак, предполагая, что вы хотите сохранить эти 2D-массивы в виде срезов в третьем измерении выходного массива,C
вот так -
C(:,:,1) = A(:,:,1)*B;
C(:,:,2) = A(:,:,2)*B;
C(:,:,3) = A(:,:,3)*B; and so on.
чтобы решить это векторизованным образом, одним из подходов было бы использование reshape A
в 2D массив, объединяющий первое и третье измерения и после выполнения матрицы-muliplication. Наконец, чтобы привести размер вывода такой же, как и ранее перечисленные C
, нам нужен последний шаг перестройки.
реализация будет выглядеть примерно так -
%// Get size and then the final output C
[m,n,r] = size(A);
out = permute(reshape(reshape(permute(A,[1 3 2]),[],n)*B,m,r,[]),[1 3 2]);
образец выполнения -
>> A = rand(4,10,3);
B = rand(10,16);
C(:,:,1) = A(:,:,1)*B;
C(:,:,2) = A(:,:,2)*B;
C(:,:,3) = A(:,:,3)*B;
>> [m,n,r] = size(A);
out = permute(reshape(reshape(permute(A,[1 3 2]),[],n)*B,m,r,[]),[1 3 2]);
>> all(C(:)==out(:)) %// Verify results
ans =
1
на comments
, если A
представляет собой 3D-массив с всегда одноэлементным измерением в начале, вы можете просто использовать squeeze
а затем матрица-умножение, как так -
C = B.'*squeeze(A)
EDIT: @LuisMendo указывает, что это действительно возможно для этого конкретного случая использования. Однако это (в целом) невозможно, если первое измерение A не равно 1.
Я боролся с этим некоторое время, и я никогда не был в состоянии придумать решение. Выполнение элементарных вычислений производится хорошо по bsxfun
, но тензорное умножение-это то, что, к сожалению, не поддерживается. Извините, и удачи!
вы можете проверить этот файл обмена файлами mathworks, что облегчит вам и поддержит поведение, которое вы ищете, но я считаю, что он также полагается на циклы. редактировать: он полагается на MEX/C++, поэтому это не чистое решение MATLAB, если это то, что вы ищете.
Я должен согласиться с @GJSein, цикл for действительно быстрый
time
0.7050 0.3145
вот функция таймера
function time
n = 1E7;
A = rand(1,n,3);
B = rand(n,16);
t = [];
C = {};
tic
C{length(C)+1} = squeeze(cell2mat(cellfun(@(x) x*B,num2cell(A,[1 2]),'UniformOutput',false)));
t(length(t)+1) = toc;
tic
for i = 1:size(A,3)
C{length(C)+1}(:,i) = A(:,:,i)*B;
end
t(length(t)+1) = toc;
disp(t)
end