GPT-OSS บน Day 0
การสนับสนุน Day‑0 สำหรับ GPT‑OSS บน H200 โดยการปรับแต่ง ROSE ด้วย FP8, sink attention และการเพิ่มประสิทธิภาพ MoE
Perplexity มุ่งมั่นที่จะจัดหารุ่น AI ที่ดีที่สุดให้กับผู้คนที่ชื่นชอบการเรียนรู้ ซึ่งต้องการคำตอบที่ถูกต้องและน่าเชื่อถือ รวมถึงการกระทำด้วยเอเจนต์ OpenAI เพิ่งประกาศเปิดตัวรุ่นน้ำหนักเปิด (gpt-oss-20b และ gpt-oss-120b) เช่นเดียวกับรุ่นชั้นนำหลายรุ่น Perplexity เป็นหนึ่งในองค์กรแรกๆ ที่ประเมิน gpt-oss-20b และ gpt-oss-120b
ในโพสต์นี้ เราจะมาแบ่งปันการตัดสินใจด้านโครงสร้างพื้นฐานของสแต็กอินเฟอเรนซ์ภายในองค์กรของเรา ซึ่งทำให้การสนับสนุนตั้งแต่วันแรก (Day-0) เป็นไปได้ เรามุ่งเน้นไปที่การให้บริการรุ่นเหล่านี้บน GPU NVIDIA H200 โดยให้รายละเอียดเกี่ยวกับการเปลี่ยนแปลงเคอร์เนล ตัวเลือกการปรับใช้ และการแลกเปลี่ยนระหว่างความเร็วและต้นทุน
GPT-OSS บน Hopper
รุ่นน้ำหนักเปิดเหล่านี้ถูกจัดส่งโดยใช้การทำควอนไทเซชันแบบ MXFP4 ซึ่งช่วยให้สามารถใส่ในหน่วยความจำบนฮาร์ดแวร์ระดับผู้บริโภคได้ หรือบรรลุอัตราการรับส่งข้อมูลสูงสุดบน NVIDIA Blackwell อย่างไรก็ตาม สำหรับการประเมินเบื้องต้น เราต้องการรันบนคลัสเตอร์ H200 Hopper ที่มีอยู่โดยมีการเปลี่ยนแปลงเอนจิ้นอินเฟอเรนซ์ให้น้อยที่สุด Hopper ไม่มีคอร์เทนเซอร์ FP4 เฉพาะ ซึ่งถูกนำมาใช้โดย Blackwell ดังนั้น เราจึงตัดสินใจให้บริการรุ่นเหล่านี้ด้วยความแม่นยำ FP8 แทน เพื่อลดความจำเป็นในการใช้เคอร์เนลแบบกำหนดเองและใช้ประโยชน์สูงสุดจากฮาร์ดแวร์ที่มีอยู่
ในระดับสูง Transformer LLM มีโครงสร้างที่เรียบง่าย:
อิมเบดดิ้งอินพุต (Input embedding)
ลำดับของเลเยอร์ Transformer แต่ละเลเยอร์ประกอบด้วยบล็อกความสนใจ (attention block) และบล็อก MLP แบบหนาแน่น (dense MLP) หรือ MoE แบบกระจัดกระจาย (sparse MoE)
การฉายล็อกจิตเอาต์พุต (Output logit projection)
เมื่อนำรุ่น Transformer ใหม่มาใช้งาน สิ่งที่เราสนใจเป็นหลักคือการเรียนรู้ว่ารุ่นเหล่านั้นตรงกับรุ่นที่มีอยู่มากน้อยเพียงใด เพื่อระบุการเปลี่ยนแปลงที่จำเป็น OpenAI ได้กรุณาแบ่งปันภาพรวมของรุ่นของตนล่วงหน้า ซึ่งช่วยให้เราสามารถปรับแต่งการตั้งค่าอินเฟอเรนซ์ของเราให้สอดคล้องกัน เราพบว่ารุ่นนี้จำเป็นต้องมีการเปลี่ยนแปลงเล็กๆ น้อยๆ จำนวนมากพอสมควร
ความสนใจ (Attention): GQA พร้อม Attention Sinks
ฮีดความสนใจ (attention head) แต่ละตัวมีพารามิเตอร์ซิงค์ที่ฝึกไว้ล่วงหน้า ซึ่งนำมาคำนวณรวมใน Softmax
การเข้ารหัสตำแหน่งแบบ YaRN คล้ายกับ DeepSeek-V3
การฉาย QKV มีไบอัส (biases) คล้ายกับ Qwen 2
การฉายเอาต์พุตมีไบอัส
MLP: Sparse Mixture-of-Expert (MoE)
ฟังก์ชันการเปิดใช้งาน SwiGLU แตกต่างจากรุ่นน้ำหนักเปิดส่วนใหญ่
Softmax หลังจาก Top-K สำหรับน้ำหนักของผู้เชี่ยวชาญ (expert weights)
ผู้เชี่ยวชาญมีไบอัส
เนื่องจากคาดว่าจำนวนพารามิเตอร์จะอยู่ระหว่าง 100B ถึง 200B เราจึงตัดสินใจที่จะ:
ขยาย FlashInfer เพื่อรองรับ attention sinks
นำ การใช้งาน MoE ที่สร้างไว้แล้วสำหรับตระกูลรุ่น DeepSeek-V3 กลับมาใช้ใหม่
เลือกการปรับสเกลบล็อก FP8 128x128 เป็นรูปแบบการทำควอนไทเซชัน โดยขยายเคอร์เนล DeepGEMM เพื่อรองรับเทอมไบอัส
เอนจิ้นอินเฟอเรนซ์ภายในองค์กร
ความพยายามด้านอินเฟอเรนซ์ของเราได้รับการสนับสนุนจาก ROSE ซึ่งเป็นเอนจิ้นอินเฟอเรนซ์ภายในองค์กรของเรา เรากำลังพัฒนา ROSE ให้เป็นเฟรมเวิร์กที่มีความยืดหยุ่น ซึ่งช่วยให้นำรุ่นใหม่มาใช้งานได้อย่างรวดเร็ว นอกจากนี้ เมื่อเรามุ่งมั่นที่จะให้บริการรุ่นในสเกลใหญ่ ROSE จะเป็นแพลตฟอร์มสำหรับปรับแต่งและเพิ่มประสิทธิภาพเพื่อให้บรรลุระดับล้ำสมัย (state of the art)
ROSE เปิดเผยเอนจิ้น LLM ซึ่งสามารถโหลดรุ่นและสร้างโทเค็นที่ถอดรหัสแล้วสำหรับรุ่นนั้นผ่านตัวถอดรหัสหลายตัว รวมถึงตัวถอดรหัสแบบคาดการณ์ (speculative) และ MTP ตัวรุ่นเองประกอบด้วยชุดเลเยอร์แบบกำหนดเอง ซึ่งรองรับการตั้งค่าคอนฟิกต่างๆ สำหรับการทำควอนไทเซชันและการทำงานแบบขนาน ภายใต้เลเยอร์เหล่านี้ ROSE ได้รวมเอาต์พุตเคอร์เนลทั้ง Triton และ CUDA ซึ่งปฏิบัติการและรวมการคำนวณที่ทำโดยเลเยอร์แต่ละเลเยอร์ได้อย่างมีประสิทธิภาพ
ROSE สร้างขึ้นด้วย Python เป็นหลักและพึ่งพา PyTorch สำหรับคำจำกัดความของรุ่น แม้ว่า Python จะช่วยให้เรามีความยืดหยุ่นและปรับตัวเข้ากับรุ่นใหม่ๆ ได้ แต่เรากำลังย้ายคอมโพเนนต์ส่วนใหญ่ที่ไวต่อประสิทธิภาพ เช่น การให้บริการและการจัดตารางเวลาแบตช์ ไปยัง Rust
ในการนำรุ่นใหม่มาใช้งาน อันดับแรกเราจะกำหนดลำดับชั้นของรุ่นและสร้างตัวแปลงน้ำหนัก (weight converter) สำหรับรุ่นนั้น หลังจากคำนวณน้ำหนักทั้งหมดแล้ว เราจะกำหนดเส้นทางไปข้างหน้า (forward pass) สำหรับกรณีการใช้งาน TP=1 ที่ง่ายที่สุดและตรวจสอบให้แน่ใจว่าทำงานได้แบบต้นทางถึงปลายทาง (end-to-end) สุดท้าย เราจะใช้งานและทดสอบการสนับสนุนรูปแบบการทำงานแบบขนานต่างๆ ก่อนที่เราจะเผยแพร่คอนเทนเนอร์ใหม่และปรับรุ่นบนคลัสเตอร์เพื่อทำการประเมิน จากนั้นเราจะวนซ้ำเพื่อปรับปรุงประสิทธิภาพ โดยอาศัยคำติชมจากทั้งแดชบอร์ดและเบนช์มาร์กที่มีความละเอียดละออมากขึ้น
ROSE ทำงานบนโทเค็นตัวเลข โดยมีความรู้น้อยมากเกี่ยวกับรูปแบบแชทนอกเหนือจากการทดสอบการรวมระบบ ในเวลาเดียวกัน เราต้องพิจารณาปรับโครงสร้างพื้นฐานรอบข้างเพื่อรองรับโทเลไนเซอร์ Harmony และแมปคำขอไปยังลำดับโทเค็นอินพุตได้อย่างถูกต้อง
ด้วยรุ่น GPT OSS เราพบว่าไม่จำเป็นต้องเปลี่ยนแปลงใดๆ กับตัวถอดรหัส, ชุดเครื่องมือ CUDA graph หรือโครงสร้างพื้นฐานรอบข้าง ซึ่งช่วยให้เราสามารถมุ่งเน้นความพยายามไปที่การปรับแต่งเคอร์เนลที่อยู่เบื้องหลังรุ่นได้
เคอร์เนลสำหรับ GPT-OSS
Sink Attention
Sink attention แนะนำปัจจัยไบอัสพิเศษก่อน softmax ซึ่งสะสมด้วยผลคูณของ Q และ K:
attn = softmax(q @ k^T * sm_scale + sink) * Vแม้ว่าการใช้งานแบบดั้งเดิมจะค่อนข้างง่าย แต่การใช้งานความสนใจที่มีประสิทธิภาพ เช่น FlashInfer จะทำการคำนวณความสนใจแบบขนานทั้งในส่วนของฮีดอิสระและความยาวลำดับ KV นอกจากนี้ เพื่อความเสถียรทางตัวเลข Softmax จะถูกคำนวณแบบออนไลน์พร้อมทั้งลบองค์ประกอบสูงสุดออกด้วยเพื่อความเสถียรทางตัวเลข:
softmax(x) = e^x / sum(e^x) = e ^ (x - max(x)) / sum(e ^ (x - max(x))การใช้งานแบบออนไลน์จะติดตามค่าสูงสุดที่วิ่งอยู่ m ซึ่งเริ่มต้นด้วย -inf และสเกล d เป็น 1 ด้วยการกำหนดค่าสูงสุดให้เท่ากับค่าซิงค์ของฮีดปัจจุบัน เราจะมั่นใจได้ว่าค่าดังกล่าวจะถูกสะสมลงใน Softmax อย่างถูกต้อง เราต้องระมัดระวังเพื่อให้แน่ใจว่าค่าสูงสุดนี้จะถูกรวมไว้เฉพาะในส่วนแรกเท่านั้น หากความสนใจถูกแบ่งออกเป็นหลายบล็อกตามความยาวลำดับ
เราได้ปรับเทมเพลตเคอร์เนล FlashInfer FA2 ซึ่งใช้สำหรับทั้ง prefill และ decode เพื่อรวมพารามิเตอร์ซิงค์เข้าไปด้วย
MoE
ความแตกต่างหลักระหว่างเลเยอร์ MoE ของรุ่นต่างๆ มักจะเป็นรูปแบบการกำหนดเส้นทาง (routing scheme) เนื่องจากคาดว่าความแปรผันจะมีมาก ROSE จึงใช้งานเคอร์เนลนี้ใน Triton ซึ่งช่วยให้เราปรับ ใช้อย่างรวดเร็วกับรุ่นใหม่ๆ ได้ ในกรณีของ GPT-OSS เราต้องปรับการให้คะแนนน้ำหนักเพื่อทำ softmax เฉพาะในส่วนของผู้เชี่ยวชาญที่เลือกแบบ Top-K เท่านั้น ซึ่งแตกต่างจากรุ่นสไตล์ DeepSeek บางรุ่นที่คำนวณ softmax กับผู้เชี่ยวชาญทั้งหมด เราพบว่าการคำนวณน้ำหนักของผู้เชี่ยวชาญด้วยความแม่นยำ bfloat16 นั้นมีความสำคัญอย่างยิ่งต่อความแม่นยำ
ความท้าทายกับเลเยอร์ MoE เกิดจากการตัดสินใจของเราที่จะนำเคอร์เนล DeepGEMM ที่มีอยู่กลับมาใช้ใหม่ ซึ่งขาดการสนับสนุนสำหรับเทอมไบอัส โชคดีที่เมื่อเวลาผ่านไปเราได้บูรณาการอย่างลึกซึ้งกับเคอร์เนลเหล่านี้ โดยทำการเปลี่ยนแปลงเพื่อให้เชื่อมต่อได้ดีขึ้นกับเคอร์เนลการกระจายแบบ all-to-all แบบกำหนดเองของเรา เราได้เพิ่มการสนับสนุนไบอัสให้กับ DeepGEMM โดยการเริ่มต้นรีจิสเตอร์ตัวสะสม WGMMA ด้วยค่าไบอัสที่โหลดจากหน่วยความจำ นี่เป็นการดำเนินการครั้งเดียวในระหว่างการประมวลผลบล็อก MN ดังนั้นต้นทุนจึงน่าจะมีน้อยมาก และ L2 cache ช่วยให้มั่นใจได้ถึงการเข้าถึงค่าเหล่านี้อย่างมีประสิทธิภาพ
เนื่องจากรุ่นเหล่านี้ไม่ได้รับประโยชน์จาก Data Parallelism มากนัก เราจึงนำเคอร์เนลการกระจายและรวมแบบ TP-only กลับมาใช้ใหม่ อินพุตสำหรับการกระจายจะถูกทำซ้ำ (replicated) ไปยังทุกแรงค์ ดังนั้นการกระจายจึงเลือกโทเค็นสำหรับผู้เชี่ยวชาญที่มีอยู่ในเครื่อง ฟังก์ชัน Combine จะทำการสะสมแบบมีน้ำหนักทั่วทั้ง NVLink
การปรับแต่งประสิทธิภาพ
แม้ว่าเป้าหมายของเราคือการนำรุ่นมาใช้งานอย่างรวดเร็ว แต่เราก็ต้องการให้แน่ใจว่าประสิทธิภาพยังคงสมเหตุสมผล หลังจากตรวจสอบความถูกต้องเทียบกับการใช้งานอ้างอิงที่จัดเตรียมโดย OpenAI แล้ว เราได้โปรไฟล์การใช้งานของเราโดยใช้ตัวโปรไฟล์ PyTorch เริ่มต้น โดยคอยระวังการจัดสรรบล็อกและเธรดข้ามเคอร์เนล ฟังก์ชันการทำงานที่เรานำกลับมาใช้ใหม่นั้นสร้างขึ้นสำหรับรุ่นที่มีมิติซ่อนเร้น (hidden dimension) ที่ใหญ่กว่าคือ 7168 ซึ่งใหญ่กว่า 2880 ของรุ่น GPT-OSS อย่างมาก เราได้ปรับแต่งตัวเปิดใช้งานเคอร์เนลเป็นพิเศษเพื่อเลือกมิติกริดที่ดีขึ้น ซึ่งช่วยเพิ่มอัตราการรับส่งข้อมูลอย่างมีนัยสำคัญ
การทำโทเค็นไนเซชันและช่องทางต่างๆ
รูปแบบแชทของ Harmony มีแนวคิดสำคัญหลายประการสำหรับการจัดโครงสร้างการสนทนา เนื้อหาการให้เหตุผล และการเรียกใช้ฟังก์ชัน (function calls) ในรูปแบบนี้ ข้อความแต่ละข้อความประกอบด้วยส่วนหัว (header) และเนื้อหา (content):
<|start|>{header}<|message|>{content}<|end|>ส่วนหัวจะมีเมทาเดตา โดยที่สำคัญที่สุดคือบทบาท (ระบบ, นักพัฒนา, ผู้ใช้, ผู้ช่วย, เครื่องมือ), ช่องทาง (channel) และผู้รับ เช่น to=functions.<function-name> เมื่อเรียกใช้การเรียกเครื่องมือ
ช่องทางต่างๆ (เช่น การวิเคราะห์, ความเห็น และคำตอบสุดท้าย) ทำให้เอาต์พุตของรุ่นมีความโปร่งใสและแบ่งส่วนได้มากขึ้น เนื่องจากรูปแบบบังคับให้มีการแยกส่วนนี้ รุ่นจึงสามารถให้เหตุผลได้อย่างโปร่งใส (และตรวจสอบได้เพื่อการดีบัก) โดยไม่ปล่อยให้กระบวนการคิด (chain-of-thought) รั่วไหลไปสู่การผลิต แท็กผู้รับ (ส่วนหัว to=) จะบอกรันไทม์ว่าตัวแสดงใดควรได้รับเพย์โหลดถัดไปอย่างแม่นยำ ไม่ว่าจะเป็นฟังก์ชัน, ตัวรุ่นเอง หรือผู้ใช้ปลายทาง
เอนจินการอนุมาน ROSE ของเราเป็นแบบไม่ยึดติดกับรูปแบบ โดยจะรับโทเค็นอินพุตเป็นชุด และสตรีมโทเค็นเอาต์พุตกลับมา ในสแตกการอนุมานของเรา หน้าที่ในการจัดรูปอินพุตให้เป็นพรอมต์ที่แปลงเป็นโทเค็นแล้ว และแยกผลลัพธ์จาก LLM กลับมาเป็นข้อความที่มีโครงสร้างนั้น ดำเนินการโดยบริการส่วนหน้า JSON API โดยเฉพาะ เราผนวก Harmony เข้าด้วยการเพิ่มตัวจัดรูปแบบ/ตัวแยกวิเคราะห์แบบปลั๊กอินใหม่ให้กับส่วนหน้านี้ ทำให้แบ็กเอนด์ไม่ต้องเปลี่ยนแปลง ขณะที่ส่วนหน้าจัดการกฎรูปแบบแชต การเรียกเครื่องมือ และการสตรีมได้อย่างเรียบร้อย การแยกความรับผิดชอบเช่นนี้ช่วยให้สถาปัตยกรรมเป็นแบบโมดูลาร์ ทำให้รองรับรูปแบบใหม่ได้อย่างรวดเร็ว พร้อมฟีเจอร์ตอบกลับโดยต้องปรับเปลี่ยนแบ็กเอนด์เพียงเล็กน้อย
ต้นทุนและประสิทธิภาพ
เนื่องจากขนาดที่ค่อนข้างเล็กของรุ่น GPT-OSS เราจึงจำกัดการปรับใช้แบบจำลอง (replica) ไว้ที่โหนดเดียวเพื่อหลีกเลี่ยงค่าใช้จ่ายในการสื่อสารระหว่างโหนด การใช้งานของเราสนับสนุนการผสมผสานที่ยืดหยุ่นของความขนานของผู้เชี่ยวชาญ (EP), ความขนานของข้อมูล (DP) และความขนานของเทนเซอร์ (TP) เพื่อกำหนดการตั้งค่าการปรับใช้ที่เหมาะสมที่สุด เราได้ทำการเบนช์มาร์กการผสมผสานกลยุทธ์การแบ่งส่วน (sharding strategies) ทั้งหมดทั่วทั้งขนาดแบตช์ตั้งแต่ 1 ถึง 128 ด้วย การแยกส่วนการเติมล่วงหน้าและการถอดรหัส (Prefill-Decode Disaggregation) เราจึงสามารถอภิปรายเกี่ยวกับการแลกเปลี่ยนระหว่างประสิทธิภาพและต้นทุนแยกกันสำหรับ prefill และ decode ได้
สำหรับการประมาณต้นทุน เราสมมติว่าอัตราตลาดของ H200 อยู่ที่ 3.00 ดอลลาร์/ชั่วโมง (หมายเหตุ: นี่ไม่ใช่ราคา GPU จริงของเรา)
เราพบว่าการตั้งค่า batch_size=1 และ DP=1 ให้ประสิทธิภาพ prefill ดีที่สุด การกำหนดค่า TP ที่แตกต่างกันจะให้การแลกเปลี่ยนที่หลากหลายระหว่างความหน่วงของโทเค็นแรกและต้นทุน ตารางด้านล่างแสดงความหน่วงของ prefill และต้นทุนต่อหนึ่งล้านโทเค็นอินพุตสำหรับการกำหนดค่าและความยาวอินพุตต่างๆ
GPT-OSS 120B:
ความยาวอินพุต | 8192 | 32768 | 65536 | 128000 |
EP1 DP1 TP1 | 0.364s, $0.037 | 2.421s, $0.062 | 7.375s, $0.094 | 23.902s, $0.156 |
EP2 DP1 TP2 | 0.190s, $0.039 | 1.245s, $0.063 | 3.786s, $0.096 | 12.116s, $0.158 |
EP4 DP1 TP4 | 0.165s, $0.067 | 0.900s, $0.092 | 2.449s, $0.125 | 7.165s, $0.187 |
EP8 DP1 TP8 | 0.179s, $0.145 | 0.839s, $0.171 | 2.003s, $0.204 | 5.119s, $0.267 |
เวลาแฝงในการ prefill และต้นทุนต่อหนึ่งล้านโทเค็นอินพุตของ GPT-OSS 120B ตามการกำหนดค่า parallelism และความยาวอินพุต
GPT-OSS 20B:
ความยาวอินพุต | 8192 | 32768 | 65536 | 128000 |
EP1 DP1 TP1 | 0.239s, $0.024 | 1.610s, $0.041 | 4.895s, $0.062 | 16.037s, $0.104 |
EP2 DP1 TP2 | 0.127s, $0.026 | 0.833s, $0.042 | 2.522s, $0.064 | 8.143s, $0.106 |
EP4 DP1 TP4 | 0.108s, $0.044 | 0.593s, $0.060 | 1.616s, $0.082 | 4.766s, $0.124 |
EP8 DP1 TP8 | 0.116s, $0.094 | 0.547s, $0.111 | 1.310s, $0.133 | 3.365s, $0.175 |
เวลาแฝงในการ prefill และต้นทุนต่อหนึ่งล้านโทเค็นอินพุตของ GPT-OSS 20B ตามการกำหนดค่า parallelism และความยาวอินพุต
สำหรับ decode เราพบว่า EP4 DP1 TP4 เป็นการกำหนดค่าที่ดีที่สุดสำหรับกรณีส่วนใหญ่ แผนผังทั้งสี่ด้านล่างแสดงการแลกเปลี่ยนระหว่างความเร็วในการถอดรหัสและต้นทุนต่อหนึ่งล้านโทเค็นเอาต์พุตสำหรับทั้งรุ่น 120B และ 20B ที่ความยาวลำดับ 8192 และ 32768
เราได้พิจารณาใช้รุ่น 20B ที่เล็กกว่าเป็นรุ่นดราฟต์สำหรับการถอดรหัสแบบคาดการณ์ (speculative decoding) สำหรับรุ่น 120B ที่ใหญ่กว่าด้วย อย่างไรก็ตาม เนื่องจากจำนวนพารามิเตอร์ที่เปิดใช้งานมีความใกล้เคียงกัน (3B เทียบกับ 5B) ความเร็วที่เพิ่มขึ้นจึงมีน้อยมาก
ข้อมูลอ้างอิง
การเติมล่วงหน้าและการถอดรหัสแบบแยกส่วน (Disaggregated Prefill and Decode)
การเร่งความเร็ว Sonar ผ่านการคาดการณ์
ความหน่วงที่ต่ำลงและอัตราการรับส่งข้อมูลที่สูงขึ้นด้วยการปรับใช้ DeepSeek แบบหลายโหนด
การสื่อสาร Mixture-of-Experts ที่มีประสิทธิภาพและพกพาได้
FlashInfer: เอนจิ้นความสนใจที่มีประสิทธิภาพและปรับแต่งได้สำหรับการให้บริการอินเฟอเรนซ์ LLM
โมเดลภาษาแบบสตรีมมิ่งที่มีประสิทธิภาพพร้อม Attention Sinks
รูปแบบการตอบสนอง OpenAI Harmony | ตำราอาหาร OpenAI
การอ้างอิง
@online{perplexity2025GptOssOnDay0,
author = {{Perplexity} and Nandor Licker and Lequn Chen and Vladimir Zaytsev and Kevin Hu and Lauren Kolm and Jesse Dwyer},
title = {{GPT-OSS on day 0}},
date = {2025-08-08},
url = {https://www.perplexity.ai/hub/blog/gpt-oss-on-day-0}
}