DeepGEMM: kernel FP8 GEMM sạch và hiệu quả nhờ scaling chi tiết
(github.com/deepseek-ai)- DeepGEMM là thư viện kernel tensor core hiệu năng cao, gom các primitive tính toán cốt lõi của LLM hiện đại như GEMM, fused MoE, MQA scoring, HyperConnection... vào một codebase CUDA duy nhất
- Tất cả kernel được biên dịch lúc chạy bằng mô-đun JIT gọn nhẹ; không cần biên dịch CUDA khi cài đặt và yêu cầu C++20, CUDA Toolkit, PyTorch, CUTLASS 4.0 trở lên
- Dù tận dụng một số khái niệm của CUTLASS và CuTe, thư viện không phụ thuộc nặng vào template hay cấu trúc đại số, và được thiết kế để việc học tối ưu hóa kernel NVIDIA GPU dễ tiếp cận hơn thông qua số lượng hàm kernel cốt lõi giới hạn
- Phạm vi hỗ trợ bao gồm FP8, FP4, BF16 GEMM, grouped GEMM, kernel MQA logits cho DeepSeek v3.2, đến Mega MoE chồng lấp giao tiếp và tính toán; các ràng buộc về layout bộ nhớ khác nhau giữa SM90 và SM100
- Dù thiết kế gọn nhẹ, thư viện hướng tới hiệu năng ngang bằng hoặc cao hơn các thư viện được tinh chỉnh chuyên sâu trên nhiều shape ma trận, và có bản cập nhật đạt tối đa 1550 TFLOPS trên H800
Mục tiêu và thiết kế của DeepGEMM
- DeepGEMM là thư viện kernel tensor core tích hợp các primitive tính toán chính dùng trong các mô hình ngôn ngữ lớn hiện đại vào một codebase CUDA duy nhất
- GEMM: FP8, FP4, BF16
- fused MoE chồng lấp giao tiếp: Mega MoE
- MQA scoring cho lightning indexer
- HyperConnection(HC)
- Tất cả kernel được biên dịch lúc chạy dưới dạng mô-đun Just-In-Time(JIT) gọn nhẹ
- Không cần biên dịch CUDA trong quá trình cài đặt
- Tận dụng một số khái niệm của CUTLASS và CuTe
- Tuy nhiên không phụ thuộc nhiều vào template nặng hay cấu trúc đại số
- Giữ codebase đơn giản bằng cách giới hạn số lượng hàm kernel cốt lõi
- Dù có thiết kế gọn nhẹ, dự án cho biết có thể đạt hiệu năng ngang bằng hoặc cao hơn các thư viện được tinh chỉnh chuyên sâu trên nhiều shape ma trận
Các cập nhật chính
- Bản cập nhật ngày 16/4/2026 bao gồm Mega MoE, FP8xFP4 GEMM, FP4 Indexer, PDL, biên dịch JIT nhanh hơn...
- Bản cập nhật ngày 28/9/2025 bổ sung kernel scoring weighted ReLU MQA logits cho DeepSeek v3.2 lightning indexer
- Chi tiết tại #200
- Bản cập nhật ngày 20/7/2025 hỗ trợ cả SM90 và SM100, đồng thời refactor toàn bộ sang mô-đun JIT CPP có overhead CPU thấp
- NVRTC và tối ưu hóa SASS sau biên dịch bị vô hiệu hóa
- NVRTC được đánh dấu là sẽ được hỗ trợ sau
- Do NVCC 12.9 tự động thực hiện FFMA interleaving, tối ưu hóa sau biên dịch không còn được hỗ trợ
- Chi tiết tại #112
- Bản cập nhật ngày 14/5/2025 bổ sung kernel weight gradient cho dense và MoE backward
- Chi tiết tại #95
- Bản cập nhật ngày 7/5/2025 cung cấp tốc độ biên dịch nhanh hơn tới 10 lần nhờ hỗ trợ NVRTC
- Có thể bật bằng
DG_JIT_USE_NVRTC=1 - Trong một số trường hợp có thể bị giảm hiệu năng
- Chi tiết tại #94
- Có thể bật bằng
- Bản cập nhật ngày 18/4/2025 đạt tối đa 1550 TFLOPS trên H800
Yêu cầu và quy trình cài đặt
- Môi trường chạy yêu cầu GPU kiến trúc NVIDIA SM90 hoặc SM100
- Yêu cầu phần mềm như sau
- Python 3.8 trở lên
- Trình biên dịch hỗ trợ C++20
- CUDA Toolkit
- SM90: CUDA 12.3 trở lên
- Khuyến nghị mạnh CUDA 12.9 trở lên để đạt hiệu năng cao nhất
- SM100: CUDA 12.9 trở lên
- PyTorch 2.1 trở lên
- CUTLASS 4.0 trở lên
- Thư viện
{fmt}
- Trong môi trường phát triển, clone repository kèm submodule rồi chạy
develop.shđể liên kết các include cần thiết và build mô-đun CPP JIT - Cài đặt bằng cách chạy
install.sh, sau đó importdeep_gemmtrong dự án Python
Giao diện GEMM và ràng buộc layout
- Quy ước đặt tên kernel GEMM của DeepGEMM là
D = C + A @ B - Layout shape đầu vào dựa trên NT
fp8_gemm_ntthực hiệnD = C + A @ B.T
- Triển khai SM90 chỉ hỗ trợ layout bộ nhớ NT
- Tương ứng với tổ hợp row-major, col-major
- Triển khai SM100 hỗ trợ toàn bộ các layout bộ nhớ NT, TN, NN, TT
- Trên cả hai kiến trúc, LHS scaling factor phải được căn chỉnh TMA và ở layout đã transpose
- SM90 yêu cầu scaling factor ở định dạng FP32
- SM100 yêu cầu định dạng packed UE8M0, đóng gói 4 UE8M0 vào một
torch.int
- Các tác vụ như transpose đầu vào hoặc cast sang FP8 cần được người dùng xử lý riêng
- Thư viện cung cấp các hàm tiện ích PyTorch đơn giản nhưng có thể chậm
- Trọng tâm chính là tối ưu hóa kernel GEMM
Dense và Grouped GEMM
- FP8 GEMM non-grouped cơ bản dùng các hàm
fp8_gemm_{nt, nn, tn, tt} - Grouped GEMM với contiguous layout chỉ group theo trục M, khác với grouped GEMM truyền thống của CUTLASS
- N và K phải cố định
- Thiết kế này phù hợp với trường hợp các expert trong mô hình MoE dùng chung shape
- Trong training forward pass hoặc inference prefilling, số token được xử lý bởi mỗi expert có thể khác nhau
- Dạng nối các token này thành một tensor duy nhất được gọi là contiguous layout
- Mỗi segment expert phải được căn chỉnh theo GEMM M block size
- Có thể kiểm tra tiêu chí căn chỉnh bằng
get_mk_alignment_for_contiguous_layout()
- Cũng cung cấp API grouped theo trục K cho MoE weight backward
- M và N phải cố định
- Hàm liên quan là
k_grouped_fp8_gemm_tn_contiguous
- Ở giai đoạn inference decoding, khi CUDA graph được bật và CPU không thể biết số token theo từng expert, thư viện hỗ trợ masked grouped GEMM
- Nếu cung cấp mask tensor, kernel chỉ tính vùng hợp lệ
- Hàm là
m_grouped_fp8_gemm_nt_masked - Có ví dụ dùng output của kernel low-latency từ DeepEP làm input
Kernel MQA cho DeepSeek v3.2 Indexer
- Họ kernel V3.2 MQA cung cấp phiên bản non-paged và paged
- non-paged dùng cho prefilling
- paged dùng cho decoding
fp8_mqa_logitsnhận 6 inputq: tensor E4M3, shape[seq_len, num_heads, head_dim]kv: tensor E4M3 và float scaling factor- shape tensor là
[seq_len_kv, head_dim] - shape scaling factor là
[seq_len_kv]
- shape tensor là
weights: tensor float, shape[seq_len, num_heads]cu_seq_len_k_start,cu_seq_len_k_end: tensor int, shape[seq_len]clean_logits: có dọn các logits chưa được lấp đầy thành-infhay không
- Shape tensor output là
[seq_len, seq_len_kv]và biểu diễn token-to-token logits - Mỗi
qtokeniduyệt qua cáckvtokenjtừcu_seq_len_k_start[i]đến trướccu_seq_len_k_end[i]- Nhân
kv_jvới scaling factor - Tính giá trị theo từng head bằng
q[i, :, :] @ kv_j - Sau khi áp dụng ReLU, nhân với
weights[i, :]rồi cộng lại để tạo scalar logit
- Nhân
- Hàm phiên bản paged là
fp8_paged_mqa_logits
Mega MoE
- Mega MoE fuse nhiều bước MoE vào một mega-kernel
- EP dispatch
- linear 1, FP8xFP4
- SwiGLU
- linear 2, FP8xFP4
- EP combine
- Mega MoE overlap giao tiếp NVLink với tính toán tensor core
- Việc chạy yêu cầu multi-process launch dùng symmetric memory
- Quy trình sử dụng như sau
- Cấp phát symmetric memory buffer bằng
deep_gemm.get_symm_buffer_for_mega_moe- Yêu cầu PyTorch 2.9 trở lên
- Chuyển đổi weight gồm FP4 và UE8M0 SF sang layout yêu cầu bằng
deep_gemm.transform_weights_for_mega_moe - Trước khi gọi, sao chép input, scaling factor, top-k index, top-k weight vào buffer
- Chạy kernel fused mega MoE bằng
deep_gemm.fp8_fp4_mega_moe
- Cấp phát symmetric memory buffer bằng
- Thiết lập multi-process đầy đủ và ví dụ benchmark nằm trong
tests/test_mega_moe.py
Tiện ích và biến môi trường
- Các hàm tiện ích chính kiểm soát tài nguyên chạy, căn chỉnh, biên dịch JIT và chuyển đổi scaling factor
deep_gemm.set_num_sms/get_num_sms: đặt và truy vấn số SM tối đa sẽ dùngdeep_gemm.set_tc_util/get_tc_util: đặt và truy vấn tỷ lệ tensor core utilization xấp xỉdeep_gemm.set_pdl/get_pdl: bật và tắt Programmatic Dependent Launch(PDL)deep_gemm.set_mk_alignment_for_contiguous_layout/get_mk_alignment_for_contiguous_layout: đặt và truy vấn group-level M/K alignment của contiguous layoutdeep_gemm.transform_sf_into_required_layout: chuyển scaling factor sang layout yêu cầudeep_gemm.get_tma_aligned_size: truy vấn kích thước TMA alignment cần thiết
- Các biến môi trường liên quan đến JIT kiểm soát output debug, vị trí cache, lựa chọn compiler và tùy chọn profiling
DG_JIT_DEBUG: xuất thông tin debug JITDG_PRINT_CONFIGS: xuất config được chọn theo từng shapeDG_JIT_CACHE_DIR: thư mục cache kernel đã biên dịch, mặc định là$HOME/.deep_gemmDG_JIT_USE_NVRTC: dùng NVRTC thay cho NVCC, cho phép biên dịch nhanh nhưng trong một số trường hợp hiệu năng có thể thấp hơnDG_JIT_NVCC_COMPILER: đường dẫn compiler NVCCDG_JIT_CPP_STANDARD: phiên bản chuẩn C++, mặc định là20
- Cũng cung cấp các biến môi trường debug và profiling
DG_JIT_DUMP_ASM,DG_JIT_DUMP_PTX,DG_JIT_DUMP_SASS: dump output PTX và SASSDG_JIT_WITH_LINEINFO: bao gồm thông tin source line cho công cụ profilingDG_COMM_KERNEL_DEBUG: khởi tạo symmetric buffer về 0 trước khi gọi Mega MoEDG_USE_NVIDIA_TOOLS: bỏ qua profiling nội bộ khi chạy công cụ NVIDIA bên ngoài
- Tùy chọn build kiểm soát cách cài đặt và tải kernel
DG_SKIP_CUDA_BUILD: bỏ qua CUDA extension build trong khi cài đặtDG_FORCE_BUILD: buộc build cục bộ thay vì tải pre-built wheelDG_JIT_USE_RUNTIME_API: dùng CUDA Runtime API để tải kernel, yêu cầu CUDA runtime 12.8 trở lên
Giấy phép và trích dẫn
- Repository DeepGEMM được phát hành theo MIT License
- Dự án cho biết được truyền cảm hứng từ CUTLASS
- Tiêu đề mục trích dẫn là
DeepGEMM: clean and efficient BLAS kernel library on GPU
1 bình luận
Ý kiến trên Hacker News
Interleaving FFMA SASS trông thật sự đáng kinh ngạc
Có vẻ như khi thấy hiệu năng kernel CUTLASS FP8 được cải thiện giữa NVCC 12.2 và 12.3, họ đã so sánh SASS đã biên dịch và phát hiện một bit trong nhiều lệnh FADD bị đảo theo mẫu interleaving; rồi tham khảo triển khai CUDA assembler mã nguồn mở để xác định bit đó là yield bit, cho phép warp hiện tại nhường quyền để warp khác chạy
Ấn tượng ở chỗ họ đã tận dụng điều này để tạo một script sửa các lệnh FFMA trong binary đã biên dịch; không chỉ yield bit mà cả reuse bit cũng được đảo cùng lúc, vì khi warp nhường quyền thì không thể tái sử dụng thanh ghi, nhờ đó các lệnh MMA và các lệnh FFMA thăng cấp trong FP8 GEMM với scaling tinh vi chồng lấp tốt hơn, tăng hiệu năng hơn 10% trong một số trường hợp
Chỉ là với vấn đề cụ thể này, có vẻ các công ty AI khác chưa thấy cần thiết nên chưa áp dụng; cuối cùng nhiều khả năng mọi người cũng sẽ đi tới những điểm tương tự
Những trường hợp như thế này cho thấy các trình biên dịch hiện nay còn cách rất xa việc khai thác hiệu năng phần cứng chỉ bằng mã cấp cao
Tôi tự hỏi cần những gì để các kỹ thuật biên dịch truyền thống hoặc các agent tối ưu hóa dựa trên AI tạo ra được kết quả như vậy
Con số tăng tốc được báo cáo là so với baseline tự xây dựng dựa trên CUTLASS
Tôi tò mò không biết đã có ai so sánh hiệu năng trực tiếp với cuBLAS chưa
Các kết quả CUTLASS GEMM tôi từng thấy cho tới nay thường trong khoảng 10% so với cuBLAS; nếu mức cải thiện 2x~2,5x như bài viết nói vẫn giữ được thì sẽ thật sự ấn tượng
Trước hết, cuBLAS cần API mở rộng cuBLASLt để xử lý các tác vụ mixed precision như FP8
Ngoài ra, nó không hỗ trợ các tổ hợp kiểu tưởng như phù hợp như E5M2 x E5M2 trong A x B, nhưng có hỗ trợ E5M2 x E4M3; và các ràng buộc vẫn tiếp diễn, chẳng hạn trên Ampere, Hopper, Blackwell, ma trận A luôn phải ở layout đã chuyển vị
Tôi đã tích hợp benchmark FP8 cuBLASLt vào repo "Less Slow C++" của mình <https://github.com/ashvardanian/less_slow.cpp>, và thêm nó vào danh sách benchmark cuBLAS hiện có cùng các benchmark CUDA/PTX tự viết
Tôi đang chạy trên GPU H200, vốn đáng lẽ có hiệu năng tương đương H100; với đầu vào vuông, throughput đạt đỉnh khoảng 1,35 Peta-ops
256 là 2,68T/s, 512 là 20,49T/s, 1024 là 144,23T/s, 2048 là 665,68T/s, 4096 là 1,26P/s, 8192 là 1,34P/s, 16384 là khoảng 1,23P/s; con số này bằng khoảng 67% mức NVIDIA quảng bá cho dense GEMM <https://resources.nvidia.com/en-us-data-center-overview-mc/e...>
Tôi đã nghĩ baseline là chọn bên tốt hơn giữa cuBLAS và CUTLASS
Mã nguồn mở kiểu này thật sự cho thấy rất rõ mục tiêu đạt hiệu quả của ngành
Tuy nhiên, lợi ích từ phần mềm này có lẽ sẽ đến với các công ty lớn đang serving mô hình ở quy mô lớn — tức những đối thủ tiềm năng của DeepSeek — nhiều hơn là với cộng đồng mã nguồn mở phổ thông muốn học hỏi, thử nghiệm hoặc serving mô hình trên phần cứng tiêu dùng
Tôi không chắc việc tối ưu theo hướng độ chính xác ngày càng thấp có tốt về dài hạn hay không
Điều này có nghĩa là mô hình thực ra khá thưa, và dù hiện tại có thể đúng như vậy, tôi cho rằng khả năng cao là do cách huấn luyện đang trộn lẫn một số ý tưởng không hay, hơn là vì về bản chất nó phải thưa như thế
Làm sao để chỉ ở độ chính xác cao hơn mới huấn luyện được các mô hình rất tốt là một vấn đề nghiên cứu, còn huấn luyện và suy luận độ chính xác thấp là vấn đề kỹ thuật
Chúng ta đã làm việc này từ thời CNN, ít nhất là 9 năm trước, và tôi nghĩ vẫn còn vài năm nữa
Điều này có thể trở nên vô nghĩa vì MXFP, tức hỗ trợ microscaling native của Blackwell
Trên Hopper, về cơ bản họ triển khai thủ công ở mức hạt thô hơn, nhưng dùng hệ số scaling FP32
Những bản trình diễn công khai chất lượng cao như thế này cho thấy rõ hào lũy của $NVDA nằm ở đâu
GPU đa dụng rất linh hoạt, nên có thể lập trình để thực hiện nhiều tác vụ hợp lý mà nhà cung cấp phần cứng ban đầu chưa nghĩ tới
Nhưng nếu dự đoán tương lai sẽ ngày càng hội tụ về hỗ trợ phần cứng chuyên dụng hơn, khiến dư địa tối ưu phần mềm kiểu này biến mất, thì cái gọi là hào lũy CUDA sẽ sụp đổ
Để tiếp tục ở lại cuộc chơi này, NVIDIA đang tự phá bỏ hào lũy của mình :p
Chà, là giấy phép MIT
Mong các công ty lớn sẽ chấp nhận kiểu hợp tác mã nguồn mở như thế này
Tôi vẫn luôn thắc mắc vì sao lại tồn tại các lệnh không được tài liệu hóa
Dù không hoàn toàn ổn định, tôi vẫn nghĩ có lẽ nên cung cấp chúng cho người dùng
Những nội dung như vậy chắc hẳn được tài liệu hóa nội bộ, nhưng tôi không hiểu vì sao lại không công khai
Bảo mật dựa vào sự mơ hồ thì không hiệu quả, còn đối thủ cạnh tranh thì kiểu gì cũng reverse engineer hết
Có thể là do thiếu thời gian, hoặc vì không muốn ám chỉ rằng mình sẽ hỗ trợ các tính năng chưa ổn định hay còn mang tính thử nghiệm
Nếu thiệt hại chỉ dừng ở mức đội ngồi bên cạnh thì việc thay đổi cũng dễ hơn nhiều
Có khả năng cao chúng chỉ nằm trong những nơi như tài liệu thiết kế kiến trúc hoặc đặc tả, và những tài liệu như vậy thì đương nhiên họ sẽ không muốn chia sẻ
Thành thật mà nói, nội dung này vượt quá phạm vi sử dụng và hiểu biết của tôi
Dù vậy, tôi thật sự biết ơn và thấy mới mẻ khi những phát hiện và cải tiến như thế này được chia sẻ để mọi người cùng hưởng lợi
Nó rất quan trọng trong phép nhân ma trận và workload học sâu
Trong SASS của NVIDIA, lệnh FFMA được mã hóa dưới dạng lệnh 64 bit hoặc 128 bit, và có nhiều bit điều khiển xác định hành vi chính xác
Khi bit yield được đặt, nó báo cho warp scheduler rằng sau lệnh này warp hiện tại có thể nhường quyền thực thi, và phần cứng có thể chạy warp khác để che giấu độ trễ
GPU đạt thông lượng cao nhờ tính song song quy mô lớn, và khi một warp bị dừng vì chờ bộ nhớ chẳng hạn, warp khác có thể tiếp tục tiến hành
Bit reuse cho biết liệu thanh ghi nguồn có thể được tái sử dụng ngay trong phép toán kế tiếp hay không, và nếu bit yield được đặt thì nó bắt buộc phải tắt
Lý do là khi một warp nhường quyền, warp được thực thi tiếp theo có thể không phải là chính nó, và warp khác có thể thay đổi trạng thái file thanh ghi, nên phần cứng không thể bảo đảm rằng giá trị thanh ghi được giữ nguyên vượt qua điểm yield
Nếu đặt bit yield cho các lệnh FFMA theo mẫu xen kẽ, trình biên dịch sẽ tạo ra các điểm lập lịch tường minh để warp khác có thể tiến hành, và để giữ tính đúng đắn cũng phải xóa bit reuse của lệnh đó
Thay đổi này đặc biệt hữu ích cho việc chồng lấp lệnh MMA, vốn là lõi của phép nhân ma trận, với lệnh FFMA nâng cấp dùng để chuyển đổi FP8 nhằm tích lũy ở độ chính xác cao hơn
FP8 GEMM thường cần quá trình chuyển đổi sang độ chính xác cao hơn để tích lũy rồi chuyển ngược lại, tạo ra các FFMA bổ sung; điều này làm giảm yêu cầu băng thông bộ nhớ nhưng tạo nên một mẫu tính toán phức tạp xen lẫn các phép nâng cấp/hạ cấp
“Scaling tinh vi” có vẻ chỉ việc quản lý độ chính xác một cách cẩn thận ở nhiều điểm trong quá trình tính toán
Việc thao tác bit yield giúp các phép toán tính toán và chuyển đổi định dạng được interleave tốt hơn, khiến các đơn vị thực thi của GPU được dùng hiệu quả hơn; nếu không có tối ưu này, warp scheduler có thể không tìm được cơ hội chuyển đổi tự nhiên, dẫn đến tài nguyên tính toán được tận dụng kém hơn