• LLM ขนาดใหญ่ปรับใช้ได้ยากเนื่องจากข้อจำกัดของหน่วยความจำ GPU แต่ DFloat11 ลดขนาดน้ำหนัก BFloat16 ลงเหลือประมาณ 70% พร้อมคงเอาต์พุตให้ เหมือนต้นฉบับในระดับบิต
  • หัวใจสำคัญคือ exponent 8 บิต ของ BFloat16 ในความเป็นจริงมีข้อมูลเพียงประมาณ 2.6 บิต โดยรักษา sign และ mantissa ไว้ และบีบอัดเฉพาะ exponent ด้วย Huffman coding
  • การเข้ารหัสความยาวแบบไดนามิกมักกลายเป็นคอขวดบน GPU ดังนั้น DFloat11 จึงปรับให้เหมาะกับ inference แบบขนานด้วย LUT แบบลำดับชั้น, kernel 2 ขั้นตอน และการคลายการบีบอัดเป็นหน่วย transformer block
  • ยืนยันได้กับ Llama 3.3, Qwen 3, Mistral 3, DeepSeek R1 Distilled, FLUX.1, Stable Diffusion 3.5 ฯลฯ ว่าลด ขนาดโมเดลได้ประมาณ 30% และคงเอาต์พุตเดิมไว้
  • throughput ของการสร้าง token สูงกว่าทางเลือกแบบ CPU offload 2.3–46.2 เท่า และทำให้ inference แบบไม่สูญเสียของ Llama 3.1 405B ขนาด 810GB ทำได้บนโหนดเดียวที่มี GPU 8×80GB

คอขวดด้านหน่วยความจำที่ DFloat11 มุ่งแก้

  • foundation model เช่น LLM และ Diffusion Model มีขนาดโตขึ้นอย่างรวดเร็ว ทำให้ปรับใช้อย่างมีประสิทธิภาพบนฮาร์ดแวร์ที่มีข้อจำกัดด้านหน่วยความจำได้ยาก
  • Llama 3.1 405B เก็บพารามิเตอร์ 405 พันล้านตัวในรูปแบบ BFloat16 และต้องใช้หน่วยความจำประมาณ 810GB สำหรับ inference ทั้งหมด
    • ซึ่งเกินความจุของเซิร์ฟเวอร์ GPU ระดับสูงทั่วไปที่มี GPU 8×80GB
    • หากต้องใช้หลายโหนด ต้นทุนการปรับใช้และภาระด้านการเข้าถึงก็จะเพิ่มขึ้น
  • DFloat11 มีเป้าหมายบีบอัดโมเดล BFloat16 ให้เหลือประมาณ 70% ของขนาดเดิม พร้อมรักษาความแม่นยำ 100% ในทุกงาน

แนวทางที่ต่างจากการ quantization แบบสูญเสีย

  • Quantization เป็นวิธีบีบอัดแบบสูญเสียที่ลดหน่วยความจำด้วยการลด precision ของน้ำหนัก
    • สามารถลดการใช้หน่วยความจำได้มากและเพิ่มความเร็ว inference ได้ แต่จะเกิดข้อผิดพลาดจากการประมาณค่า
    • การสูญเสียความแม่นยำคาดการณ์ได้ยาก เพราะขึ้นอยู่กับโมเดลฐาน วิธี quantization, benchmark ประเมินผล และ bit-width เป้าหมาย
  • ตัวอย่างเช่น เมื่อใช้ 8-bit SmoothQuant กับ DeepSeek-R1-Distill-Qwen-1.5B ความแม่นยำเฉลี่ยใน reasoning task ลดลง 9.09%
  • แม้ตัวชี้วัดความแม่นยำโดยรวมจะใกล้เคียงกัน โมเดลที่ผ่าน quantization ก็อาจแสดงพฤติกรรมการตอบที่ต่างจากต้นฉบับ
    • Dutta et al. สังเกตปรากฏการณ์ flips ที่คำตอบถูกเปลี่ยนเป็นผิด หรือคำตอบผิดเปลี่ยนเป็นถูก
    • Qwen2-1.5B ที่ quantize ด้วย W8A16 GPTQ มีความแม่นยำ GSM8K 8-shot ลดลงเพียง 0.3% แต่สถานะถูก/ผิดของคำตอบเปลี่ยนไปใน 6.37% ของคำตอบ
  • ในโดเมนอย่างการเงินและการแพทย์ การเปลี่ยนแปลงเอาต์พุตของโมเดลที่ผ่าน quantization อาจทำให้ยากต่อการตอบสนองข้อกำหนดด้าน กฎระเบียบและความน่าเชื่อถือ
  • การบีบอัดโมเดลแบบไม่สูญเสียที่มีอยู่เดิมมักเน้นประสิทธิภาพการจัดเก็บ checkpoint, การลดเวลาดาวน์โหลดจาก model hub และฮาร์ดแวร์เฉพาะทางอย่าง FPGA จึงให้ประโยชน์น้อยสำหรับ inference บน GPU ทั่วไป

