Giám sát hiệu suất GPU trong PyTorch Container với nvidia-smi

Trong quá trình phát triển các dự án học sâu, một tình huống phổ biến là bạn khởi chạy một tác vụ huấn luyện, kỳ vọng mô hình sẽ hội tụ nhanh chóng, nhưng lại phát hiện tốc độ huấn luyện cực kỳ chậm. Khi kiểm tra bằng lệnh nvidia-smi trong terminal, bạn thấy tỷ lệ sử dụng GPU chỉ đạt 5%, bộ nhớ GPU còn trống nhiều, trong khi CPU lại hoạt động hết công suất. Tình trạng "có công cụ mạnh mẽ nhưng không sử dụng hết" này gần như ai làm kỹ thuật AI cũng từng gặp.

Vấn đề nằm ở đâu? Tại sao PyTorch không thực sự tận dụng GPU? Làm thế nào để theo dõi trạng thái sức khỏe của GPU trong thời gian thực? Câu trả lời nằm ở công cụ nvidia-smi, một công cụ tưởng chừng đơn giản nhưng cực kỳ mạnh mẽ. Đặc biệt khi làm việc với các container PyTorch-CUDA, khả năng giám sát hiệu quả tài nguyên GPU quyết định trực tiếp đến hiệu quả gỡ lỗi và tính ổn định của quá trình huấn luyện.

Hiểu sâu về nvidia-smi: Không chỉ là xem tỷ lệ sử dụng

nvidia-smi (NVIDIA System Management Interface) không chỉ là một công cụ dòng lệnh để xem trạng thái GPU. Nó là cầu nối quan trọng giữa ứng dụng cấp cao và phần cứng cấp thấp. Khi bạn chạy mã PyTorch trong một container Docker, ngay cả những thao tác CUDA tensor nhỏ nhất cũng được nó ghi nhận chính xác.

Khả năng cốt lõi của nó đến từ NVML (NVIDIA Management Library), một thư viện C có chi phí thấp do driver NVIDIA cung cấp, được thiết kế chuyên biệt cho việc giám sát hệ thống. nvidia-smi hoạt động bằng cách gọi các giao diện NVML để đọc trực tiếp dữ liệu thời gian thực từ các thanh ghi GPU, bao gồm:

  • Tỷ lệ sử dụng lõi tính toán GPU
  • Tình trạng chiếm dụng bộ nhớ GPU
  • Nhiệt độ, mức tiêu thụ năng lượng, tốc độ quạt
  • Danh sách các tiến trình đang sử dụng GPU, bao gồm cả PID của chúng

Toàn bộ quá trình này diễn ra giữa nhân hệ điều hành và không gian người dùng, gần như không gây tổn thất hiệu năng. Do đó, bạn có thể yên tâm kiểm tra với tần suất từng giây mà không ảnh hưởng đến hiệu suất huấn luyện.

Quan trọng hơn, trong các container chính thức như PyTorch-CUDA-v2.8, nvidia-smi đã được cài đặt sẵn và có thể sử dụng trực tiếp. Điều này có nghĩa là bạn có thể bắt đầu giám sát ngay lập tức mà không cần cài đặt thêm bất kỳ phụ thuộc nào. Điều này rất quan trọng để nhanh chóng xác minh cấu hình môi trường và khắc phục các điểm nghẽn về tài nguyên.

Các lệnh thường dùng trong thực tế: Từ nhập môn đến tự động hóa

Chẩn đoán cơ bản: Xác nhận nhanh trạng thái GPU

Cách sử dụng đơn giản nhất là nhập lệnh:


nvidia-smi

Lệnh này sẽ xuất ra thông tin tổng quan về tất cả các GPU trong hệ thống của bạn. Bạn sẽ thấy nội dung tương tự như sau:


