ทำไม MATLAB ถึงรวดเร็วในการคูณเมทริกซ์?


190

ฉันกำลังสร้างมาตรฐานด้วย CUDA, C ++, C #, Java และการใช้ MATLAB สำหรับการตรวจสอบและสร้างเมทริกซ์ เมื่อฉันทำการคูณเมทริกซ์ด้วย MATLAB 2048x2048และเมทริกซ์ที่ยิ่งใหญ่กว่าก็จะถูกคูณด้วยเกือบทันที

             1024x1024   2048x2048   4096x4096
             ---------   ---------   ---------
CUDA C (ms)      43.11      391.05     3407.99
C++ (ms)       6137.10    64369.29   551390.93
C# (ms)       10509.00   300684.00  2527250.00
Java (ms)      9149.90    92562.28   838357.94
MATLAB (ms)      75.01      423.10     3133.90

มีเพียง CUDA เท่านั้นที่สามารถแข่งขันได้ แต่ฉันคิดว่าอย่างน้อย C ++ จะค่อนข้างใกล้เคียงและไม่ช้ากว่า 60 เท่า ฉันยังไม่รู้ว่าจะคิดอย่างไรเกี่ยวกับผลลัพธ์ C # อัลกอริทึมเป็นเพียงเช่นเดียวกับ C ++ และ Java แต่มีกระโดดยักษ์จาก20481024

MATLAB ทำการคูณเมทริกซ์รวดเร็วแค่ไหน?

รหัส C ++:

float temp = 0;
timer.start();
for(int j = 0; j < rozmer; j++)
{
    for (int k = 0; k < rozmer; k++)
    {
        temp = 0;
        for (int m = 0; m < rozmer; m++)
        {
            temp = temp + matice1[j][m] * matice2[m][k];
        }
        matice3[j][k] = temp;
    }
}
timer.stop();

14
อาจเป็นคำถามของอัลกอริทึมที่คุณใช้
Robert J.

24
ตรวจสอบให้แน่ใจว่า Matlab ไม่ได้แคผลลัพธ์จากคุณมันเป็นสัตว์ร้าย ก่อนอื่นให้แน่ใจว่ากำลังทำการคำนวณจริงแล้วเปรียบเทียบ
rubenvb


10
ฉันคิดว่าโพสต์นี้น่าสนใจจริงๆ แต่ฉันอยากจะดูมาตรฐานที่เหมาะสมกว่านี้ ตัวอย่างเช่นฉันคิดว่า Matlab R2011a ใช้มัลติเธรดโดยอัตโนมัติและการคูณเมทริกซ์ถูกนำไปใช้โดยใช้ไลบรารี mkl / blas ของ Intel ดังนั้นฉันเดาว่า c ++ เร็วกว่าหากใช้การเรียก mkl ทำการคูณเมทริกซ์ คำถามก็คือค่าใช้จ่ายของ Matlab คืออะไร ฉันรู้ว่านี่ขึ้นอยู่กับรายละเอียดเพิ่มเติมของการคูณเมทริกซ์ แต่ตอนนี้ตัวเลขข้างต้นค่อนข้างไม่มีความหมายเลย
ลูคัส

1
คุณสามารถใช้ "อัลกอริทึม Strassen" ของเวลารัน O (n ^ 2.81) สำหรับการคูณเมทริกซ์สแควร์ขนาดใหญ่ซึ่งเร็วกว่าการคูณแบบเนทีฟประมาณ 10 เท่าซึ่งทำงานใน O (n ^ 3) SSE / AVX ยังสามารถช่วยให้คุณทำงานได้เร็วขึ้นประมาณ 8-20x สำหรับการเรียกใช้โค้ด คุณสามารถใช้งาน ac ได้เร็วกว่าของ MATLAB
DU Jiaen

คำตอบ:


85

นี่คือผลลัพธ์ของฉันโดยใช้ MATLAB R2011a + กล่องเครื่องมือคำนวณแบบขนานบนเครื่องที่มี Tesla C2070:

