Accelerate documentation

Profiler

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v1.15.0).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Profiler

Profiler là công cụ cho phép thu thập các chỉ số hiệu năng trong quá trình huấn luyện và suy luận. API trình quản lý ngữ cảnh của Profiler có thể được sử dụng để hiểu rõ hơn về các toán tử mô hình nào tốn kém nhất, kiểm tra hình dạng đầu vào và vết chồng xếp (stack trace) của chúng, nghiên cứu hoạt động của kernel trên thiết bị, và trực quan hóa vết thực thi. Công cụ này cung cấp thông tin chi tiết về hiệu năng của mô hình, giúp bạn tối ưu và cải thiện nó.

Hướng dẫn này giải thích cách sử dụng PyTorch Profiler để đo lường thời gian và mức tiêu thụ bộ nhớ của các toán tử trong mô hình, cũng như cách tích hợp công cụ này với Accelerate. Chúng ta sẽ xem xét các trường hợp sử dụng khác nhau và cung cấp ví dụ cho từng trường hợp.

Sử dụng profiler để phân tích thời gian thực thi

Profiler cho phép kiểm tra các toán tử nào đã được gọi trong quá trình thực thi của một phạm vi mã được bọc bởi trình quản lý ngữ cảnh profiler.

Hãy xem cách chúng ta có thể sử dụng profiler để phân tích thời gian thực thi:

PyTorch
Accelerate
import torch
import torchvision.models as models
from torch.profiler import profile, record_function, ProfilerActivity

model = models.resnet18()
inputs = torch.randn(5, 3, 224, 224)

with profile(activities=[ProfilerActivity.CPU], record_shapes=True) as prof:
    model(inputs)

print(prof.key_averages().table(sort_by="cpu_time_total", row_limit=10))

Bảng kết quả (bỏ qua một số cột):

---------------------------------  ------------  ------------  ------------  ------------  
                             Name      Self CPU     CPU total  CPU time avg    # of Calls  
---------------------------------  ------------  ------------  ------------  ------------  
                     aten::conv2d     171.000us      52.260ms       2.613ms            20  
                aten::convolution     227.000us      52.089ms       2.604ms            20  
               aten::_convolution     270.000us      51.862ms       2.593ms            20  
         aten::mkldnn_convolution      51.273ms      51.592ms       2.580ms            20  
                 aten::batch_norm     118.000us       7.059ms     352.950us            20  
     aten::_batch_norm_impl_index     315.000us       6.941ms     347.050us            20  
          aten::native_batch_norm       6.305ms       6.599ms     329.950us            20  
                 aten::max_pool2d      40.000us       4.008ms       4.008ms             1  
    aten::max_pool2d_with_indices       3.968ms       3.968ms       3.968ms             1  
                       aten::add_     780.000us     780.000us      27.857us            28  
---------------------------------  ------------  ------------  ------------  ------------  
Self CPU time total: 67.016ms

Để có kết quả chi tiết hơn và bao gồm hình dạng đầu vào của toán tử, hãy truyền group_by_input_shape=True (lưu ý: điều này yêu cầu chạy trình phân tích với record_shapes=True):

print(prof.key_averages(group_by_input_shape=True).table(sort_by="cpu_time_total", row_limit=10))

Sử dụng profiler để phân tích mức tiêu thụ bộ nhớ

Profiler cũng có thể hiển thị lượng bộ nhớ (được sử dụng bởi các tensor của mô hình) đã được cấp phát (hoặc giải phóng) trong quá trình thực thi các toán tử của mô hình. Để bật tính năng theo dõi bộ nhớ, hãy truyền profile_memory=True.

PyTorch
Accelerate
model = models.resnet18()
inputs = torch.randn(5, 3, 224, 224)

with profile(activities=[ProfilerActivity.CPU],
        profile_memory=True, record_shapes=True) as prof:
    model(inputs)

print(prof.key_averages().table(sort_by="self_cpu_memory_usage", row_limit=10))

Bảng kết quả (bỏ qua một số cột):

---------------------------------  ------------  ------------  ------------  
                             Name       CPU Mem  Self CPU Mem    # of Calls  
---------------------------------  ------------  ------------  ------------  
                      aten::empty      94.85 Mb      94.85 Mb           205  
    aten::max_pool2d_with_indices      11.48 Mb      11.48 Mb             1  
                      aten::addmm      19.53 Kb      19.53 Kb             1  
                       aten::mean      10.00 Kb      10.00 Kb             1  
              aten::empty_strided         492 b         492 b             5  
                        aten::cat         240 b         240 b             6  
                        aten::abs         480 b         240 b             4  
              aten::masked_select         120 b         112 b             1  
                         aten::ne          61 b          53 b             3  
                         aten::eq          30 b          30 b             1  
---------------------------------  ------------  ------------  ------------  
Self CPU time total: 69.332ms

Nếu bạn chỉ cần một hoặc hai con số tổng hợp để theo dõi thí nghiệm thay vì một bảng toán tử đầy đủ, hãy kết hợp trình phân tích (profiler) với các thống kê bộ nhớ thời gian chạy do PyTorch cung cấp. Điều này thường là đủ để ghi lại mức sử dụng bộ nhớ cao nhất cho mỗi lần chạy:

import torch
from accelerate import Accelerator, PartialState, ProfileKwargs

# Resolve the device type/module (cuda, xpu, ...) instead of hardcoding CUDA
device_type = PartialState().device.type
device_module = getattr(torch, device_type)


def summarize_memory_stats():
    return {
        "peak_allocated_mb": device_module.max_memory_allocated() / 1024**2,
        "peak_reserved_mb": device_module.max_memory_reserved() / 1024**2,
    }


