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.
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.
| Giả định lưu trữ | Byte đã tính | GiB gần đúng |
|---|---|---|
| 32 bit đồng nhất | 28 000 000 000 | 26,08 |
| 16 bit đồng nhất | 14 000 000 000 | 13,04 |
| 4 bit gọn, không kể metadata | 3 500 000 000 | 3,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
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
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.
Nguồn kỹ thuật: Hugging Face — các chiến lược cache, cấp phát tĩnh và cửa sổ
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ộ đếm | Câu hỏi mà nó trả lời | Lỗi cần tránh |
|---|---|---|
| memory_allocated | Cá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_reserved | Allocator 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_reserved | Allocator 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ó
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.
| Thời điểm minh họa | Allocated | Reserved | Reserved − allocated tại thời điểm này |
|---|---|---|---|
| A | 8 GiB | 10 GiB | 2 GiB |
| B | 6 GiB | 12 GiB | 6 GiB |
Nguồn kỹ thuật: PyTorch — định nghĩa và giới hạn của max_memory_reserved
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
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.
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.
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- Notebook tính toán và đo lường
Notebook độc lập để mở, xem lại và chạy trong môi trường của bạn.
- Script mesure_memoire.py
Tính toán không phụ thuộc bên ngoài, kiểm tra môi trường và đo lường GPU rõ ràng.
- Hướng dẫn sử dụng thư mục
Điều kiện tiên quyết, lệnh, phạm vi các giai đoạn và giới hạn diễn giải.
- Archive IteraGPU Lab v1
Các tài nguyên đã được đánh phiên bản hợp nhất, cùng hướng dẫn sử dụng và giấy phép.
- Giấy phép tài nguyên
Điều kiện tái sử dụng các tệp được cung cấp.
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.
| Quan sát | Kiểm tra hữu ích | Thử 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ược | Microbatch, đầ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ại | Batch đá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ác | Cá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án | Cá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ơn | Phạ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ớ
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
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