>> A = rand(1024); gA = gpuArray(A);
% warm up by executing the operations a couple of times, and then:
>> tic, C = A * A; toc
Elapsed time is 0.075396 seconds.
>> tic, gC = gA * gA; toc
Elapsed time is 0.008621 seconds.

MATLAB ใช้ไลบรารีที่ปรับให้เหมาะสมสูงสุดสำหรับการคูณเมทริกซ์ซึ่งเป็นสาเหตุที่การคูณเมทริกซ์ MATLAB ธรรมดาทำได้รวดเร็ว gpuArrayรุ่นใช้MAGMA

อัพเดทโดยใช้ R2014aบนเครื่องที่มี Tesla K20c และใหม่timeitและgputimeitฟังก์ชั่น:

>> A = rand(1024); gA = gpuArray(A);
>> timeit(@()A*A)
ans =
    0.0324
>> gputimeit(@()gA*gA)
ans =
    0.0022

อัพเดตโดยใช้ R2018bบนเครื่อง WIN64 ที่มี 16 ฟิสิคัลคอร์และ Tesla V100:

>> timeit(@()A*A)
ans =
    0.0229
>> gputimeit(@()gA*gA)
ans =
   4.8019e-04

(หมายเหตุ: ณ จุดหนึ่ง (ฉันลืมเมื่อแน่นอน) gpuArrayเปลี่ยนจาก MAGMA เป็น cuBLAS - MAGMA ยังคงใช้สำหรับgpuArrayการดำเนินการบางอย่าง)


เหตุใดเรื่องนี้
นักฟิสิกส์บ้า

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

175

คำถามประเภทนี้เกิดขึ้นอีกและควรตอบให้ชัดเจนยิ่งกว่า "MATLAB ใช้ไลบรารีที่ปรับให้เหมาะสมที่สุด" หรือ "MATLAB ใช้ MKL" เป็นครั้งเดียวใน Stack Overflow

ประวัติความเป็นมา:

การคูณเมทริกซ์ (ร่วมกับเมทริกซ์ - เวกเตอร์, การคูณเวกเตอร์ - เวกเตอร์และการสลายตัวเมทริกซ์จำนวนมาก) คือ (เป็น) ปัญหาที่สำคัญที่สุดในพีชคณิตเชิงเส้น วิศวกรได้แก้ไขปัญหาเหล่านี้กับคอมพิวเตอร์มาตั้งแต่ต้น

ฉันไม่ใช่ผู้เชี่ยวชาญเกี่ยวกับประวัติ แต่เห็นได้ชัดว่าทุกคนเพิ่งเขียนเวอร์ชัน FORTRAN ของเขาใหม่ด้วยลูปเรียบง่าย มาตรฐานบางอย่างก็มาพร้อมกับการระบุ "เมล็ด" (การปฏิบัติขั้นพื้นฐาน) ว่าปัญหาพีชคณิตเชิงเส้นส่วนใหญ่ที่จำเป็นเพื่อที่จะได้รับการแก้ไข การดำเนินงานขั้นพื้นฐานเหล่านี้ได้รับการมาตรฐานในข้อกำหนดที่เรียกว่า: โปรแกรมพีชคณิตเชิงเส้นพื้นฐาน (BLAS) วิศวกรสามารถเรียกรูทีน BLAS มาตรฐานเหล่านี้ที่ได้รับการทดสอบเป็นอย่างดีในโค้ดทำให้การทำงานง่ายขึ้นมาก

หน่าย:

BLAS วิวัฒนาการมาจากระดับ 1 (เวอร์ชันแรกที่กำหนดการดำเนินการสเกลาร์ - เวกเตอร์และเวกเตอร์ - เวกเตอร์) เป็นระดับ 2 (การดำเนินงานเวกเตอร์เมทริกซ์) ถึงระดับ 3 (การดำเนินการเมทริกซ์เมทริกซ์) และให้ "เมล็ด" มากขึ้น และอื่น ๆ ของการดำเนินงานพีชคณิตเชิงเส้นพื้นฐาน เดิม FORTRAN 77 การใช้งานยังคงมีอยู่ในเว็บไซต์ของ netlib

เพื่อประสิทธิภาพที่ดีขึ้น:

ดังนั้นในช่วงหลายปีที่ผ่านมา (โดยเฉพาะอย่างยิ่งระหว่างรุ่น BLAS ระดับ 1 และระดับ 2: ช่วงต้นยุค 80) ฮาร์ดแวร์เปลี่ยนไปเมื่อมีการปฏิบัติการของเวกเตอร์และลำดับชั้นแคช การวิวัฒนาการเหล่านี้ทำให้สามารถเพิ่มประสิทธิภาพของรูทีนย่อย BLAS ได้อย่างมาก จากนั้นผู้ค้าหลายรายก็มาพร้อมกับการใช้งานประจำของ BLAS ซึ่งมีประสิทธิภาพมากขึ้น

ฉันไม่รู้การใช้งานทางประวัติศาสตร์ทั้งหมด (ฉันไม่ได้เกิดหรือเป็นเด็ก) แต่มีสิ่งที่น่าสังเกตมากที่สุดสองอย่างในช่วงต้นยุค 2000: Intel MKL และ GotoBLAS Matlab ของคุณใช้ Intel MKL ซึ่งเป็น BLAS ที่ดีมากและได้รับการปรับปรุงและอธิบายประสิทธิภาพที่ยอดเยี่ยมที่คุณเห็น

รายละเอียดทางเทคนิคเกี่ยวกับการคูณเมทริกซ์:

เหตุใด Matlab (MKL) จึงรวดเร็วที่dgemm(การคูณเมทริกซ์เมทริกซ์ทั่วไปความแม่นยำสองเท่า) ในแง่ง่าย: เพราะมันใช้ vectorization และการแคชข้อมูลที่ดี ในแง่ที่ซับซ้อนยิ่งขึ้น: ดูบทความที่จัดทำโดย Jonathan Moore

โดยทั่วไปเมื่อคุณทำการคูณในรหัส C ++ ที่คุณให้ไว้คุณจะไม่เป็นมิตรกับแคชเลย เนื่องจากฉันสงสัยว่าคุณสร้างอาร์เรย์ของพอยน์เตอร์ไปยังแถวอาเรย์การเข้าถึงในลูปภายในของคุณไปยังคอลัมน์ k-th ของ "matice2": matice2[m][k]ช้ามาก แน่นอนเมื่อคุณเข้าถึงmatice2[0][k]คุณจะต้องได้องค์ประกอบ k-th ของอาร์เรย์ 0 ของเมทริกซ์ของคุณ จากนั้นในการทำซ้ำครั้งถัดไปคุณต้องเข้าถึงmatice2[1][k]ซึ่งเป็นองค์ประกอบ k-th ของอาร์เรย์อื่น (อาร์เรย์ 1) จากนั้นในการทำซ้ำครั้งต่อไปคุณเข้าถึงอีกอาร์เรย์หนึ่งและอื่น ๆ ... เนื่องจากเมทริกซ์ทั้งหมดmatice2ไม่เหมาะกับแคชสูงสุด (มันมี8*1024*1024ขนาดใหญ่เป็นไบต์) โปรแกรมจะต้องดึงองค์ประกอบที่ต้องการจากหน่วยความจำหลักเสียมาก เวลา.

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

timer.start();
float temp = 0;
//transpose matice2
for (int p = 0; p < rozmer; p++)
{
    for (int q = 0; q < rozmer; q++)
    {
        tempmat[p][q] = matice2[q][p];
    }
}
for(int j = 0; j < rozmer; j++)
{
    for (int k = 0; k < rozmer; k++)
    {
        temp = 0;
        for (int m = 0; m < rozmer; m++)
        {
            temp = temp + matice1[j][m] * tempmat[k][m];
        }
        matice3[j][k] = temp;
    }
}
timer.stop();

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

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


2
ฉันเพิ่งดูวิดีโอ Scott Meyers เกี่ยวกับความสำคัญของขนาดแคชและการปรับข้อมูลให้เหมาะกับขนาดแคชของบรรทัดและปัญหาที่คุณสามารถมีได้กับโซลูชันแบบมัลติเธรดที่ไม่มีข้อมูลที่ใช้ร่วมกันในแหล่งข้อมูล แต่จบลงด้วยข้อมูลที่ใช้ร่วมกันที่ฮาร์ดแวร์ / ระดับคอร์ - เธรด: youtu.be/WDIkqP4JbkE
WillC