ช่องว่างสำหรับการบีบอัดที่ยังเหลืออยู่ใน exponent ของ BFloat16

  • BFloat16 แบ่ง 16 บิตออกเป็น sign 1 บิต, exponent 8 บิต, mantissa 7 บิต
  • จุดเริ่มต้นของ DFloat11 คือการวิเคราะห์ Shannon entropy ขององค์ประกอบ BFloat16 แต่ละส่วนในน้ำหนักของ LLM
    • entropy ของ sign และ mantissa ใกล้เคียงกับ bit-width ของแต่ละส่วน จึงมีพื้นที่ให้บีบอัดจำกัด
    • exponent ได้รับการจัดสรร 8 บิต แต่มี entropy เพียงประมาณ 2.6 บิต
  • การกระจายของค่า exponent ไม่สมดุลอย่างมาก
    • จากค่า 8 บิตที่เป็นไปได้ 256 ค่า มีการใช้เพียงประมาณ 40 ค่า
    • ค่าที่เหลือไม่ปรากฏ
    • ลำดับความถี่ก็ลดลงอย่างรวดเร็ว
  • ด้วย entropy ที่ต่ำ exponent จึงเป็นเป้าหมายสำหรับการบีบอัดแบบไม่สูญเสีย และข้อมูล exponent ประมาณ 5.4 บิตสามารถบีบอัดได้

รูปแบบ DFloat11

  • DFloat11 หรือ DF11 เป็นรูปแบบ floating-point ความยาวแบบไดนามิกที่บีบอัดเฉพาะ exponent ของน้ำหนัก BFloat16 ด้วย entropy coding
  • Huffman tree ถูกสร้างจากการกระจายของ exponent ในน้ำหนักโมเดล
    • ค่า exponent ที่พบได้บ่อยจะได้รับโค้ดสั้น
    • ค่าที่พบได้น้อยจะได้รับโค้ดยาว
  • sign และ mantissa ถูกเก็บไว้เหมือนต้นฉบับ
    • exponent ถูกเก็บใน byte array EncodedExponent ในรูปแบบ bit-packed
    • sign และ mantissa ถูกเก็บแยกต่างหากใน byte array PackedSignMantissa
  • ผลคือ น้ำหนัก BFloat16 ลดลงเหลือเฉลี่ยประมาณ 11 บิต และสามารถกู้คืนกลับเป็นค่า BFloat16 เดิมได้โดยไม่สูญเสีย precision

