วิธีที่ดีที่สุดในการกำหนดจำนวนของศูนย์ที่ไม่ใช่ในการคูณเมทริกซ์เบาบางคืออะไร?


17

ฉันสงสัยว่ามีวิธีที่รวดเร็วและมีประสิทธิภาพในการค้นหาจำนวนศูนย์ที่ไม่ใช่ล่วงหน้าสำหรับการดำเนินการคูณเมทริกซ์กระจัดกระจายสมมติว่าเมทริกซ์ทั้งสองอยู่ในรูปแบบ CSC หรือ CSR

ฉันรู้ว่ามีหนึ่งในแพ็คเกจ smmp แต่ฉันต้องการสิ่งที่มีการใช้งานแล้วใน C หรือ C ++

ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชม. ขอบคุณล่วงหน้า.


เมทริกซ์ของคุณมีความสมมาตรหรือโครงสร้างไปยังตำแหน่งของรายการที่ไม่เป็นศูนย์หรือไม่?
Godric Seer

@GodricSeer ... ไม่ฉันเพียงแค่พูดถึงเมทริกซ์กระจัดกระจาย Matlab มี nnz (A) ที่ A เป็นวิธีเมทริกซ์กระจัดกระจายเพื่อหาจำนวนของศูนย์ที่ไม่ใช่ฉันสงสัยว่ามีวิธีการใด ๆ
Recker

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

นอกจากนี้ฉันยังพบกระดาษนี้ซึ่งอธิบายถึงวิธีการประมาณจำนวนในผลิตภัณฑ์เมทริกซ์บูลีน (ซึ่งเหมือนกับการนับองค์ประกอบในผลิตภัณฑ์เมทริกซ์ใด ๆ )
Godric Seer

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

คำตอบ:


14

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


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

มันเป็นความคิดที่ดี แต่ด้วยทรานซิสเตอร์หลายล้านตัวที่ทำแบบลอย * แบบขนานเราแค่พูดถึงการประหยัดความเร็ว 50% หรือราว ๆ นั้นที่นี่
Evgeni Sergeev

1
@EvgeniSergeev - ประเด็นไม่ใช่การประหยัดในการคำนวณ แต่เป็นการประหยัดในการโอนหน่วยความจำ เนื่องจากคุณใช้เวลา 80% หรือมากกว่าในวันนี้ในการถ่ายโอนหน่วยความจำสำหรับการคูณเมทริกซ์แบบกระจายคุณอาจได้รับอย่างมากหากคุณไม่ต้องอ่าน / เขียนข้อมูลทศนิยมจาก / สู่หน่วยความจำ
Wolfgang Bangerth

คุณจะระบุความซับซ้อนของวิธีการของคุณอย่างชัดเจน หากคือmคูณkดูเหมือนว่าวิธีการของคุณต้องใช้O ( m k )ทำงานใช่ไหม? ม.kO(ม.k)
Carl Christian

@CarlChristian - ฉันต้องคิดรายละเอียด แต่ก็ไม่สามารถเป็นได้ มันต้องเกี่ยวข้องกับจำนวนที่ไม่ใช่ศูนย์ต่อแถว ถ้าคุณมีค่าเฉลี่ยp ไม่ใช่ศูนย์ในแต่ละแถวและเพื่อความง่ายถ้าคุณมีm = kแล้วฉันคิดว่าคุณควรจะสามารถใช้วิธีการในสิ่งที่ต้องการO ( m p log p )หรือคล้ายกัน ดีกว่าO ( m 2 )มาก O(ม.k)พีม.=kO(ม.พีเข้าสู่ระบบพี)O(ม.2)
Wolfgang Bangerth

13

ฉันเขียนโค้ดดั้งเดิมใน Matlab สำหรับ A * B ทั้ง A และ B หร็อมแหร็ม การจัดสรรพื้นที่ล่วงหน้าสำหรับผลลัพธ์เป็นส่วนที่น่าสนใจ เราสังเกตสิ่งที่ Godric ชี้ให้เห็น - การรู้จำนวนที่ไม่ใช่ศูนย์ใน AB นั้นมีค่าใช้จ่ายเท่ากับการคำนวณ AB

เราได้เริ่มต้นใช้งาน Matlab ที่กระจัดกระจายรอบปี 1990 ก่อนหน้ากระดาษ Edith Cohen ที่ให้วิธีการปฏิบัติแรกและรวดเร็วในการประมาณขนาดของ AB อย่างถูกต้อง เรารวมตัวประมาณขนาดที่ด้อยกว่าเข้าด้วยกันและถ้าเราใช้พื้นที่ในการคำนวณกลางให้เพิ่มการจัดสรรและเพิ่มผลลัพธ์ที่คำนวณได้บางส่วนเป็นสองเท่า