40

นี่คือเหตุผลที่ MATLAB ไม่ทำการคูณเมทริกซ์ที่ไร้เดียงสาโดยการวนซ้ำทุกองค์ประกอบเดียวกับที่คุณทำในรหัส C ++ ของคุณ

แน่นอนฉันสมมติว่าคุณเพิ่งใช้C=A*Bแทนที่จะเขียนฟังก์ชันการคูณด้วยตัวคุณเอง


19

Matlab ได้รวม LAPACK ไว้ก่อนแล้วดังนั้นฉันคิดว่าการคูณเมทริกซ์ของพวกเขาจะใช้บางอย่างที่รวดเร็ว LAPACK ซอร์สโค้ดและเอกสารพร้อมใช้งาน

คุณอาจดูกระดาษ "กายวิภาคของการคูณเมทริกซ์ประสิทธิภาพสูง" ของ Goto และ Van De Geijn ที่http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.1.140.1785&rep=rep1&type=pdf


7
MATLAB ใช้ไลบรารี Intel MKL ซึ่งให้การใช้งานตามปกติของ BLAS / LAPACK เป็นอย่างดี: stackoverflow.com/a/16723946/97160
Amro

11

คำตอบคือห้องสมุดLAPACKและBLASทำให้ MATLAB รวดเร็วในการดำเนินการของเมทริกซ์ซึ่งไม่ใช่รหัสที่เป็นกรรมสิทธิ์ของคนที่ MATLAB

ใช้ไลบรารี LAPACKและ / หรือBLASในรหัส C ++ ของคุณสำหรับการดำเนินการกับเมทริกซ์และคุณควรได้รับประสิทธิภาพที่ใกล้เคียงกับ MATLAB ห้องสมุดเหล่านี้ควรมีอิสระในระบบที่ทันสมัยและชิ้นส่วนได้รับการพัฒนามานานหลายทศวรรษในสถาบันการศึกษา ทราบว่ามีการใช้งานต่างๆรวมถึงแหล่งที่มาปิดบางอย่างเช่นIntel MKL

การสนทนาเกี่ยวกับวิธีที่ BLAS ให้ประสิทธิภาพสูงมีให้ที่นี่


BTW มันเป็นความเจ็บปวดที่ร้ายแรงในประสบการณ์ของฉันที่จะเรียกห้องสมุด LAPACK โดยตรงจาก c (แต่คุ้มค่า) คุณต้องอ่านเอกสารอย่างละเอียดมาก


8

O(n^3)เมื่อทำคูณเมทริกซ์คุณใช้วิธีการคูณไร้เดียงสาซึ่งต้องใช้เวลาในการ

O(n^2.4)มีขั้นตอนวิธีการคูณเมทริกซ์ซึ่งจะใช้เวลาที่มีอยู่ ซึ่งหมายความว่าในn=2000อัลกอริธึมของคุณต้องการการคำนวณมากกว่าอัลกอริธึมที่ดีที่สุดประมาณ 100 เท่า
คุณควรตรวจสอบหน้าวิกิพีเดียสำหรับการคูณเมทริกซ์เพื่อหาข้อมูลเพิ่มเติมเกี่ยวกับวิธีที่มีประสิทธิภาพในการปรับใช้


และ MATLAB อาจใช้อัลกอริทึมดังกล่าวเนื่องจากเวลาสำหรับ 1024 * 1024 matrix คูณกันนั้นเล็กกว่า 8 เท่าของเวลาสำหรับการคูณเมทริกซ์ 2048 * 2048! ทำได้ดีมากพวก MATLAB
Renaud

