LLM ต่อหน้า NPU ของ Ascend ทำไมถึง “พูดไม่ออก”? AscendCraft ใช้ DSL สร้างสะพานเชื่อม ทำให้อัตราความสำเร็จในการสร้างเคอร์เนลพุ่งสูงถึง 98.1% (1/4)
ในวงการชิป AI การเขียนเคอร์เนลโอเปอเรเตอร์ที่มีประสิทธิภาพสูงนั้นเปรียบเสมือนการเต้นรำอย่างแม่นยำบนเครื่องจักรที่ละเอียดอ่อน ซับซ้อน และมีเอกสารคู่มือน้อยมาก แม้ว่าโมเดลภาษาขนาดใหญ่ (LLM) จะแสดงผลได้ค่อนข้างดีในการสร้างโค้ด CUDA ซึ่งเป็นผลมาจากระบบนิเวศขนาดใหญ่ที่ NVIDIA สร้างมาอย่างยาวนาน: โค้ดโอเพนซอร์สจำนวนมหาศาล เอกสารที่ละเอียดครบถ้วน และชุมชนที่เติบโตเต็มที่ อย่างไรก็ตาม เมื่อเป้าหมายเปลี่ยนไปเป็นหน่วยประมวลผลประสาทเทียม (NPU) อย่าง Huawei Ascend สถานการณ์ก็เปลี่ยนไปอย่างสิ้นเชิง การวิจัยล่าสุดแสดงให้เห็นว่า แม้แต่ LLM ที่ทันสมัยที่สุด อัตราความถูกต้องในการสร้างเคอร์เนล AscendC ที่ใช้งานได้โดยตรงก็ต่ำกว่า 5%
ทำไมจึงมีช่องว่างที่ใหญ่โตเช่นนี้? เพราะว่าโมเดลการเขียนโปรแกรมของ NPU นั้นเป็นแบบ “เกาะโดดเดี่ยว” พวกมันเป็นแบบเฉพาะโดเมน มีข้อจำกัดด้านฮาร์ดแวร์ที่เข้มงวด (เช่น การจัดตำแหน่งหน่วยความจำ กลไกซิงโครไนซ์ที่ซับซ้อน) API ที่ไม่เป็นกระแสหลัก และตัวอย่างสาธารณะที่หายาก สำหรับ LLM ที่เรียนรู้ผ่านการ “กลืน” คอร์ปัสสาธารณะเป็นหลัก สิ่งนี้ก็ไม่ต่างจากการขอให้มันเขียนวิทยานิพนธ์ระดับดุษฎีบัณฑิตด้วยภาษาที่แทบไม่เคยเรียนมาก่อน

เมื่อเผชิญกับภาวะลำบากนี้ ทีมวิจัยร่วมจากมหาวิทยาลัยหนานจิงและหัวเหว่ยได้เสนอทางออกใหม่นั่นคือ AscendCraft แกนความคิดหลักของพวกเขาไม่ใช่การพยายามทำให้ LLM “ฉลาดขึ้น” แต่เป็นการสร้างสะพานให้กับมัน สะพานนั้นก็คือ ภาษาเฉพาะโดเมน (DSL) ที่ออกแบบมาอย่างดี

