GPU cho nghiên cứu ML · Thanh toán crypto không KYC
IteraGPU
Phương pháp 01 · Từ ước tính đến đo lường

Vì sao mức đỉnh bộ nhớ vượt quá ước tính của bạn?

Công thức trọng số mô tả việc lưu trữ các tham số; mức đỉnh mô tả một lần thực thi, cùng với đầu vào và các cấp phát tạm thời của nó. Để giải thích chênh lệch, hãy giữ nguyên đơn vị, đo từng pha và tách biệt bộ nhớ được cấp phát, bộ nhớ được dành riêng và mức chiếm dụng của card. Hồ sơ IteraGPU Lab v1 cung cấp một phép tính tái lập được và một bài tập nhỏ có gắn thiết bị đo. Các con số minh họa bên dưới là các phép tính, không bao giờ là số đo GPU đã công bố.

01 /

Xác định khối lượng công việc trước khi chọn đồng hồ đo

« Một mô hình 7B » không nêu rõ cách biểu diễn trọng số lẫn công việc cần thực hiện. Hãy ghi lại bản sửa đổi của nó, framework, phiên bản các tiện ích mở rộng, định dạng thực sự được nạp và thao tác: huấn luyện, thích ứng hay sinh. Với văn bản, ghi lại độ dài đầu vào và đầu ra; với thị giác, độ phân giải và số lượng ảnh. Một mô hình đa phương thức đòi hỏi phải giữ cả hai chiều này.

Hãy chuẩn bị một đầu vào thông thường, một đầu vào dài nhưng trong dự kiến và một đầu vào gần giới hạn hoạt động của bạn. Giữ chúng trong suốt quá trình so sánh. Kiểm tra các kích thước sau khi token hóa, padding, gom nhóm hoặc thay đổi kích thước: giá trị ghi trong cấu hình không chứng minh kích thước thực sự được xử lý.

Hãy cố định luôn những gì đồng thời còn trong bộ nhớ: một chuỗi, một microbatch, nhiều truy vấn hay một đợt đánh giá được khởi chạy sau huấn luyện. Câu hỏi của bạn trở nên kiểm chứng được: khối lượng công việc đầy đủ này có vừa trên từng thiết bị được dùng không, kể cả trong bước đòi hỏi khắt khe nhất của nó?

  • Danh tính của lần thử: mô hình hoặc mã, bản sửa đổi, tập đầu vào và seed khi cần thiết.
  • Kích thước: batch, ngữ cảnh, token được sinh, độ phân giải hoặc số truy vấn đồng thời.
  • Môi trường: GPU được chọn, driver, Python, PyTorch, backend CUDA hoặc HIP/ROCm và các thiết lập allocator.
  • Phạm vi: tải, tính toán, truyền, đánh giá, xuất; lượt chạy đầu tiên hoặc lượt chạy sau khi khởi động nóng.
02 /

Tính trọng số mà không trộn lẫn GB và GiB

Một GB tương ứng 1 000 000 000 byte; một GiB tương ứng 1 073 741 824 byte. Các bộ đếm PyTorch dùng ở đây trả về đơn vị byte. Hãy giữ nguyên giá trị thô này trong tệp kết quả, rồi chỉ áp dụng một phép quy đổi duy nhất để so sánh các dòng. Nhãn thương mại của một card không thay thế dung lượng thực tế mà thiết bị khai báo.

Với một tập dense bảy tỷ tham số lưu trữ trên hai byte mỗi tham số, trọng số chiếm 14 000 000 000 byte: 14 GB, hay khoảng 13,04 GiB. Phép tính này không bao gồm activation, gradient, cache KV hay trạng thái optimizer. Thêm dự phòng 4 GiB cho ra khoảng 17,04 GiB như giả định chuẩn bị; điều đó không chứng minh rằng một workload sẽ vừa trong phạm vi này.

Phép chia lý thuyết xuống bốn bit giả định lưu trữ gọn đồng nhất. Một lần tải lượng tử hóa thực tế có thể thêm scale và thông tin khác, đồng thời giữ một số module ở độ chính xác khác. Vì vậy định dạng lưu trữ trọng số và định dạng tính toán phải xuất hiện riêng biệt trong bảng của bạn.