4
ฉันค่อนข้างสงสัยว่าพวกเขาใช้อัลกอริธึมการคูณ "มีประสิทธิภาพ" แม้จะมีข้อได้เปรียบทางทฤษฎี แม้แต่อัลกอริทึมของ Strassen ก็ยังมีปัญหาในการใช้งานและอัลกอริทึมของ Coppersmith – Winograd ที่คุณอาจอ่านได้เพียงแค่เรื่องธรรมดานั้นยังไม่สามารถนำไปใช้ได้จริง (ตอนนี้) นอกจากนี้เธรด SO ที่เกี่ยวข้อง: stackoverflow.com/questions/17716565/…
Ernir

อัลกอริทึมนั้นมีไว้สำหรับเมทริกซ์ที่มีขนาดใหญ่มากเท่านั้น

@Renaud นั่นคือคำจำกัดความของค่าใช้จ่ายที่ค่อนข้างคงที่
นักฟิสิกส์บ้า

6

ฉันเชื่อว่าอาจใช้ GPU ของคุณอยู่แล้วทั้งนี้ขึ้นอยู่กับเวอร์ชัน Matlab ของคุณ

อีกสิ่งหนึ่งที่; Matlab ติดตามคุณสมบัติมากมายของเมทริกซ์ของคุณ ไม่ว่าจะเป็นแนวเส้นทแยงมุมเฮอร์เมียนและอื่น ๆ และมีความเชี่ยวชาญด้านอัลกอริธึมของมัน บางทีมันมีความเชี่ยวชาญโดยอาศัยเมทริกซ์ศูนย์ที่คุณผ่านไปหรืออย่างนั้น บางทีมันอาจจะเป็นการแคชฟังก์ชั่นการโทรซ้ำซึ่งทำให้การจับเวลาของคุณยุ่งเหยิง? บางทีมันอาจทำให้ผลิตภัณฑ์เมทริกซ์ที่ไม่ได้ใช้ซ้ำได้อย่างเหมาะสมหรือไม่

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


4
ในฐานะผู้ใช้ ML ที่หนักหน่วงฉันสามารถบอกได้ว่าพวกเขายังไม่ได้ใช้ GPGPU matlab เวอร์ชันใหม่ใช้ SSE1 / 2 (ในที่สุด) แต่ฉันได้ทำการทดสอบ MexFunction ปฏิบัติเป็นองค์ประกอบที่ชาญฉลาดคูณวิ่งเร็วเป็นสองเท่าA.*Bไม่ ดังนั้น OP จึงเกือบจะทำอะไรบางอย่างผิดไป
KitsuneYMG

6
Matlab พร้อมกล่องเครื่องมือการคำนวณแบบขนานสามารถใช้ CUDA GPU แต่มันชัดเจน - คุณต้องส่งข้อมูลไปยัง GPU
Edric

ฉันใช้ M1 = single (แรนด์ (1024,1024) * 255); M2 = เดี่ยว (แรนด์ (1024,1024) * 255); และ M3 = M1 * M2; ... จากนั้นเขียนไปยังไฟล์ไบนารีของการลอยตัวมันทำเสร็จเร็วมาก
Wolf

3

MATLAB ใช้การดำเนินการเพิ่มประสิทธิภาพสูงของ LAPACK จากอินเทลที่รู้จักกันเป็นIntel Math Kernel Library (Intel MKL) - โดยเฉพาะฟังก์ชั่น dgemm ความเร็วห้องสมุดนี้ใช้ประโยชน์จากคุณสมบัติโปรเซสเซอร์รวมถึงคำแนะนำ SIMD และโปรเซสเซอร์มัลติคอร์ พวกเขาไม่ได้จัดทำเอกสารอัลกอริทึมเฉพาะที่พวกเขาใช้ ถ้าคุณต้องโทรหา Intel MKL จาก C ++ คุณควรเห็นประสิทธิภาพที่คล้ายกัน

ผมไม่แน่ใจว่าสิ่งที่ห้องสมุดใช้ MATLAB สำหรับการคูณ GPU แต่อาจบางอย่างเช่นnVidia CUBLAS


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

ขออภัยฉันหมายถึง MKL ไม่ใช่ IPP
gregswiss

คุณพูดถูกอีกคำตอบก็คือ มันละเอียดมากจนฉันพลาดมันไป
gregswiss

2

