Thực thi liên tục và hàng đợi tin nhắn nhanh

Mạng thần kinh HAL 1.2 giới thiệu khái niệm thực thi hàng loạt. Thực thi liên tục là một chuỗi các thực thi của cùng một mô hình đã chuẩn bị diễn ra liên tiếp nhanh chóng, chẳng hạn như các hoạt động trên các khung của ảnh chụp máy ảnh hoặc các mẫu âm thanh liên tiếp. Đối tượng cụm được sử dụng để kiểm soát một tập hợp các lần thực thi cụm và để bảo toàn tài nguyên giữa các lần thực thi, cho phép các lần thực thi có chi phí thấp hơn. Đối tượng Burst cho phép ba tối ưu hóa:

  1. Một đối tượng cụm được tạo trước một chuỗi thực thi và được giải phóng khi chuỗi đó kết thúc. Do đó, thời gian tồn tại của đối tượng bùng nổ gợi ý cho trình điều khiển khoảng thời gian nó sẽ duy trì ở trạng thái hiệu suất cao.
  2. Một đối tượng bùng nổ có thể bảo toàn tài nguyên giữa các lần thực thi. Ví dụ: trình điều khiển có thể ánh xạ một đối tượng bộ nhớ trong lần thực thi đầu tiên và lưu ánh xạ vào bộ nhớ đệm trong đối tượng cụm để sử dụng lại trong các lần thực thi tiếp theo. Mọi tài nguyên được lưu trong bộ nhớ đệm đều có thể được giải phóng khi đối tượng cụm bị hủy hoặc khi thời gian chạy NNAPI thông báo cho đối tượng cụm rằng tài nguyên không còn cần thiết nữa.
  3. Một đối tượng bùng nổ sử dụng hàng đợi tin nhắn nhanh (FMQ) để liên lạc giữa các quy trình ứng dụng và trình điều khiển. Điều này có thể giảm độ trễ vì FMQ bỏ qua HIDL và truyền dữ liệu trực tiếp đến một quy trình khác thông qua FIFO vòng tròn nguyên tử trong bộ nhớ dùng chung. Quá trình tiêu dùng biết cách loại bỏ một mục và bắt đầu xử lý bằng cách thăm dò số lượng phần tử trong FIFO hoặc bằng cách chờ cờ sự kiện của FMQ do nhà sản xuất báo hiệu. Cờ sự kiện này là một mutex không gian người dùng nhanh (futex).

FMQ là cấu trúc dữ liệu cấp thấp, không đảm bảo trọn đời cho các quy trình và không có cơ chế tích hợp để xác định xem quy trình ở đầu bên kia của FMQ có chạy như mong đợi hay không. Do đó, nếu nhà sản xuất FMQ chết, người tiêu dùng có thể phải chờ đợi dữ liệu không bao giờ đến. Một giải pháp cho vấn đề này là trình điều khiển liên kết FMQ với đối tượng cụm cấp cao hơn để phát hiện khi quá trình thực thi cụm kết thúc.

Vì các quá trình thực thi hàng loạt hoạt động trên cùng một đối số và trả về cùng kết quả như các đường dẫn thực thi khác nên các FMQ cơ bản phải truyền cùng một dữ liệu đến và đi từ trình điều khiển dịch vụ NNAPI. Tuy nhiên, FMQ chỉ có thể chuyển các loại dữ liệu cũ. Việc truyền dữ liệu phức tạp được thực hiện bằng cách tuần tự hóa và giải tuần tự hóa các bộ đệm lồng nhau (loại vectơ) trực tiếp trong FMQ và sử dụng các đối tượng gọi lại HIDL để truyền các bộ xử lý nhóm bộ nhớ theo yêu cầu. Phía nhà sản xuất của FMQ phải gửi yêu cầu hoặc thông báo kết quả đến người tiêu dùng một cách nguyên tử bằng cách sử dụng MessageQueue::writeBlocking nếu hàng đợi bị chặn hoặc bằng cách sử dụng MessageQueue::write nếu hàng đợi không bị chặn.

Giao diện bùng nổ

Các giao diện bùng nổ cho Mạng thần kinh HAL được tìm thấy trong hardware/interfaces/neuralnetworks/1.2/ và được mô tả bên dưới. Để biết thêm thông tin về các giao diện bùng nổ trong lớp NDK, hãy xem frameworks/ml/nn/runtime/include/NeuralNetworks.h .

các loại.hal

types.hal xác định loại dữ liệu được gửi qua FMQ.

  • FmqRequestDatum : Một phần tử duy nhất của biểu diễn được tuần tự hóa của đối tượng Request thực thi và giá trị MeasureTiming , được gửi qua hàng đợi tin nhắn nhanh.
  • FmqResultDatum : Một phần tử duy nhất biểu diễn các giá trị được tuần tự hóa được trả về từ một lần thực thi ( ErrorStatus , OutputShapesTiming ), được trả về thông qua hàng đợi tin nhắn nhanh.

IBurstContext.hal

IBurstContext.hal xác định đối tượng giao diện HIDL tồn tại trong dịch vụ Mạng thần kinh.

  • IBurstContext : Đối tượng bối cảnh để quản lý tài nguyên của một cụm.

IBurstCallback.hal

IBurstCallback.hal xác định đối tượng giao diện HIDL cho lệnh gọi lại được tạo bởi thời gian chạy Mạng thần kinh và được dịch vụ Mạng thần kinh sử dụng để truy xuất các đối tượng hidl_memory tương ứng với mã định danh vị trí.

  • IBurstCallback : Đối tượng gọi lại được dịch vụ sử dụng để truy xuất các đối tượng bộ nhớ.

