Một nhà phát triển đã phát hiện ra một nút thắt hiệu suất đáng kể trong các công cụ suy luận LLM phổ biến và tìm ra một giải pháp đơn giản đáng ngạc nhiên giúp tăng gấp đôi tốc độ xử lý. Đột phá này xuất hiện sau nhiều ngày khắc phục sự cố tại sao llama.cpp gặp khó khăn với xử lý theo lô trong khi vLLM xử lý cùng khối lượng công việc một cách dễ dàng.
Vấn đề bố cục bộ nhớ ẩn giấu
Vấn đề không nằm ở việc sử dụng GPU hay sức mạnh tính toán, mà là cách dữ liệu được sắp xếp trong bộ nhớ. Khi chạy cả llama.cpp và vLLM trên cùng card đồ họa RTX 4070, nhà phát triển nhận thấy rằng llama.cpp bắt đầu chậm lại nghiêm trọng khi xử lý 8 hoặc nhiều lời nhắc đồng thời, mặc dù việc sử dụng GPU có vẻ bình thường. Trong khi đó, vLLM xử lý cùng khối lượng công việc theo lô mà không gặp khó khăn gì.
Nguyên nhân gốc rễ nằm ở cách mỗi hệ thống tổ chức dữ liệu key-value cache trong bộ nhớ. Llama.cpp sử dụng bố cục bộ nhớ phẳng hoạt động tốt với các lời nhắc đơn lẻ nhưng tạo ra các mẫu truy cập bộ nhớ không hiệu quả khi xử lý nhiều lời nhắc cùng lúc. Điều này buộc GPU phải thực hiện các lần đọc bộ nhớ rải rác, không tuần tự, làm lãng phí băng thông quý giá.
Key-value cache: Một kỹ thuật tối ưu hóa bộ nhớ lưu trữ các giá trị attention đã tính toán trước đó để tránh tính toán lại, rất quan trọng cho suy luận mô hình ngôn ngữ hiệu quả.
So sánh Bố cục Bộ nhớ:
- Bố cục llama.cpp gốc: [sequence, head, dimension] - gây ra truy cập bộ nhớ theo bước nhảy
- Bố cục được tối ưu hóa: [head, sequence, dimension] - cho phép đọc bộ nhớ liên tục
- Cải thiện hiệu suất: Tăng tốc 2 lần với cùng các phép toán
Giải pháp đơn giản thay đổi mọi thứ
Giải pháp liên quan đến việc định hình lại cách dữ liệu được lưu trữ trong tensor bộ nhớ. Bằng cách thay đổi bố cục từ [sequence, head, dimension] thành [head, sequence, dimension], nhà phát triển đã căn chỉnh cấu trúc dữ liệu với cách các streaming multiprocessor của GPU tự nhiên muốn truy cập bộ nhớ. Thay đổi tưởng chừng nhỏ này cho phép đọc bộ nhớ hoàn toàn kết hợp mà không có các bước nhảy có khoảng cách.
GPU không bao giờ là nút thắt cổ chai. đó là bố cục bộ nhớ không căn chỉnh với stride truy cập dự kiến của SM.
Sự sửa đổi này đã đưa các mẫu truy cập bộ nhớ của llama.cpp gần hơn với cách tiếp cận của vLLM, sử dụng paged key-value cache với các bố cục được tối ưu hóa cho kiến trúc bộ nhớ GPU. Điều này giải thích tại sao vLLM mở rộng tốt hơn với các kích thước lô lớn hơn - nó được thiết kế từ đầu để hoạt động với cách GPU hiện đại xử lý bộ nhớ.
Streaming multiprocessors (SMs): Các đơn vị xử lý cốt lõi trong GPU NVIDIA thực hiện các phép tính song song hiệu quả nhất khi truy cập các vị trí bộ nhớ liền kề.
Hiệu suất Engine Suy luận:
Công cụ | Xử lý Batch Size | Bố cục Bộ nhớ | Mở rộng Hiệu suất |
---|---|---|---|
llama.cpp | Kém khi vượt quá batch 8 | Bố cục phẳng | Hạn chế |
vLLM | Xuất sắc | Paged KV cache | Vượt trội |
sglang | Xuất sắc | Được tối ưu hóa | Vượt trội |
Vượt ra ngoài sự thống trị của NVIDIA
Trong khi tối ưu hóa này tập trung vào phần cứng NVIDIA, cuộc thảo luận rộng hơn tiết lộ những phát triển thú vị trong bối cảnh GPU. Instinct MI300 của AMD cung cấp các đặc tính hiệu suất khác nhau với lên đến 160 TFLOPS hiệu suất FP32 kết hợp với băng thông HBM3 6 TB/s. Điều này tạo ra một ridge-point khoảng 27 FLOP mỗi byte, gấp khoảng đôi so với A100 của NVIDIA ở mức 13 FLOP mỗi byte.
Tuy nhiên, lợi thế hệ sinh thái phần mềm của NVIDIA vẫn mạnh mẽ. Mặc dù có thông số kỹ thuật phần cứng cạnh tranh và các tùy chọn bộ nhớ trên gói lớn hơn (128-256 GB) của AMD, việc thiếu các công cụ phần mềm trưởng thành vẫn giữ hầu hết các nhà phát triển trong hệ sinh thái của NVIDIA.
Đặc điểm hiệu năng GPU:
- NVIDIA A100: điểm ridge 13 FLOPs/byte
- AMD Instinct MI300: điểm ridge 27 FLOPs/byte, 160 TFLOPS FP32, băng thông HBM3 ~6 TB/s
- Dung lượng bộ nhớ: AMD cung cấp 128-256 GB trên package so với các cấu hình nhỏ hơn của NVIDIA
Bức tranh toàn cảnh
Khám phá này làm nổi bật một bài học quan trọng cho các nhà phát triển AI: các nút thắt hiệu suất thường ẩn giấu ở những nơi không ngờ tới. Trong khi các biểu đồ sử dụng GPU có thể trông hoàn hảo, giới hạn thực sự có thể ẩn nấp trong các mẫu truy cập bộ nhớ hoặc lựa chọn bố cục dữ liệu. Quá trình gỡ lỗi hai ngày dẫn đến đột phá này cho thấy tầm quan trọng của việc nhìn xa hơn các chỉ số bề mặt khi tối ưu hóa khối lượng công việc AI.
Trải nghiệm của nhà phát triển cũng chứng minh giá trị của việc so sánh các engine suy luận khác nhau. Bằng cách chạy cùng khối lượng công việc trên cả llama.cpp và vLLM, họ có thể xác định rằng vấn đề không phải là bản chất của phần cứng hay chính nhiệm vụ, mà là cách một công cụ tổ chức các cấu trúc dữ liệu của nó.