Trọng số ước tính theo GiB = tham số × bit mỗi tham số ÷ 8 ÷ 1 073 741 824
Phép tính minh họa cho 7 000 000 000 tham số; không phải kết quả thực thi.
Giả định lưu trữByte đã tínhGiB gần đúng
32 bit đồng nhất28 000 000 00026,08
16 bit đồng nhất14 000 000 00013,04
4 bit gọn, không kể metadata3 500 000 0003,26

Nguồn kỹ thuật: NIST — tiền tố nhị phân và so sánh GB/GiB · Hugging Face — định dạng và module lượng tử hóa với bitsandbytes

03 /

Khi huấn luyện, đo một bước hoàn chỉnh

Trọng số tồn tại song song với các đối tượng khác: gradient, trạng thái optimizer, activation cần cho lượt lan truyền ngược và các tensor tạm thời. Kích thước của chúng phụ thuộc vào vòng lặp, độ chính xác và kích thước của workload. Một hằng số phổ quát tính bằng byte mỗi tham số sẽ che khuất đặc biệt ảnh hưởng của microbatch và đầu vào.

Hãy đo lượt lan truyền xuôi, tính loss, lan truyền ngược và cập nhật. Để quan sát các trạng thái thực sự do optimizer của bạn tạo ra, đừng chỉ dừng ở việc tải mô hình. Đồng thời giữ một phép đo cho bước hoàn chỉnh đầu tiên: một lần khởi động nóng thành công có thể đã thực hiện một khởi tạo mà bạn phải có khả năng chi trả bằng bộ nhớ ngay từ đầu.

Hãy thêm đánh giá và xuất mà dự án của bạn cần. Nếu lỗi xảy ra trong lúc đánh giá, chỉ giảm batch huấn luyện không khắc phục được giai đoạn đó. Một phương án tinh chỉnh chỉ huấn luyện ít tham số vẫn có thể giữ lại một mô hình nền và các activation lớn.

Nguồn kỹ thuật: Hugging Face — các loại bộ nhớ trong quá trình huấn luyện

04 /

Khi suy luận, theo dõi ngữ cảnh và mức đồng thời

Trong sinh văn bản tự hồi quy với attention, cache KV lưu các trạng thái gắn với token. Với một cache dense đồng nhất, kích thước của nó phụ thuộc vào các lớp, các đầu KV, chiều của chúng, số token được giữ lại và các chuỗi hiện diện cùng lúc. Hãy dùng các đầu KV của mô hình, chứ không mặc nhiên dùng các đầu truy vấn của nó.

Ví dụ số học: 32 lớp, 8 đầu KV, chiều 128, 8 192 token, hai byte mỗi giá trị và một chuỗi cho ra 1 073 741 824 byte, tức 1 GiB cho cả K và V. Bốn chuỗi giống nhau cho ra 4 GiB chỉ riêng cho khoản này. Phép tính này không đo băng thông hay mức sử dụng toàn bộ GPU.

Hãy điều chỉnh công thức cho cache thực sự được dùng. Một cửa sổ trượt không nhất thiết giữ toàn bộ lịch sử; một cache tĩnh có thể cấp phát trước dung lượng tối đa của nó. Cache lượng tử hóa và cache chuyển ra ngoài cũng thay đổi bài toán. Hãy đo riêng bước xử lý đầu vào ban đầu và bước sinh, mà không mặc nhiên quy toàn bộ chênh lệch của chúng cho cache.

KV dense tính bằng byte ≈ 2 × số lớp × số đầu KV × chiều mỗi đầu × số token được giữ × số chuỗi × byte mỗi giá trị

Nguồn kỹ thuật: Hugging Face — các chiến lược cache, cấp phát tĩnh và cửa sổ

05 /

Allocated và reserved: hai chỉ số không cộng lại với nhau

memory_allocated mô tả các byte bị chiếm bởi các tensor được PyTorch theo dõi trên thiết bị. memory_reserved mô tả bộ nhớ được allocator có cache của nó quản lý, bao gồm cả phần đã dùng cho chính các tensor đó. Cộng hai giá trị lại sẽ tính trùng một phần bộ nhớ. Hãy giữ chúng trong hai cột riêng biệt.