IPreparedModel.hal

IPreparedModel.hal được mở rộng trong HAL 1.2 với phương thức tạo đối tượng IBurstContext từ một mô hình đã chuẩn bị sẵn.

  • configureExecutionBurst : Định cấu hình một đối tượng cụm được sử dụng để thực hiện nhiều suy luận trên một mô hình đã chuẩn bị liên tiếp.

Hỗ trợ thực thi hàng loạt trong trình điều khiển

Cách đơn giản nhất để hỗ trợ các đối tượng cụm trong dịch vụ HIDL NNAPI là sử dụng hàm tiện ích cụm ::android::nn::ExecutionBurstServer::create , được tìm thấy trong ExecutionBurstServer.h và được đóng gói trong các thư viện tĩnh libneuralnetworks_commonlibneuralnetworks_util . Chức năng nhà máy này có hai tình trạng quá tải:

  • Một tình trạng quá tải chấp nhận một con trỏ tới đối tượng IPreparedModel . Hàm tiện ích này sử dụng phương thức executeSynchronously trong đối tượng IPreparedModel để thực thi mô hình.
  • Một tình trạng quá tải chấp nhận một đối tượng IBurstExecutorWithCache có thể tùy chỉnh, đối tượng này có thể được sử dụng để lưu vào bộ nhớ đệm các tài nguyên (chẳng hạn như ánh xạ hidl_memory ) tồn tại qua nhiều lần thực thi.

Mỗi tình trạng quá tải trả về một đối tượng IBurstContext (đại diện cho đối tượng cụm) chứa và quản lý luồng trình nghe chuyên dụng của riêng nó. Chuỗi này nhận các yêu cầu từ FMQ requestChannel , thực hiện suy luận, sau đó trả về kết quả thông qua FMQ kênh resultChannel . Chuỗi này và tất cả các tài nguyên khác có trong đối tượng IBurstContext sẽ tự động được giải phóng khi máy khách của cụm mất tham chiếu đến IBurstContext .

Ngoài ra, bạn có thể tạo triển khai IBurstContext của riêng mình để hiểu cách gửi và nhận tin nhắn qua FMQ requestChannelresultChannel được chuyển tới IPreparedModel::configureExecutionBurst .

Các hàm tiện ích cụm được tìm thấy trong ExecutionBurstServer.h .

/**
 * Create automated context to manage FMQ-based executions.
 *
 * This function is intended to be used by a service to automatically:
 * 1) Receive data from a provided FMQ
 * 2) Execute a model with the given information
 * 3) Send the result to the created FMQ
 *
 * @param callback Callback used to retrieve memories corresponding to
 *     unrecognized slots.
 * @param requestChannel Input FMQ channel through which the client passes the
 *     request to the service.
 * @param resultChannel Output FMQ channel from which the client can retrieve
 *     the result of the execution.
 * @param executorWithCache Object which maintains a local cache of the
 *     memory pools and executes using the cached memory pools.
 * @result IBurstContext Handle to the burst context.
 */
static sp<ExecutionBurstServer> create(
        const sp<IBurstCallback>& callback, const FmqRequestDescriptor& requestChannel,
        const FmqResultDescriptor& resultChannel,
        std::shared_ptr<IBurstExecutorWithCache> executorWithCache);

/**
 * Create automated context to manage FMQ-based executions.
 *
 * This function is intended to be used by a service to automatically:
 * 1) Receive data from a provided FMQ
 * 2) Execute a model with the given information
 * 3) Send the result to the created FMQ
 *
 * @param callback Callback used to retrieve memories corresponding to
 *     unrecognized slots.
 * @param requestChannel Input FMQ channel through which the client passes the
 *     request to the service.
 * @param resultChannel Output FMQ channel from which the client can retrieve
 *     the result of the execution.
 * @param preparedModel PreparedModel that the burst object was created from.
 *     IPreparedModel::executeSynchronously will be used to perform the
 *     execution.
 * @result IBurstContext Handle to the burst context.
 */
  static sp<ExecutionBurstServer> create(const sp<IBurstCallback>& callback,
                                         const FmqRequestDescriptor& requestChannel,
                                         const FmqResultDescriptor& resultChannel,
                                         IPreparedModel* preparedModel);

Sau đây là cách triển khai tham chiếu của giao diện cụm được tìm thấy trong trình điều khiển mẫu Mạng thần kinh tại frameworks/ml/nn/driver/sample/SampleDriver.cpp .

Return<void> SamplePreparedModel::configureExecutionBurst(
        const sp<V1_2::IBurstCallback>& callback,
        const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
        const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
        configureExecutionBurst_cb cb) {
    NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_EXECUTION,
                 "SampleDriver::configureExecutionBurst");
    // Alternatively, the burst could be configured via:
    // const sp<V1_2::IBurstContext> burst =
    //         ExecutionBurstServer::create(callback, requestChannel,
    //                                      resultChannel, this);
    //
    // However, this alternative representation does not include a memory map
    // caching optimization, and adds overhead.
    const std::shared_ptr<BurstExecutorWithCache> executorWithCache =
            std::make_shared<BurstExecutorWithCache>(mModel, mDriver, mPoolInfos);
    const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(
            callback, requestChannel, resultChannel, executorWithCache);
    if (burst == nullptr) {
        cb(ErrorStatus::GENERAL_FAILURE, {});
    } else {
        cb(ErrorStatus::NONE, burst);
    }
    return Void();
}