Chọn một câu hỏi trước khi mở một trace
Một trace trả lời tốt hơn cho một câu hỏi cụ thể: liệu phép tính có đang chờ dữ liệu, một bản sao có bị lặp lại, hay một toán tử nhỏ có bị gọi quá thường xuyên? Hãy xác định đầu vào, đầu ra và các ranh giới của bước của bạn. Với huấn luyện, hãy nêu rõ bước đó có chứa lan truyền ngược, cập nhật bộ tối ưu và đọc batch hay không. Với suy luận, hãy tách riêng việc tải mô hình và truy vấn.
Hãy giữ một kịch bản ngắn mà bạn biết rõ tính đúng đắn. Ghi lại hình dạng, batch, độ chính xác, chế độ mô hình, khả năng biên dịch và nguồn dữ liệu. Một đầu vào được đơn giản hóa có thể giúp cô lập một hành vi, nhưng nó không còn nhất thiết đại diện cho toàn bộ tải. Hãy nêu rõ khác biệt này trong báo cáo.
Hãy cố định đơn vị cuối cùng: mili giây mỗi bước hoặc số ví dụ xử lý được mỗi giây. Tổng các sự kiện không thay thế cho thời gian trôi qua. Hãy so sánh các cửa sổ có cùng ranh giới đọc và truyền.
Phân biệt thời gian CPU, công việc GPU và thời gian chờ
CPU chuẩn bị và khởi chạy các phép toán; GPU có thể thực thi chúng sau đó. Vì vậy một khoảng Python có thể chứa thời gian khởi chạy, thời gian chờ, hoặc cả hai. Tài liệu CUDA của PyTorch chỉ ra rằng các phép đo chính xác phải tính đến tính bất đồng bộ này, đặc biệt bằng đồng bộ hóa hoặc các sự kiện phù hợp với phạm vi đo.
Đối với một phép đo thời lượng GPU có mục tiêu, các sự kiện CUDA có thể phù hợp. Đối với độ trễ từ đầu đến cuối, hãy chờ công việc nằm trong độ trễ đó kết thúc và đo toàn bộ yêu cầu. Đừng trộn lẫn hai đơn vị này. Một đồng bộ hóa được thêm vào giữa mỗi phép toán có thể loại bỏ sự chồng lấn thực sự và biến đổi chương trình mà bạn đang cố tìm hiểu.
Trong profiler, thời gian riêng của một toán tử và thời gian bao gồm các toán tử con cũng trả lời những câu hỏi khác nhau. Hãy xem dòng thời gian trước khi cộng các dòng trong bảng. Các hoạt động đồng thời hoặc lồng nhau không đại diện cho những phần thời gian trôi qua tách rời nhau.
Dành riêng một giai đoạn khởi động và một cửa sổ hoạt động
Lần chạy đầu tiên có thể bao gồm khởi tạo, tải hoặc biên dịch. Hãy quyết định xem câu hỏi của bạn liên quan đến giai đoạn khởi động này hay đến một giai đoạn đã ổn định. Hãy giữ lại cả hai quan sát khi chúng quan trọng đối với việc sử dụng, thay vì xóa đi chi phí ban đầu bằng một giá trị trung bình được trình bày như thể là tổng thể.
Hàm schedule cho phép phân biệt thời gian chờ, thời gian chuẩn bị thu thập và cửa sổ hoạt động. Việc khởi động profiler không phải là bằng chứng rằng mô hình của bạn đã đạt trạng thái ổn định. Hãy kiểm tra cả các hình dạng gặp phải và trạng thái của các bộ nhớ đệm. Một ứng dụng có đầu vào thay đổi có thể gặp những đường đi mới sau nhiều lần lặp.
Lịch trình mang tính minh họa được đề xuất bên dưới chờ một bước, chuẩn bị một bước và ghi lại hai bước. Bốn bước đủ để giải thích cơ chế, nhưng không đủ để thiết lập một phân bố hiệu năng. Trong một chiến dịch thực sự, hãy chọn một cửa sổ có lý do chính đáng và lặp lại phép đo bên ngoài profiler sau khi phân tích.
Ví dụ đề xuất: bốn bước với các ranh giới dễ đọc
Đoạn mã sau đây chưa được thực thi. Nó giả định rằng model, optimizer, loss_fn, loader và device đều tồn tại, rằng mô hình nằm trên device và loader cung cấp ít nhất bốn batch gồm các cặp x, y. Nó thực hiện các cập nhật: hãy dùng một trạng thái thử nghiệm được dành cho việc này, chứ không phải một phiên mà bạn cần giữ nguyên các trọng số.
Các nhãn phân tách việc đọc CPU, truyền dữ liệu và huấn luyện. Iterator được tạo trước cửa sổ, điều này loại trừ một phần thời gian khởi động của nó khỏi phạm vi đo. Tệp được chọn mới để tránh ghi đè lên một vết cũ. Ví dụ từ chối thu thập GPU khi không khả dụng thay vì âm thầm trình bày một vết CPU như một phân tích GPU.
Tín hiệu step() đẩy tiến trình lập lịch sau mỗi bước. Công thức chính thức mô tả mối liên hệ này giữa các vòng lặp và việc thu thập. Trên một hệ ROCm, thiết bị PyTorch vẫn được đặt tên là cuda; tuy nhiên khả năng thu thập trên bộ tăng tốc phụ thuộc vào bản build và các công cụ của nó. Hãy kiểm tra những hoạt động thực sự có trong kết quả.
from pathlib import Path
import torch
from torch.profiler import (
profile, schedule, record_function,
ProfilerActivity, supported_activities,
)
trace = Path("trace-etape.json")
if trace.exists():
raise FileExistsError("Chọn một tên vết mới")
activities = [ProfilerActivity.CPU]
if device.type == "cuda":
if ProfilerActivity.CUDA not in supported_activities():
raise RuntimeError("Thu thập GPU không khả dụng trong bản build này")
activities.append(ProfilerActivity.CUDA)
iterator = iter(loader)
model.train()
with profile(
activities=activities,
schedule=schedule(wait=1, warmup=1, active=2, repeat=1),
record_shapes=False, profile_memory=False, with_stack=False,
on_trace_ready=lambda p: p.export_chrome_trace(str(trace)),
) as prof:
for _ in range(4):
with record_function("lecture_batch_cpu"):
x, y = next(iterator)
with record_function("transfert"):
x, y = x.to(device), y.to(device)
with record_function("entrainement"):
optimizer.zero_grad(set_to_none=True)
loss = loss_fn(model(x), y)
loss.backward()
optimizer.step()
prof.step()
print(prof.key_averages().table(
sort_by="self_cpu_time_total", row_limit=8,
))Biến một quan sát thành giả thuyết có thể kiểm chứng
Hãy bắt đầu với cửa sổ đang hoạt động và kiểm tra xem các nhãn mong đợi có xuất hiện không. Sau đó xem xét các khoảng trống giữa các hoạt động, các bản sao chép và các lần lặp lại. Một khoảng chờ dài trong lecture_batch_cpu hướng đến pipeline đầu vào; nó không đo trực tiếp lưu trữ. Việc sao chép thường xuyên gợi ý nên xem xét vị trí đặt các tensor, nhưng không chứng minh rằng nó là vô ích.
Hãy đưa ra một giả thuyết duy nhất rồi đề xuất một thay đổi có kiểm soát. Ví dụ, nếu một hằng số được tạo lại và truyền đi ở mỗi bước, hãy kiểm tra xem vòng đời của nó có thể bao trùm nhiều bước mà không làm thay đổi kết quả hay không. Nếu một toán tử có vẻ chiếm ưu thế, hãy xem xét các hình dạng và số lần gọi của nó trước khi tìm một thứ thay thế.
Các dòng dưới đây là những cách đọc khả dĩ, không phải những kết luận rút ra từ một vết đã thực thi. Không có thời lượng hay mức tăng tốc nào được công bố. Kết luận hữu ích là một thử nghiệm tiếp theo có thể xác nhận hoặc bác bỏ nguyên nhân được đề xuất.
Cuộn bảng để xem tất cả các cột.| Quan sát khả dĩ | Giả thuyết | Kiểm tra tiếp theo |
|---|---|---|
| GPU không hoạt động trong khi đọc | Pipeline đầu vào không theo kịp | Cùng một phép tính với batch đã được chuẩn bị sẵn |
| Sao chép lặp lại một hằng số | Vị trí hoặc vòng đời không phù hợp | Di chuyển một lần, kiểm tra các đầu ra |
| Nhiều lần khởi chạy nhỏ | Công việc bị phân mảnh | Xem xét việc gộp nhóm và chi phí tổng thể |
| Một toán tử chạy lâu | Hình dạng hoặc thuật toán mang tính quyết định | So sánh cùng toán tử đó và các đầu vào của nó |
Giới hạn chi phí và thông tin của việc ghi đo
Hãy bắt đầu với một lần thu thập ngắn và ít tùy chọn. Chỉ bật hình dạng, ngăn xếp hoặc bộ nhớ khi có một câu hỏi yêu cầu. API PyTorch nêu rõ rằng những thông tin này làm tăng chi phí; việc thu thập hình dạng thậm chí có thể giữ các tham chiếu đến tensor. Do đó, một hồ sơ chi tiết có thể làm thay đổi thời lượng hoặc mức sử dụng bộ nhớ của chương trình.
Một trace có thể chứa tên toán tử, các shape và, tùy theo tùy chọn, đường dẫn mã. Hãy kiểm tra nó trước khi chia sẻ. Nhãn vùng phải mô tả bước mà không kèm email, token, đường dẫn riêng tư hay nội dung đầu vào. Hãy chọn trình đọc trace phù hợp với môi trường của bạn và giữ quyền kiểm soát việc thu thập.
Nếu các sự kiện GPU mong đợi không xuất hiện, đừng điền thời gian của chúng bằng số không. Hãy nêu rõ chúng chưa được quan sát và xem xét khả năng hỗ trợ của việc thu thập. Việc công cụ không có sự kiện không phải là bằng chứng cho thấy không có tính toán.
Xác nhận tối ưu hóa ngoài profiler
Hãy bắt đầu lại từ cùng một trạng thái liên quan và so sánh tính đúng đắn trước và sau khi thay đổi. Với huấn luyện, một bước bổ sung sẽ thay đổi trọng số; hai lần ghi lại chạy liên tiếp không nhất thiết tạo thành một so sánh tương đương. Hãy giữ mã, tham số và điểm khởi đầu để có thể giải thích sự khác biệt.
Sau đó đo kịch bản mà không thu thập chi tiết, với cùng bước khởi động và nhiều lần chạy. Hãy báo cáo phạm vi, giá trị thô và độ phân tán của chúng. Một cải thiện cục bộ có thể biến mất trong toàn bộ vòng lặp hoặc làm giảm chất lượng: cả hai đều phải nằm trong quyết định.
Cuối cùng, hãy dùng các quan sát để xác định rõ tài nguyên thực sự cần thiết. Một trace trên máy của bạn không xếp hạng các gói Kernodeck và không chứng minh được CPU máy chủ hay mạng của một server đi thuê. So sánh GPU đòi hỏi tải, điều kiện và kết quả có thể so sánh trên các tài nguyên liên quan.