Tối ưu hóa hiệu suất inference với vLLM trên GPU đơn lẻ
Trong kỷ nguyên bùng nổ của các mô hình ngôn ngữ lớn (LLM), việc triển khai các mô hình này trên phần cứng hạn chế là một thách thức không nhỏ đối với các kỹ sư hệ thống và nhà phát triển. Một trong những vấn đề phổ biến nhất là tốc độ xử lý đầu vào (token/sec) thấp và độ trễ cao khi chỉ sử dụng một card đồ họa (GPU) để chạy các mô hình nặng như Llama-3 hoặc Mistral. Bài viết này sẽ phân tích sâu về giải pháp vLLM, một framework inference hiệu suất cao, và hướng dẫn chi tiết cách thiết lập nó để đạt được thông số tối ưu trên một server tiêu chuẩn chỉ có một GPU, so sánh trực tiếp với các phương pháp truyền thống.
Tại sao chọn vLLM thay vì Ollama cho workload hiệu suất cao?
Để hiểu rõ lý do nên ưu tiên vLLM trong các trường hợp cần thông lượng lớn, chúng ta cần nhìn vào cơ chế quản lý bộ nhớ. Ollama, mặc dù rất tiện lợi cho việc cài đặt nhanh và chạy cục bộ, chủ yếu dựa trên backend llama.cpp. Điểm mạnh của llama.cpp là khả năng nén mô hình xuống định dạng lượng tử hóa (quantization) rất tốt để chạy trên RAM hệ thống hoặc CPU, nhưng nó lại thiếu các kỹ thuật tối ưu hóa tiên tiến cho GPU như PagedAttention. Ngược lại, vLLM được thiết kế từ đầu để khai thác tối đa băng thông bộ nhớ của GPU. Kỹ thuật PagedAttention giúp vLLM quản lý bộ nhớ ngữ cảnh (KV cache) theo từng trang, tương tự như cách hệ điều hành quản lý bộ nhớ RAM, giúp giảm thiểu tình trạng phân mảnh bộ nhớ (memory fragmentation). Điều này cho phép vLLM phục vụ nhiều yêu cầu đồng thời (concurrent requests) với hiệu suất ổn định hơn nhiều so với các thư viện truyền thống như Hugging Face Transformers hoặc llama.cpp khi xử lý các ngữ cảnh dài.
Thiết lập môi trường và cài đặt vLLM tối thiểu
Bước đầu tiên để triển khai vLLM là chuẩn bị môi trường Python sạch sẽ, ưu tiên sử dụng conda để quản lý các phiên bản PyTorch tương thích với CUDA. Chúng ta cần đảm bảo rằng driver CUDA trên máy đã được cập nhật mới nhất. Sau đó, hãy tạo một môi trường ảo và cài đặt các gói cần thiết. Lưu ý quan trọng là vLLM yêu cầu phiên bản PyTorch tương thích với phiên bản CUDA đang chạy, do đó việc sử dụng lệnh cài đặt chính thức từ vLLM là bắt buộc để đảm bảo các thành phần C++ tối ưu hóa được biên dịch đúng cách.
Để bắt đầu, hãy mở terminal và thực hiện các lệnh sau để tạo môi trường conda với Python 3.10, phiên bản Python được hỗ trợ tốt nhất cho hầu hết các thư viện AI hiện nay. Sau khi kích hoạt môi trường, chúng ta sẽ cài đặt vLLM với tùy chọn flash-attn nếu GPU của bạn hỗ trợ (thường là RTX 3090, 4090 hoặc A100 trở lên). Flash-attn là một thư viện tối ưu hóa cực kỳ quan trọng giúp tăng tốc độ attention mechanism, nhưng nếu bạn đang dùng GPU đời cũ hơn hoặc không có flash-attn, vLLM vẫn có thể chạy với hiệu suất tốt nhưng không bằng.
conda create -n vllm_env python=3.10 -y
conda activate vllm_env
pip install vllm
Nếu bạn muốn cài đặt với flash-attn2 để đạt hiệu suất cực đại trên GPU mới, hãy sử dụng lệnh sau. Tuy nhiên, hãy cẩn thận kiểm tra phiên bản CUDA trước khi chạy lệnh này để tránh lỗi build.
pip install vllm --no-deps && pip install flash-attn --no-build-isolation
Triển khai mô hình Llama-3 với cấu hình GPU đơn
Sau khi cài đặt xong, bước tiếp theo là tải và chạy mô hình. Chúng ta sẽ sử dụng mô hình Meta-Llama-3-8B-Instruct vì đây là một trong những mô hình cân bằng nhất giữa chất lượng và yêu cầu tài nguyên, hoàn toàn chạy vừa trên một card GPU 24GB như RTX 3090. Để tận dụng tối đa bộ nhớ GPU, chúng ta cần cấu hình tham số `max_model_len` và `gpu_memory_utilization`. Tham số `gpu_memory_utilization` cho phép vLLM tự động ước lượng và sử dụng phần lớn bộ nhớ GPU (mặc định là 0.9) để lưu trữ model weights và KV cache. Việc tăng con số này lên 0.95 trên GPU đơn lẻ có thể giúp bạn xử lý nhiều request hơn nhưng cần cẩn trọng để không gây tràn bộ nhớ (OOM).
Để khởi động server inference của vLLM, chúng ta sẽ sử dụng lệnh CLI trực tiếp. Lệnh này sẽ tải mô hình từ Hugging Face Hub, khởi động một HTTP server và sẵn sàng nhận request dưới dạng REST API. Chúng ta sẽ đặt `max-model-len` thành 8192 để hỗ trợ ngữ cảnh dài hơn so với mặc định 2048, và thiết lập `tensor-parallel-size` bằng 1 vì chúng ta chỉ có một GPU. Nếu bạn muốn thử nghiệm với nhiều GPU, con số này sẽ được tăng lên tương ứng, nhưng trong bài hướng dẫn này chúng ta tập trung vào hiệu quả của một GPU đơn.
vllm serve meta-llama/Meta-Llama-3-8B-Instruct --max-model-len 8192 --gpu-memory-utilization 0.95 --tensor-parallel-size 1
Server sẽ khởi động và chờ đợi yêu cầu tại địa chỉ localhost trên port 8000. Bạn có thể kiểm tra trạng thái bằng cách gửi một request đơn giản qua curl để xác nhận model đã được tải thành công và sẵn sàng phản hồi.
curl -X POST http://localhost:8000/v1/completions -H "Content-Type: application/json" -d '{ "model": "meta-llama/Meta-Llama-3-8B-Instruct", "prompt": "Giải thích vLLM là gì?", "max_tokens": 200 }'
Phân tích hiệu năng và tối ưu hóa thêm
Khi server đã chạy, bạn có thể quan sát thấy sự khác biệt rõ rệt về tốc độ. Với vLLM, thời gian để sinh ra token đầu tiên (TTFT - Time to First Token) thường rất nhanh, và tốc độ sinh token (tokens per second) ổn định ngay cả khi xử lý nhiều yêu cầu song song. Điều này là nhờ cơ chế PagedAttention đã đề cập ở trên. Nếu bạn muốn đưa hệ thống này vào môi trường production thực tế, bạn nên kết hợp vLLM với một load balancer như Nginx hoặc Envoy để phân phối traffic, và sử dụng OpenTelemetry để giám sát các chỉ số hiệu suất. Ngoài ra, việc sử dụng định dạng lượng tử hóa như AWQ hoặc GPTQ thông qua vLLM cũng là một lựa chọn tuyệt vời để giảm nhu cầu bộ nhớ GPU xuống còn một nửa, cho phép bạn chạy các mô hình lớn hơn (như 70B) trên một GPU 24GB, dù tốc độ có thể giảm nhẹ nhưng vẫn khả thi hơn nhiều so với các framework khác.
Tổng kết lại, việc chuyển từ các phương pháp inference truyền thống sang vLLM trên GPU đơn lẻ là một bước tiến quan trọng để nâng cao hiệu suất hệ thống AI. Bằng cách tận dụng PagedAttention và quản lý bộ nhớ thông minh, bạn có thể khai thác tối đa phần cứng hiện có, giảm độ trễ và tăng thông lượng phục vụ người dùng. Hãy thử nghiệm các tham số khác nhau như `max-num-seq-token` hoặc `max-num-batched-token` để điều chỉnh hành vi của server cho phù hợp với use case cụ thể của bạn, và bạn sẽ thấy vLLM thực sự là một công cụ mạnh mẽ trong tay của các kỹ sư phần mềm hiện đại.