ด้วยการแยกตรรกะอัลกอริทึมหลักออกจากความซับซ้อนของฮาร์ดแวร์ พวกเขาสามารถเพิ่มอัตราความสำเร็จในการคอมไพล์เคอร์เนลที่สร้างขึ้นเป็น 98.1% โดยมีอัตราความถูกต้องเชิงฟังก์ชันสูงถึง 90.4% และทำให้เกือบครึ่งหนึ่งของเคอร์เนลที่สร้างขึ้นมีประสิทธิภาพเหนือกว่า PyTorch นี่ไม่เพียงแต่เป็นการก้าวข้ามในการสร้างโค้ดเท่านั้น แต่ยังเป็นการสำรวจเชิงลึกถึงความสามารถของโมเดลขนาดใหญ่ในการทำความเข้าใจนามธรรมของฮาร์ดแวร์อีกด้วย
บทความนี้จะตีความบทความวิจัย AscendCraft เพื่อสำรวจว่า มันใช้ DSL ในการชี้นำและการลดระดับอย่างมีโครงสร้างอย่างไร เพื่อให้ LLM สามารถสร้างเคอร์เนลโอเปอเรเตอร์ที่ทั้งถูกต้องและมีประสิทธิภาพในดินแดน NPU ที่ไม่คุ้นเคยได้สำเร็จ
สารบัญ
- 1. ภาวะลำบาก: ทำไม LLM ถึงเขียนเคอร์เนล NPU ไม่ได้ดี?
- 1.1 “ความต่างกัน” ของสถาปัตยกรรมฮาร์ดแวร์
- 1.2 “ความซับซ้อน” ของโมเดลการเขียนโปรแกรม
- 2. การแก้ไขปัญหา: แนวคิดการออกแบบและวิธีการหลักของ AscendCraft
- 2.1 ระยะที่ 1: การสร้าง DSL – การสร้าง “โลกเลโก้” ให้กับ LLM
- 2.2 ระยะที่ 2: การคอมไพล์แบบลดระดับ – การ “แปล” แบบมีโครงสร้างจาก DSL ไปยัง AscendC
- 3. การทดสอบยืนยัน: จาก “ความสิ้นหวัง 5%” สู่ “ความประหลาดใจ 90%”
- 3.1 RQ1: ความถูกต้อง – จาก “แทบใช้ไม่ได้” สู่ “เชื่อถือได้ในระดับพื้นฐาน”
- 3.2 RQ2: ประสิทธิภาพ – ไม่ใช่แค่ “ใช้ได้” แต่ยัง “ใช้ดี” อีกด้วย
- 3.3 RQ3: ความสามารถในการปรับใช้ทั่วไป – การรับมือกับความท้าทาย “ที่ไม่รู้จัก”
- 4. งานที่เกี่ยวข้อง: ยืนบนบ่าของยักษ์
- 5. อนาคตและบทสรุป
1. ภาวะลำบาก: ทำไม LLM ถึงเขียนเคอร์เนล NPU ไม่ได้ดี?
เพื่อเข้าใจคุณค่าของ AscendCraft ก่อนอื่นต้องเข้าใจความท้าทายที่มันเผชิญอย่างลึกซึ้ง การให้ LLM สร้างเคอร์เนล NPU โดยตรง ก็เหมือนกับการขอให้เด็กฝึกงานที่ไม่เคยเห็นเครื่องยนต์รถยนต์มาก่อนมาซ่อมมัน ในขณะที่เขามีแค่ตำราเรียนระดับมหาวิทยาลัยเกี่ยวกับหลักการของเครื่องยนต์สันดาปภายในเท่านั้น
1.1 “ความต่างกัน” ของสถาปัตยกรรมฮาร์ดแวร์
ต่างจาก GPU ทั่วไป NPU ถูกสร้างขึ้นสำหรับโหมดการคำนวณเฉพาะ ตัวอย่างเช่น NPU Huawei Ascend หน่วยประมวลผลหลักแบ่งออกเป็นสามประเภท:
- หน่วยสเกลาร์ (Scalar Unit): ประมวลผลโฟลว์ควบคุมและข้อมูลสเกลาร์
- หน่วยเวกเตอร์ (Vector Unit): ดำเนินการดำเนินการ SIMD (คำสั่งเดียว ข้อมูลหลายชุด) เช่น การบวกระดับองค์ประกอบและฟังก์ชันกระตุ้น
- หน่วยคิวบ์ (Cube Unit): นี่คือ “อาวุธลับ” ของ NPU ออกแบบมาเฉพาะสำหรับการคำนวณการคูณและบวกเมทริกซ์ สามารถทำการคูณเมทริกซ์ขนาด MxK กับ KxN ให้เสร็จในหนึ่งรอบคำสั่ง
นอกจากนี้ โครงสร้างลำดับชั้นของหน่วยความจำยังซับซ้อนมากอีกด้วย รวมถึงหน่วยความจำส่วนกลาง (GM) บัฟเฟอร์ L1 บัฟเฟอร์รวม (UB) และบัฟเฟอร์ L0 นักพัฒนาต้องควบคุมการเคลื่อนย้ายข้อมูลระหว่างระดับเหล่านี้อย่างชัดเจน

