โมเดลและแพลตฟอร์ม AI
การเพิ่มประสิทธิภาพหน่วยความจำสำหรับการอนุมานและการปรับให้เหมาะสมของโมเดลภาษาขนาดใหญ่
โมเดลภาษาขนาดใหญ่ (LLM) เช่น GPT-4, Bloom และ LLaMA มีความสามารถที่น่าประทับใจโดยการปรับขนาดขึ้นเป็นพันล้านพารามิเตอร์ อย่างไรก็ตาม การใช้งานโมเดลขนาดใหญ่เหล่านี้สำหรับการอนุมานหรือการปรับให้เหมาะสมเป็นเรื่องที่ท้าทายเนื่องจากต้องการหน่วยความจำจำนวนมาก ในบล็อกเทคนิคนี้ เราจะสำรวจเทคนิคสำหรับการประมาณการและเพิ่มประสิทธิภาพการใช้หน่วยความจำระหว่างการอนุมานและการปรับให้เหมาะสมของ LLM บนฮาร์ดแวร์ต่างๆ
การทำความเข้าใจความต้องการหน่วยความจำ
หน่วยความจำที่ต้องการในการโหลด LLM จะถูกกำหนดโดยจำนวนพารามิเตอร์และความแม่นยำตัวเลขที่ใช้ในการจัดเก็บพารามิเตอร์ กฎง่ายๆ คือ:
- การโหลดโมเดลที่มีพารามิเตอร์ X พันล้านต้องการประมาณ 4X GB ของ VRAM ในความแม่นยำ 32-bit float
- การโหลดโมเดลที่มีพารามิเตอร์ X พันล้านต้องการประมาณ 2X GB ของ VRAM ในความแม่นยำ 16-bit bfloat16/float16
ตัวอย่างเช่น การโหลดโมเดล GPT-3 ที่มีพารามิเตอร์ 175B จะต้องการประมาณ 350GB ของ VRAM ในความแม่นยำ bfloat16 ในปัจจุบัน GPU ที่ใหญ่ที่สุดที่มีจำหน่ายเช่น NVIDIA A100 และ H100 มี VRAM เพียง 80GB ซึ่งต้องการเทคนิค tensor parallelism และ model parallelism
ระหว่างการอนุมาน รอยเท้าหน่วยความจำจะถูกครอบงำโดยพารามิเตอร์ของโมเดลและเทนเซอร์ activation ชั่วคราวที่ผลิตขึ้น การประมาณการระดับสูงสำหรับการใช้หน่วยความจำสูงสุดระหว่างการอนุมานคือผลรวมของหน่วยความจำที่ต้องการในการโหลดพารามิเตอร์ของโมเดลและหน่วยความจำสำหรับ activation
การ量หน่วยความจำสำหรับการอนุมาน
มาทำความเข้าใจความต้องการหน่วยความจำสำหรับการอนุมานโดยใช้โมเดล OctoCode ซึ่งมีพารามิเตอร์ประมาณ 15 พันล้านในรูปแบบ bfloat16 (~ 31GB) เราจะใช้ไลบรารี Transformers เพื่อโหลดโมเดลและสร้างข้อความ:
จาก transformers import AutoModelForCausalLM, AutoTokenizer, pipeline นำเข้า torch <p>model = AutoModelForCausalLM.from_pretrained("bigcode/octocoder", torch_dtype=torch.bfloat16, device_map="auto", pad_token_id=0) tokenizer = AutoTokenizer.from_pretrained("bigcode/octocoder") pipe = pipeline("text-generation", model=model, tokenizer=tokenizer)</p> <p>prompt = "คำถาม: โปรดเขียนฟังก์ชัน Python เพื่อแปลงไบต์เป็นกิกะไบต์.\n\nคำตอบ:" result = pipe(prompt, max_new_tokens=60)[0]["generated_text"][len(prompt):]</p> <p>def bytes_to_gigabytes(bytes): return bytes / 1024 / 1024 / 1024</p> <p>bytes_to_gigabytes(torch.cuda.max_memory_allocated())
ผลลัพธ์:
29.0260648727417การใช้หน่วยความจำสูงสุดของ GPU อยู่ที่ประมาณ 29GB ซึ่งสอดคล้องกับการประมาณการของเราที่ 31GB สำหรับการโหลดพารามิเตอร์ของโมเดลในรูปแบบ bfloat16
การเพิ่มประสิทธิภาพหน่วยความจำสำหรับการอนุมานด้วย Quantization
แม้ว่า bfloat16 จะเป็นความแม่นยำที่ใช้ในการฝึกอบรม LLM แต่นักวิจัยพบว่าการปรับขนาดน้ำหนักโมเดลให้精度ต่ำลง เช่น 8 บิตหรือ 4 บิต สามารถลดการใช้หน่วยความจำได้อย่างมากโดยไม่สูญเสียความแม่นยำมากนักสำหรับการอนุมาน
มาดูการประหยัดหน่วยความจำจาก Quantization 8 บิตและ 4 บิตของโมเดล OctoCode:
&lt;/div&gt; # 8-bit quantization model = AutoModelForCausalLM.from_pretrained("bigcode/octocoder", load_in_8bit=True, pad_token_id=0) pipe = pipeline("text-generation", model=model, tokenizer=tokenizer) result = pipe(prompt, max_new_tokens=60)[0]["generated_text"][len(prompt):] bytes_to_gigabytes(torch.cuda.max_memory_allocated())</pre>
ผลลัพธ์:
15.219234466552734# 4-bit quantization model = AutoModelForCausalLM.from_pretrained("bigcode/octocoder", load_in_4bit=True, low_cpu_mem_usage=True, pad_token_id=0) pipe = pipeline("text-generation", model=model, tokenizer=tokenizer) result = pipe(prompt, max_new_tokens=60)[0]["generated_text"][len(prompt):] bytes_to_gigabytes(torch.cuda.max_memory_allocated())
ผลลัพธ์:
9.543574333190918ด้วยการปรับขนาด 8 บิต ความต้องการหน่วยความจำลดลงจาก 31GB เป็น 15GB ในขณะที่การปรับขนาด 4 บิต ลดความต้องการหน่วยความจำลงอีกเป็น 9.5GB! ทำให้สามารถรันโมเดล OctoCode ที่มีพารามิเตอร์ 15B บน GPU สำหรับผู้บริโภค เช่น RTX 3090 (24GB VRAM)
อย่างไรก็ตาม โปรดทราบว่าการปรับขนาดที่รุนแรง เช่น 4 บิต อาจทำให้ความแม่นยำลดลงเมื่อเทียบกับการปรับขนาด 8 บิตหรือ bfloat16 ในบางกรณี ผู้ใช้ต้องประเมินความสมดุลระหว่างการประหยัดหน่วยความจำและความแม่นยำสำหรับการใช้งานของตน
การปรับขนาดเป็นเทคนิคที่มีประสิทธิภาพที่สามารถทำให้โมเดล LLM ใช้งานได้บนเครื่องมือที่มีทรัพยากรจำกัด เช่น ตัวอย่างอินสแตนซ์ คลาวด์ อุปกรณ์เอดจ์ หรือแม้แต่โทรศัพท์มือถือ โดยการลดรอยเท้าหน่วยความจำอย่างมาก
การประมาณการหน่วยความจำสำหรับการปรับให้เหมาะสม
แม้ว่าการปรับขนาดจะใช้สำหรับการอนุมานอย่างมีประสิทธิภาพเทคนิค เช่น tensor parallelism และ model parallelism มีความสำคัญสำหรับการจัดการความต้องการหน่วยความจำระหว่างการฝึกอบรมหรือการปรับให้เหมาะสมของโมเดลภาษาขนาดใหญ่
การบริโภคหน่วยความจำสูงสุดระหว่างการปรับให้เหมาะสมมักจะสูงกว่าการอนุมาน 3-4 เท่า เนื่องจากต้องการหน่วยความจำเพิ่มเติมสำหรับ:
- เกรเดียนต์
- สถานะของออปติมाइเซอร์
- แอคติเวชันจากกระบวนการไปข้างหน้าที่เก็บไว้สำหรับการย้อนกลับ
การประมาณการที่ระมัดระวังคือการปรับให้เหมาะสมของ LLM ที่มีพารามิเตอร์ X พันล้านต้องการประมาณ 4 * (2X) = 8X GB ของ VRAM ในความแม่นยำ bfloat16
ตัวอย่างเช่น การปรับให้เหมาะสมของโมเดล LLaMA ที่มีพารามิเตอร์ 7B จะต้องการประมาณ 7 * 8 = 56GB ของ VRAM ต่อ GPU ในความแม่นยำ bfloat16 ซึ่งเกินความจุหน่วยความจำของ GPU ในปัจจุบัน ทำให้ต้องใช้เทคนิคการปรับให้เหมาะสมแบบกระจาย
เทคนิคการปรับให้เหมาะสมแบบกระจาย
มีเทคนิคการปรับให้เหมาะสมแบบกระจายหลายวิธีที่ได้ถูกเสนอเพื่อเอาชนะข้อจำกัดหน่วยความจำของ GPU สำหรับโมเดลขนาดใหญ่:
- การขนานข้อมูล: วิธีการขนานข้อมูลแบบดั้งเดิมซึ่งทำซ้ำโมเดลทั้งหมดบน GPU หลายตัวในขณะที่แบ่งและกระจายชุดข้อมูลการฝึกอบรม
- ZeRO Stage 3: รูปแบบขนานข้อมูลที่ซับซ้อนซึ่งแบ่งพารามิเตอร์ของโมเดล เกรเดียนต์ และสถานะของออปติมाइเซอร์บน GPU
- การขนานเทนเซอร์: แทนที่จะทำซ้ำโมเดล การขนานเทนเซอร์แบ่งพารามิเตอร์ของโมเดลออกเป็นแถวหรือคอลัมน์และกระจายบน GPU
- การขนานไปเป็น: เทคนิคนี้แบ่งโมเดลออกเป็นชั้นบน GPU/คนงานที่แตกต่างกัน โดยมีแต่ละอุปกรณ์ทำงานบนชุดย่อยของชั้น
การประมาณการหน่วยความจำสำหรับวิธีการกระจายเหล่านี้ไม่ใช่เรื่องง่าย เนื่องจากการกระจายพารามิเตอร์ เกรเดียนต์ แอคติเวชัน และสถานะของออปติมाइเซอร์แตกต่างกันไปตามเทคนิค
LLMem
นักวิจัยได้เสนอ LLMem ซึ่งเป็นวิธีการที่สามารถประมาณการการใช้หน่วยความจำของ GPU ได้อย่างแม่นยำเมื่อใช้เทคนิคการปรับให้เหมาะสมแบบกระจายสำหรับโมเดลภาษาขนาดใหญ่บน GPU หลายตัว
LLMem พิจารณาปัจจัยต่างๆ เช่น การรวมพารามิเตอร์ก่อนการคำนวณ การรวบรวมเอาต์พุตในกระบวนการย้อนกลับ และกลยุทธ์การจัดสรรหน่วยความจำที่แตกต่างกันสำหรับส่วนต่างๆ ของโมเดล
ผลการทดลองแสดงให้เห็นว่า LLMem สามารถประมาณการการใช้หน่วยความจำสูงสุดของ GPU สำหรับการปรับให้เหมาะสมของ LLM บน GPU เดียวได้ด้วยอัตราความผิดพลาดสูงสุด 1.6% ซึ่งดีกว่าอัตราความผิดพลาดเฉลี่ยของ DNNMem ที่ 42.6% เมื่อใช้เทคนิคการปรับให้เหมาะสมแบบกระจายสำหรับ LLM ที่มีพารามิเตอร์มากกว่า 1 พันล้านบน GPU หลายตัว LLMem สามารถบรรลุอัตราความผิดพลาดเฉลี่ย 3.0%













