Skip to main content

NCA-AIIO 6: GPUDirect, công cụ AI và NCCL nâng cao

Loạt NCA-AIIO (9 phần): 1. Tổng quan & GPU cơ bản · 2. CUDA & lập trình song song · 3. Container & inference serving · 4. H100, H200 & DGX · 5. Networking data center · 6. GPUDirect & NCCL · 7. Blackwell & NVL72 · 8. HGX, DGX & SuperPOD · 9. Vận hành, điện & sizing

Phần 6/9 trong loạt NCA-AIIO: đọc sau Phần 5. Lớp phần mềm nằm trên hạ tầng mạng vừa dựng: GPUDirect, TensorRT và các phép collective của NCCL.

Cập nhật: 2026-10-23

Mục lục​


1. Dữ liệu phải đi qua bao nhiêu chặng mới tới được GPU?​

Một tình huống hay gặp khi theo dõi cụm training: GPU utilization dao động quanh 40%, nhưng CPU lại chạy gần kịch trần. Nhìn qua thì tưởng thiếu GPU, thực tế là GPU đang đói dữ liệu.

Nguyên nhân nằm ở đường đi mặc định của dữ liệu. Để nạp một batch ảnh từ ổ NVMe vào bộ nhớ GPU theo cách thông thường, dữ liệu phải: đi từ ổ đĩa vào RAM hệ thống qua DMA, được CPU chép sang một vùng đệm trung gian gọi là bounce buffer, rồi mới từ đó chép tiếp vào bộ nhớ GPU. CPU tham gia vào hai trong ba chặng, và ở tốc độ hàng chục GB mỗi giây thì chính CPU trở thành nút thắt.

Chuyện tương tự xảy ra với mạng. Gửi dữ liệu từ GPU máy A sang GPU máy B theo cách thông thường cần bốn lần chép: bộ nhớ GPU sang RAM máy A, RAM sang NIC, NIC máy B sang RAM máy B, RAM sang bộ nhớ GPU.

GPUDirect là họ công nghệ xoá bỏ các chặng trung gian đó. Phần này đi qua từng thành viên của họ công nghệ này, rồi tới các công cụ phần mềm hay gặp và phần NCCL nâng cao.

💡 Hình dung như thế này: chuyển hàng từ kho ra xe tải theo cách thông thường giống việc bắt buộc mọi kiện hàng phải qua quầy thủ kho: thủ kho nhận, ghi sổ, rồi mới chuyển ra bến. Khi lượng hàng còn ít thì không sao, nhưng khi cả nghìn kiện đổ về cùng lúc thì chính cái quầy đó thành chỗ tắc, dù kho rộng và xe tải chờ sẵn. GPUDirect là việc mở một cửa riêng nối thẳng kho với bến, để hàng đi thẳng mà không ghé quầy.

2. GPUDirect, một họ công nghệ chứ không phải một sản phẩm​

NVIDIA GPUDirect gồm ba thành viên chính, phân biệt theo chỗ dữ liệu đi tới:

TênNối GPU vớiPhạm vi
GPUDirect Peer-to-PeerGPU khácTrong cùng một máy
GPUDirect RDMAGPU trên máy khác, qua NICGiữa các node
GPUDirect StorageThiết bị lưu trữỔ cục bộ hoặc qua mạng

Trong ba cái, hai cái quan trọng nhất với kỳ thi là GPUDirect RDMA và GPUDirect Storage.

Điểm chung của cả họ: bỏ bớt các lần chép qua RAM hệ thống và bỏ bớt sự tham gia của CPU.

Data Path With and Without GPUDirectWithout GPUDirectNVMe storageSystem RAMBounce bufferCPU copies hereGPU memorywaits for dataThree hops, CPU involved in two of themCPU saturates before the GPU is busyWith GPUDirect StorageNVMe storageSystem RAMbypassedGPU memoryfed at full rateby direct DMAdirect DMAOne hop, CPU stays out of the data pathCPU is free for data preparation workThe same idea applies across the network with GPUDirect RDMA, and between GPUs with Peer-to-Peer

3. GPUDirect Peer-to-Peer​

