Wednesday, July 15, 2020

การคูณเมตริกซ์แบบต่างๆ

ในโปรแกรม MATLAB เป็นที่รู้กันว่ามีการคูณmatrix 2 แบบ

  1. Element wise multiplication แทนด้วย A.*B คือการคูณแบบตำแหน่งต่อตำแหน่ง
  2. Matrix multiplication แทนด้วย A*B คือการคูณเมตริกซ์
โพสที่แล้วเราโชว์การคูณแบบ element wise ให้ดู โพสนี้เราจะมาแสดงการคูณแบบเมตริกซ์ให้ดู 

แต่ก่อนอื่นเรามาทบทวนนิยามการคูณแบบเมตริกซ์ก่อน


สมมติเรามี matrix A และ B ดังนี้


ผลคูณ A*B = C จะได้

โดยที่ 

การคูณใน MATLAB อาจทำได้ 3 แบบ แต่วันนี้จะลองแค่ 2 แบบให้ดูเป็นตัวอย่าง

A = [2,3;3,5];
B = [3,5;2,7];
tic
C1 = A*B;
toc
tic
C2 = sum(bsxfun(@times, permute(A,[1,3,2]),permute(B,[3,2,1])),3);
toc
C1 ใช้เวลา 0.000134 seconds.
C2 ใช้เวลา 0.000244 seconds.

แบบแรกใช้คำสั่งคูณธรรมดา ใช้เวลาน้อยกว่าแบบที่2 ที่ให้ bsxfun .... ก็สรุปว่าการคูณแบบธรรมดา เร็วกว่าการคูณแบบพิสดารนะคะ

แต่ค่ะแต่...เราคงไม่แสดงวิธีที่สองให้ดูถ้ามันไม่มีอะไรน่าสนใจ
สำหรับ 2D matrix การคูณธรรมดานั้นเร็วที่สุด แต่ถ้าสมมติว่าเรามี 2D matrix หลายๆอันมาต่อกันในมิติที่สาม, k,แล้วเราต้องการคูณเมตริกซ์ k ครั้ง เราควรจะใช้วิธีไหน


โค้ดที่ใช้ในการทดสอบเป็นดังนี้


n = 3;
A = rand(n,n);
B = rand(n,n);
[m,n] = size(A);
vecK = [10,50,100,200,500,1000,3000,1e4];
t1 = zeros(1,length(vecK));
t2 = t1;
t3 = t1;
for ii = 1:length(vecK)
    K = vecK(ii);
    k = 1:K;
    A1 = ones(1,1,K).*A;
    B1 = ones(1,1,K).*B;
    C1 = zeros(m,n,K);
    tic;
    for k = 1:K
      C1(:,:,k) = A1(:,:,k) * B1(:,:,k);
    end
    t1(ii)=toc;

    tic;
    C2 = zeros(m,n,k);
    for i = 1:m
      for j = 1:m
        for k = 1:n
          C2(i,k,:) = C2(i,k,:) + A1(i,j,:).*B1(j,k,:);
        end
      end
    end
    t2(ii)=toc;

    tic;
    C3 = zeros(m,n,K);
    for j = 1:size(A,2)
      C3 = C3 + bsxfun(@times,A1(:,j,:),B1(j,:,:));
    end
    t3(ii)=toc;
end
h=plot(vecK,t1,'-*b',vecK,t2,'-*r',vecK,t3,'-*g');
h(1).LineWidth = 2;
h(2).LineWidth = 2;
h(3).LineWidth = 2;
set(gca,'FontSize',14);
axis tight;
xlabel('k');ylabel('time(s)');grid on;
legend('A*B', 'vectorized', 'bsxfun');
ใน code ข้างบน เราแสดงวิธีคูณให้ดู 3 แบบค่ะ
C1 คือ แบบ A*B ใน for loop ธรรมดา
C2 คือ การคูณตามนิยามการคูณเมตริกส์ในรูปแบบ vectorized
C3 คือ การคูณโดยใช้ bsxfun

จะเห็นได้ว่าการคูณแบบ bsxfun นั้นเร็วกว่าการคูณธรรมดาไปหลายขุมเลยค่ะ แต่ค่ะแต่ สมมติว่าเราเปลี่ยนขนาด matrix n จาก 3 เป็น 50 ล่ะ
พอขนาดเมตริกซ์ที่ต้องการคูณใหญ่ขึ้น การคูณแบบ vectorized กลับใช้เวลามากสุดและการคูณธรรมดาใช้เวลาน้อยสุด

ดังนั้นโพสนี้จึงขอสรุปว่า แม้ว่าการคูณเมตริกซ์สามารถทำได้หลายวิธี แต่ขนาดของเมตริกซ์ก็มีผลกับการเลือกใช้วิธีในการคูณเมตริกซ์นั้น ดังนั้นเลือกวิธีให้เหมาะกับงานค่ะ

No comments:

Post a Comment