profile_kwargs = ProfileKwargs(
    activities=["cpu", device_type],
    profile_memory=True,
    record_shapes=True,
)

accelerator = Accelerator(kwargs_handlers=[profile_kwargs])

device_module.reset_peak_memory_stats()

with accelerator.profile() as prof:
    model(inputs)

print(prof.key_averages().table(sort_by=f"self_{device_type}_memory_usage", row_limit=10))
print(summarize_memory_stats())

Mẫu này giữ cho đầu ra của trình phân tích (profiler) luôn sẵn sàng để gỡ lỗi, đồng thời tạo ra các giá trị gọn gàng có thể được ghi log vào trình theo dõi thí nghiệm.

Xuất trace chrome

Bạn có thể xem xét trình tự các toán tử và kernel CUDA được profile trong trình xem trace của Chrome (chrome://tracing):

profile_export

PyTorch
Accelerate
# Pick the available accelerator (cuda, xpu, ...) instead of hardcoding CUDA
device = torch.accelerator.current_accelerator()
device_activity = getattr(ProfilerActivity, device.type.upper())

model = models.resnet18().to(device)
inputs = torch.randn(5, 3, 224, 224).to(device)

with profile(activities=[ProfilerActivity.CPU, device_activity]) as prof:
    model(inputs)

prof.export_chrome_trace("trace.json")

Sử dụng Profiler để Phân Tích Các Công Việc Chạy Lâu

Profiler cung cấp một API bổ sung để xử lý các tác vụ chạy lâu (chẳng hạn như vòng lặp huấn luyện). Việc theo dõi toàn bộ quá trình thực thi có thể gây chậm và dẫn đến các tệp trace rất lớn. Để tránh điều này, hãy sử dụng các đối số tùy chọn:

  • schedule_option: Các tùy chọn lập lịch cho phép bạn kiểm soát thời điểm profiling được kích hoạt. Điều này hữu ích cho các tác vụ chạy dài để tránh thu thập quá nhiều dữ liệu. Các khóa khả dụng là wait, warmup, active, repeat và skip_first. Trình profiler sẽ bỏ qua skip_first bước đầu tiên, sau đó chờ trong wait bước, tiếp theo thực hiện warmup trong warmup bước kế tiếp, sau đó ghi nhận hoạt động trong active bước tiếp theo và lặp lại chu kỳ bắt đầu bằng wait bước. Số chu kỳ tùy chọn được chỉ định bằng tham số repeat, giá trị bằng không có nghĩa là các chu kỳ sẽ tiếp tục cho đến khi profiling kết thúc.
  • on_trace_ready: chỉ định một hàm nhận tham chiếu đến profiler làm đầu vào và được profiler gọi mỗi khi trace mới sẵn sàng.

Để minh họa cách API hoạt động, hãy xem xét ví dụ sau:

PyTorch
Accelerate
from torch.profiler import schedule

my_schedule = schedule(
    skip_first=1,
    wait=5,
    warmup=1,
    active=3,
    repeat=2
)

def trace_handler(p):
    output = p.key_averages().table(sort_by=f"self_{device.type}_time_total", row_limit=10)
    print(output)
    p.export_chrome_trace("/tmp/trace_" + str(p.step_num) + ".json")

with profile(
    activities=[ProfilerActivity.CPU, device_activity],
    schedule=my_schedule,
    on_trace_ready=trace_handler
) as p:
    for idx in range(8):
        model(inputs)
        p.step()

FLOPS

Sử dụng công thức để ước tính FLOPs (phép toán số dấu phẩy động) của các toán tử cụ thể (nhân ma trận và tích chập 2D).

Để đo các phép toán số dấu phẩy động (FLOPS):

PyTorch
Accelerate
with profile(
    activities=[ProfilerActivity.CPU, device_activity],
    with_flops=True
) as prof:
    model(inputs)

print(prof.key_averages().table(sort_by="flops", row_limit=10))

Bảng kết quả (bỏ qua một số cột):

-------------------------------------------------------  ------------  ------------  ------------  
                                                   Name      Self CPU     Self CUDA    Total FLOPs  
-------------------------------------------------------  ------------  ------------  ------------  
                                           aten::conv2d     197.000us       0.000us  18135613440.000  
                                            aten::addmm     103.000us      17.000us     5120000.000  
                                              aten::mul      29.000us       2.000us          30.000  
                                      aten::convolution     409.000us       0.000us            --  
                                     aten::_convolution     253.000us       0.000us            --  
                                aten::cudnn_convolution       5.465ms       2.970ms            --  
                                        cudaEventRecord     138.000us       0.000us            --  
                                  cudaStreamIsCapturing      43.000us       0.000us            --  
                                  cudaStreamGetPriority      40.000us       0.000us            --  
                       cudaDeviceGetStreamPriorityRange      10.000us       0.000us            --  
-------------------------------------------------------  ------------  ------------  ------------  
Self CPU time total: 21.938ms
Self CUDA time total: 4.165ms

Kết luận và Thông tin thêm

PyTorch Profiler là một công cụ mạnh mẽ để phân tích hiệu suất của các mô hình của bạn. Bằng cách tích hợp nó với Accelerate, bạn có thể dễ dàng tạo hồ sơ (profile) cho các mô hình và thu được những hiểu biết về hiệu suất của chúng, giúp bạn tối ưu hóa và cải thiện chúng.

Để biết thêm thông tin chi tiết, hãy tham khảo tài liệu PyTorch Profiler.

Update on GitHub