การคลายการบีบอัดที่ปรับให้เหมาะกับ inference บน GPU

  • น้ำหนักที่ผ่าน entropy coding ใช้การเข้ารหัสความยาวแบบไดนามิก จึงไม่สามารถนำเข้า matrix multiplication ได้โดยตรง
    • ต้องคลายการบีบอัด weight matrix ที่ต้องใช้ให้กลับเป็น BFloat16 เดิมทันที
    • เมื่อ matrix multiplication เสร็จแล้ว matrix BFloat16 จะถูกทิ้งทันทีเพื่อประหยัดหน่วยความจำ GPU
  • Huffman decoding ทั่วไปต้องเดิน tree ทีละบิตตามลำดับ จึงไม่เข้ากับโครงสร้างขนานของ GPU
    • หากให้ thread เดียวรับผิดชอบการคลายการบีบอัด การใช้งาน GPU จะต่ำและ latency จะสูง

การถอดรหัสด้วย LUT แบบลำดับชั้น

  • DFloat11 ใช้ การถอดรหัสบน lookup table แทนการเดิน Huffman tree
  • หากความยาวสูงสุดของ Huffman code คือ L, LUT เดี่ยวต้องมีขนาด 2^L
    • ใน LLM ค่า L มักอยู่ในช่วง 24–32
    • LUT ระดับ 2^32 รายการวางบน SRAM ของ GPU ได้ยาก
  • เพื่อหลีกเลี่ยงปัญหานี้ Huffman tree จะถูกแบ่งเป็น subtree ที่ไม่ทับซ้อนกันความสูง 8 และแต่ละ subtree จะถูกทำเป็น compact LUT ขนาด 256-entry
  • ใน LUT แบบลำดับชั้น บางรายการต้องทำหน้าที่เป็น reference ชี้ไปยัง LUT ชั้นล่าง
    • ใช้ประโยชน์จากข้อเท็จจริงที่มีค่า exponent จำนวนมากที่ไม่ได้ใช้ใน LLM
    • นำค่า exponent ที่ไม่ได้ใช้ในช่วง 240–255 กลับมาใช้เป็น pointer ภายใน
    • ค่าเหล่านี้แทนขนาดที่ใหญ่มากระดับ ±2^113 ถึง ±2^128 และไม่ปรากฏในน้ำหนัก LLM
  • ในการทดลอง จำนวน compact LUT k ของ Huffman tree สำหรับ exponent ของ BFloat16 อยู่ในช่วง 4–8 รายการ
    • ใช้หน่วยความจำสูงสุด (8 + 1) × 256 bytes รวมกับ CodeLengths
    • ขนาดระดับนี้ใส่ใน SRAM ได้และทำ repeated lookup ได้รวดเร็ว

GPU kernel 2 ขั้นตอนและ metadata เสริม

  • GPU thread แต่ละตัวรับผิดชอบช่วงต่อเนื่อง n byte ของ encoded exponent
    • ในการทดลองใช้ n = 8
    • thread จะถอดรหัส Huffman code ที่เริ่มอยู่ภายในช่วงของตนเอง
  • โค้ดความยาวแบบไดนามิกทำให้เกิดปัญหา 2 อย่าง
    • ตำแหน่งบิตเริ่มต้นที่ถูกต้องของแต่ละ thread ไม่ชัดเจน
    • ยกเว้น thread แรกแล้ว เป็นเรื่องยากที่จะรู้ output index ของ decoded element
  • ปัญหาแรกแก้ด้วย array Gaps
    • Gaps มีหนึ่งรายการต่อ thread
    • แต่ละรายการระบุ bit offset ของ Huffman code ที่ valid ตัวแรก โดยอ้างอิงจาก byte เริ่มต้นของ thread
    • เมื่อความยาว code สูงสุดคือ 32 บิต offset จะอยู่ในช่วง [0, 31] และเก็บด้วย 5 บิต
  • ปัญหาตำแหน่งเอาต์พุตลด overhead หน่วยความจำด้วยการเก็บเฉพาะตำแหน่งระดับ thread block
    • หากเก็บตำแหน่งเอาต์พุต 32 บิตต่อ thread overhead จะสูงสำหรับ thread หลายหมื่นตัวต่อ weight matrix
    • DFloat11 เก็บเฉพาะตำแหน่งเอาต์พุตของ element แรกในแต่ละ thread block
  • kernel ทำงานเป็น 2 ขั้นตอน
    • ขั้นที่ 1 แต่ละ thread ถอดรหัสช่วงของตนเอง เพียงนับจำนวน element และไม่เขียนลง HBM
    • thread ภายใน block ทำ prefix sum ด้วย Blelloch algorithm เพื่อคำนวณตำแหน่งเอาต์พุตของแต่ละ thread
    • ขั้นที่ 2 ถอดรหัสช่วงเดิมอีกครั้ง และเขียนค่าที่ decoded แล้วลงใน SRAM write buffer ตามตำแหน่งที่คำนวณไว้
    • encoded exponent ถูกโหลดเข้า SRAM ก่อน pass แรกเพื่อหลีกเลี่ยงการเข้าถึง global memory ซ้ำ
    • หลังจาก decoded exponent ทั้งหมดถูกเขียนลง SRAM แล้ว จึงทำ coalesced write ไปยัง HBM หนึ่งครั้ง

