Mô hình và nền tảng AI
Tối ưu hóa Bộ nhớ cho Sự suy luận và Điều chỉnh Mô hình Ngôn ngữ Lớn
Các mô hình ngôn ngữ lớn (LLM) như GPT-4, Bloom và LLaMA đã đạt được khả năng đáng kể bằng cách mở rộng quy mô lên hàng tỷ tham số. Tuy nhiên, việc triển khai các mô hình khổng lồ này cho suy luận hoặc điều chỉnh là một thách thức do nhu cầu bộ nhớ khổng lồ của chúng. Trong bài viết kỹ thuật này, chúng tôi sẽ khám phá các kỹ thuật để ước tính và tối ưu hóa tiêu thụ bộ nhớ trong quá trình suy luận và điều chỉnh LLM trên các thiết lập phần cứng khác nhau.
Hiểu về Yêu cầu Bộ nhớ
Bộ nhớ cần thiết để tải một LLM chủ yếu được xác định bởi số lượng tham số và độ chính xác số được sử dụng để lưu trữ các tham số. Một quy tắc đơn giản là:
- Tải một mô hình với X tỷ tham số yêu cầu khoảng 4X GB VRAM ở độ chính xác 32-bit float
- Tải một mô hình với X tỷ tham số yêu cầu khoảng 2X GB VRAM ở độ chính xác 16-bit bfloat16/float16
Ví dụ, tải mô hình GPT-3 với 175 tỷ tham số sẽ yêu cầu khoảng 350GB VRAM ở độ chính xác bfloat16. Hiện tại, các GPU lớn nhất có sẵn trên thị trường như NVIDIA A100 và H100 chỉ cung cấp 80GB VRAM, đòi hỏi phải sử dụng các kỹ thuật song song tensor và mô hình.
Trong quá trình suy luận, dấu chân bộ nhớ được thống trị bởi các tham số mô hình và các tensor kích hoạt tạm thời được tạo ra. Một ước tính cao cấp cho sử dụng bộ nhớ đỉnh trong suy luận là tổng của bộ nhớ cần thiết để tải các tham số mô hình và bộ nhớ cho các kích hoạt.
Quantifying Inference Memory
Hãy lượng hóa nhu cầu bộ nhớ cho suy luận bằng cách sử dụng mô hình OctoCode, có khoảng 15 tỷ tham số ở định dạng bfloat16 (~ 31GB). Chúng tôi sẽ sử dụng Thư viện Transformers để tải mô hình và tạo văn bản:
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline import 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 = "Câu hỏi: Hãy viết một hàm Python để chuyển đổi byte sang gigabyte.\n\nĐáp á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())
Kết quả:
29.0260648727417Sử dụng bộ nhớ đỉnh trên GPU là khoảng 29GB, phù hợp với ước tính của chúng tôi là 31GB để tải các tham số mô hình ở định dạng bfloat16.
Tối ưu hóa Bộ nhớ Suy luận với Quantization
Mặc dù bfloat16 là độ chính xác phổ biến được sử dụng để đào tạo LLM, các nhà nghiên cứu đã tìm thấy rằng việc định lượng hóa trọng số mô hình xuống độ chính xác thấp hơn như 8-bit hoặc 4-bit có thể giảm đáng kể nhu cầu bộ nhớ với tổn thất độ chính xác tối thiểu cho các nhiệm vụ suy luận như tạo văn bản.
Hãy xem xét tiết kiệm bộ nhớ từ định lượng hóa 8-bit và 4-bit của mô hình OctoCode:
&lt;/div&gt; # Định lượng hóa 8-bit 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>
Kết quả:
15.219234466552734# Định lượng hóa 4-bit 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())
Kết quả:
9.543574333190918Với định lượng hóa 8-bit, nhu cầu bộ nhớ giảm từ 31GB xuống 15GB, trong khi định lượng hóa 4-bit giảm thêm xuống chỉ 9,5GB! Điều này cho phép chạy mô hình OctoCode 15 tỷ tham số trên các GPU tiêu dùng như RTX 3090 (24GB VRAM).
Tuy nhiên, lưu ý rằng định lượng hóa hung hăng hơn như 4-bit đôi khi có thể dẫn đến suy giảm độ chính xác so với độ chính xác 8-bit hoặc bfloat16. Có một sự cân bằng giữa tiết kiệm bộ nhớ và độ chính xác mà người dùng nên đánh giá cho trường hợp của họ.
Định lượng hóa là một kỹ thuật mạnh mẽ có thể cho phép triển khai LLM trên các môi trường có tài nguyên hạn chế như các thể hiện đám mây, thiết bị biên hoặc thậm chí điện thoại di động bằng cách giảm đáng kể dấu chân bộ nhớ.
Ước tính Bộ nhớ cho Điều chỉnh Mô hình
Mặc dù định lượng hóa chủ yếu được sử dụng cho suy luận hiệu quả, các kỹ thuật như song song tensor và mô hình là rất quan trọng để quản lý nhu cầu bộ nhớ trong quá trình đào tạo hoặc điều chỉnh mô hình ngôn ngữ lớn.
Sử dụng bộ nhớ đỉnh trong quá trình điều chỉnh thường cao hơn 3-4 lần so với suy luận do nhu cầu bộ nhớ bổ sung cho:
- Độ dốc
- Trạng thái tối ưu hóa
- Kích hoạt từ quá trình chuyển tiếp được lưu trữ cho quá trình ngược
Một ước tính thận trọng là điều chỉnh mô hình LLM với X tỷ tham số yêu cầu khoảng 4 * (2X) = 8X GB VRAM ở độ chính xác bfloat16.
Ví dụ, điều chỉnh mô hình LLaMA 7 tỷ tham số sẽ yêu cầu khoảng 7 * 8 = 56GB VRAM trên mỗi GPU ở độ chính xác bfloat16. Điều này vượt quá khả năng chứa bộ nhớ của các GPU hiện tại, đòi hỏi phải sử dụng các kỹ thuật điều chỉnh phân tán.
Kỹ thuật Điều chỉnh Phân tán
Một số phương pháp điều chỉnh phân tán đã được đề xuất để vượt qua các hạn chế về bộ nhớ GPU cho các mô hình lớn:
- Đồng song song Dữ liệu: Phương pháp đồng song song dữ liệu cổ điển nhân bản toàn bộ mô hình trên nhiều GPU trong khi chia và phân phối các lô dữ liệu đào tạo. Điều này giảm thời gian đào tạo tuyến tính với số lượng GPU nhưng không giảm nhu cầu bộ nhớ đỉnh trên mỗi GPU.
- Giai đoạn ZeRO 3: Một hình thức nâng cao của đồng song song dữ liệu, phân vùng các tham số mô hình, độ dốc và trạng thái tối ưu hóa trên các GPU. Nó giảm bộ nhớ so với đồng song song dữ liệu cổ điển bằng cách chỉ giữ dữ liệu phân vùng cần thiết trên mỗi GPU trong các giai đoạn đào tạo khác nhau.
- Đồng song song Tensor: Thay vì nhân bản mô hình, đồng song song tensor chia các tham số mô hình thành hàng hoặc cột và phân phối chúng trên các GPU. Mỗi GPU hoạt động trên một tập hợp phân vùng của các tham số, độ dốc và trạng thái tối ưu hóa, dẫn đến tiết kiệm bộ nhớ đáng kể.
- Đồng song song Dòng ống: Kỹ thuật này phân vùng các lớp mô hình trên các GPU/làm việc khác nhau, với mỗi thiết bị thực hiện một tập hợp con của các lớp. Các kích hoạt được truyền giữa các công nhân, giảm bộ nhớ đỉnh nhưng tăng thêm tải trọng truyền thông.
Ước tính sử dụng bộ nhớ cho các phương pháp phân tán này không đơn giản vì sự phân phối của các tham số, độ dốc, kích hoạt và trạng thái tối ưu hóa khác nhau giữa các kỹ thuật. Hơn nữa, các thành phần khác nhau như thân chuyển đổi và đầu mô hình ngôn ngữ có thể hiển thị các hành vi phân bổ bộ nhớ khác nhau.
Giải pháp LLMem
Các nhà nghiên cứu gần đây đã đề xuất LLMem, một giải pháp ước tính chính xác nhu cầu bộ nhớ GPU khi áp dụng các phương pháp điều chỉnh phân tán cho LLM trên nhiều GPU.
LLMem xem xét các yếu tố như tái kết hợp các tham số trước khi tính toán (Giai đoạn ZeRO 3), thu thập đầu ra trong quá trình ngược (đồng song song tensor) và các chiến lược phân bổ bộ nhớ khác nhau cho thân chuyển đổi và đầu mô hình ngôn ngữ.
Kết quả thực nghiệm cho thấy LLMem có thể ước tính sử dụng bộ nhớ GPU đỉnh cho điều chỉnh mô hình LLM trên một GPU đơn với tỷ lệ lỗi lên đến 1,6%, vượt qua tỷ lệ lỗi trung bình của DNNMem là 42,6%. Khi áp dụng các phương pháp điều chỉnh phân tán cho LLM với hơn một tỷ tham số trên nhiều GPU, LLMem đạt được tỷ lệ lỗi trung bình ấn tượng là 3,0%.