GPUDirect P2P cho phép một GPU đọc và ghi thẳng vào bộ nhớ của GPU khác trong cùng một máy, không qua RAM hệ thống.

Khi hai GPU nối bằng NVLink, đường đi này chạy trên NVLink với băng thông đầy đủ. Khi chúng chỉ nối qua PCIe, P2P vẫn hoạt động nhưng bị giới hạn bởi băng thông PCIe và bởi topology: hai GPU cắm dưới cùng một PCIe switch nói chuyện với nhau nhanh hơn hai GPU phải đi vòng qua CPU.

NCCL dựa trên P2P để thực hiện các phép collective trong phạm vi một node, và chính nó tự dò xem cặp GPU nào có đường P2P nào.

4. GPUDirect RDMA​

GPUDirect RDMA mở rộng ý tưởng đó ra khỏi phạm vi một máy: NIC đọc thẳng từ bộ nhớ GPU rồi đẩy lên mạng, và ở đầu kia NIC ghi thẳng vào bộ nhớ GPU đích. CPU của cả hai máy không chạm vào dữ liệu.

Công nghệ này xuất hiện lần đầu trên GPU dòng Kepler cùng CUDA 5 vào năm 2012, nên đã có lịch sử khá dài.

Chênh lệch độ trễ là con số đáng nhớ cho kỳ thi:

Đường điĐộ trễ
GPU sang GPU qua InfiniBand với GPUDirect RDMAkhoảng 1 tới 2 microgiây
GPU sang GPU phải đi vòng qua CPUkhoảng 10 tới 30 microgiây

Khoảng cách một bậc độ lớn đó quyết định việc một job training 1.000 GPU chạy được hay không. Mỗi bước huấn luyện có một phép đồng bộ, và nhân độ trễ với số bước trong nhiều ngày thì chênh lệch tích luỹ thành vài chục phần trăm thời gian chạy.

Về tốc độ, GPUDirect RDMA hỗ trợ đầy đủ InfiniBand thế hệ NDR, tức 400 Gb/s mỗi cổng. Tốc độ thực tế còn phụ thuộc loại cáp và transceiver đang lắp: cùng là NDR nhưng cáp NDR200 chỉ cho 200 Gb/s. Bản thân GPUDirect RDMA không bị giới hạn bởi thế hệ InfiniBand, mà bởi năng lực của cặp GPU và NIC đang dùng.

Cấu hình điển hình mà đề thi hay mô tả: GPU ở hai node, mỗi node có card ConnectX, nối qua fabric InfiniBand, bật GPUDirect RDMA. Kết quả là giao tiếp GPU-to-GPU xuyên node ở độ trễ dưới hai microgiây.

5. GPUDirect Storage​

GPUDirect Storage (viết tắt GDS) tạo một đường dữ liệu trực tiếp để truyền DMA giữa bộ nhớ GPU và thiết bị lưu trữ, bỏ qua bounce buffer trên CPU. Không có nó, giai đoạn nạp dữ liệu sinh ra thời gian rảnh đáng kể trên GPU.

Dấu hiệu nhận biết cần bật GDS: CPU usage tăng vọt đúng trong giai đoạn nạp dữ liệu, trong khi GPU utilization lại thấp. Đúng tình huống mở đầu phần này.

Hướng xử lý khi gặp triệu chứng đó:

  • Bật GPUDirect Storage để bỏ chặng chép qua CPU.
  • Dùng RAPIDS cuDF để phần biến đổi dữ liệu cũng chạy trên GPU thay vì trên CPU.
  • Tăng số tiến trình data loader để song song hoá phần việc còn lại của CPU.

cuFile là thư viện API của GDS, chỗ ứng dụng và framework gọi vào để dùng được đường truyền trực tiếp này.

6. NVIDIA RAPIDS và cuDF​

NVIDIA RAPIDS là bộ thư viện cho phép chạy cả một pipeline khoa học dữ liệu trên GPU thay vì CPU. Trong bộ này, thư viện cần nhớ nhất là cuDF.

