Trang này mô tả các cấu trúc dữ liệu và phương thức được dùng để giao tiếp hiệu quả các vùng đệm toán hạng giữa trình điều khiển và khung.
Tại thời điểm biên dịch mô hình, khung sẽ cung cấp các giá trị của toán hạng hằng số cho trình điều khiển. Tuỳ thuộc vào thời gian tồn tại của toán hạng hằng số, các giá trị của toán hạng này nằm trong một vectơ HIDL hoặc một nhóm bộ nhớ dùng chung.
- Nếu thời gian tồn tại là
CONSTANT_COPY
, thì các giá trị nằm trong trườngoperandValues
của cấu trúc mô hình. Vì các giá trị trong vectơ HIDL được sao chép trong quá trình giao tiếp giữa các quy trình (IPC), nên vectơ này thường chỉ được dùng để lưu giữ một lượng nhỏ dữ liệu, chẳng hạn như các toán hạng vô hướng (ví dụ: vô hướng kích hoạt trongADD
) và các tham số tensor nhỏ (ví dụ: tensor hình dạng trongRESHAPE
). - Nếu thời gian tồn tại là
CONSTANT_REFERENCE
, thì các giá trị nằm trong trườngpools
của cấu trúc mô hình. Chỉ các mã nhận dạng của nhóm bộ nhớ dùng chung được sao chép trong quá trình IPC thay vì sao chép các giá trị thô. Do đó, việc lưu trữ một lượng lớn dữ liệu (ví dụ: các tham số trọng số trong tích chập) bằng cách sử dụng các nhóm bộ nhớ dùng chung sẽ hiệu quả hơn so với các vectơ HIDL.
Tại thời gian thực thi mô hình, khung sẽ cung cấp các vùng đệm của toán hạng đầu vào và đầu ra cho trình điều khiển. Không giống như các hằng số thời gian biên dịch có thể được gửi trong một vectơ HIDL, dữ liệu đầu vào và đầu ra của một quá trình thực thi luôn được truyền thông qua một tập hợp các nhóm bộ nhớ.
Kiểu dữ liệu HIDL hidl_memory
được dùng trong cả quá trình biên dịch và thực thi để biểu thị một nhóm bộ nhớ dùng chung chưa được ánh xạ. Trình điều khiển phải liên kết bộ nhớ cho phù hợp để có thể sử dụng bộ nhớ dựa trên tên của kiểu dữ liệu hidl_memory
.
Sau đây là các tên bộ nhớ được hỗ trợ:
ashmem
: Bộ nhớ dùng chung của Android. Để biết thêm thông tin, hãy xem phần bộ nhớ.mmap_fd
: Bộ nhớ dùng chung được hỗ trợ bằng một bộ mô tả tệp thông quammap
.hardware_buffer_blob
: Bộ nhớ dùng chung được AHardwareBuffer hỗ trợ với định dạngAHARDWARE_BUFFER_FORMAT_BLOB
. Có trong HAL 1.2 của Mạng nơ-ron (NN). Để biết thêm thông tin, hãy xem AHardwareBuffer.hardware_buffer
: Bộ nhớ dùng chung được hỗ trợ bởi AHardwareBuffer chung không sử dụng định dạngAHARDWARE_BUFFER_FORMAT_BLOB
. Vùng đệm phần cứng ở chế độ không phải BLOB chỉ được hỗ trợ trong quá trình thực thi mô hình.Có trong NN HAL 1.2. Để biết thêm thông tin, hãy xem AHardwareBuffer.
Từ NN HAL 1.3, NNAPI hỗ trợ các miền bộ nhớ cung cấp giao diện bộ phân bổ cho các vùng đệm do trình điều khiển quản lý. Bạn cũng có thể dùng các vùng đệm do trình điều khiển quản lý làm dữ liệu đầu vào hoặc đầu ra thực thi. Để biết thêm thông tin, hãy xem phần Miền bộ nhớ.
Trình điều khiển NNAPI phải hỗ trợ việc ánh xạ tên bộ nhớ ashmem
và mmap_fd
. Từ NN HAL 1.3, trình điều khiển cũng phải hỗ trợ việc lập bản đồ hardware_buffer_blob
. Bạn không bắt buộc phải hỗ trợ chế độ không phải BLOB chung hardware_buffer
và các miền bộ nhớ.
AHardwareBuffer
AHardwareBuffer là một loại bộ nhớ dùng chung bao bọc một vùng đệm Gralloc. Trong Android 10, Neural Networks API (NNAPI) hỗ trợ việc sử dụng AHardwareBuffer, cho phép trình điều khiển thực hiện các hoạt động mà không cần sao chép dữ liệu, nhờ đó cải thiện hiệu suất và mức tiêu thụ điện năng cho các ứng dụng. Ví dụ: ngăn xếp HAL camera có thể truyền các đối tượng AHardwareBuffer đến NNAPI cho các khối lượng công việc học máy bằng cách sử dụng các xử lý AHardwareBuffer do camera NDK và API NDK đa phương tiện tạo ra. Để biết thêm thông tin, hãy xem ANeuralNetworksMemory_createFromAHardwareBuffer
.
Các đối tượng AHardwareBuffer được dùng trong NNAPI sẽ được truyền đến trình điều khiển thông qua một cấu trúc hidl_memory
có tên là hardware_buffer
hoặc hardware_buffer_blob
.
Cấu trúc hidl_memory
hardware_buffer_blob
chỉ biểu thị các đối tượng AHardwareBuffer có định dạng AHARDWAREBUFFER_FORMAT_BLOB
.
Thông tin mà khung này yêu cầu được mã hoá trong trường hidl_handle
của cấu trúc hidl_memory
. Trường hidl_handle
bao bọc native_handle
, mã hoá tất cả siêu dữ liệu bắt buộc về AHardwareBuffer hoặc vùng đệm Gralloc.
Trình điều khiển phải giải mã đúng trường hidl_handle
được cung cấp và truy cập vào bộ nhớ do hidl_handle
mô tả. Khi phương thức getSupportedOperations_1_2
, getSupportedOperations_1_1
hoặc getSupportedOperations
được gọi, trình điều khiển sẽ phát hiện xem phương thức này có thể giải mã hidl_handle
đã cung cấp và truy cập vào bộ nhớ do hidl_handle
mô tả hay không. Quá trình chuẩn bị mô hình phải thất bại nếu trường hidl_handle
được dùng cho một toán hạng hằng số không được hỗ trợ. Quá trình thực thi phải thất bại nếu trường hidl_handle
được dùng cho một toán hạng đầu vào hoặc đầu ra của quá trình thực thi không được hỗ trợ. Trình điều khiển nên trả về mã lỗi GENERAL_FAILURE
nếu quá trình chuẩn bị hoặc thực thi mô hình không thành công.
Miền bộ nhớ
Đối với các thiết bị chạy Android 11 trở lên, NNAPI hỗ trợ các miền bộ nhớ cung cấp giao diện bộ phân bổ cho các vùng đệm do trình điều khiển quản lý. Điều này cho phép truyền các bộ nhớ gốc của thiết bị giữa các quá trình thực thi, ngăn chặn việc sao chép và chuyển đổi dữ liệu không cần thiết giữa các quá trình thực thi liên tiếp trên cùng một trình điều khiển. Quy trình này được minh hoạ trong Hình 1.
Hình 1. Truyền dữ liệu đệm bằng các miền bộ nhớ
Tính năng miền bộ nhớ dành cho các tensor sử dụng chủ yếu trong nội bộ cho trình điều khiển và không cần thường xuyên truy cập vào phía máy khách. Ví dụ về các tensor như vậy bao gồm các tensor trạng thái trong mô hình chuỗi. Đối với các tensor cần truy cập CPU thường xuyên ở phía máy khách, bạn nên sử dụng các nhóm bộ nhớ dùng chung.
Để hỗ trợ tính năng miền bộ nhớ, hãy triển khai IDevice::allocate
để cho phép khung yêu cầu phân bổ vùng đệm do trình điều khiển quản lý. Trong quá trình phân bổ, khung sẽ cung cấp các thuộc tính và mẫu sử dụng sau đây cho vùng đệm:
BufferDesc
mô tả các thuộc tính bắt buộc của vùng đệm.BufferRole
mô tả mẫu sử dụng tiềm năng của vùng đệm làm đầu vào hoặc đầu ra của một mô hình đã chuẩn bị. Bạn có thể chỉ định nhiều vai trò trong quá trình phân bổ vùng đệm và vùng đệm được phân bổ chỉ có thể được dùng làm những vai trò đã chỉ định.
Vùng đệm được phân bổ là vùng đệm nội bộ của trình điều khiển. Trình điều khiển có thể chọn mọi vị trí bộ nhớ đệm hoặc bố cục dữ liệu. Khi vùng đệm được phân bổ thành công, ứng dụng của trình điều khiển có thể tham chiếu hoặc tương tác với vùng đệm bằng mã thông báo được trả về hoặc đối tượng IBuffer
.
Mã thông báo từ IDevice::allocate
được cung cấp khi tham chiếu vùng đệm dưới dạng một trong các đối tượng MemoryPool
trong cấu trúc Request
của một quá trình thực thi. Để ngăn một quy trình cố gắng truy cập vào bộ đệm được phân bổ trong một quy trình khác, trình điều khiển phải áp dụng quy trình xác thực thích hợp cho mỗi lần sử dụng bộ đệm. Trình điều khiển phải xác thực rằng mức sử dụng bộ nhớ đệm là một trong các vai trò BufferRole
được cung cấp trong quá trình phân bổ và phải ngay lập tức thất bại khi thực thi nếu mức sử dụng là bất hợp pháp.
Đối tượng IBuffer
được dùng để sao chép bộ nhớ một cách rõ ràng. Trong một số trường hợp, máy khách của trình điều khiển phải khởi động vùng đệm do trình điều khiển quản lý từ một nhóm bộ nhớ dùng chung hoặc sao chép vùng đệm ra một nhóm bộ nhớ dùng chung. Ví dụ về các trường hợp sử dụng:
- Khởi chạy tensor trạng thái
- Lưu kết quả trung gian vào bộ nhớ đệm
- Thực thi dự phòng trên CPU
Để hỗ trợ những trường hợp sử dụng này, trình điều khiển phải triển khai IBuffer::copyTo
và IBuffer::copyFrom
bằng ashmem
, mmap_fd
và hardware_buffer_blob
nếu trình điều khiển hỗ trợ việc phân bổ miền bộ nhớ. Trình điều khiển không bắt buộc phải hỗ trợ chế độ không phải BLOB hardware_buffer
.
Trong quá trình phân bổ vùng đệm, kích thước của vùng đệm có thể được suy ra từ các toán hạng mô hình tương ứng của tất cả các vai trò do BufferRole
chỉ định và kích thước được cung cấp trong BufferDesc
. Khi kết hợp tất cả thông tin về kích thước, vùng đệm có thể có kích thước hoặc thứ hạng không xác định. Trong trường hợp như vậy, vùng đệm ở trạng thái linh hoạt, trong đó các phương diện được cố định khi dùng làm đầu vào mô hình và ở trạng thái động khi dùng làm đầu ra mô hình. Bạn có thể dùng cùng một vùng đệm với nhiều hình dạng đầu ra trong nhiều lần thực thi và trình điều khiển phải xử lý việc đổi kích thước vùng đệm một cách thích hợp.
Miền bộ nhớ là một tính năng không bắt buộc. Trình điều khiển có thể xác định rằng không thể hỗ trợ một yêu cầu phân bổ nhất định vì một số lý do. Ví dụ:
- Bộ nhớ đệm được yêu cầu có kích thước động.
- Trình điều khiển có các quy tắc ràng buộc về bộ nhớ, ngăn trình điều khiển xử lý các vùng đệm lớn.
Có thể có nhiều luồng khác nhau đọc từ vùng đệm do trình điều khiển quản lý cùng một lúc. Việc truy cập vào vùng đệm đồng thời để ghi hoặc đọc/ghi là không xác định, nhưng không được làm hỏng dịch vụ trình điều khiển hoặc chặn người gọi vô thời hạn. Trình điều khiển có thể trả về lỗi hoặc để nội dung của vùng đệm ở trạng thái không xác định.