Các biến thể max của chúng mỗi cái ghi lại một đỉnh kể từ khi bắt đầu theo dõi hoặc lần đặt lại gần nhất. Đây là những đỉnh tuyệt đối của khoảng thời gian, bao gồm cả các cấp phát đã có từ đầu. Kết quả không tự động đại diện cho chỉ các đối tượng được tạo ra bởi giai đoạn đó.

Một phép đọc ở mức hệ thống có thể có phạm vi rộng hơn. Các cấp phát do thư viện CUDA thực hiện trực tiếp, ví dụ một số giao tiếp NCCL, không phải đều hiển thị trong allocator của PyTorch. Do đó, một sự khác biệt với công cụ hệ thống không tự nó chứng minh có rò rỉ.

Bốn bộ đếm, đều tính bằng byte, cần ghi nhận cho cùng một thiết bị.
Bộ đếmCâu hỏi mà nó trả lờiLỗi cần tránh
memory_allocatedCác tensor chiếm bao nhiêu tại điểm đọc này?Coi đó là toàn bộ mức chiếm dụng của card.
memory_reservedAllocator quản lý bao nhiêu tại điểm đọc này?Cộng nó vào allocated.
max_memory_allocatedĐỉnh nào của các tensor đã được theo dõi trong khoảng thời gian?Nhầm nó với giá trị cuối giai đoạn.
max_memory_reservedAllocator báo cáo đỉnh đặt trước nào?Giả định nó xảy ra cùng thời điểm với đỉnh kia.

Nguồn kỹ thuật: PyTorch — memory_allocated · PyTorch — memory_reserved · PyTorch — max_memory_allocated · PyTorch — các cấp phát ngoài allocator của nó

06 /

Vì sao hiệu số giữa hai đỉnh không đo được bộ nhớ đệm

Chỉ xét hai thời điểm giả định trong bảng. Đỉnh allocated là 8 GiB và đỉnh reserved là 12 GiB. Hiệu số của chúng, 4 GiB, không phải là hiệu số quan sát được tại bất kỳ thời điểm nào trong hai thời điểm đó: hiệu số này lần lượt là 2 và 6 GiB. Hai giá trị cực đại không nhất thiết mô tả cùng một trạng thái.

Để nghiên cứu khoảng cách của chúng tại một thời điểm nhất định, hãy ghi nhận allocated và reserved tại cùng một điểm kiểm tra, sau khi đồng bộ và không có thao tác chủ ý mới nào giữa các lần đọc. Bạn nhận được khoảng cách giữa các bộ đếm tại thời điểm đó, không phải phép đo bộ nhớ đệm KV của mô hình, cũng không phải bảo đảm rằng toàn bộ phần chênh lệch đó có thể đáp ứng cấp phát tiếp theo.

Cũng hãy ghi lại backend của allocator trong báo cáo. Tài liệu PyTorch 2.14 nêu rõ rằng, với cudaMallocAsync, max_memory_reserved có thể kết hợp các mức cao nhất của hai pool và cung cấp một cận trên của đỉnh đồng thời. Điều này càng khẳng định sự cần thiết phải giữ tên và phạm vi của bộ đếm.

Hai trạng thái hư cấu để giải thích phép tính; bảng này không phải là một vết GPU.
Thời điểm minh họaAllocatedReservedReserved − allocated tại thời điểm này
A8 GiB10 GiB2 GiB
B6 GiB12 GiB6 GiB

Nguồn kỹ thuật: PyTorch — định nghĩa và giới hạn của max_memory_reserved

07 /

Phân định từng giai đoạn trước khi ghi nhận đỉnh của nó

Các thao tác GPU có thể được xếp hàng trước khi hoàn tất. Để đo theo từng giai đoạn, hãy kết thúc các công việc trước đó trước khi đặt lại các đỉnh về không, rồi chờ giai đoạn kết thúc trước khi đọc. torch.cuda.synchronize chờ các kernel của mọi stream trên thiết bị đã chọn; lựa chọn này định ra một ranh giới rõ ràng cho giao thức đó.