การคลายการบีบอัดเป็นหน่วย Transformer block

  • การคลายการบีบอัด weight matrix เดี่ยวอาจมีขนาดเล็กเกินกว่าจะใช้ทรัพยากร GPU ได้เต็มที่
  • ยิ่ง matrix มีขนาดใหญ่ throughput การคลายการบีบอัดของ DFloat11 ก็ยิ่งดีขึ้น
  • คลายการบีบอัดหลาย matrix พร้อมกันเพื่อเพิ่ม throughput และซ่อน latency
    • weight matrix ของ DFloat11 ทั้งหมดใน transformer block จะถูกคลายการบีบอัดรวมกันเป็น batch เดียว
    • batched decompression นี้ทำก่อน forward pass ของ transformer block นั้นทันที
  • token embedding และ language modeling head ของ LLM ก็เป็นเป้าหมายการบีบอัดเช่นกัน
    • matrix เหล่านี้ใหญ่พอที่จะทำให้ทรัพยากร GPU อิ่มตัว จึงไม่จำเป็นต้อง batching แยก

ผลการประเมินและผลจริง

  • DFloat11 ถูกประเมินกับ LLM และ diffusion transformer รวมถึง Llama 3, Qwen 3, Mistral 3, DeepSeek R1 Distilled, FLUX.1, Stable Diffusion 3.5 เป็นต้น
  • ผลลัพธ์แสดงให้เห็นว่า ลดขนาดโมเดลได้ประมาณ 30% และคงเอาต์พุตต้นฉบับไว้ได้อย่างสมบูรณ์
    • เอาต์พุตเหมือนกับโมเดลต้นฉบับแบบ bit-for-bit
    • เนื่องจากไม่ใช่การบีบอัดแบบสูญเสีย จึงรักษา precision ของน้ำหนัก BFloat16 ต้นฉบับไว้
  • เมื่อเทียบกับทางเลือกที่ offload ส่วนหนึ่งของโมเดลที่ไม่บีบอัดไปยัง CPU เพื่อให้เข้ากับข้อจำกัดหน่วยความจำ DFloat11 ทำ throughput ในการสร้าง token ได้สูงกว่า 2.3–46.2 เท่า
  • ภายใต้งบประมาณหน่วยความจำ GPU คงที่ ช่วยให้ generation length ยาวกว่าโมเดลที่ไม่บีบอัด 5.7–14.9 เท่า
  • Llama 3.1 405B เป็นโมเดลขนาด 810GB แต่ DFloat11 ทำให้ inference แบบไม่สูญเสียทำได้บนโหนดเดียวที่มี GPU A100 8×80GB
  • ผลลัพธ์นี้แสดงให้เห็นว่าสามารถลดข้อกำหนดฮาร์ดแวร์ที่ต้องใช้ในการรัน Llama-3.1-405B ลงครึ่งหนึ่ง พร้อมทำ inference ได้โดยไม่มี accuracy loss

ยังไม่มีความคิดเห็น

ยังไม่มีความคิดเห็น