1 คะแนน โดย GN⁺ 2025-10-04 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • รีแฟกเตอร์เคอร์เนล 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 ความคิดเห็น

 
GN⁺ 2025-10-04
ความเห็นจาก 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 ไม่สามารถให้ข้อมูลที่น่าเชื่อถือกว่านี้ได้ (เช่นข้อมูลเชิงโครงสร้าง)

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

    • ช่วงต้นปี 2024 SPEC เพิกถอนผลเบนช์มาร์ก CPU Intel Xeon 2,600 รายการ เพราะ Intel compiler ใช้การเพิ่มประสิทธิภาพที่ไม่เป็นธรรมเพื่อดันคะแนน (บทความของ Tom's Hardware)
    • Microsoft ก็เคยทำอะไรคล้ายกันกับตัวชี้วัดเบนช์มาร์กของคอมไพเลอร์ Java/C
    • และตอนนี้ทุกคนก็กำลังแข่งขันกันโกงเบนช์มาร์ก AI (เรื่องอื้อฉาวเบนช์มาร์ก AI)
  • ทำให้นึกถึงเมื่อราว 10 ปีก่อน ใน Webpack เวอร์ชันหนึ่ง ถ้าใช้ชื่อไฟล์ add.svg การบิลด์จะพัง
    สุดท้ายต้องแก้โดยเปลี่ยนชื่อไฟล์เป็น plus.svg

    • numpy ก็คล้ายกัน
      เคยมีคนเจอว่าการใช้ไฟล์ชื่อ 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 ฯลฯ)
    สำหรับคนที่สร้างไลบรารีประสิทธิภาพสูง ถ้าประสิทธิภาพไม่ถึง ก็แทบส่งออกใช้งานไม่ได้เลย
    ในสถานการณ์แบบนี้จึงอาจต้องใช้ทริกอย่างการทำให้ชื่อฟังก์ชันไปกระตุ้นการแปลงโค้ดบางอย่าง
    การเพิ่มประสิทธิภาพแบบนี้พบได้ทั่วไปในโลกจริง และฉันไม่คิดว่ามันจะเทียบชั้นกับการลดคุณภาพภาพเพื่อโกงเบนช์มาร์กได้

    • แล้วในกรณีแบบนี้ ทำไมไม่ใช้ inline assembly ล่ะ ก็มีคนถามเหมือนกัน
  • เรื่องนี้ถูกพูดถึงไปแล้วตั้งแต่ตอน PR นี้ถูกเปิดครั้งแรก
    รู้สึกว่าไม่มีอะไรใหม่
    การสนทนาก่อนหน้า

    • ดูคุ้น ๆ เหมือนเคยเห็นมาก่อน เลยรู้สึกว่าน่าจะอ่านไปแล้ว
  • อยากให้มีโครงสร้างเศรษฐกิจที่เอื้อต่อการแบ่งปันโค้ดได้ง่ายกว่านี้
    ไม่ใช่โครงสร้างซับซ้อนอย่างไดรเวอร์แบบ binary blob, baseband และอะไรทำนองนั้น แต่เป็นโลกที่ทุกคนเข้าถึงข้อมูลได้ง่ายและช่วยลดเวลา ความพยายามที่สูญเปล่า
    วิศวกรและนักวิจัยเก่ง ๆ จำนวนมากต้องใช้เวลาหลายเดือนหรือหลายปีไปกับการ reverse engineer และถอดความเอกสาร วงจร และไบนารีโค้ดที่จริง ๆ แล้วมีคนอื่นถืออยู่แล้ว
    บริษัทอย่าง CUDA และ NVIDIA ทำให้รู้สึกอึดอัดมาก

    • แก่นของปัญหาคือต้นทุนคงที่เริ่มต้นในการพัฒนา codebase ซอฟต์แวร์ ค่าแรงบำรุงรักษาต่อเนื่อง และต้นทุนการกระจายที่เล็กน้อย (เช่นเซิร์ฟเวอร์ดาวน์โหลด)
      สำหรับแอปเดสก์ท็อป ต้นทุนส่วนเพิ่มต่อผู้ใช้หนึ่งคนแทบเป็นศูนย์
      เพราะอย่างนั้นซอฟต์แวร์จึงต้องมีโครงสร้างรายรับประจำต่อเนื่อง แต่รายรับนั้นก็ไม่ควรเพิ่มขึ้นเรื่อย ๆ ตามจำนวนผู้ใช้
      คนที่ลงทุนพัฒนาโค้ดใหม่ควรจะได้เงินลงทุนคืนเมื่อผลิตภัณฑ์ได้รับความนิยม แต่คราวด์ฟันดิงแบบเดิมไม่ตอบโจทย์โครงสร้างนี้
      ยิ่งมีผู้ใช้มาก เงินสมทบต่อคนก็ยิ่งลดลงมาก จนต่อให้ทุกคนจ่ายเพียง 100% หรือ 10% หรือแม้แต่ 1% ของมูลค่าที่ได้รับ ยอดรวมก็อาจสูงมหาศาล
      สุดท้ายฉันคิดว่าต้องใช้ระบบ pledge แบบประมูล
      โครงสร้างนี้เองก็มีปัญหา โดยเฉพาะการเปลี่ยนผ่านระหว่างโหมดผูกขาดกับไม่ผูกขาด
      ถ้ามีบริษัทใหญ่ไม่กี่แห่งออกเงินค่าพัฒนาทั้งหมดแล้วปล่อยเป็นโอเพนซอร์ส คนอื่น ๆ ที่เหลือทั้งบุคคลและบริษัทก็แทบจะกลายเป็นผู้โดยสารฟรีไปโดยปริยาย