Uỷ quyền GPU cho LiteRT

Việc sử dụng đơn vị xử lý đồ hoạ (GPU) để chạy các mô hình học máy (ML) có thể cải thiện đáng kể hiệu suất của mô hình và trải nghiệm người dùng của các ứng dụng có hỗ trợ ML. LiteRT cho phép sử dụng GPU và các bộ xử lý chuyên dụng khác thông qua trình điều khiển phần cứng có tên là delegate. Việc cho phép sử dụng GPU với các ứng dụng ML LiteRT có thể mang lại những lợi ích sau:

  • Tốc độ – GPU được thiết kế để có thông lượng cao cho các khối lượng công việc song song ở mức cao. Thiết kế này giúp chúng phù hợp với các mạng nơ-ron sâu, bao gồm một số lượng lớn các toán tử, mỗi toán tử hoạt động trên các tensor đầu vào có thể được xử lý song song, thường dẫn đến độ trễ thấp hơn. Trong trường hợp tốt nhất, việc chạy mô hình trên GPU có thể diễn ra đủ nhanh để cho phép các ứng dụng theo thời gian thực mà trước đây không thể thực hiện được.
  • Hiệu suất năng lượng – GPU thực hiện các phép tính học máy theo cách rất hiệu quả và tối ưu, thường tiêu thụ ít năng lượng hơn và tạo ra ít nhiệt hơn so với cùng một tác vụ chạy trên CPU.

Tài liệu này cung cấp thông tin tổng quan về khả năng hỗ trợ GPU trong LiteRT và một số cách sử dụng nâng cao cho bộ xử lý GPU. Để biết thêm thông tin cụ thể về cách triển khai tính năng hỗ trợ GPU trên các nền tảng cụ thể, hãy xem các hướng dẫn sau:

Hỗ trợ các thao tác ML trên GPU

Có một số hạn chế đối với những thao tác học máy (hoặc ops) TensorFlow có thể được tăng tốc bằng uỷ quyền GPU LiteRT. Uỷ quyền này hỗ trợ các thao tác sau với độ chính xác của số thực 16 bit và 32 bit:

  • ADD
  • AVERAGE_POOL_2D
  • CONCATENATION
  • CONV_2D
  • DEPTHWISE_CONV_2D v1-2
  • EXP
  • FULLY_CONNECTED
  • LOGICAL_AND
  • LOGISTIC
  • LSTM v2 (Basic LSTM only)
  • MAX_POOL_2D
  • MAXIMUM
  • MINIMUM
  • MUL
  • PAD
  • PRELU
  • RELU
  • RELU6
  • RESHAPE
  • RESIZE_BILINEAR v1-3
  • SOFTMAX
  • STRIDED_SLICE
  • SUB
  • TRANSPOSE_CONV

Theo mặc định, tất cả các thao tác chỉ được hỗ trợ ở phiên bản 1. Việc bật tính năng hỗ trợ lượng tử hoá sẽ bật các phiên bản thích hợp, ví dụ: ADD v2.

Khắc phục sự cố về việc hỗ trợ GPU

Nếu một số thao tác không được uỷ quyền GPU hỗ trợ, thì khung sẽ chỉ chạy một phần của biểu đồ trên GPU và phần còn lại trên CPU. Do chi phí đồng bộ hoá CPU/GPU cao, chế độ thực thi phân chia như thế này thường dẫn đến hiệu suất chậm hơn so với khi toàn bộ mạng chỉ chạy trên CPU. Trong trường hợp này, ứng dụng sẽ tạo cảnh báo, chẳng hạn như:

WARNING: op code #42 cannot be handled by this delegate.

Không có lệnh gọi lại cho các lỗi thuộc loại này, vì đây không phải là lỗi thời gian chạy thực tế. Khi kiểm thử việc thực thi mô hình bằng uỷ quyền GPU, bạn nên chú ý đến những cảnh báo này. Số lượng cảnh báo lớn có thể cho thấy mô hình của bạn không phù hợp nhất để sử dụng cho tính năng tăng tốc GPU và có thể yêu cầu tái cấu trúc mô hình.

Ví dụ về các mô hình

Các mô hình ví dụ sau đây được xây dựng để tận dụng tính năng tăng tốc GPU bằng LiteRT và được cung cấp để tham khảo và thử nghiệm:

Tối ưu hoá cho GPU