คำตอบทั่วไปของ "ทำไม matlab เร็วกว่าในการทำ xxx มากกว่าโปรแกรมอื่น ๆ " คือ MATLAB มีฟังก์ชั่นที่ปรับแต่งมามากมายในตัว

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

สามารถตีความได้สองวิธี:

1) วิธีการทั่วไป / ทางทฤษฎี: Matlab ไม่ได้เร็วขึ้นอย่างมีนัยสำคัญคุณเพียงแค่ทำผิดมาตรฐาน

2) วิธีที่เป็นจริง: สำหรับสิ่งนี้ Matlab นั้นเร็วกว่าในทางปฏิบัติเพราะภาษา c ++ นั้นใช้ง่ายเกินไปในวิธีที่ไม่มีประสิทธิภาพ


7
เขาเปรียบเทียบความเร็ว MATLAB กับความเร็วของฟังก์ชั่นที่เขาเขียนในสองนาที ฉันสามารถเขียนฟังก์ชั่นที่เร็วขึ้นใน 10 นาทีหรือฟังก์ชั่นที่เร็วขึ้นในสองชั่วโมง พวก MATLAB ใช้เวลามากกว่าสองชั่วโมงในการทำให้การคูณเมทริกซ์ของพวกเขารวดเร็ว
gnasher729

2

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

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

#include <vector>

struct matrix {
    matrix(int x, int y) : n_row(x), n_col(y), M(x * y) {}
    int n_row;
    int n_col;
    std::vector<double> M;
    double &operator()(int i, int j);
};

และ

double &matrix::operator()(int i, int j) {
    return M[n_col * i + j];
}

ควรใช้อัลกอริธึมการคูณเดียวกันเพื่อให้จำนวนฟล็อพเหมือนกัน (n ^ 3 สำหรับเมทริกซ์จตุรัสขนาด n)

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


2

มันช้าใน C ++ เพราะคุณไม่ได้ใช้มัลติเธรด โดยพื้นฐานแล้วถ้า A = BC ซึ่งเป็นเมทริกซ์ทั้งหมดแถวแรกของ A สามารถคำนวณได้อย่างอิสระจากแถวที่ 2 เป็นต้นหาก A, B และ C เป็นเมทริกซ์ n ทั้งหมดโดย n คุณสามารถเร่งการคูณได้โดย ปัจจัยของ n ^ 2 เช่น

a_ {i, j} = sum_ {k} b_ {i, k} c_ {k, j}

