Neural Networks HAL 1.2 giới thiệu khái niệm về thực thi hàng loạt. Thực thi hàng loạt là một chuỗi quá trình thực thi cùng một mô hình đã chuẩn bị diễn ra liên tiếp và nhanh chóng, chẳng hạn như quá trình thực thi hoạt động trên các khung hình của một lần thu nạp máy ảnh/máy quay hoặc mẫu âm thanh liên tiếp. Đối tượng hàng loạt được dùng để kiểm soát một tập hợp các quá trình thực thi hàng loạt và để giữ lại tài nguyên giữa các quá trình thực thi, cho phép các quá trình thực thi có chi phí thấp hơn. Đối tượng Burst cho phép 3 phương pháp tối ưu hoá:
- Đối tượng hàng loạt được tạo trước một chuỗi các quá trình thực thi và được giải phóng khi chuỗi đó kết thúc. Do đó, vòng đời của đối tượng hàng loạt sẽ gợi ý cho trình điều khiển biết thời gian cần duy trì trạng thái hiệu suất cao.
- Đối tượng hàng loạt có thể giữ lại tài nguyên giữa các quá trình thực thi. Ví dụ: trình điều khiển có thể liên kết đối tượng bộ nhớ trong lần thực thi đầu tiên và lưu trữ mối liên kết đó vào bộ nhớ đệm trong đối tượng hàng loạt để dùng lại trong các lần thực thi tiếp theo. Mọi tài nguyên được lưu vào bộ nhớ đệm đều có thể được giải phóng khi đối tượng hàng loạt bị huỷ hoặc khi thời gian chạy NNAPI thông báo cho đối tượng hàng loạt rằng không còn cần tài nguyên đó nữa.
- Đối tượng hàng loạt sử dụng hàng đợi tin nhắn nhanh (FMQ) để giao tiếp giữa các quy trình ứng dụng và trình điều khiển. Điều này có thể làm 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 nguyên tử trong bộ nhớ dùng chung. Quy trình người tiêu dùng biết cách loại bỏ một mục khỏi hàng đợi 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 (được nhà sản xuất báo hiệu). Cờ sự kiện này là mutex không gian người dùng nhanh (futex).
FMQ là một cấu trúc dữ liệu cấp thấp không đảm bảo vòng đời trên các quy trình và không có cơ chế tích hợp để xác định xem quy trình ở đầu kia của FMQ có chạy như mong đợi hay không. Do đó, nếu nhà sản xuất cho FMQ ngừng hoạt động, thì người tiêu dùng có thể bị kẹt khi chờ 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 hàng loạt cấp cao hơn để phát hiện thời điểm quá trình thực thi hàng loạt kết thúc.
Vì các quá trình thực thi hàng loạt hoạt động trên cùng các đố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 dữ liệu đến và 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ũ đơn giản. Việc chuyển dữ liệu phức tạp được thực hiện bằng cách chuyển đổi tuần tự và huỷ chuyển đổi tuần tự 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 để chuyển các trình 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 các thông báo yêu cầu hoặc 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 đang chặn hoặc
bằng cách sử dụng MessageQueue::write nếu hàng đợi không chặn.
Giao diện hàng loạt
Bạn có thể tìm thấy các giao diện hàng loạt cho Neural Networks HAL 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 hàng loạt trong lớp NDK, hãy xem
frameworks/ml/nn/runtime/include/NeuralNetworks.h.
types.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 chuyển đổi tuần tự của đối tượng thực thiRequestvà giá trịMeasureTiming, được gửi qua hàng đợi tin nhắn nhanh.FmqResultDatum: Một phần tử duy nhất của biểu diễn được chuyển đổi tuần tự của các giá trị được trả về từ một quá trình thực thi (ErrorStatus,OutputShapesvàTiming), đượ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 nằm trong dịch vụ Neural Networks.
IBurstContext: Đối tượng ngữ cảnh để quản lý tài nguyên của một hàng loạt.
IBurstCallback.hal
IBurstCallback.hal
xác định đối tượng giao diện HIDL cho lệnh gọi lại do thời gian chạy Neural Networks tạo và được dịch vụ Neural Networks dùng để truy xuất các đối tượng hidl_memory tương ứng với mã nhận dạng vị trí.
- IBurstCallback: Đối tượng gọi lại được dịch vụ dùng để truy xuất các đối tượng bộ nhớ.
IPreparedModel.hal
IPreparedModel.hal
được mở rộng trong HAL 1.2 bằng một phương thức để tạo đối tượng IBurstContext từ một mô hình đã chuẩn bị.
configureExecutionBurst: Định cấu hình đối tượng hàng loạt dùng để thực thi nhiều suy luận trên một mô hình đã chuẩn bị liên tiếp và nhanh chóng.
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 loạt ảnh trong dịch vụ HIDL NNAPI là sử dụng
hàm hiệu dụng loạt ảnh ::android::nn::ExecutionBurstServer::create. Hàm này
có trong
ExecutionBurstServer.h
và được đóng gói trong các thư viện tĩnh libneuralnetworks_common và libneuralnetworks_util
. Hàm nhà máy này có 2 phương thức nạp chồng:
- Một phương thức nạp chồng chấp nhận con trỏ đến đối tượng
IPreparedModel. Hàm hiệu dụng này sử dụng phương thứcexecuteSynchronouslytrong đối tượngIPreparedModelđể thực thi mô hình. - Một phương thức nạp chồng chấp nhận đối tượng
IBurstExecutorWithCachecó thể tuỳ chỉnh. Đối tượng này có thể được dùng để lưu trữ các tài nguyên vào bộ nhớ đệm (chẳng hạn như các mối liên kếthidl_memory) tồn tại trên nhiều quá trình thực thi.
Mỗi phương thức nạp chồng trả về một đối tượng IBurstContext (đại diện cho đối tượng hàng loạt) chứa và quản lý luồng trình nghe riêng. Luồng 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 resultChannel. Luồng 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 hàng loạt mất tham chiếu đến IBurstContext.
Ngoài ra, bạn có thể tạo quá trình triển khai IBurstContext của riêng mình để hiểu cách gửi và nhận tin nhắn qua các FMQ requestChannel và resultChannel được truyền đến IPreparedModel::configureExecutionBurst.
Bạn có thể tìm thấy các hàm tiện ích hàng loạt 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à quá trình triển khai tham chiếu của giao diện hàng loạt có trong trình điều khiển mẫu Neural Networks 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();
}