1 điểm bởi GN⁺ 2024-07-05 | 1 bình luận | Chia sẻ qua WhatsApp

Tóm tắt

Giới thiệu

  • Nhân ma trận là một thành phần thiết yếu trong các mạng nơ-ron hiện đại
  • NumPy đạt hiệu năng cao bằng cách sử dụng các thư viện BLAS bên ngoài
  • Bài viết này giải thích cách triển khai phép nhân ma trận hiệu năng cao theo cách đơn giản, có tính di động và có thể mở rộng

Hiệu năng của NumPy

  • NumPy sử dụng OpenBLAS trên CPU AMD
  • Hiệu năng được đo bằng FLOP/s
  • Đo hiệu năng đơn luồng và đa luồng của NumPy trên CPU Ryzen 7 7700

Giới hạn lý thuyết

  • Giải thích cấu trúc phân cấp bộ nhớ của CPU và các mở rộng SIMD
  • Về lý thuyết có thể đạt 163 GFLOPS ở đơn luồng và 1203 GFLOPS ở đa luồng

Triển khai đơn giản

  • Giải thích thuật toán nhân ma trận cơ bản và đo hiệu năng của cách triển khai đơn giản
  • Cách triển khai đơn giản đạt 2.7 GFLOPS

Kernel

  • Giải thích cách giải bài toán bằng cách chia phép nhân ma trận thành các bài toán con nhỏ
  • Tối ưu hóa kernel bằng các lệnh SIMD
  • Đạt 147 GFLOPS với kernel 16x6

Masking và packing

  • Giải thích cách xử lý các trường hợp biên để hỗ trợ kích thước ma trận tùy ý
  • Tối ưu hóa hiệu năng bằng masking và packing
  • Cách triển khai mới đạt 56 GFLOPS

Caching

  • Giải thích hệ thống bộ nhớ của CPU cache
  • Tối ưu hóa việc tái sử dụng dữ liệu và quản lý cache bằng cách tận dụng cache

Ý kiến của GN⁺

  • Bài viết này rất giàu tính giáo dục khi giải thích từng bước cách triển khai phép nhân ma trận hiệu năng cao
  • Có thể học được các phương pháp tối ưu hóa bằng lệnh SIMD và CPU cache
  • Hữu ích để hiểu cách hoạt động bên trong của các thư viện như NumPy
  • Các dự án khác có chức năng tương tự gồm Intel MKL, OpenBLAS, v.v.
  • Khi áp dụng công nghệ mới hoặc mã nguồn mở, cần cân nhắc giữa hiệu năng và tính di động

1 bình luận

 
GN⁺ 2024-07-05
Ý kiến Hacker News
  • Phần lớn phần mềm chưa được tối ưu, nên vẫn còn nhiều dư địa để cải thiện hiệu năng

    • Việc chọn thuật toán là quan trọng nhất
    • Cần kiểm tra xem có thể giảm các tác vụ nặng như lời gọi kernel hay không
    • Có thể cải thiện hiệu năng thông qua vector hóa
    • Cần kiểm tra xem có thể tối ưu hiệu quả bộ nhớ đệm hay không
    • Cần xem xét khả năng tối ưu hóa chuyên biệt cho phần cứng
  • Các bài báo được tham chiếu trong repo BLIS là tài liệu có thẩm quyền để hiểu chủ đề này

    • Không hiểu vì sao lại nghĩ rằng BLAS đã tối ưu có hiệu năng kém
    • Nên dùng BLAS của AMD thay vì numpy
    • BLIS được song song hóa tốt hơn OpenBLAS
  • Lệnh SIMD không cần thiết cho việc vector hóa micro-kernel

    • Nếu dùng kích thước khối phù hợp, micro-kernel thuần C của BLIS có thể đạt hơn 80% hiệu năng của bản triển khai được tối ưu thủ công
  • Hầu hết các mẫu lập trình không được chuyên biệt hoàn toàn cho phần cứng nên đang bỏ lỡ rất nhiều hiệu năng

    • Đáng tham khảo bài báo kinh điển trong CS "There's plenty of room at the top"
  • Đáng khen ở chỗ giúp việc lặp lại benchmark trở nên dễ dàng

    • Trên CPU Xeon 16 nhân, matmul.c mất 1,41 giây khi biên dịch bằng gcc -O3, 1,47 giây khi biên dịch bằng clang -O2, còn NumPy mất 1,07 giây
    • Tin rằng kernel avx512 sẽ nhanh hơn
    • Dùng pthreads thay vì omp và quản lý thread pool một cách tường minh có thể giảm overhead
  • Nghi ngờ liệu phần triển khai của NumPy có thực sự dùng đa luồng hay không

  • Tò mò vì sao nó lại nhanh hơn OpenBLAS

    • Có xử lý các chi tiết như caching
    • Tò mò không biết liệu nó có được tối ưu hơn cho một bộ xử lý cụ thể hay không
  • So sánh một bên là Python, bên kia là C thì không công bằng

    • Tốt hơn là viết cả hai bằng C rồi so sánh
  • Sự kém hiệu quả trong việc tạo mask khiến người ta bận tâm

    • Có những cách hiệu quả hơn như tạo mảng hằng toàn cục hoặc so sánh với vector hằng
    • Nhưng đây chỉ là vấn đề nhỏ, trên thực tế có lẽ không tạo ra khác biệt lớn
  • Đặt câu hỏi về tính thực tiễn của việc đa luồng hóa chính phép nhân ma trận

    • Đa luồng có lẽ hữu ích hơn cho các thuật toán sử dụng phép nhân ma trận
  • Nhắc đến tinyBLAS của jart

    • Cung cấp liên kết liên quan