reset_peak_memory_stats đặt lại việc theo dõi các đỉnh bắt đầu từ trạng thái hiện tại; nó không giải phóng các tensor của chương trình. Trước tiên hãy ghi nhận các mức khởi đầu. Cuối cùng, giữ lại cả hai đỉnh tuyệt đối và cả hai mức hiện tại. Đừng trình bày phép trừ một mức khởi đầu như thể tích chính xác của mọi tensor tạm thời: các đối tượng trước đó cũng có thể đã được giải phóng trong giai đoạn.

Việc đo đạc này có thể làm thay đổi sự chồng lấn thông thường giữa các giai đoạn. Hãy dùng nó để định vị vấn đề, rồi cũng kiểm tra toàn bộ vòng lặp với thứ tự thực thi thực tế của nó. Với nhiều card, hãy lặp lại các phép đọc cho từng thiết bị; một phép đo trên cuda:0 không mô tả các GPU khác.

  • 1. Đặt tên cho giai đoạn và ghi lại các đầu vào chính xác của nó.
  • 2. Đồng bộ thiết bị, rồi ghi nhận allocated và reserved khởi đầu.
  • 3. Gọi reset_peak_memory_stats trên chính thiết bị đó.
  • 4. Thực thi giai đoạn đã định, giữ lại các đầu ra cần cho phần tiếp theo.
  • 5. Đồng bộ, ghi nhận các đỉnh và các mức cuối, rồi ghi lại thành công hay lỗi.
  • 6. Giữ nguyên kết quả thô, các kích thước và cấu hình ; không điền số 0 vào bất kỳ phép đo nào còn thiếu.

Nguồn kỹ thuật: PyTorch — đồng bộ một thiết bị · PyTorch — đặt lại thống kê đỉnh

08 /

Phân biệt lần chạy đầu tiên và các lần chạy sau khởi động

Lần chạy thử đầu tiên và một vòng lặp đã chuẩn bị sẵn không trả lời cùng một câu hỏi. Hãy lưu lại dấu vết của quá trình nạp và lần chạy đầu tiên, rồi ghi lại số lần lặp khởi động trước các lần lặp chính. Đừng xóa một lần khởi tạo thất bại với lý do rằng các lần chạy sau sẽ nhẹ hơn.

Script IteraGPU phân biệt model_load, inputs, cold_forward, warmup và warm_forward. cold_forward của nó là lần chạy đầu tiên của mô hình nhỏ sau khi khởi tạo thiết bị. Nó không đo toàn bộ quá trình khởi động của một server, một driver hay một dịch vụ. Các lần lặp warm_forward vẫn nằm trong cùng một tiến trình và tận dụng trạng thái sẵn có của nó.

Với mô hình của bạn, hãy bắt đầu một loạt mới trong một tiến trình mới khi bạn thay đổi một điều kiện có thể để lại các đối tượng hoặc vùng cấp phát trước đó. Ghi lại thứ tự các lần chạy thử và chính sách khởi động. Chạy lại năm lần cùng một vòng lặp và khởi chạy năm tiến trình không phải là cùng một giao thức.

09 /

Sử dụng notebook và script IteraGPU Lab v1

Bắt đầu với README, sau đó tải notebook độc lập hoặc script Python. Phần tính toán estimate dùng thư viện chuẩn. Phần đo lường yêu cầu PyTorch đã cài đặt với backend GPU tương thích và một thiết bị truy cập được; nó không tải mô hình hay gói nào. Notebook yêu cầu một môi trường có khả năng đọc các tệp ipynb.

Bài tập đo lường dùng một mạng dense nhỏ nguyên bản và các đầu vào tổng hợp. Các tùy chọn batch, context và width mô tả các tensor của nó; context ở đây không phải là độ dài của một LLM thực sự có cache KV. Công cụ này dùng để xem xét phương pháp đo lường và thay đổi một chiều. Nó không chứng minh năng lực của một card cho mô hình nghiên cứu của bạn.

