7

Giả sử tôi có:Làm thế nào để nhân tensors trong MATLAB mà không looping?

A = rand(1,10,3); 
B = rand(10,16); 

Và tôi muốn nhận được:

C(:,1) = A(:,:,1)*B; 
C(:,2) = A(:,:,2)*B; 
C(:,3) = A(:,:,3)*B; 

Tôi có thể bằng cách nào đó nhân này trong một dòng duy nhất để nó là nhanh hơn?

gì nếu tôi có thể tạo mới tensor b như thế này

for i = 1:3 
    b(:,:,i) = B; 
end 

Tôi có thể nhân A và b để có được cùng C nhưng nhanh hơn? Thời gian thực hiện trong việc tạo ra b bởi vòng lặp trên không quan trọng vì tôi sẽ cần C cho nhiều A-s khác nhau trong khi B vẫn giữ nguyên.

+0

Điều gì xảy ra nếu 'A = rand (4,10,3)', đó là mảng '3D' không có kích thước đơn? Điều gì phải là đầu ra sau đó? – Divakar

+0

@Divakar Nó luôn luôn đơn giản trong vấn đề của tôi. –

+4

Trong trường hợp đó, chỉ cần 'squeeze'' A' và sử dụng phép nhân ma trận - 'C = B. '* Squeeze (A)'. – Divakar

Trả lời

7

hoán vị kích thước của AB và sau đó áp dụng phép nhân ma trận:

C = B.'*permute(A, [2 3 1]); 
+3

Bạn hoàn toàn chính xác. Tuy nhiên, OP nên lưu ý rằng giải pháp này chỉ hoạt động vì kích thước đầu tiên của A là singleton. – GJStein

+1

Giảm 10% thời gian thực hiện! Cảm ơn bạn rất nhiều! –

+1

Rất đẹp, nhưng tôi tự hỏi tại sao OP lại sử dụng mảng 3 chiều với kích thước đơn – Justin

1

EDIT: @LuisMendo chỉ ra rằng điều này thực sự có thể cho trường hợp sử dụng cụ thể này. Tuy nhiên, nó không phải là (nói chung) có thể nếu thứ nguyên đầu tiên của A không phải là 1.

Tôi đã vật lộn với điều này một thời gian, và tôi chưa bao giờ có thể đưa ra giải pháp. Thực hiện các tính toán theo nguyên tố được thực hiện tốt đẹp bởi bsxfun, nhưng phép nhân tensor là cái gì đó không được hỗ trợ. Xin lỗi, và chúc may mắn!

Bạn có thể xem this mathworks file exchange file, điều này sẽ giúp bạn dễ dàng hơn và hỗ trợ hành vi bạn đang tìm kiếm, nhưng tôi tin rằng nó cũng dựa trên các vòng lặp. Chỉnh sửa: nó dựa trên MEX/C++, do đó, nó không phải là một giải pháp MATLAB tinh khiết nếu đó là những gì bạn đang tìm kiếm.

+0

Bạn đã chính xác, tôi đã cập nhật câu trả lời của mình. Tôi sẽ để nó ở đây để chỉ ra rằng, nói chung, giải pháp của bạn không giữ. Tuy nhiên, nó thực sự giải quyết các câu hỏi đặt ra ở đây. – GJStein

+2

Tôi đã xóa bỏ phiếu giảm giá của tôi sau khi chỉnh sửa. Nó không rõ ràng với tôi rằng tensor nhân là những gì OP là sau, mặc dù. Nếu thứ nguyên đầu tiên của 'A' không có' 1', phép gán 'C (:, 1) = A (:,:, 1) * B' trong câu hỏi sẽ không có ý nghĩa, bởi vì' A (:, :, 1) * B' sẽ là một ma trận, không phải là một vector –

0

tôi phải đồng ý với @GJSein, các vòng lặp for thực sự là nhanh

time 
    0.7050 0.3145 

Đây là chức năng hẹn giờ

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 
5

Nếu Ađúng mảng 3D, giống như A = rand(4,10,3) và giả định rằng B vẫn là một mảng 2D, sau đó mỗi A(:,:,1)*B sẽ mang lại một mảng 2D.

Vì vậy, giả định rằng bạn muốn lưu trữ những mảng 2D như lát trong chiều thứ ba của mảng đầu ra, C như vậy -

C(:,:,1) = A(:,:,1)*B; 
C(:,:,2) = A(:,:,2)*B; 
C(:,:,3) = A(:,:,3)*B; and so on. 

Để giải quyết việc này một cách vectorized, một trong những cách tiếp cận sẽ là sử dụng định dạng lại A thành mảng 2D kết hợp thứ nguyên đầu tiên và thứ ba và sau đó thực hiện ma trận-muliplication. Cuối cùng, để mang lại kích thước đầu ra giống như trước đó được liệt kê C, chúng ta cần một bước cuối cùng của định hình lại.

Việc thực hiện sẽ giống như thế này -

%// 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]); 

mẫu chạy -

>> 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 

Theo comments, nếu A là một mảng 3D với luôn luôn là một chiều kích singleton tại bắt đầu, bạn chỉ có thể sử dụng squeeze và sau đó nhân ma trận như vậy -

C = B.'*squeeze(A) 
Các vấn đề liên quan