cuDF là thư viện dataframe chạy trên GPU, viết cho Python, xây trên định dạng bộ nhớ dạng cột của Apache Arrow. Nó làm các việc quen thuộc của một dataframe: nạp dữ liệu, join, aggregate, filter, biến đổi cột.

Điểm khiến cuDF dễ tiếp cận là API gần như trùng với pandas. Chuyển một đoạn code pandas sang cuDF phần lớn chỉ là đổi dòng import:

# Trước: chạy trên CPU
import pandas as pd
df = pd.read_csv("events.csv")
result = df.groupby("user_id").agg({"amount": "sum"})

# Sau: chạy trên GPU, phần còn lại giữ nguyên
import cudf as pd
df = pd.read_csv("events.csv")
result = df.groupby("user_id").agg({"amount": "sum"})

Trong bối cảnh của bài này, cuDF đáng nhớ vì nó là một mảnh của lời giải cho vấn đề CPU nghẽn ở khâu chuẩn bị dữ liệu.

7. NVIDIA NeMo framework​

NVIDIA NeMo là nền tảng phát triển để xây dựng các model generative AI tuỳ chỉnh. Nó phủ large language model, computer vision, nhận dạng giọng nói, xử lý ngôn ngữ tự nhiên, tổng hợp giọng nói, và cả việc xây dựng cùng giám sát AI agent.

Cách hình dung đơn giản nhất: NeMo là hệ quản lý vòng đời đầu cuối cho công việc AI, tương đương các nền tảng ML end-to-end khác trên thị trường nhưng là bản của NVIDIA, tối ưu cho phần cứng của họ.

8. MIG, nhắc lại ở góc độ phần mềm​

MIG (Multi-Instance GPU) chia một GPU vật lý thành nhiều instance cách ly hoàn toàn, mỗi instance trình diện như một thiết bị GPU riêng.

Việc phân vùng diễn ra ngay trên silicon: mỗi instance nhận SM riêng, lát cache L2 riêng và bộ điều khiển bộ nhớ riêng. Khác biệt so với time-slicing nằm ở đó, cách ly bằng phần cứng chứ không phải luân phiên theo thời gian.

MIG không phủ mọi GPU từ Ampere trở đi, mà chỉ một danh sách cụ thể: A30, A100, H100, H200, B200, GB300 và RTX PRO Blackwell. Ada Lovelace (L4, L40S) không hỗ trợ MIG dù có compute capability 8.9, nên không suy ra được khả năng này từ số compute capability đã nói ở phần về CUDA. Số instance tối đa phụ thuộc từng dòng phần cứng.

Phần cấu hình bằng nvidia-smi mig và danh sách profile đầy đủ nằm ở phần về H100 của loạt bài.

💡 Hình dung như thế này: một GPU chưa chia giống căn nhà lớn cho một hộ ở, mọi phòng và tiện ích dùng chung, ai cũng có thể chiếm hết nước nóng. MIG giống việc cải tạo thành nhiều căn hộ độc lập, mỗi căn có đồng hồ điện nước riêng và đường ống riêng, nên hàng xóm mở vòi cả ngày cũng không làm nhà bên cạnh mất nước.

9. ONNX, định dạng model trung lập framework​

ONNX (Open Neural Network Exchange) là định dạng model mã nguồn mở, trung lập về framework, export được từ hầu hết framework ML lớn.

Vấn đề mà nó giải quyết: một model huấn luyện bằng PyTorch mặc định chỉ chạy được bằng PyTorch. Muốn đem sang môi trường khác, hoặc muốn tối ưu bằng công cụ của bên thứ ba, phải có một cách mô tả model không gắn với framework nào. ONNX cung cấp đúng ngôn ngữ chung đó: nó định nghĩa sẵn các phép toán chuẩn mà mọi framework đều hiểu như nhau.

Model ở định dạng này thường được gọi là ONNX graph, vì bản chất nó là một đồ thị các phép toán nối với nhau. Hệ sinh thái quanh ONNX có đủ công cụ để xây, chuyển đổi, triển khai, tối ưu và trực quan hoá model.

Công cụ trực quan hoá đáng biết là Netron: nạp một file ONNX vào rồi xem toàn bộ đồ thị, chạy ngay trên trình duyệt, miễn phí, và hỗ trợ nhiều định dạng khác ngoài ONNX.