ตอนนี้ฉันไม่รู้ว่ามีอะไรใน Matlab

ความเป็นไปได้อีกอย่างก็คือการคำนวณ AB ทีละคอลัมน์ แต่ละคอลัมน์สามารถเก็บไว้ชั่วคราวใน sparse accumulator (ดูกระดาษ Matlab สำหรับคำอธิบายเหล่านี้) และพื้นที่ที่จัดสรรเพื่อเก็บขนาดผลลัพท์ที่แน่นอนของคอลัมน์ผลลัพธ์ ผลลัพธ์จะอยู่ในรูปแบบคอลัมน์กระจัดกระจายที่ถูกบีบอัด - แต่ละคอลัมน์ใน CSC แต่ไม่มีความเกี่ยวข้องกันระหว่างคอลัมน์ - โดยใช้ 2 เวกเตอร์ของ numcols ความยาว (col start, col col), มากกว่าหนึ่งเป็น meta-data มันเป็นรูปแบบการจัดเก็บที่อาจจะคุ้มค่าดู; มันมีความแข็งแกร่งอื่น - คุณสามารถสร้างคอลัมน์ได้โดยไม่ต้องจัดสรรเมทริกซ์ใหม่ทั้งหมด


สำหรับการติดตั้ง GPU ของฉันฉันพบว่าโครงสร้างที่ไม่ใช่ศูนย์เป็นอันดับแรกจากนั้นหาเมทริกซ์ที่แท้จริงประสิทธิภาพที่ได้ตามที่คาดไว้ฉันคิดว่าพวกเขาใช้วิธีที่อธิบายไว้ในหนังสือเล่มนี้เพื่อเพิ่มเมทริกซ์สองตัวบน MATLAB
Recker

2
เย็นจริงๆขอบคุณสำหรับมุมมองทางประวัติศาสตร์และยินดีที่จะ scicomp :)
Aron Ahmadia

4

กระดาษนี้จะอธิบายอัลกอริทึมเพื่อประมาณขนาดของผลลัพธ์จากผลิตภัณฑ์เมทริกซ์ของเมทริกซ์กระจัดกระจายสองตัว

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

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


0

สำหรับ CSR หรือ CSC คุณรับประกันได้หรือไม่ว่าอาเรย์ขององค์ประกอบเมทริกซ์ของคุณไม่มีเลขศูนย์อยู่แล้ว? ในกรณีนี้มันง่ายที่จะเข้าใจว่ามีองค์ประกอบที่ไม่เป็นศูนย์จำนวนเท่าใดโดยใช้สิ่งที่คล้ายกับ:

int nnz = sizeof(My_Array)/sizeof(long int);

แต่ถ้ากรณีนี้ไม่ได้ (ที่ดูเหมือนว่าบิตง่ายเกินไป) สิ่งที่คุณอาจจะลองเป็นลดลง ถ้าอาร์เรย์เมทริกซ์ของคุณมีขนาดใหญ่มากนี่อาจเป็นวิธีที่มีประสิทธิภาพที่สุดในการคำนวณจำนวนองค์ประกอบที่ไม่ใช่ศูนย์ หลายขนาน C / C ++ ห้องสมุดเช่นแทง (ห้องสมุด CUDA) หรือ OpenCL (ซึ่งคุณไม่จำเป็นต้อง GPU ในการใช้งาน) มีการสนับสนุนการลดเงื่อนไข - Condition(Element)สำหรับแต่ละองค์ประกอบเพิ่มผลมาจากการ หากคุณตั้งเงื่อนไขให้Element != 0คุณจะเพิ่มจำนวนองค์ประกอบที่ไม่ใช่ศูนย์ คุณอาจต้องการลบองค์ประกอบที่มีค่าเป็นศูนย์ออกจากองค์ประกอบของคุณอาร์เรย์ของดัชนีแถว / คอลัมน์และปรับตัวชี้คอลัมน์ / แถวของคุณ


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

0

วิธีที่ง่ายที่สุดในการดำเนินการ CSR คือพยายาม

std::vector< std::map<int, complex<float>> > 

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

std::map< int, complex<float> >::iterator

ในแต่ละแถว ดีที่สุด ..


2
STL สำหรับเมื่อคุณคิดว่าการกระจัดกระจายเมทริกซ์ของคุณไม่สามารถทำให้ช้าลงได้
Jed Brown
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.