+-----------------------------------------------------------------------------+
| NVIDIA-SMI 535.129.03   Driver Version: 535.129.03   CUDA Version: 12.2     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  NVIDIA A100-SXM4...  On  | 00000000:00:1B.0 Off |                   Off |
| N/A   65C    P0    75W / 400W |  32400MiB / 40960MiB |     85%      Default |
|                               |                      |                      |
+-------------------------------+----------------------+----------------------+
|   1  NVIDIA A100-SXM4...  On  | 00000000:00:1C.0 Off |                   Off |
| N/A   58C    P0    68W / 400W |   2048MiB / 40960MiB |      5%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                                    |
|  GPU   PID   Type   Process name                             GPU Memory Usage |
|=============================================================================|
|    0  12345  C+G    python                                      32390MiB      |
+-----------------------------------------------------------------------------+

Hãy chú ý đến các trường sau:

  • Temp: Nhiệt độ trên 80°C có thể gây giảm hiệu năng.
  • Memory-Usage: Gần đến giới hạn có thể gây ra lỗi OOM (Out of Memory).
  • GPU-Util: Liên tục dưới 30% có thể là dấu hiệu của tắc nghẽn trong việc tải dữ liệu.
  • Processes: Xác định rõ ai đang chiếm dụng GPU.

Giám sát động: Quan sát sự biến động trong quá trình huấn luyện

Nếu bạn đang chạy một tác vụ huấn luyện và muốn xem liệu tải GPU có ổn định không, bạn có thể bật chế độ tự động làm mới:


nvidia-smi -l 2

Lệnh này sẽ làm mới trạng thái trên terminal mỗi 2 giây. Nó rất hữu ích để quan sát các hiện tượng như:

  • Giai đoạn tải dữ liệu có gây ra tình trạng không tải định kỳ hay không.
  • Sự mất cân bằng tải khi huấn luyện đa GPU.
  • Ảnh hưởng của việc tích lũy gradient hoặc kích thước batch lớn đối với bộ nhớ GPU.

Lưu ý: Chế độ này yêu cầu bạn nhấn Ctrl+C để thoát, đừng quên tắt nó kịp thời để không chiếm dụng terminal.

Xuất dữ liệu có cấu trúc: Phân tích bằng script

Khi bạn cần ghi dữ liệu giám sát vào tệp nhật ký hoặc xử lý tiếp theo, định dạng CSV là lựa chọn thân thiện nhất:


nvidia-smi --query-gpu=name,temperature.gpu,utilization.gpu,memory.used,memory.total --format=csv

Ví dụ đầu ra:


name, temperature.gpu, utilization.gpu [%], memory.used [MiB], memory.total [MiB]
NVIDIA A100-SXM4-40GB, 65, 85, 32400, 40960

Định dạng này có thể được nhập trực tiếp vào Pandas để vẽ biểu đồ hoặc kết hợp với script Shell để thu thập dữ liệu định kỳ:


while true; do
    echo "$(date), $(nvidia-smi --query-gpu=utilization.gpu,memory.used --format=csv,noheader)" >> gpu_log.csv
    sleep 5
done

Một mẹo nhỏ: Sử dụng tham số noheader,nounits để làm cho đầu ra gọn gàng hơn, dễ dàng cho chương trình phân tích.

Tích hợp giám sát trong Python: Làm cho mã nguồn "tự kiểm tra"

Mặc dù dòng lệnh rất tiện lợi, nhưng trong môi trường Jupyter Notebook hoặc khi triển khai dịch vụ, chúng ta thường muốn lấy trạng thái GPU bằng cách nguyên bản của Python. Lúc này, bạn có thể sử dụng subprocess để gọi nvidia-smi và phân tích kết quả:


import subprocess
import csv
from io import StringIO

def get_gpu_info():
    cmd = [
        "nvidia-smi",
        "--query-gpu=name,temperature.gpu,utilization.gpu,memory.used,memory.total",
        "--format=csv,noheader,nounits"
    ]
    try:
        result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=5)
        if result.returncode != 0:
            print("Lỗi khi thực thi nvidia-smi:", result.stderr)
            return

        reader = csv.reader(StringIO(result.stdout))
        for row in reader:
            name, temp, util, mem_used, mem_total = [r.strip() for r in row]
            print(f"GPU: {name}")
            print(f"  Nhiệt độ: {temp}°C")
            print(f"  Tỷ lệ sử dụng: {util}%")
            print(f"  Bộ nhớ: {mem_used}MB / {mem_total}MB")
    except Exception as e:
        print("Lỗi giám sát:", str(e))