1.2 “ความซับซ้อน” ของโมเดลการเขียนโปรแกรม
AscendC โมเดลการเขียนโปรแกรมที่ออกแบบมาสำหรับ NPU Ascend นี้ สร้างขึ้นบนพื้นฐานของความซับซ้อนของฮาร์ดแวร์ดังกล่าว มันเป็นโมเดลการเขียนโปรแกรมแบบไปป์ไลน์ที่ใช้ C++ เป็นพื้นฐาน
- ไปป์ไลน์แบบชัดเจน: การดำเนินการเคอร์เนลถูกแบ่งออกเป็นสามระยะอย่างชัดเจน ได้แก่
CopyIn(ย้ายข้อมูลเข้า)Compute(คำนวณ) และCopyOut(ย้ายข้อมูลออก) นักพัฒนาต้องจัดการการซ้อนทับและซิงโครไนซ์ของระยะเหล่านี้ด้วยตนเอง เพื่อเพิ่มประสิทธิภาพการใช้ฮาร์ดแวร์ให้สูงสุด - การจัดการหน่วยความจำ: การแยกแยะระหว่าง
GlobalTensor(เทนเซอร์ส่วนกลาง) กับLocalTensor(เทนเซอร์ท้องถิ่น) รวมถึงข้อจำกัดฮาร์ดแวร์เช่นการจัดตำแหน่งหน่วยความจำ ขนาดการเข้าถึงขั้นต่ำ ฯลฯ กำหนดให้นักพัฒนาต้องจัดการเลย์เอาต์หน่วยความจำอย่างแม่นยำ - คิวและการพึ่งพา: เพื่อประสานการทำงานระหว่างหน่วยคำนวณต่างๆ กับเครื่องยนต์ถ่ายโอนหน่วยความจำ (MTE) Ascend C ได้นำกลไกคิว (Queue) มาใช้ เมื่อข้อมูลไหลระหว่างหน่วยต่างๆ ต้องใช้การดำเนินการ “เข้าคิว/ออกคิว” เพื่อจัดการความสัมพันธ์การพึ่งพาอย่างชัดเจน
สำหรับโมเดลภาษาขนาดใหญ่ (LLM) การขอให้มันสร้างโค้ดที่ตรงตามข้อจำกัดความหมายที่ซับซ้อนดังกล่าวทั้งหมดในครั้งเดียว เป็นความท้าทายอย่างยิ่ง ข้อผิดพลาดเล็กน้อยใดๆ เช่น ที่อยู่หน่วยความจำไม่จัดตำแหน่งหรือลำดับคิวสับสน อาจทำให้การคอมไพล์ล้มเหลวหรือเกิดข้อผิดพลาดขณะรันได้ นี่คือสาเหตุหลักที่ทำให้อัตราความสำเร็จของวิธีการสร้างโดยตรงต่ำมาก
2. การแก้ไขปัญหา: แนวคิดการออกแบบและวิธีการหลักของ AscendCraft
เมื่อเผชิญกับ “สามเหลี่ยมที่เป็นไปไม่ได้” (ความซับซ้อน ข้อจำกัด ความหายาก) ของการสร้างโดยตรง AscendCraft ใช้กลยุทธ์แบ่งแยกและปกครอง: นามธรรมมาก่อน การคอมไพล์แบบลดระดับ แกนความคิดหลักคือให้ LLM ทำการอธิบายตรรกะที่มันถนัดในระดับนามธรรม และปล่อยให้การนำไปปฏิบัติจริง ดำเนินการโดยกระบวนการลดระดับที่มีโครงสร้างและควบคุมได้
กระบวนการทั้งหมดแบ่งออกเป็นสองระยะหลัก ดังแสดงในรูปที่ 3:

รูปที่ 3: แผนภาพเฟรมเวิร์ก AscendCraft แสดงกระบวนการสร้างเคอร์เนล Ascend C แบบสองระยะโดยสมบูรณ์ของ AscendCraft ระยะที่ 1 LLM สร้างภาษาเฉพาะโดเมน (DSL) ตามตัวอย่างเฉพาะหมวดหมู่ โดยมุ่งเน้นที่การคำนวณหลักและกลยุทธ์การแบ่งบล็อก ระยะที่ 2 ผ่านการแปลลดระดับหลายรอบที่ชี้นำโดย LLM ค่อยๆ แปลง DSL เป็นโค้ด Ascend C และรวมการแก้ไขตามผลตอบรับการคอมไพล์ เฟรมเวิร์กนี้มีเป้าหมายเพื่อแก้ไขปัญหาอัตราความถูกต้องต่ำจากการสร้างโดยตรง โดยการแยกส่วนอย่างมีโครงสร้างและการจำกัดพื้นที่การสร้างด้วย DSL นามธรรม ทำให้อัตราความสำเร็จเพิ่มขึ้นอย่างมีนัยสำคัญ
2.1 ระยะที่ 1: การสร้าง DSL – การสร้างอินเทอร์เฟซนามธรรมให้กับ LLM
หนึ่งในนวัตกรรมหลักของ AscendCraft คือการนำภาษาเฉพาะโดเมน (DSL) ขนาดเล็กและเบามาใช้ DSL นี้ถูกออกแบบให้เป็น “บัฟเฟอร์” ระหว่าง LLM กับรายละเอียดฮาร์ดแวร์ที่ซับซ้อน โดยยึดหลักการออกแบบดังต่อไปนี้:
- ไวยากรณ์ที่มีโครงสร้างกระชับ: ไวยากรณ์ DSL กระชับ กำจัดรายละเอียดที่ยุ่งยากของ C++ ออกไป ทำให้ LLM สามารถมุ่งความสนใจไปที่ตรรกะอัลกอริทึม (เช่น กลยุทธ์การแบ่งบล็อกและโฟลว์ข้อมูล)
- นามธรรมในระดับที่เหมาะสม: DSL จงใจซ่อนรายละเอียดระดับล่างที่ยุ่งยากแต่ไม่ใช่แกนหลักใน Ascend C (เช่น การกำหนดค่าที่ซับซ้อนสำหรับการจัดการการเข้าถึงหน่วยความจำที่ไม่จัดตำแหน่ง) และให้ไพรมิทีฟการดำเนินการที่กระชับกว่า
- การสร้างแบบจำลองความหมายของฮาร์ดแวร์: DSL สร้างแบบจำลองความหมายการดำเนินการหลักของฮาร์ดแวร์ Ascend อย่างชัดเจน เช่น การจัดสรรบัฟเฟอร์บนชิปผ่านคำสั่งเฉพาะ และการแบ่งระยะไปป์ไลน์ผ่านการแบ่งบล็อกโค้ดที่ชัดเจน