Chạy các lệnh bên dưới từ thư mục chứa script. Trước tiên hãy xem báo cáo environment. Nếu thiếu PyTorch hoặc GPU, measure phải dừng lại rõ ràng với mã 2; không kết quả CPU nào được diễn giải như một phép đo GPU. JSON đầu ra của một phép đo thành công được tạo trong môi trường của bạn. Hãy chọn một tên tệp mới cho mỗi loạt: script từ chối ghi đè lên kết quả đã có.

Lệnh đầu tiên tính lại trọng số và vùng dự trữ giả định 4 GB. Với các lệnh sau, hãy dùng một thiết bị mà bạn được phép khai thác và giữ kích thước khiêm tốn lúc ban đầu. Ghi lại phiên bản PyTorch thực sự được dùng: các tài liệu tham chiếu kỹ thuật của trang này mô tả cụ thể phiên bản 2.14, nhưng không bắt buộc bạn phải cài đặt nó.

Hoạt động của script đã được kiểm tra trên một trường hợp nhỏ: RTX 5070 cục bộ không có trong danh mục, driver 610.62, Python 3.14.6 và PyTorch 2.11.0+cu128. Lần chạy thử dùng batch 1, context 16, width 64, float32, một lần khởi động và hai lần lặp. Nó xác nhận đường thực thi này, mà không đánh giá một LLM, một quá trình huấn luyện hay các GPU được cho thuê. Notebook được cung cấp không có đầu ra và bảng so sánh không có kết quả; cơ chế kiểm tra thiếu PyTorch cũng đã được xác minh trong một môi trường riêng biệt.

shell
python mesure_memoire.py estimate --parameters 7000000000 --bits 16 --reserve-gib 4
python mesure_memoire.py environment --device cuda:0
python mesure_memoire.py measure --device cuda:0 --batch 2 --context 128 --width 1024 --dtype float32 --warmup 3 --repeats 5 --output mesures.json
10 /

Diễn giải một lỗi trước khi đổi card

Một lần chạy thử không hoàn tất vẫn là một quan sát hữu ích. Hãy lưu lại giai đoạn, các kích thước yêu cầu, thông báo lỗi và các giá trị cuối cùng còn có được. Một đỉnh một phần trước khi bão hòa không phải là nhu cầu bộ nhớ của một lần chạy đầy đủ. Hãy giảm một chiều duy nhất để tạo một trường hợp chạy thành công, rồi tìm ranh giới giữa thành công và thất bại.

empty_cache giải phóng các khối không dùng đến trong bộ đệm của bộ cấp phát, chứ không giải phóng các tensor còn sống. Đây không phải là giải pháp phổ quát cho tình trạng quá tải. Gọi nó giữa mỗi lần lặp sẽ thay đổi điều kiện: hãy ghi lại lựa chọn đó thay vì trộn lẫn những lần thử này với những lần giữ nguyên bộ đệm.

Nếu các bộ đếm đơn giản không giải thích được tình hình, một bản trace bộ nhớ có thể giúp xác định các cấp phát theo thời gian. Phạm vi của nó vẫn giới hạn trong các cấp phát mà PyTorch nhìn thấy. Do đó, đỉnh allocated thấp không loại trừ một cấp phát bên ngoài hoặc một người dùng khác của card.

Liên kết triệu chứng với bước kiểm tra tiếp theo, không chẩn đoán tự động.
Quan sátKiểm tra hữu íchThử nghiệm tiếp theo
Thất bại trong khi tảiĐịnh dạng được tải, vị trí các trọng số và bộ nhớ đã bị chiếm.Tái hiện riêng bước tải trong một tiến trình mới.
Tải thành công, không thể lan truyền ngượcMicrobatch, đầu vào, các activation được giữ lại và trạng thái vòng lặp.Giảm một chiều rồi thực hiện lại toàn bộ bước.
Chỉ riêng đánh giá bị thất bạiBatch đánh giá, các đầu ra được giữ lại và ngữ cảnh tính toán.Đo lường đánh giá với các giới hạn riêng của nó.
Allocated tăng từ lần lặp này sang lần lặp khácCác tham chiếu được giữ trong danh sách, bộ đệm ứng dụng hoặc đồ thị.Kiểm tra vòng đời của chúng trước khi đổ lỗi cho bộ cấp phát.
Reserved vẫn cao sau khi tính toánCác tensor còn sống và chính sách bộ đệm.So sánh các giá trị hiện tại, không cộng dồn các bộ đếm.
Một công cụ hệ thống cho thấy nhiều hơnPhạm vi của công cụ, ngữ cảnh GPU, các tiến trình khác và thư viện.Cô lập tải và đối chiếu với các số đọc được lấy cùng thời điểm.

