- รีแฟกเตอร์เคอร์เนล Attention ให้เป็นแบบ persistent เพื่อปรับปรุงประสิทธิภาพในช่วงที่มี context length ต่ำ
- ใน fp16 เมื่อ context ขนาดใหญ่ จะเกิดประสิทธิภาพตกจาก ปัญหาการจัดตารางคำสั่งของ ptxas ในส่วน softmax
- ใน fp8 พบว่าเมื่อมี "cutlass" อยู่ในชื่อเคอร์เนล จะได้ ประสิทธิภาพเพิ่มขึ้นราว 100 TFLOPS
- มีการวิเคราะห์ว่านี่คือ ทริกการเพิ่มประสิทธิภาพแบบฮาร์ดโค้ดผ่านการตั้งชื่อเคอร์เนล
- ผลต่อประสิทธิภาพและสาเหตุการทำงานเป็น พฤติกรรมเฉพาะจากการติดตั้งภายในของ NVIDIA ptxas
สรุป: การรีแฟกเตอร์ Persistent Attention kernel และผลของการตั้งชื่อว่า "cutlass"
ภาพรวม
- Pull Request นี้เป็นการรีแฟกเตอร์ attention kernel ของ Triton ให้เป็นแบบ persistent attention
- เป้าหมายหลักคือเพื่อให้ได้ การปรับประสิทธิภาพในช่วง context length ต่ำ
- อย่างไรก็ตาม ใน ชนิด fp16 เมื่อ context มีขนาดใหญ่ขึ้น จะเกิดอาการประสิทธิภาพลดลงจาก ปัญหาการจัดตารางคำสั่งของ ptxas ในส่วน softmax
ผลของการใช้ชื่อ "cutlass" ใน fp8
- เมื่อใช้โมเดล fp8 มีการวัดได้ว่า ถ้าใส่ "cutlass" ไว้ในชื่อเคอร์เนล ประสิทธิภาพจะเพิ่มขึ้นได้ถึงราว 100 TFLOPS
- เหตุผลคือ ptxas (PTX assembler) ของ NVIDIA ภายในมีการใช้ การเพิ่มประสิทธิภาพพิเศษ เมื่อชื่อเคอร์เนลมีคำว่า "cutlass"
- ในโค้ดจริง หาก dtype เป็น float8e5 จะกำหนดชื่อเคอร์เนลเป็น "cutlass_gluon_attention" เป็นต้น
- จากการวิเคราะห์ disassembly ของ ptxas พบว่าในโค้ดภายในมีเงื่อนไข
strstr(kernel_name, "cutlass") อยู่จริง
เบนช์มาร์กประสิทธิภาพ
- จากข้อมูล benchmark ก่อนและหลังการรีแฟกเตอร์ พบว่า หลังใช้ persistent attention มีประสิทธิภาพลดลงเมื่อเทียบกับก่อนหน้าใน D=64
- สาเหตุเกิดจากปัญหาการจัดตารางคำสั่งในส่วน softmax
- แต่เมื่อใช้ชนิด fp8 ร่วมกับการตั้งชื่อแบบ "cutlass" จะได้ throughput สูงเด่นชัด ในบาง context และบางขนาด
- สรุปผลเด่น ๆ:
- Attention Z=4, H=32, D=64, causal=False:
- ก่อนใช้ persistent: triton-fp16 ประมาณ 383, triton-fp8 ประมาณ 413, cudnn-fp16 ประมาณ 565
- หลังใช้ persistent: triton-fp16 ประมาณ 360, triton-fp8 ประมาณ 370
- Attention Z=4, H=32, D=128, causal=True:
- ก่อนใช้ persistent: triton-fp16 ประมาณ 312, triton-fp8 ประมาณ 345, cudnn-fp16 ประมาณ 553
- หลังใช้ persistent: triton-fp16 ประมาณ 356, triton-fp8 ประมาณ 351
การค้นพบทริกการตั้งชื่อและการวิเคราะห์
- ชุมชนวิเคราะห์ยืนยันว่าเมื่อมีสตริง
"cutlass" อยู่ในชื่อเคอร์เนล จะ เปิดใช้รูทีนการเพิ่มประสิทธิภาพเชิงทดลอง ใน NVIDIA ptxas
- ใน ptxas มีลอจิกฮาร์ดโค้ดสำหรับจับคู่ชื่อ (
strstr(kernel_name, "cutlass"))
- ทริกนี้เป็นการเพิ่มประสิทธิภาพแบบ aggressive และ experimental โดยความแม่นยำของเคอร์เนลจะเปลี่ยนหรือไม่อาจขึ้นอยู่กับฮาร์ดแวร์และสถานการณ์
การอภิปรายในชุมชน
- ผู้รีวิวหลายคนตั้งคำถามและวิเคราะห์เรื่องการเปรียบเทียบประสิทธิภาพ ความถูกต้อง และแนวทางการเพิ่มประสิทธิภาพ
- ยังมีการพูดถึงเนื้อหาใน Deepseek technical report และความแตกต่างบน สถาปัตยกรรมเฉพาะ เช่น GPU ตระกูล Hopper
- มีการตั้งประเด็นด้วยว่าการเพิ่มประสิทธิภาพผ่านการเปลี่ยนชื่อถูกนำไปใช้กว้างแค่ไหน และมีปัญหาเสถียรภาพหรือไม่
บทสรุปและนัยสำคัญ
- การที่ แค่ชื่อเคอร์เนลเพียงอย่างเดียว ก็ทำให้เกิดความเปลี่ยนแปลงด้านประสิทธิภาพอย่างมีนัยในระดับฮาร์ดแวร์ได้ ถือเป็นพฤติกรรมที่แปลกมาก
- สิ่งนี้ชี้ว่าในซอฟต์แวร์สแต็กของ NVIDIA (ptxas) มี trigger การเพิ่มประสิทธิภาพที่ซ่อนอยู่ และ กฎการตั้งชื่ออาจส่งผลต่อประสิทธิภาพ ในการพัฒนาเฟรมเวิร์ก AI
- ในทางปฏิบัติ หากจะใช้ทริกนี้ควรทดสอบเรื่อง การทำซ้ำผลลัพธ์และความเสถียร อย่างรอบคอบ และควรจับตานโยบายการเพิ่มประสิทธิภาพจากผู้ผลิตฮาร์ดแวร์อย่างใกล้ชิด
1 ความคิดเห็น
ความเห็นจาก Hacker News
ลองแยกดู
ptxasแล้วพบว่ามีลอจิกที่ฮาร์ดโค้ดไว้เพื่อตรวจจับชื่อเคอร์เนลว่าเป็น "cutlass"จึงดูเหมือนว่า NVIDIA จะใส่การเพิ่มประสิทธิภาพที่ไม่เสถียร เป็นการทดลอง และค่อนข้างดุดันไว้ตรงนี้ โดยมองว่าถ้าเปิดใช้การเพิ่มประสิทธิภาพนี้ตลอดเวลาแบบไม่มีเงื่อนไข อาจก่อให้เกิดบั๊กที่จับยากได้
คอมไพเลอร์สำหรับ GPU เป็นเรื่องที่ยากมาก และพอพยายามทำอะไรเกินกว่าการเพิ่มประสิทธิภาพพื้นฐาน ก็มักได้ผลลัพธ์ที่ปะปนกับปัญหาเสมอ
บางเคอร์เนลเร็วขึ้น บางเคอร์เนลช้าลง และการหวังให้ประสิทธิภาพโดยรวมดีขึ้นนั้นทำได้ยากมาก
แทบไม่เคยมีการเพิ่มประสิทธิภาพเพียงอย่างเดียวที่ทำให้ทุกอย่างเร็วขึ้นได้เสมอตลอดทั้งชุดทดสอบ
ประสบการณ์ของฉันอยู่กับระบบ GPU ที่ไม่ใช่ Nvidia แต่สถานการณ์นี้ฟังดูคุ้นเคยมาก
ดูเหมือนว่า Nvidia เองก็คงค้นพบการเพิ่มประสิทธิภาพที่ให้ผลยอดเยี่ยมกับเคอร์เนลบางชุด แต่ให้ผลแย่มากกับอีกบางชุด และก็หาหลักเกณฑ์ที่เชื่อถือได้พอจะใช้เปิดมันแบบอัตโนมัติไม่ได้
ขอบคุณที่อธิบายบริบทแบบนี้
ฉันไม่ได้อยู่ในสายนี้ (และเพิ่งเคยได้ยินชื่อโปรเจกต์นี้ครั้งแรก) เลยไม่เข้าใจเลยว่าหัวข้อกับเนื้อหาใน PR ต้องการจะสื่ออะไร
ทำให้นึกถึงเมื่อ 25 ปีก่อนที่ ATI (AMD) ถูกจับได้ว่าโกง เพราะประสิทธิภาพในเบนช์มาร์ก Quake III เปลี่ยนไปเมื่อเปลี่ยนชื่อไฟล์รันจาก executable เป็น 'quack'
มีลิงก์ที่เกี่ยวข้องด้วย: รีวิวจาก techreport.com, รีวิวจาก hardocp.com, บทความจาก 3dcenter.de
สรุปไว้เผื่อมีคนเข้าใจผิดแบบฉัน
ATI ตรวจจับชื่อไฟล์รันว่าเป็น 'quake' แล้วเปลี่ยนคุณภาพของ texture เป็นต้น เพื่อดันคะแนนเบนช์มาร์กขึ้น
คนเลยลองเปลี่ยนชื่อไฟล์รันเป็น 'quack' แล้วพบว่าคุณภาพภาพดีขึ้นแต่คะแนนลดลง แสดงว่าไดรเวอร์ของ ATI จงใจลดคุณภาพเพื่อแลกกับความเร็ว
ดังนั้นไม่ใช่ว่า ATI เป็นคนเปลี่ยนชื่อไฟล์ แต่เป็นผู้ใช้ที่เปลี่ยนเอง
หรืออีกกรณีคือ Intel C++ Compiler ที่เคยมีประเด็นตรวจสอบสตริง "GenuineIntel" ในผลลัพธ์
ลิงก์วิกิที่เกี่ยวข้องอยู่ที่นี่
จนถึงทุกวันนี้ ผู้ขายทุกรายก็ยังทำเรื่องแบบนี้กันอยู่
ไดรเวอร์จะเข้าไปดัก rendering loop ของเกมยอดนิยมเพื่อแก้บั๊ก หรือสลับ shader ไปใช้เวอร์ชันที่ปรับแต่งมาดีกว่า หรือเปิด fast code path ให้ เป็นต้น
การเปลี่ยนแปลงเหล่านี้ควรส่งผลต่อผลลัพธ์ให้น้อยที่สุด แต่บางกรณีก็ปรับแบบดุดันเกินไปจนคุณภาพตกลงอย่างมาก
ทั้งหมดนี้ก็เพื่อให้เกมรันบนฮาร์ดแวร์ของตัวเองได้เร็วขึ้น
ถ้าอยากคุยเรื่องนี้ลึกขึ้น มีเธรดที่อภิปรายไว้มากกว่านี้ แนะนำดูที่นี่
ที่น่าสนใจคือมันเป็นโพสต์เก่าเกี่ยวกับการเพิ่มประสิทธิภาพ cutlass แบบเดียวกันนี่แหละ
กรณีแบบนี้พบได้บ่อยมาก
ผู้ผลิตชิปมือถือก็เคยโกงเพื่อเบนช์มาร์ก (VW เรื่องไอเสีย, Nvidia กับเบนช์มาร์ก 3DMark, Intel กับเบนช์มาร์ก SPEC สำหรับ Xeon ฯลฯ)
ในวงการคอมพิวเตอร์กราฟิก ตอนนี้แทบกลายเป็นธรรมเนียมไปแล้วที่ไดรเวอร์จะยัด tweak, setting, workaround และอื่น ๆ รายเกมเข้าไป
(น่าเสียดายที่ทุกวันนี้ลิงก์แหล่งอ้างอิงดี ๆ หายไปบ่อยมากจนต้องพึ่ง archive.org ฉันคิดว่าความทรงจำแบบนี้ควรถูกเก็บไว้)
ลิงก์อ้างอิง: การโกงเบนช์มาร์กของ Mediatek, เรื่องอื้อฉาวการโกงไอเสียของ Volkswagen, ประเด็นถกเถียงเรื่อง Nvidia 3DMark, ผลกระทบของ Intel compiler ต่อเบนช์มาร์ก SPEC
จากมุมของคนที่ทำงานกับคอมไพเลอร์ การเพิ่มประสิทธิภาพแบบนี้บางครั้งก็อาศัยชื่อ (schema, substring ฯลฯ) จริง ๆ
ถึงจะไม่ชอบ แต่มันก็เป็นความจริงของการทำงาน
ไม่จำเป็นต้องมีเจตนาร้ายเสมอไป และการออกแบบให้การเพิ่มประสิทธิภาพไปมีผลเฉพาะกับไลบรารีของตัวเอง ก็อาจเป็นทางเลือกที่ปลอดภัยกว่าการเสี่ยงทำให้ทั้งระบบพัง
หรือบางครั้งก็เป็นเพราะ frontend ไม่สามารถให้ข้อมูลที่น่าเชื่อถือกว่านี้ได้ (เช่นข้อมูลเชิงโครงสร้าง)
ฉันคิดว่าวิธีแบบนี้ไม่ได้ช่วยอะไรนัก
ฉันว่าไม่ค่อยมีอะไรใหม่
ทำให้นึกถึงเมื่อราว 10 ปีก่อน ใน Webpack เวอร์ชันหนึ่ง ถ้าใช้ชื่อไฟล์
add.svgการบิลด์จะพังสุดท้ายต้องแก้โดยเปลี่ยนชื่อไฟล์เป็น
plus.svgnumpyก็คล้ายกันเคยมีคนเจอว่าการใช้ไฟล์ชื่อ
secret.pyทำให้numpyพังโดยไม่ได้ตั้งใจประทับใจที่เขาเขียนข้อความคอมมิตแบบตรงไปตรงมา
มีคนวิจารณ์วิธีจัด diff ของคอมมิตนั้น
แต่พอมีคนเขียนว่า "ทำให้บางอย่างเร็วขึ้นประมาณ 100 tflops" กลับมีคนบอกว่า "ข้อความคอมมิตไม่ดี" ... ถ้าอย่างนั้นก็คงไม่ชอบสไตล์คอมมิตของ John Carmack ด้วยเหมือนกัน
ส่วนตัวฉันชอบข้อความตรง ๆ แบบนี้
รู้สึกว่าดีกว่าการเจอแต่ข้อความคอมมิตที่ AI สร้างให้อัตโนมัติอย่าง "refactored X" ซ้ำ ๆ เต็มไปหมด
ฉันคิดว่าควร squash แล้วรวมประวัติคอมมิตเข้าด้วยกัน
ไม่ค่อยเข้าใจว่าทำไมตอนอัปขึ้น GitHub ถึงไม่ squash
ทำให้นึกถึงตอนเรียนรู้การใช้งาน NVIDIA Jetson
ตอนนั้นรู้ว่ารันคำสั่งเดียวแล้วทุกอย่างจะเร็วขึ้น (ลิงก์ที่เกี่ยวข้อง)
ถ้าดูตามบทความ มันมีสองแบบคือ 5W กับ 10W และ 10W เป็นค่าปริยาย ดังนั้นอาจตีความได้ว่า "เร็วขึ้น" จะเกิดก็ต่อเมื่อเปลี่ยนจากค่าเริ่มต้นไปเป็น 5W เท่านั้น หรือว่าฉันเข้าใจอะไรผิดไป
บางครั้งคุณเขียนโค้ดที่จูนหนักมากในภาษาระดับสูงอย่าง C++ และคาดหวังผลลัพธ์ที่เฉพาะเจาะจงแม้ในระดับ GPU assembly แต่คอมไพเลอร์กลับไม่สร้างสิ่งที่ต้องการ
ถ้าไปคุยกับทีมคอมไพเลอร์ เขาอาจเสนอวิธีแก้ได้หลายแบบ แต่ถ้าเป็นโอเพนซอร์ส วิธีจำนวนมากก็ใช้จริงไม่ได้ (เช่น
#pragmaแบบเฉพาะค่าย, intrinsic แบบปิด proprietary ฯลฯ)สำหรับคนที่สร้างไลบรารีประสิทธิภาพสูง ถ้าประสิทธิภาพไม่ถึง ก็แทบส่งออกใช้งานไม่ได้เลย
ในสถานการณ์แบบนี้จึงอาจต้องใช้ทริกอย่างการทำให้ชื่อฟังก์ชันไปกระตุ้นการแปลงโค้ดบางอย่าง
การเพิ่มประสิทธิภาพแบบนี้พบได้ทั่วไปในโลกจริง และฉันไม่คิดว่ามันจะเทียบชั้นกับการลดคุณภาพภาพเพื่อโกงเบนช์มาร์กได้
เรื่องนี้ถูกพูดถึงไปแล้วตั้งแต่ตอน PR นี้ถูกเปิดครั้งแรก
รู้สึกว่าไม่มีอะไรใหม่
การสนทนาก่อนหน้า
อยากให้มีโครงสร้างเศรษฐกิจที่เอื้อต่อการแบ่งปันโค้ดได้ง่ายกว่านี้
ไม่ใช่โครงสร้างซับซ้อนอย่างไดรเวอร์แบบ binary blob, baseband และอะไรทำนองนั้น แต่เป็นโลกที่ทุกคนเข้าถึงข้อมูลได้ง่ายและช่วยลดเวลา ความพยายามที่สูญเปล่า
วิศวกรและนักวิจัยเก่ง ๆ จำนวนมากต้องใช้เวลาหลายเดือนหรือหลายปีไปกับการ reverse engineer และถอดความเอกสาร วงจร และไบนารีโค้ดที่จริง ๆ แล้วมีคนอื่นถืออยู่แล้ว
บริษัทอย่าง CUDA และ NVIDIA ทำให้รู้สึกอึดอัดมาก
สำหรับแอปเดสก์ท็อป ต้นทุนส่วนเพิ่มต่อผู้ใช้หนึ่งคนแทบเป็นศูนย์
เพราะอย่างนั้นซอฟต์แวร์จึงต้องมีโครงสร้างรายรับประจำต่อเนื่อง แต่รายรับนั้นก็ไม่ควรเพิ่มขึ้นเรื่อย ๆ ตามจำนวนผู้ใช้
คนที่ลงทุนพัฒนาโค้ดใหม่ควรจะได้เงินลงทุนคืนเมื่อผลิตภัณฑ์ได้รับความนิยม แต่คราวด์ฟันดิงแบบเดิมไม่ตอบโจทย์โครงสร้างนี้
ยิ่งมีผู้ใช้มาก เงินสมทบต่อคนก็ยิ่งลดลงมาก จนต่อให้ทุกคนจ่ายเพียง 100% หรือ 10% หรือแม้แต่ 1% ของมูลค่าที่ได้รับ ยอดรวมก็อาจสูงมหาศาล
สุดท้ายฉันคิดว่าต้องใช้ระบบ pledge แบบประมูล
โครงสร้างนี้เองก็มีปัญหา โดยเฉพาะการเปลี่ยนผ่านระหว่างโหมดผูกขาดกับไม่ผูกขาด
ถ้ามีบริษัทใหญ่ไม่กี่แห่งออกเงินค่าพัฒนาทั้งหมดแล้วปล่อยเป็นโอเพนซอร์ส คนอื่น ๆ ที่เหลือทั้งบุคคลและบริษัทก็แทบจะกลายเป็นผู้โดยสารฟรีไปโดยปริยาย