Các kỹ thuật sau đây có thể giúp bạn đạt được hiệu suất tốt hơn khi chạy các mô hình trên phần cứng GPU bằng cách sử dụng uỷ quyền GPU LiteRT:

  • Các thao tác định hình lại – Một số thao tác diễn ra nhanh trên CPU có thể tốn nhiều chi phí cho GPU trên thiết bị di động. Các thao tác định hình lại đặc biệt tốn kém khi chạy, bao gồm BATCH_TO_SPACE, SPACE_TO_BATCH, SPACE_TO_DEPTH, v.v. Bạn nên xem xét kỹ việc sử dụng các thao tác định hình lại và cân nhắc rằng thao tác này có thể chỉ được áp dụng để khám phá dữ liệu hoặc cho các lần lặp lại ban đầu của mô hình. Việc xoá các thành phần này có thể cải thiện đáng kể hiệu suất.

  • Các kênh dữ liệu hình ảnh – Trên GPU, dữ liệu tensor được chia thành 4 kênh. Do đó, một phép tính trên tensor có hình dạng [B,H,W,5] sẽ thực hiện gần như tương tự trên tensor có hình dạng [B,H,W,8], nhưng kém hơn đáng kể so với [B,H,W,4]. Nếu phần cứng camera mà bạn đang sử dụng hỗ trợ khung hình ảnh ở định dạng RGBA, thì việc truyền dữ liệu đầu vào 4 kênh đó sẽ nhanh hơn đáng kể, vì việc này tránh được việc sao chép bộ nhớ từ RGB 3 kênh sang RGBX 4 kênh.

  • Các mô hình được tối ưu hoá cho thiết bị di động – Để có hiệu suất tốt nhất, bạn nên cân nhắc việc huấn luyện lại trình phân loại bằng một cấu trúc mạng được tối ưu hoá cho thiết bị di động. Việc tối ưu hoá để suy luận trên thiết bị có thể giảm đáng kể độ trễ và mức tiêu thụ điện năng bằng cách tận dụng các tính năng phần cứng của thiết bị di động.

Hỗ trợ GPU nâng cao

Bạn có thể sử dụng các kỹ thuật nâng cao khác với quy trình xử lý GPU để cải thiện hiệu suất cho các mô hình của mình, bao gồm cả việc lượng tử hoá và chuyển đổi tuần tự. Các phần sau đây sẽ mô tả chi tiết hơn về những kỹ thuật này.

Sử dụng các mô hình được lượng tử hoá

Phần này giải thích cách uỷ quyền GPU tăng tốc các mô hình được định lượng 8 bit, bao gồm cả những mô hình sau:

Để tối ưu hoá hiệu suất, hãy sử dụng các mô hình có cả tensor đầu vào và đầu ra dấu phẩy động.

Cơ chế này hoạt động như thế nào?

Vì phần phụ trợ GPU chỉ hỗ trợ việc thực thi dấu phẩy động, nên chúng tôi chạy các mô hình được lượng tử hoá bằng cách cung cấp cho mô hình đó "chế độ xem dấu phẩy động" của mô hình ban đầu. Nhìn chung, quá trình này bao gồm các bước sau:

  • Các tensor hằng số (chẳng hạn như trọng số/độ lệch) sẽ được giảm lượng tử hoá một lần vào bộ nhớ GPU. Thao tác này xảy ra khi uỷ quyền được bật cho LiteRT.

  • Đầu vào và đầu ra của chương trình GPU (nếu được định lượng 8 bit) sẽ được huỷ định lượng và định lượng (tương ứng) cho mỗi lượt suy luận. Thao tác này được thực hiện trên CPU bằng cách sử dụng các nhân được tối ưu hoá của LiteRT.

  • Trình mô phỏng lượng tử hoá được chèn giữa các thao tác để mô phỏng hành vi được lượng tử hoá. Phương pháp này là cần thiết đối với các mô hình mà các hoạt động dự kiến sẽ tuân theo các giới hạn đã học được trong quá trình lượng tử hoá.

Để biết thông tin về cách bật tính năng này bằng uỷ quyền GPU, hãy xem phần sau:

Giảm thời gian khởi chạy bằng cách sử dụng quy trình chuyển đổi tuần tự

Tính năng uỷ quyền GPU cho phép bạn tải từ mã nhân đã biên dịch trước và dữ liệu mô hình được chuyển đổi tuần tự và lưu trên đĩa từ các lần chạy trước. Phương pháp này tránh được việc biên dịch lại và có thể giảm thời gian khởi động tới 90%. Sự cải thiện này đạt được bằng cách đánh đổi dung lượng ổ đĩa để tiết kiệm thời gian. Bạn có thể bật tính năng này bằng một số lựa chọn cấu hình, như trong các ví dụ về mã sau:

C++

    TfLiteGpuDelegateOptionsV2 options = TfLiteGpuDelegateOptionsV2Default();
    options.experimental_flags |= TFLITE_GPU_EXPERIMENTAL_FLAGS_ENABLE_SERIALIZATION;
    options.serialization_dir = kTmpDir;
    options.model_token = kModelToken;

    auto* delegate = TfLiteGpuDelegateV2Create(options);
    if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;
      

Java

    GpuDelegate delegate = new GpuDelegate(
      new GpuDelegate.Options().setSerializationParams(
        /* serializationDir= */ serializationDir,
        /* modelToken= */ modelToken));

    Interpreter.Options options = (new Interpreter.Options()).addDelegate(delegate);
      

Khi sử dụng tính năng chuyển đổi tuần tự, hãy đảm bảo mã của bạn tuân thủ các quy tắc triển khai sau:

  • Lưu trữ dữ liệu tuần tự hoá trong một thư mục mà các ứng dụng khác không truy cập được. Trên thiết bị Android, hãy sử dụng getCodeCacheDir(). Thư mục này trỏ đến một vị trí riêng tư đối với ứng dụng hiện tại.
  • Mã thông báo mô hình phải là duy nhất đối với thiết bị cho mô hình cụ thể. Bạn có thể tính toán mã thông báo mô hình bằng cách tạo dấu vân tay từ dữ liệu mô hình bằng các thư viện như farmhash::Fingerprint64.