Nguồn kỹ thuật: PyTorch — empty_cache giải phóng những gì · PyTorch — trace và giới hạn khả năng hiển thị bộ nhớ

11 /

Xây dựng biên an toàn từ các tải có thể so sánh

Đừng dùng một tỷ lệ biên an toàn được trình bày như thể phổ quát. Biên an toàn phải bao phủ các biến thiên đã được xác định: đầu vào dài hơn, batch được phép, đánh giá, xuất, phiên bản thư viện hoặc mức chiếm dụng khác của card. Hãy thử các trường hợp giới hạn dự kiến, rồi ghi lại những gì còn nằm ngoài phạm vi. Một lần chạy thành công trên chỉ một đầu vào nhỏ không xác nhận được tải tối đa.

Hãy thay đổi từng biến một: batch 1 rồi 2 với ngữ cảnh không đổi, hoặc ngữ cảnh 2 048 rồi 4 096 với batch không đổi. Giữ nguyên nội dung và các quy tắc chuẩn bị. Việc cắt ngắn loại bỏ một thông tin cần thiết sẽ khiến tác vụ trở nên khác đi, ngay cả khi nó làm giảm đỉnh.

Nếu các trọng số chiếm ưu thế, hãy nghiên cứu một định dạng khác trong khi kiểm soát chất lượng. Nếu các activation chiếm ưu thế, microbatch hoặc checkpointing activation có thể là hướng đi. Cách sau đánh đổi bộ nhớ lấy tính toán lại: hãy đo cả thời lượng và kiểm tra kết quả. Nếu bộ đệm KV chiếm ưu thế, hãy xem xét ngữ cảnh, mức đồng thời và chiến lược bộ đệm. Hồ sơ so sánh hoàn thiện phương pháp này bằng một quy tắc chất lượng chung.

Nguồn kỹ thuật: PyTorch — checkpointing activation và tính toán lại

12 /

Chuyển từ trace sang quyết định cấu hình

Đầu ra bạn cần là một phiếu ngắn: ước tính trọng số, tải tối đa đã thử, các pha thành công hoặc thất bại, bốn bộ đếm kèm đơn vị, môi trường và lựa chọn đã chọn. Đính kèm kết quả thô vào phiếu này. Hãy tách biệt những gì bạn đã tính, những gì bạn đã quan sát và những gì bạn còn giả định.

Sau đó so sánh nhu cầu với năng lực của từng card, đồng thời giữ các ràng buộc phần mềm. Nhiều GPU đòi hỏi phải phân chia công việc và dữ liệu; sự hiện diện của chúng không tự động tạo ra một bể bộ nhớ duy nhất cho ứng dụng. Một thất bại trên một card có thể vẫn tiếp diễn dù card khác còn bộ nhớ trống.

Giao thức PyTorch sử dụng giao diện torch.cuda; một bản build HIP/ROCm của PyTorch dùng lại tên này. Hãy xác định backend thực sự được cài đặt trước khi so sánh hai dòng phần cứng. Việc dùng cùng một hàm Python không chứng minh rằng các kernel, độ chính xác hay kết quả là tương đương.

Công cụ ước lượng kích thước cho phép lấy lại giả định ban đầu; các phiếu GPU cho phép so sánh năng lực. Sau đó hãy quay lại cùng một trường hợp công việc để kiểm tra lựa chọn. Mạng nhỏ trong phần tải xuống vẫn chỉ là bài tập về đo lường: chỉ việc chạy tải của chính bạn, trong môi trường đã được ghi lại, mới có thể xác nhận biên an toàn của bạn.

Nguồn kỹ thuật: NVIDIA — phân chia công việc trên nhiều GPU · PyTorch — giao diện torch.cuda trong các bản build HIP/ROCm