10. TensorRT và TensorRT-LLM​

TensorRT là bộ API và trình tối ưu cho deep learning inference trên GPU NVIDIA. Nó nhận một model đã huấn luyện rồi biên dịch thành một engine gắn chặt với đúng dòng GPU đích, trong quá trình đó gộp các lớp lại với nhau, chọn thuật toán nhanh nhất cho từng phép và hạ độ chính xác ở những chỗ chịu được.

Engine sinh ra chỉ chạy trên dòng GPU mà nó được build cho. Build trên H100 rồi đem sang A100 là không chạy được, chi tiết hay gây bất ngờ khi triển khai.

TensorRT-LLM là nhánh chuyên cho LLM, dùng được từ Python. Quy trình ba bước:

  1. Chuyển checkpoint của model sang định dạng checkpoint của TensorRT-LLM.
  2. Build engine từ checkpoint đó, kèm các tuỳ chọn về độ chính xác và kích thước batch.
  3. Chạy inference bằng engine vừa build.

TensorRT-LLM cũng là thành phần nằm bên trong các container NIM, lo phần tối ưu cho model mà NIM đóng gói sẵn.

11. TensorRT for RTX, bản dễ nhầm tên​

TensorRT for RTX là một thư viện inference riêng, không phải bản rút gọn của TensorRT. Nó nhắm tới việc chạy model AI trên GPU dòng RTX, từ thế hệ Turing tới Blackwell, và giải quyết một vấn đề đặc thù của máy cá nhân: workload AI không được chiếm hết hiệu năng đồ hoạ, vì người dùng thường vừa chạy AI vừa dùng phần mềm cần GPU cho việc khác.

Đặc điểm: thay thế trực tiếp được cho TensorRT trong ứng dụng nhắm GPU RTX, có trình tối ưu just-in-time, kích thước dưới 200 MB, tối ưu các model CNN, diffusion và speech ở định dạng ONNX hoặc qua API C++ gốc.

Điểm phân biệt cần nhớ, và là chỗ đề thi hay gài vì hai tên quá giống nhau:

TensorRTTensorRT for RTX
Nền tảng hỗ trợData center, edge, embedded, RTXChỉ GPU RTX
Kích thướcLớn hơnDưới 200 MB
Tối ưuBuild trước thành engineCó thêm tối ưu just-in-time

TensorRT for RTX không hỗ trợ GPU data center, edge hay embedded.

12. Lượng tử hoá model​

Quantization giảm dung lượng bộ nhớ và chi phí tính toán bằng cách chuyển trọng số model sang độ chính xác thấp hơn, ví dụ từ BF16 xuống FP8 hoặc FP4. TensorRT-LLM có sẵn các công thức cho FP4, FP8 và nhiều định dạng khác.

Một phương pháp quantization được mô tả bằng ba phần: định dạng độ chính xác của trọng số, định dạng độ chính xác của activation, và thuật toán xử lý activation. Vì vậy mới có các tên gọi kiểu W4A8, nghĩa là trọng số 4 bit và activation 8 bit.

Các phương pháp hay gặp và đánh đổi của chúng:

Phương phápCách làmĐánh đổi
FP8Hạ cả trọng số lẫn activation xuống 8 bit dấu phẩy độngGiữ độ chính xác tốt nhất trong nhóm, được phần cứng Hopper và Blackwell hỗ trợ sẵn
INT8 SmoothQuant8 bit số nguyên, kèm kỹ thuật san phẳng các giá trị ngoại lai của activationPhụ thuộc vào tham số hiệu chỉnh, kết quả dao động theo kích thước model
INT4 AWQChỉ lượng tử hoá trọng số xuống 4 bit, giữ activation ở độ chính xác cao hơnTiết kiệm bộ nhớ nhiều nhất, mất độ chính xác rõ hơn
INT4 GPTQTương tự AWQ, thuật toán hiệu chỉnh khácTương đương AWQ trên benchmark học thuật