# Gọi định kỳ
get_gpu_info()

Hàm này có thể được gọi định kỳ trong vòng lặp huấn luyện, ví dụ: cứ sau 10 bước lại in ra trạng thái một lần, giúp xác định xem mô hình có thực sự chạy trên GPU hay không.

Lưu ý: Không nên gọi quá thường xuyên (ví dụ: mỗi bước) vì chi phí I/O có thể ảnh hưởng đến hiệu suất tổng thể. Nên cách nhau ít nhất 1-5 giây.

Cơ chế phối hợp trong PyTorch-CUDA Container

Việc phát triển AI hiện đại ngày càng phụ thuộc vào môi trường container hóa, và container PyTorch-CUDA-v2.8 được tạo ra cho mục đích này. Nó không chỉ đơn thuần là đóng gói phần mềm, mà là một hệ thống phối hợp phần mềm và phần cứng hoàn chỉnh:

  1. Máy chủ vật lý phải cài đặt driver NVIDIA.
  2. Docker Engine cần được tích hợp với NVIDIA Container Toolkit (trước đây gọi là nvidia-docker).
  3. Khi khởi chạy container, sử dụng tham số --gpus để cấp phát thiết bị.
  4. Bên trong container, các thư viện driver và CUDA Toolkit được tự động gắn kết.
  5. Cuối cùng, torch.cuda.is_available() trả về True.

Điều này có nghĩa là mọi dòng mã .cuda() hoặc .to('cuda') bạn chạy trong container đều có thể được ánh xạ liền mạch tới GPU vật lý bên dưới. Lý do nvidia-smi hoạt động bình thường trong container chính là vì cơ chế này cũng truyền tải cả giao diện quản lý.

Bạn có thể hình dung nó như một "phòng điều hành trong suốt": môi trường container được cách ly, nhưng bạn lại có thể hoàn toàn kiểm soát "trái tim" GPU phía sau.

Xử lý sự cố điển hình: Chiến lược đối phó với ba loại lỗi thường gặp

Lỗi 1: Huấn luyện chậm, GPU hầu như không hoạt động

Đây là vấn đề phổ biến nhất với người mới bắt đầu. Mặc dù mã nguồn có ghi .cuda(), nhưng thực tế tính toán vẫn diễn ra trên CPU.

Các bước chẩn đoán:
  1. Chạy nvidia-smi để xác nhận không có sự chiếm dụng GPU rõ ràng.
  2. Kiểm tra xem mô hình và dữ liệu đã được chuyển sang GPU chưa:
    
    model = model.to('cuda')
    data = data.to('cuda')  # Cần chú ý đến pin_memory và num_workers trong DataLoader
            
  3. Sử dụng mã sau để xác minh:
    
    print(next(model.parameters()).device)  # Nên hiển thị 'cuda:0'
    print(data.device)                     # Nên hiển thị 'cuda:0'
            

Nếu vẫn là cpu, nghĩa là bạn đã bỏ sót bước chuyển đổi.

Lỗi 2: Nhiều người dùng chung máy chủ, không biết ai đang chiếm dụng card

Các nhóm nghiên cứu thường gặp tình huống này: một card đồ họa bị chiếm dụng đầy, nhưng không biết ai đang sử dụng.

Giải pháp là xem thông tin tiến trình chi tiết:


nvidia-smi --query-compute-apps=pid,process_name,used_memory,username --format=csv

Ví dụ đầu ra:


pid, process_name, used_memory [MiB], username
12345, python, 20480, user1

Sau đó, kết hợp với lệnh hệ thống để xác định tác vụ cụ thể:


ps aux | grep 12345

Bạn sẽ thấy đường dẫn lệnh đầy đủ, thậm chí có thể nhận ra đó là instance Jupyter notebook nào đang chạy.

Lỗi 3: Tràn bộ nhớ GPU (CUDA OOM)

Ngay cả khi kích thước batch không lớn, bạn vẫn có thể gặp sự cố do rò rỉ bộ nhớ dẫn đến lỗi ở giai đoạn sau.

Các phương pháp xử lý:
  • Sử dụng nvidia-smi -l 1 để theo dõi xu hướng tăng trưởng của bộ nhớ GPU.
  • Kiểm tra xem có biến trung gian nào chưa được giải phóng không, đặc biệt là các tensor có gradient.
  • Trong quá trình suy luận, hãy đảm bảo sử dụng with torch.no_grad():.
  • Nếu cần thiết, hãy xóa bộ nhớ cache thủ công (sử dụng cẩn thận):
    
    import torch
    torch.cuda.empty_cache()
            

Tuy nhiên, empty_cache() chỉ trả bộ nhớ đã được cấp phát về lại cho bộ nhớ cache, không giải phóng bộ nhớ đã sử dụng. Nó không giải quyết được vấn đề gốc rễ.

Thực tiễn tốt nhất: Xây dựng vòng lặp phát triển hiệu quả

Để tối đa hóa việc sử dụng bộ công cụ giám sát này, bạn nên tuân theo các thói quen kỹ thuật sau:

Cảnh báo Khuyến nghị
Xác minh môi trường Sau mỗi lần khởi chạy container, việc đầu tiên là chạy nvidia-smi và torch.cuda.is_available().
Phân bổ GPU Sử dụng docker run --gpus '"device=0"' để chỉ định rõ số card, tránh tranh chấp.
Ghi nhật ký Chuyển hướng đầu ra của nvidia-smi vào tệp để tra cứu sau này.
Giám sát tự động Viết tác vụ cron để lấy mẫu định kỳ, tạo báo cáo trực quan.
Kiểm soát an ninh Trong môi trường đa người dùng, hạn chế quyền truy cập thông tin GPU cho những người không cần thiết.

Đặc biệt, bạn nên thêm một ô "Kiểm tra sức khỏe" ở đầu Notebook Jupyter:


!nvidia-smi --query-gpu=utilization.gpu,memory.used --format=csv

Bằng cách này, mỗi lần mở dự án, bạn đều có thể nhanh chóng xác nhận trạng thái tài nguyên, tránh đưa ra đánh giá sai lầm.

Lời kết

Nắm vững cách sử dụng nvidia-smi không chỉ đơn thuần là học vài lệnh. Nó đại diện cho một tư duy kỹ thuật: nhạy bén với trạng thái tài nguyên, có khả năng quan sát được quá trình vận hành.

Với sự phổ biến ngày càng tăng của các container PyTorch-CUDA, việc thiết lập môi trường trở nên dễ dàng hơn, nhưng điều này cũng mang đến những thách thức mới – mọi người dễ dàng bỏ qua hiệu suất thực tế của tài nguyên cấp thấp.

Chính vì vậy, những nhà phát triển có thể thành thạo sử dụng nvidia-smi để chẩn đoán thường có thể xác định gốc rễ vấn đề ngay từ đầu, thay vì đoán mò hoặc khởi động lại.

Dù là thử nghiệm cá nhân, làm việc nhóm hay triển khai sản xuất, bộ cơ chế giám sát nhẹ nhàng nhưng mạnh mẽ này là tuyến phòng thủ quan trọng để đảm bảo tính ổn định của quá trình huấn luyện và hiệu quả sử dụng tài nguyên. Đối với mọi kỹ sư phát triển học sâu, đây không chỉ là một kỹ năng, mà còn là một tố chất cơ bản.

Thẻ: PyTorch GPU nvidia-smi docker container

Đăng vào ngày 11 tháng 11 lúc 23:54