รูปที่ 2: ตัวอย่างเคอร์เนล Softmax ที่เขียนด้วย DSL ของ Ascend ตัวอย่างนี้แสดงการแยกการวางแผนการดำเนินการฝั่งโฮสต์และการคำนวณเคอร์เนลฝั่งอุปกรณ์ รวมถึงโหมดการดำเนินการแบบแบ่งระยะของ CopyIn, Compute, CopyOut แสดงให้เห็นความสามารถของ DSL นี้ในการแสดงออกถึงตรรกะการคำนวณแบบแบ่งบล็อก การใช้บัฟเฟอร์บนชิป และโฟลว์ข้อมูลระหว่างเคอร์เนลได้อย่างมีประสิทธิภาพ ในขณะเดียวกันก็ซ่อนรายละเอียดระดับล่าง
ในระยะการสร้าง LLM จะได้รับข้อกำหนด DSL และตัวอย่างผู้เชี่ยวชาญสำหรับหมวดหมู่โอเปอเรเตอร์เฉพาะ (เช่น “การลด”) ซึ่งทำให้ LLM สามารถเรียนรู้รูปแบบการปรับแต่งขั้นสูงได้ โดยไม่ต้องจมอยู่กับรายละเอียด API ระดับล่างที่เฉพาะเจาะจง
2.2 ระยะที่ 2: การคอมไพล์แบบลดระดับ – การแปลงแบบมีโครงสร้างจาก DSL ไปยัง Ascend C
นี่คือกุญแจสำคัญในการนำ AscendCraft ไปปฏิบัติจริง เฟรมเวิร์กนี้ไม่ได้พยายามให้ LLM ทำการแปลงจาก DSL ไปเป็น Ascend C ให้เสร็จในครั้งเดียว แต่แยกกระบวนการนี้ออกเป็นสี่ระยะของการลดระดับที่มีลำดับและชี้นำโดย LLM แต่ละระยะมุ่งเน้นเฉพาะงานการแปลงเฉพาะอย่างหนึ่ง และมีเทมเพลตพรอมต์ที่ออกแบบมาอย่างดีประกอบ
สี่ระยะนี้มีดังนี้:
ระยะที่ 1: การสร้างโค้ดฝั่งโฮสต์
- งาน: แปลงฟังก์ชันฝั่งโฮสต์ใน DSL เป็นโค้ดโฮสต์ของ Ascend C รวมถึงการกำหนดโครงสร้างข้อมูล การคำนวณพารามิเตอร์การแบ่งบล็อก และการกำหนดค่าพารามิเตอร์การเรียกใช้เคอร์เนล
- สิ่งสำคัญ: ตรวจสอบให้แน่ใจว่าพารามิเตอร์ทั้งหมดที่คำนวณฝั่งโฮสต์สามารถส่งผ่านไปยังเคอร์เนลได้อย่างถูกต้อง
ระยะที่ 2: การสร้างโค้ดเริ่มต้นเคอร์เนล
- งาน: สร้างตรรกะการเริ่มต้นเคอร์เนล รวมถึงการกำหนดค่าพารามิเตอร์ การคำนวณออฟเซ็ตข้อมูลหลัก และการเริ่มต้นทรัพยากรหน่วยความจำบนชิป
- การแมปที่สำคัญ: แมปคำสั่งการจัดสรรบัฟเฟอร์ใน DSL เป็นคิวการถ่ายโอน (
TQue) หรือบัฟเฟอร์ชั่วคราว (TBuf) ใน Ascend C
ระยะที่ 3: การสร้างโค้ดคำนวณเคอร์เนล (แกนกลาง)
- งาน: แปลงบล็อกโค้ด
copyin,compute,copyoutในเคอร์เนล DSL เป็นฟังก์ชันที่สอดคล้องกันใน Ascend C - การแมปที่สำคัญ:
copyin: ย้ายข้อมูลจากหน่วยความจำส่วนกลางไปยังคิวบนชิปcompute: ดึงข้อมูลออกจากคิว และแมปไพรมิทีฟการคำนวณของ DSL เป็น API การดำเนินการเว
⚠️ หมายเหตุ: เนื้อหาได้รับการแปลโดย AI และตรวจสอบโดยมนุษย์ หากมีข้อผิดพลาดโปรดแจ้ง
☕ สนับสนุนค่ากาแฟทีมงาน
หากคุณชอบบทความนี้ สามารถสนับสนุนเราได้ผ่าน PromptPay
SCAN TO PAY WITH ANY BANK本文来自网络搜集,不代表คลื่นสร้างอนาคต立场,如有侵权,联系删除。转载请注明出处:http://www.itsolotime.com/th/archives/26914