Số liệu từ thử nghiệm của NVIDIA trên dòng Llama 3 cho thấy mức độ đánh đổi: FP8 giữ được 99,2% độ chính xác MMLU so với bản FP16 gốc ở model 8 tỉ tham số, và 99,6% ở model 70 tỉ tham số. INT8 SmoothQuant và INT4 AWQ cùng đạt khoảng 96,2% ở model 8 tỉ tham số. Về tốc độ, INT4 AWQ cho mức tăng cao nhất so với FP16 ở batch size 1, khoảng 2,66 lần trên model 70 tỉ tham số.

Hướng chọn rút ra từ đó: FP8 là lựa chọn mặc định an toàn khi phần cứng hỗ trợ, vì gần như không mất độ chính xác. Chỉ xuống INT4 khi bộ nhớ là ràng buộc cứng và chấp nhận được mức giảm chất lượng.

Với H100, Transformer Engine được thiết kế cho inference ở FP8, nên một model LLaMA 70 tỉ tham số thường được lượng tử hoá về FP8 để chạy tối ưu trên phần cứng này. Nhắc lại điều đã nói ở phần về Hopper: Transformer Engine chạy FP8 hoặc FP16, và FP8 là phương án cho hiệu năng tốt nhất.

Một cảnh báo thực tế: lượng tử hoá không phải lúc nào cũng nhanh hơn. Trên một số nền tảng, engine INT8 chạy chậm hơn bản FP16 vì phần chuyển đổi định dạng tốn thêm thời gian. Luôn đo trên đúng phần cứng đích trước khi kết luận.

13. NCCL: rank và các phép collective​

NCCL cung cấp năm phép collective chuẩn: all-reduce, broadcast, reduce, all-gather và reduce-scatter. Ba mẫu hình hay được nhắc cùng nhóm là all-to-all, gather và scatter, nhưng chúng vốn được dựng từ cặp primitive điểm-điểm ncclSend và ncclRecv chứ không phải collective API riêng; API riêng cho ba mẫu hình này (ncclAlltoAll, ncclGather, ncclScatter) chỉ xuất hiện từ NCCL 2.28. Nhóm năm phép chuẩn là phần đề thi bám theo.

Trước hết cần hiểu rank: đó là định danh duy nhất gán cho mỗi tiến trình tham gia một phép tính phân tán. Mỗi GPU nhận một rank khi vào nhóm. NCCL cho phép giao tiếp GPU-to-GPU cả trong cùng máy lẫn qua mạng giữa các rack.

Quy tắc bắt buộc: khi thực hiện một phép collective, mọi rank phải gọi cùng một phép với tham số khớp nhau. Rank 0, 1, 2, 3 đều phải cùng gọi all-reduce, cùng kiểu dữ liệu, cùng kích thước. Một rank gọi lệch là cả nhóm treo, và đây là nguyên nhân phổ biến của các job training đứng im không báo lỗi.

Ứng dụng thường gặp nhất: all-reduce dùng để cộng gradient của mọi GPU trong huấn luyện phân tán.

Năm phép collective chuẩn:

Phép toánMô tả
All-reduceThực hiện một phép reduction (sum, min, max) trên dữ liệu của mọi rank, rồi lưu cùng một kết quả vào mọi rank
ReduceReduction tương tự, nhưng kết quả chỉ lưu vào một rank nhận duy nhất
Reduce-scatterKết quả reduction được chia thành các khối bằng nhau, mỗi rank nhận một khối theo chỉ số rank
BroadcastSao chép buffer N phần tử từ rank gốc sang mọi rank khác
All-gatherGom N giá trị từ K rank vào một buffer kích thước K nhân N, sắp theo thứ tự rank

Ba mẫu hình dựng từ primitive điểm-điểm ncclSend và ncclRecv:

Mẫu hìnhMô tả
All-to-allMỗi rank gửi một khối riêng tới từng rank khác và nhận lại một khối từ từng rank
GatherGom dữ liệu từ mọi rank về một rank
ScatterChia dữ liệu từ một rank ra mọi rank, ngược với gather
Four Common NCCL Communication Patterns (4 ranks = 4 GPUs)ALL-REDUCE (e.g. sum)2514reduce (sum)12121212Every rank receives the SAME result(2+5+1+4 = 12, copied to all 4 ranks)Most common: gradient averaging in trainingBROADCAST7emptyemptyemptyroot rank sends to everyone7777Copies the exact value from theroot rank to all other ranksGATHERABCDcollected into 1 rankA, B, C, DEach rank contributes its own data,all combined into exactly 1 receiving rankSCATTERA, B, C, Dsplit evenly across 4 ranksABCDOpposite of Gather: one rankdistributes, each rank gets one partAll-reduce and Broadcast are standard collectives; Gather and Scatter gained their own API only in NCCL 2.28

Trong nhóm này, all-reduce là phép xuất hiện nhiều nhất trong câu hỏi liên quan tới NCCL. Các phép phức tạp hơn như reduce-scatter và all-to-all chỉ cần biết là chúng tồn tại và làm gì.

14. Ring hay tree, NCCL chọn thế nào?​

Cùng một phép all-reduce, NCCL có thể thực hiện theo nhiều thuật toán khác nhau, và nó tự chọn dựa trên topology cùng kích thước dữ liệu. Hai thuật toán chính:

Ring all-reduce xếp các GPU thành một vòng tròn logic, rồi chạy hai giai đoạn: một pha reduce-scatter đi quanh vòng để mỗi GPU gom xong một phần kết quả, tiếp theo một pha all-gather cũng đi quanh vòng để phát phần kết quả đó cho mọi GPU. Ưu điểm là mọi đường truyền đều hoạt động ở mọi bước, nên tận dụng hết băng thông. Nhược điểm là số bước tăng tuyến tính theo số GPU, nên độ trễ cộng dồn lớn khi cụm rất rộng.

Tree all-reduce dùng cấu trúc cây nhị phân kép cho giao tiếp giữa các node: một pha reduce đi ngược lên gốc cây, rồi một pha broadcast đi xuôi xuống. Số bước tăng theo logarit của số GPU thay vì tuyến tính, nên độ trễ tốt hơn hẳn ở quy mô lớn. NCCL đưa thuật toán này vào từ phiên bản 2.4.

Ring All-Reduce versus Tree All-Reduce in NCCLRing all-reduceGPU 0GPU 1GPU 2GPU 3Phase 1: reduce-scatterPhase 2: all-gatherEvery link is busy at every stepBandwidth optimal for large messages2 times (N minus 1) steps for N GPUsStep count grows linearly with GPU countLatency adds up on very wide clustersTree all-reduceRoot rankInner rankInner rankLeaf rankLeaf rankLeaf rankLeaf rankreduce phasebroadcast phaseDouble binary tree between nodesReduce climbs to the root, then broadcast descendsStep count grows with the logarithm of GPU countLatency friendly for small messages at large scaleNCCL picks the algorithm itself from topology and message sizeLarge messages on a moderate cluster favor ring, small messages at huge scale favor tree

Cách chọn trên thực tế:

Tình huốngThuật toán thường thắng
Thông điệp lớn, cụm vừa phảiRing, vì tận dụng hết băng thông
Thông điệp nhỏ, cụm rất lớnTree, vì độ trễ tăng theo logarit

Với all-gather và reduce-scatter, NCCL dùng thuật toán ring. NVIDIA đang phát triển một thuật toán mới tên PAT (Parallel Aggregated Trees) cho hai phép này nhằm đạt độ trễ logarit, nên cần kiểm tra release note của phiên bản NCCL đang dùng nếu chi tiết này quan trọng.

Người dùng thường không phải chọn thủ công, NCCL tự quyết. Hiểu nguyên lý này có ích ở chỗ khác: nó giải thích vì sao topology mạng rail-optimized lại quan trọng tới vậy. Các thuật toán trên đều giả định GPU cùng vị trí trong các node khác nhau nói chuyện được với nhau nhanh, và cách bố trí rail tồn tại để bảo đảm đúng điều đó.


Nguồn tham khảo​

Nguồn gốc: NVIDIA-Certified Associate AI Infrastructure and Operations (NCA AIIO) Free Study Course, kênh freeCodeCamp.org.

Đã fact-check (truy cập 2026-10-23):