หากคุณใช้พูดว่า Eigen [ http://eigen.tuxfamily.org/dox/GettingStarted.html ] การทำมัลติเธรดก็มีอยู่แล้วภายในและจำนวนเธรดสามารถปรับได้


2

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

และถ้าเราดูผลลัพธ์การคำนวณของคุณ:

             1024x1024   2048x2048   4096x4096
             ---------   ---------   ---------
CUDA C (ms)      43.11      391.05     3407.99
C++ (ms)       6137.10    64369.29   551390.93
C# (ms)       10509.00   300684.00  2527250.00
Java (ms)      9149.90    92562.28   838357.94
MATLAB (ms)      75.01      423.10     3133.90

จากนั้นเราจะเห็นได้ว่าไม่เพียง แต่ MATLAB จะรวดเร็วในการคูณเมทริกซ์: CUDA C (ภาษาการเขียนโปรแกรมจาก NVIDIA) มีผลลัพธ์ที่ดีกว่า MATLAB CUDA C มีห้องสมุดที่พัฒนาขึ้นเป็นพิเศษสำหรับการคูณเมทริกซ์และใช้ GPU

ประวัติย่อของ MATLAB

Cleve Moler ประธานแผนกวิทยาศาสตร์คอมพิวเตอร์ของ University of New Mexico เริ่มพัฒนา MATLAB ในปลายปี 1970 เขาออกแบบมันเพื่อให้นักเรียนของเขาเข้าถึงLINPACK (ห้องสมุดซอฟต์แวร์สำหรับการแสดงพีชคณิตเชิงเส้นเชิงตัวเลข) และEISPACK(เป็นห้องสมุดซอฟต์แวร์สำหรับการคำนวณเชิงตัวเลขของพีชคณิตเชิงเส้น) โดยที่พวกเขาไม่ต้องเรียนรู้ Fortran ในไม่ช้ามันก็แพร่กระจายไปยังมหาวิทยาลัยอื่น ๆ และพบว่ามีผู้ชมที่แข็งแกร่งภายในชุมชนคณิตศาสตร์ประยุกต์ Jack Little วิศวกรเปิดเผยระหว่างการเยี่ยมชม Moler ที่ทำกับ Stanford University ในปี 1983 โดยตระหนักถึงศักยภาพเชิงพาณิชย์ของเขาเขาได้เข้าร่วมกับ Moler และ Steve Bangert พวกเขาเขียน MATLAB ใน C และก่อตั้ง MathWorks ในปี 1984 เพื่อดำเนินการพัฒนาต่อไป ไลบรารีที่เขียนใหม่เหล่านี้รู้จักกันในชื่อ JACKPAC ในปี 2000 MATLAB ถูกเขียนใหม่เพื่อใช้ไลบรารีชุดใหม่สำหรับการจัดการเมทริกซ์ LAPACK (เป็นไลบรารีซอฟต์แวร์มาตรฐานสำหรับพีชคณิตเชิงเส้นเชิงตัวเลข)

แหล่ง

CUDA C คืออะไร

CUDA C ใช้ไลบรารีที่พัฒนาโดยเฉพาะสำหรับการคูณเมทริกซ์เช่นOpenGL (Open Graphics Library) มันยังใช้ GPU และ Direct3D (บน MS Windows)

แพลตฟอร์ม CUDAถูกออกแบบมาเพื่อทำงานร่วมกับการเขียนโปรแกรมภาษาเช่น C, C ++ และ Fortran การเข้าถึงได้ง่ายขึ้นสำหรับผู้เชี่ยวชาญในการเขียนโปรแกรมแบบขนานเพื่อใช้ทรัพยากร GPU ในทางตรงกันข้ามกับ API ก่อนหน้าเช่นDirect3DและOpenGLซึ่งต้องการทักษะขั้นสูงในการเขียนโปรแกรมกราฟิก นอกจากนี้ CUDA สนับสนุนกรอบการเขียนโปรแกรมเช่นOpenACCและOpenCL

ป้อนคำอธิบายรูปภาพที่นี่

ตัวอย่างของกระบวนการประมวลผล CUDA:

  1. คัดลอกข้อมูลจากหน่วยความจำหลักไปยังหน่วยความจำ GPU
  2. CPU เริ่มต้นเคอร์เนลการคำนวณ GPU
  3. แกนประมวลผล CUDA ของ GPU รันเคอร์เนลแบบขนาน
  4. คัดลอกข้อมูลที่ได้จากหน่วยความจำ GPU ไปยังหน่วยความจำหลัก

เปรียบเทียบ CPU และ GPU Execution Speeds

เราใช้มาตรฐานในการวัดระยะเวลาในการดำเนินการ 50 ขั้นตอนสำหรับขนาดกริด 64, 128, 512, 1024 และ 2048 สำหรับ Intel Xeon Processor X5650 และใช้ NVIDIA Tesla C2050 GPU

ป้อนคำอธิบายรูปภาพที่นี่

สำหรับขนาดกริดของ 2048 อัลกอริทึมจะแสดงเวลาการคำนวณลดลง 7.5 เท่าจากมากกว่าหนึ่งนาทีบน CPU ไปจนถึงน้อยกว่า 10 วินาทีบน GPU พล็อตมาตราส่วนบันทึกแสดงให้เห็นว่า CPU เร็วขึ้นจริงสำหรับขนาดกริดขนาดเล็ก ในขณะที่เทคโนโลยีวิวัฒนาการและพัฒนาไปเรื่อย ๆ โซลูชั่น GPU จะสามารถรับมือกับปัญหาที่เล็กลงได้มากขึ้นซึ่งเป็นแนวโน้มที่เราคาดว่าจะดำเนินต่อไป

แหล่ง

จากการแนะนำสำหรับคู่มือการเขียนโปรแกรม CUDA C:

ขับเคลื่อนโดยความต้องการของตลาดไม่เพียงพอสำหรับเรียลไทม์ความละเอียดสูงกราฟิก 3D ที่สามารถตั้งโปรแกรมกราฟิกหน่วยประมวลผลหรือ GPU มีการพัฒนาเป็นขนานสูงแบบมัลติเธรดโปรเซสเซอร์ manycore กับแรงม้าคำนวณอย่างมากและแบนด์วิดธ์หน่วยความจำสูงมากดังที่แสดงด้วยและFigure 1Figure 2

รูปที่ 1. การใช้จุดลอยตัวต่อวินาทีสำหรับ CPU และ GPU

ป้อนคำอธิบายรูปภาพที่นี่

รูปที่ 2 Memory Bandwidth สำหรับ CPU และ GPU

ป้อนคำอธิบายรูปภาพที่นี่

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

รูปที่ 3 GPU ใช้ทรานซิสเตอร์มากในการประมวลผลข้อมูล

ป้อนคำอธิบายรูปภาพที่นี่

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

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

แหล่ง

การอ่านขั้นสูง


บางสิ่งที่น่าสนใจ

ฉันได้เขียนการคูณเมทริกซ์ C ++ ที่เร็วเท่ากับ Matlab แต่ก็ต้องใส่ใจบ้าง (ก่อน Matlab ใช้ GPU สำหรับสิ่งนี้)

Сitationจากคำตอบนี้


2
คำพูดสุดท้ายนั้นไม่ใช่“ ความจริง” มันเป็นการโอ้อวดเปล่า ๆ บุคคลนั้นได้รับคำขอหลายรหัสตั้งแต่เขาโพสต์สิ่งนั้น แต่ไม่มีรหัสในสายตา
Cris Luengo

1
คำอธิบายของคุณว่าคุณสามารถคำนวณด้วย GPU ได้รวดเร็วแค่ไหนไม่ได้ตอบคำถามทั้งหมด เราทุกคนรู้ว่ามี 128 คอร์เล็ก ๆ สามารถทำงานแบบเดียวกันซ้ำซากจำเจได้มากกว่า 2 คอร์ใหญ่ “ และตอนนี้ MATLAB ยังสามารถใช้ GPU (หน่วยประมวลผลกราฟิก) สำหรับสิ่งนี้เพิ่มเติมได้” ใช่ แต่ไม่ใช่โดยค่าเริ่มต้น การคูณเมทริกซ์ปกติยังคงใช้ BLAS
Cris Luengo

@ ChrisLuengo โอเคมันไม่ใช่ความจริง! บางทีคุณอาจมีสิทธิ์ในการ "โอ้อวด" ของเขา - เราไม่รู้เกี่ยวกับมันและเราก็ไม่รู้ด้วยว่าทำไมเขาถึงไม่ตอบ สำหรับความคิดเห็นที่สอง: คำอธิบายของการคำนวณบน GPU ตอบคำถามเพราะสำหรับการคูณเมทริกซ์ในพีชคณิตเชิงเส้นจะใช้การดำเนินการจุดลอย บางทีมันอาจไม่ใช่สำหรับ peole ที่เข้าใจได้ทั้งหมด แต่ฉันคิดว่าพวกเขาต้องเข้าใจพื้นฐานนี้ ในกรณีอื่นพวกเขาต้องเรียนรู้พื้นฐานนี้ในตอนแรกก่อนที่จะอ่านบทความเกี่ยวกับเมทริกซ์ และถ้ามีคนอื่นเขียนถึงฉันฉันจะเพิ่มรายละเอียดนี้ ขอบคุณ!
Bharata

@CrisLuengo "additionally"ผมเขียนคำว่า มันหมายถึง: มันสามารถใช้ นอกจากนี้ยังหมายความว่าการคูณเมทริกซ์ปกติยังคงใช้ไลบรารีซอฟต์แวร์ คุณคิดว่าฉันต้องเปลี่ยนโพสต์ของฉันให้เข้าใจได้มากกว่านี้ไหม? ขอบคุณสำหรับความคิดเห็นของคุณ!
Bharata
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.