Trình điều khiển Neural Networks API

Trang này cung cấp thông tin tổng quan về cách triển khai trình điều khiển Neural Networks API (NNAPI). Để biết thêm thông tin chi tiết, hãy xem tài liệu có trong các tệp định nghĩa HAL trong hardware/interfaces/neuralnetworks. Bạn có thể xem ví dụ về cách triển khai trình điều khiển trong frameworks/ml/nn/driver/sample.

Để biết thêm thông tin về Neural Networks API, hãy xem phần Neural Networks API.

HAL mạng nơron

HAL của Mạng nơron (NN) xác định một bản tóm tắt của nhiều thiết bị, chẳng hạn như đơn vị xử lý đồ hoạ (GPU) và bộ xử lý tín hiệu kỹ thuật số (DSP) trong một sản phẩm (ví dụ: điện thoại hoặc máy tính bảng). Trình điều khiển cho các thiết bị này phải tuân thủ NN HAL. Giao diện được chỉ định trong các tệp định nghĩa HAL trong hardware/interfaces/neuralnetworks.

Quy trình chung của giao diện giữa khung và trình điều khiển được mô tả trong hình 1.

Quy trình của mạng nơron

Hình 1. Quy trình của mạng nơron

Khởi chạy

Khi khởi động, khung này sẽ truy vấn trình điều khiển về các chức năng của trình điều khiển bằng cách sử dụng IDevice::getCapabilities_1_3. Cấu trúc @1.3::Capabilities bao gồm tất cả các loại dữ liệu và biểu thị hiệu suất không thư giãn bằng một vectơ.

Để xác định cách phân bổ các phép tính cho các thiết bị có sẵn, khung này sử dụng các chức năng để hiểu tốc độ và mức tiết kiệm năng lượng của từng trình điều khiển có thể thực hiện một quá trình thực thi. Để cung cấp thông tin này, trình điều khiển phải cung cấp các con số hiệu suất được chuẩn hoá dựa trên việc thực thi khối lượng công việc tham chiếu.

Để xác định các giá trị mà trình điều khiển trả về để phản hồi IDevice::getCapabilities_1_3, hãy sử dụng ứng dụng điểm chuẩn NNAPI để đo lường hiệu suất cho các loại dữ liệu tương ứng. Bạn nên sử dụng các mô hình MobileNet v1 và v2, asr_floattts_float để đo lường hiệu suất cho các giá trị dấu phẩy động 32 bit và các mô hình lượng tử hoá MobileNet v1 và v2 cho các giá trị lượng tử hoá 8 bit. Để biết thêm thông tin, hãy xem bài viết Bộ kiểm thử học máy Android.

Trong Android 9 trở xuống, cấu trúc Capabilities chỉ bao gồm thông tin về hiệu suất trình điều khiển cho tensor dấu phẩy động và lượng tử hoá, đồng thời không bao gồm các loại dữ liệu vô hướng.

Trong quá trình khởi chạy, khung có thể truy vấn thêm thông tin bằng cách sử dụng IDevice::getType, IDevice::getVersionString, IDevice:getSupportedExtensionsIDevice::getNumberOfCacheFilesNeeded.

Giữa các lần khởi động lại sản phẩm, khung này dự kiến tất cả các truy vấn được mô tả trong phần này sẽ luôn báo cáo cùng một giá trị cho một trình điều khiển nhất định. Nếu không, ứng dụng sử dụng trình điều khiển đó có thể giảm hiệu suất hoặc hoạt động không chính xác.

Biên dịch

Khung này xác định thiết bị nào sẽ sử dụng khi nhận được yêu cầu từ ứng dụng. Trong Android 10, ứng dụng có thể khám phá và chỉ định các thiết bị mà khung này chọn. Để biết thêm thông tin, hãy xem phần Khám phá và chỉ định thiết bị.

Tại thời điểm biên dịch mô hình, khung sẽ gửi mô hình đến từng trình điều khiển đề xuất bằng cách gọi IDevice::getSupportedOperations_1_3. Mỗi trình điều khiển trả về một mảng boolean cho biết các thao tác nào của mô hình được hỗ trợ. Trình điều khiển có thể xác định rằng trình điều khiển không thể hỗ trợ một thao tác nhất định vì một số lý do. Ví dụ:

  • Trình điều khiển không hỗ trợ loại dữ liệu.
  • Trình điều khiển chỉ hỗ trợ các thao tác có tham số đầu vào cụ thể. Ví dụ: một trình điều khiển có thể hỗ trợ 3x3 và 5x5, nhưng không hỗ trợ các phép tích chập 7x7.
  • Trình điều khiển có các quy tắc ràng buộc về bộ nhớ khiến trình điều khiển không thể xử lý các biểu đồ hoặc dữ liệu đầu vào lớn.

Trong quá trình biên dịch, toán hạng đầu vào, đầu ra và nội bộ của mô hình, như mô tả trong OperandLifeTime, có thể có kích thước hoặc thứ hạng không xác định. Để biết thêm thông tin, hãy xem phần Hình dạng đầu ra.

Khung này hướng dẫn từng trình điều khiển đã chọn chuẩn bị để thực thi một tập hợp con của mô hình bằng cách gọi IDevice::prepareModel_1_3. Sau đó, mỗi trình điều khiển sẽ biên dịch tập hợp con của trình điều khiển đó. Ví dụ: trình điều khiển có thể tạo mã hoặc tạo bản sao trọng số được sắp xếp lại. Vì có thể mất một khoảng thời gian đáng kể giữa quá trình biên dịch mô hình và quá trình thực thi các yêu cầu, nên bạn không nên chỉ định các tài nguyên như các phần lớn bộ nhớ thiết bị trong quá trình biên dịch.

Nếu thành công, trình điều khiển sẽ trả về một tay điều khiển @1.3::IPreparedModel. Nếu trình điều khiển trả về mã lỗi khi chuẩn bị tập hợp con của mô hình, thì khung sẽ chạy toàn bộ mô hình trên CPU.

Để giảm thời gian biên dịch khi ứng dụng khởi động, trình điều khiển có thể lưu các cấu phần phần mềm biên dịch vào bộ nhớ đệm. Để biết thêm thông tin, hãy xem phần Lưu vào bộ nhớ đệm quá trình biên dịch.

Thực thi

Khi một ứng dụng yêu cầu khung thực thi một yêu cầu, theo mặc định, khung sẽ gọi phương thức HAL IPreparedModel::executeSynchronously_1_3 để thực hiện quá trình thực thi đồng bộ trên một mô hình đã chuẩn bị. Bạn cũng có thể thực thi một yêu cầu một cách không đồng bộ bằng cách sử dụng phương thức execute_1_3, phương thức executeFenced (xem phần Thực thi có hàng rào) hoặc thực thi bằng cách sử dụng thực thi theo luồng.

Lệnh gọi thực thi đồng bộ cải thiện hiệu suất và giảm hao tổn khi tạo luồng so với lệnh gọi không đồng bộ vì quyền kiểm soát chỉ được trả về cho quy trình ứng dụng sau khi quá trình thực thi hoàn tất. Điều này có nghĩa là trình điều khiển không cần một cơ chế riêng để thông báo cho quy trình ứng dụng rằng quá trình thực thi đã hoàn tất.

Với phương thức execute_1_3 không đồng bộ, quyền kiểm soát sẽ quay lại quy trình ứng dụng sau khi quá trình thực thi bắt đầu và trình điều khiển phải thông báo cho khung khi quá trình thực thi hoàn tất bằng cách sử dụng @1.3::IExecutionCallback.

Tham số Request được truyền đến phương thức thực thi liệt kê các toán hạng đầu vào và đầu ra được dùng để thực thi. Bộ nhớ lưu trữ dữ liệu toán hạng phải sử dụng thứ tự hàng chính với phương diện đầu tiên lặp lại chậm nhất và không có khoảng đệm ở cuối bất kỳ hàng nào. Để biết thêm thông tin về các loại toán hạng, hãy xem phần Toán hạng.

Đối với trình điều khiển NN HAL 1.2 trở lên, khi một yêu cầu hoàn tất, trạng thái lỗi, hình dạng đầu rathông tin về thời gian sẽ được trả về khung. Trong quá trình thực thi, toán hạng đầu ra hoặc toán hạng nội bộ của mô hình có thể có một hoặc nhiều chiều không xác định hoặc hạng không xác định. Khi ít nhất một toán hạng đầu ra có thứ hạng hoặc phương diện không xác định, trình điều khiển phải trả về thông tin đầu ra có kích thước động.

Đối với trình điều khiển có NN HAL 1.1 trở xuống, hệ thống chỉ trả về trạng thái lỗi khi một yêu cầu hoàn tất. Bạn phải chỉ định đầy đủ các phương diện cho toán hạng đầu vào và đầu ra để quá trình thực thi hoàn tất thành công. Toán hạng nội bộ có thể có một hoặc nhiều phương diện không xác định, nhưng phải có thứ hạng đã chỉ định.

Đối với các yêu cầu của người dùng trải dài trên nhiều trình điều khiển, khung này chịu trách nhiệm đặt trước bộ nhớ trung gian và sắp xếp các lệnh gọi đến từng trình điều khiển.

Bạn có thể khởi tạo nhiều yêu cầu song song trên cùng một @1.3::IPreparedModel. Trình điều khiển có thể thực thi các yêu cầu song song hoặc tuần tự hoá các lần thực thi.

Khung này có thể yêu cầu trình điều khiển giữ nhiều mô hình đã chuẩn bị. Ví dụ: chuẩn bị mô hình m1, chuẩn bị m2, thực thi yêu cầu r1 trên m1, thực thi r2 trên m2, thực thi r3 trên m1, thực thi r4 trên m2, phát hành (mô tả trong phần Dọn dẹp) m1 và phát hành m2.

Để tránh việc thực thi lần đầu chậm có thể dẫn đến trải nghiệm người dùng kém (ví dụ: khung hình đầu tiên bị giật), trình điều khiển phải thực hiện hầu hết các hoạt động khởi chạy trong giai đoạn biên dịch. Việc khởi chạy trong lần thực thi đầu tiên phải được giới hạn ở các thao tác ảnh hưởng tiêu cực đến tình trạng hệ thống khi được thực hiện sớm, chẳng hạn như đặt trước bộ đệm tạm thời lớn hoặc tăng tốc độ xung nhịp của thiết bị. Các trình điều khiển chỉ có thể chuẩn bị một số lượng mô hình đồng thời có hạn có thể phải khởi chạy lần đầu tiên.

Trong Android 10 trở lên, trong trường hợp nhiều quá trình thực thi với cùng một mô hình đã chuẩn bị được thực thi liên tiếp nhanh chóng, ứng dụng có thể chọn sử dụng đối tượng luồng thực thi để giao tiếp giữa các quy trình ứng dụng và trình điều khiển. Để biết thêm thông tin, hãy xem phần Thực thi theo đợt và hàng đợi thông báo nhanh.

Để cải thiện hiệu suất cho nhiều lần thực thi liên tiếp, trình điều khiển có thể giữ lại vùng đệm tạm thời hoặc tăng tốc độ xung nhịp. Bạn nên tạo luồng trình quan sát để giải phóng tài nguyên nếu không có yêu cầu mới nào được tạo sau một khoảng thời gian cố định.

Hình dạng đầu ra

Đối với các yêu cầu mà một hoặc nhiều toán hạng đầu ra không có tất cả các kích thước được chỉ định, trình điều khiển phải cung cấp danh sách các hình dạng đầu ra chứa thông tin kích thước cho mỗi toán hạng đầu ra sau khi thực thi. Để biết thêm thông tin về phương diện, hãy xem OutputShape.

Nếu không thực thi được do bộ đệm đầu ra có kích thước nhỏ, trình điều khiển phải cho biết những toán hạng đầu ra nào có kích thước bộ đệm không đủ trong danh sách hình dạng đầu ra và phải báo cáo nhiều thông tin kích thước nhất có thể, sử dụng giá trị 0 cho các kích thước không xác định.

Thời gian

Trong Android 10, ứng dụng có thể yêu cầu thời gian thực thi nếu ứng dụng đã chỉ định một thiết bị duy nhất để sử dụng trong quá trình biên dịch. Để biết thông tin chi tiết, hãy xem MeasureTiming và phần Khám phá và chỉ định thiết bị. Trong trường hợp này, trình điều khiển NN HAL 1.2 phải đo lường thời lượng thực thi hoặc báo cáo UINT64_MAX (để cho biết thời lượng không có sẵn) khi thực thi yêu cầu. Trình điều khiển phải giảm thiểu mọi hình phạt về hiệu suất do đo lường thời lượng thực thi.

Trình điều khiển báo cáo các khoảng thời gian sau đây tính bằng micro giây trong cấu trúc Timing:

  • Thời gian thực thi trên thiết bị: Không bao gồm thời gian thực thi trong trình điều khiển chạy trên bộ xử lý máy chủ.
  • Thời gian thực thi trong trình điều khiển: Bao gồm thời gian thực thi trên thiết bị.

Các khoảng thời gian này phải bao gồm thời gian thực thi bị tạm ngưng, ví dụ: khi thực thi bị các tác vụ khác chiếm quyền hoặc khi đang chờ tài nguyên có sẵn.

Khi trình điều khiển chưa được yêu cầu đo lường thời lượng thực thi hoặc khi có lỗi thực thi, trình điều khiển phải báo cáo thời lượng dưới dạng UINT64_MAX. Ngay cả khi được yêu cầu đo lường thời lượng thực thi, trình điều khiển cũng có thể báo cáo UINT64_MAX cho thời gian trên thiết bị, thời gian trong trình điều khiển hoặc cả hai. Khi trình điều khiển báo cáo cả hai khoảng thời gian dưới dạng một giá trị khác với UINT64_MAX, thời gian thực thi trong trình điều khiển phải bằng hoặc lớn hơn thời gian trên thiết bị.

Thực thi có hàng rào

Trong Android 11, NNAPI cho phép các quá trình thực thi chờ danh sách các tay điều khiển sync_fence và tuỳ ý trả về một đối tượng sync_fence. Đối tượng này sẽ được báo hiệu khi quá trình thực thi hoàn tất. Điều này giúp giảm hao tổn cho các mô hình trình tự nhỏ và các trường hợp sử dụng phát trực tuyến. Việc thực thi có hàng rào cũng cho phép khả năng tương tác hiệu quả hơn với các thành phần khác có thể báo hiệu hoặc chờ sync_fence. Để biết thêm thông tin về sync_fence, hãy xem phần Khung đồng bộ hoá.

Trong quá trình thực thi có hàng rào, khung này sẽ gọi phương thức IPreparedModel::executeFenced để khởi chạy quá trình thực thi không đồng bộ, có hàng rào trên một mô hình đã chuẩn bị với một vectơ hàng rào đồng bộ hoá để chờ. Nếu tác vụ không đồng bộ hoàn tất trước khi lệnh gọi trả về, thì một tay cầm trống có thể được trả về cho sync_fence. Bạn cũng phải trả về một đối tượng IFencedExecutionCallback để cho phép khung truy vấn trạng thái lỗi và thông tin về thời lượng.

Sau khi quá trình thực thi hoàn tất, bạn có thể truy vấn hai giá trị thời gian sau đây đo lường thời lượng thực thi thông qua IFencedExecutionCallback::getExecutionInfo.

  • timingLaunched: Thời lượng từ khi executeFenced được gọi đến khi executeFenced báo hiệu syncFence được trả về.
  • timingFenced: Thời lượng từ khi tất cả các hàng rào đồng bộ hoá mà quá trình thực thi chờ được báo hiệu cho đến khi executeFenced báo hiệu syncFence được trả về.

Luồng điều khiển

Đối với các thiết bị chạy Android 11 trở lên, NNAPI bao gồm hai toán tử luồng điều khiển, IFWHILE, lấy các mô hình khác làm đối số và thực thi các mô hình đó theo điều kiện (IF) hoặc lặp lại (WHILE). Để biết thêm thông tin về cách triển khai điều này, hãy xem phần Luồng điều khiển.

Chất lượng dịch vụ

Trong Android 11, NNAPI giúp nâng cao chất lượng dịch vụ (QoS) bằng cách cho phép ứng dụng cho biết các mức độ ưu tiên tương đối của các mô hình, khoảng thời gian tối đa dự kiến cần để chuẩn bị một mô hình nhất định và thời lượng tối đa dự kiến cần để hoàn tất một phép tính nhất định. Để biết thêm thông tin, hãy xem phần Chất lượng dịch vụ.

Dọn dẹp

Khi một ứng dụng hoàn tất việc sử dụng mô hình đã chuẩn bị, khung sẽ phát hành tham chiếu đến đối tượng @1.3::IPreparedModel. Khi đối tượng IPreparedModel không còn được tham chiếu, đối tượng này sẽ tự động bị huỷ trong dịch vụ trình điều khiển đã tạo đối tượng đó. Bạn có thể thu hồi tài nguyên dành riêng cho mô hình tại thời điểm này trong quá trình triển khai hàm huỷ của trình điều khiển. Nếu dịch vụ trình điều khiển muốn đối tượng IPreparedModel được tự động huỷ khi ứng dụng không cần nữa, thì dịch vụ này không được giữ bất kỳ tham chiếu nào đến đối tượng IPreparedModel sau khi đối tượng IPreparedeModel được trả về thông qua IPreparedModelCallback::notify_1_3.

Mức sử dụng CPU

Trình điều khiển dự kiến sẽ sử dụng CPU để thiết lập các phép tính. Trình điều khiển không nên sử dụng CPU để thực hiện các phép tính đồ thị vì điều đó sẽ ảnh hưởng đến khả năng của khung để phân bổ công việc một cách chính xác. Trình điều khiển phải báo cáo các phần mà trình điều khiển không thể xử lý cho khung và để khung xử lý phần còn lại.

Khung này cung cấp cách triển khai CPU cho tất cả các thao tác NNAPI, ngoại trừ các thao tác do nhà cung cấp xác định. Để biết thêm thông tin, hãy xem phần Tiện ích của nhà cung cấp.

Các toán tử được giới thiệu trong Android 10 (API cấp 29) chỉ triển khai CPU tham chiếu để xác minh rằng các kiểm thử CTS và VTS là chính xác. Bạn nên triển khai các phương thức tối ưu hoá có trong khung học máy dành cho thiết bị di động thay vì triển khai CPU NNAPI.

Hàm hiệu dụng

Cơ sở mã NNAPI bao gồm các hàm tiện ích mà các dịch vụ trình điều khiển có thể sử dụng.

Tệp frameworks/ml/nn/common/include/Utils.h chứa nhiều hàm tiện ích, chẳng hạn như các hàm dùng để ghi nhật ký và chuyển đổi giữa các phiên bản NN HAL khác nhau.

  • VLogging: VLOG là một macro trình bao bọc xung quanh LOG của Android, chỉ ghi nhật ký thông báo nếu thẻ thích hợp được đặt trong thuộc tính debug.nn.vlog. Bạn phải gọi initVLogMask() trước khi thực hiện bất kỳ lệnh gọi nào đến VLOG. Bạn có thể sử dụng macro VLOG_IS_ON để kiểm tra xem VLOG có đang bật hay không, cho phép bỏ qua mã ghi nhật ký phức tạp nếu không cần thiết. Giá trị của thuộc tính này phải là một trong các giá trị sau:

    • Chuỗi trống, cho biết không cần ghi nhật ký.
    • Mã thông báo 1 hoặc all, cho biết tất cả hoạt động ghi nhật ký đều phải được thực hiện.
    • Danh sách các thẻ, được phân tách bằng dấu cách, dấu phẩy hoặc dấu hai chấm, cho biết cần ghi nhật ký nào. Các thẻ này là compilation, cpuexe, driver, execution, managermodel.
  • compliantWithV1_*: Trả về true nếu đối tượng HAL NN có thể được chuyển đổi thành cùng một loại của một phiên bản HAL khác mà không làm mất thông tin. Ví dụ: lệnh gọi compliantWithV1_0 trên V1_2::Model sẽ trả về false nếu mô hình bao gồm các loại toán tử được giới thiệu trong NN HAL 1.1 hoặc NN HAL 1.2.

  • convertToV1_*: Chuyển đổi đối tượng NN HAL từ phiên bản này sang phiên bản khác. Hệ thống sẽ ghi lại một cảnh báo nếu quá trình chuyển đổi làm mất thông tin (tức là nếu phiên bản mới của loại không thể thể hiện đầy đủ giá trị).

  • Chức năng: Bạn có thể sử dụng các hàm nonExtensionOperandPerformanceupdate để giúp tạo trường Capabilities::operandPerformance.

  • Truy vấn các thuộc tính của các loại: isExtensionOperandType, isExtensionOperationType, nonExtensionSizeOfData, nonExtensionOperandSizeOfData, nonExtensionOperandTypeIsScalar, tensorHasUnspecifiedDimensions.

Tệp frameworks/ml/nn/common/include/ValidateHal.h chứa các hàm tiện ích để xác thực rằng đối tượng HAL NN là hợp lệ theo thông số kỹ thuật của phiên bản HAL.

  • validate*: Trả về true nếu đối tượng HAL NN hợp lệ theo thông số kỹ thuật của phiên bản HAL. Các loại OEM và loại tiện ích chưa được xác thực. Ví dụ: validateModel trả về false nếu mô hình chứa một toán tử tham chiếu đến chỉ mục toán hạng không tồn tại hoặc một toán tử không được hỗ trợ ở phiên bản HAL đó.

Tệp frameworks/ml/nn/common/include/Tracing.h chứa các macro để đơn giản hoá việc thêm thông tin theo dõi hệ thống vào mã Mạng nơron. Để biết ví dụ, hãy xem các lệnh gọi macro NNTRACE_* trong trình điều khiển mẫu.

Tệp frameworks/ml/nn/common/include/GraphDump.h chứa một hàm tiện ích để kết xuất nội dung của Model ở dạng đồ hoạ cho mục đích gỡ lỗi.

  • graphDump: Ghi nội dung đại diện cho mô hình ở định dạng Graphviz (.dot) vào luồng đã chỉ định (nếu có) hoặc vào logcat (nếu không có luồng nào được cung cấp).

Xác nhận kết quả

Để kiểm thử cách triển khai NNAPI, hãy sử dụng các bài kiểm thử VTS và CTS có trong khung Android. VTS thực thi trình điều khiển trực tiếp (không sử dụng khung), trong khi CTS thực thi trình điều khiển gián tiếp thông qua khung. Các hàm này kiểm thử từng phương thức API và xác minh rằng tất cả các thao tác do trình điều khiển hỗ trợ đều hoạt động chính xác và cung cấp kết quả đáp ứng các yêu cầu về độ chính xác.

Sau đây là các yêu cầu về độ chính xác trong CTS và VTS đối với NNAPI:

  • Dấu phẩy động: abs(expected - actual) <= atol + rtol  * abs(expected); trong đó:

    • Đối với fp32, atol = 1e-5f, rtol = 5.0f * 1.1920928955078125e-7
    • Đối với fp16, atol = rtol = 5.0f * 0.0009765625f
  • Đã lượng tử hoá: sai số một (ngoại trừ mobilenet_quantized, sai số ba)

  • Boolean: khớp chính xác

Một cách để CTS kiểm thử NNAPI là tạo các biểu đồ giả ngẫu nhiên cố định dùng để kiểm thử và so sánh kết quả thực thi của từng trình điều khiển với cách triển khai tham chiếu NNAPI. Đối với trình điều khiển có NN HAL 1.2 trở lên, nếu kết quả không đáp ứng các tiêu chí về độ chính xác, thì CTS sẽ báo lỗi và kết xuất tệp thông số kỹ thuật cho mô hình không thành công trong /data/local/tmp để gỡ lỗi. Để biết thêm thông tin chi tiết về tiêu chí độ chính xác, hãy xem TestRandomGraph.cppTestHarness.h.

Kiểm thử mờ

Mục đích của kiểm thử tìm lỗi mã nguồn là tìm sự cố, câu nhận định, lỗi vi phạm bộ nhớ hoặc hành vi không xác định chung trong mã đang được kiểm thử do các yếu tố như dữ liệu đầu vào không mong muốn. Đối với kiểm thử tìm lỗi ngẫu nhiên NNAPI, Android sử dụng các kiểm thử dựa trên libFuzzer. Các kiểm thử này hiệu quả trong việc tìm lỗi ngẫu nhiên vì sử dụng mức độ bao phủ dòng của các trường hợp kiểm thử trước đó để tạo dữ liệu đầu vào ngẫu nhiên mới. Ví dụ: libFuzzer ưu tiên các trường hợp kiểm thử chạy trên các dòng mã mới. Điều này giúp giảm đáng kể thời gian kiểm thử để tìm mã có vấn đề.

Để kiểm thử tìm lỗi mã nguồn nhằm xác thực việc triển khai trình điều khiển, hãy sửa đổi frameworks/ml/nn/runtime/test/android_fuzzing/DriverFuzzTest.cpp trong tiện ích kiểm thử libneuralnetworks_driver_fuzzer có trong AOSP để đưa mã trình điều khiển vào. Để biết thêm thông tin về kiểm thử tìm lỗi ngẫu nhiên NNAPI, hãy xem frameworks/ml/nn/runtime/test/android_fuzzing/README.md.

Bảo mật

Vì các quy trình ứng dụng giao tiếp trực tiếp với quy trình của trình điều khiển, nên trình điều khiển phải xác thực các đối số của lệnh gọi mà chúng nhận được. Quy trình xác thực này được VTS xác minh. Mã xác thực nằm trong frameworks/ml/nn/common/include/ValidateHal.h.

Trình điều khiển cũng phải đảm bảo rằng các ứng dụng không thể can thiệp vào các ứng dụng khác khi sử dụng cùng một thiết bị.

Bộ kiểm thử học máy Android

Bộ kiểm thử máy học Android (MLTS) là một điểm chuẩn NNAPI có trong CTS và VTS để xác thực độ chính xác của các mô hình thực trên thiết bị của nhà cung cấp. Điểm chuẩn này đánh giá độ trễ và độ chính xác, đồng thời so sánh kết quả của trình điều khiển với kết quả sử dụng TF Lite chạy trên CPU, cho cùng một mô hình và tập dữ liệu. Điều này đảm bảo rằng độ chính xác của trình điều khiển không kém hơn so với cách triển khai tham chiếu CPU.

Nhà phát triển nền tảng Android cũng sử dụng MLTS để đánh giá độ trễ và độ chính xác của trình điều khiển.

Bạn có thể tìm thấy điểm chuẩn NNAPI trong hai dự án trong AOSP:

Mô hình và tập dữ liệu

Điểm chuẩn NNAPI sử dụng các mô hình và tập dữ liệu sau.

  • MobileNetV1 float và u8 được lượng tử hoá ở nhiều kích thước, chạy trên một tập hợp con nhỏ (1500 hình ảnh) của Tập dữ liệu hình ảnh mở v4.
  • MobileNetV2 float và u8 được lượng tử hoá ở nhiều kích thước, chạy trên một tập hợp con nhỏ (1500 hình ảnh) của Tập dữ liệu hình ảnh mở v4.
  • Mô hình âm thanh dựa trên bộ nhớ ngắn hạn dài (LSTM) để chuyển văn bản sang lời nói, chạy trên một tập hợp con nhỏ của tập hợp CMU Arctic.
  • Mô hình âm thanh dựa trên LSTM để tự động nhận dạng lời nói, chạy trên một tập hợp con nhỏ của tập dữ liệu LibriSpeech.

Để biết thêm thông tin, hãy xem platform/test/mlts/models.

Kiểm thử tải

Bộ kiểm thử học máy Android bao gồm một loạt các bài kiểm thử sự cố để xác thực khả năng phục hồi của trình điều khiển trong điều kiện sử dụng nhiều hoặc trong các trường hợp đặc biệt về hành vi của ứng dụng.

Tất cả các thử nghiệm sự cố đều cung cấp các tính năng sau:

  • Phát hiện tình trạng treo: Nếu ứng dụng NNAPI bị treo trong quá trình kiểm thử, thì kiểm thử sẽ không thành công với lý do lỗi là HANG và bộ kiểm thử sẽ chuyển sang kiểm thử tiếp theo.
  • Phát hiện sự cố ứng dụng NNAPI: Các chương trình kiểm thử vẫn hoạt động sau khi ứng dụng gặp sự cố và các chương trình kiểm thử không thành công với lý do lỗi là CRASH.
  • Phát hiện sự cố trình điều khiển: Các chương trình kiểm thử có thể phát hiện sự cố trình điều khiển gây ra lỗi trên lệnh gọi NNAPI. Xin lưu ý rằng có thể có sự cố trong các quy trình trình điều khiển không gây ra lỗi NNAPI và không gây ra lỗi kiểm thử. Để khắc phục loại lỗi này, bạn nên chạy lệnh tail trên nhật ký hệ thống để tìm lỗi hoặc sự cố liên quan đến trình điều khiển.
  • Nhắm mục tiêu tất cả trình tăng tốc hiện có: Các chương trình kiểm thử sẽ chạy trên tất cả trình điều khiển hiện có.

Tất cả các thử nghiệm sự cố đều có thể có 4 kết quả sau:

  • SUCCESS: Quá trình thực thi đã hoàn tất mà không gặp lỗi.
  • FAILURE: Không thực thi được. Thường là do lỗi khi kiểm thử mô hình, cho biết trình điều khiển không biên dịch hoặc thực thi mô hình.
  • HANG: Quy trình kiểm thử không phản hồi.
  • CRASH: Quy trình kiểm thử gặp sự cố.

Để biết thêm thông tin về kiểm thử tải trọng và danh sách đầy đủ các kiểm thử sự cố, hãy xem platform/test/mlts/benchmark/README.txt.

Sử dụng MLTS

Cách sử dụng MLTS:

  1. Kết nối thiết bị mục tiêu với máy trạm và đảm bảo thiết bị đó có thể truy cập được thông qua adb. Xuất biến môi trường ANDROID_SERIAL của thiết bị mục tiêu nếu có nhiều thiết bị được kết nối.
  2. cd vào thư mục nguồn cấp cao nhất của Android.

    source build/envsetup.sh
    lunch aosp_arm-userdebug # Or aosp_arm64-userdebug if available.
    ./test/mlts/benchmark/build_and_run_benchmark.sh
    

    Khi kết thúc quá trình chạy điểm chuẩn, kết quả sẽ được trình bày dưới dạng một trang HTML và được truyền đến xdg-open.

Để biết thêm thông tin, hãy xem platform/test/mlts/benchmark/README.txt.

Phiên bản HAL của mạng nơron

Phần này mô tả các thay đổi được đưa vào các phiên bản HAL của Android và Neural Networks.

Android 11

Android 11 ra mắt NN HAL 1.3, bao gồm các thay đổi đáng chú ý sau.

  • Hỗ trợ lượng tử hoá 8 bit đã ký trong NNAPI. Thêm loại toán hạng TENSOR_QUANT8_ASYMM_SIGNED. Trình điều khiển có NN HAL 1.3 hỗ trợ các thao tác với lượng tử hoá chưa ký cũng phải hỗ trợ các biến thể đã ký của các thao tác đó. Khi chạy các phiên bản đã ký và chưa ký của hầu hết các thao tác được lượng tử hoá, trình điều khiển phải tạo ra cùng một kết quả với độ lệch tối đa là 128. Có 5 trường hợp ngoại lệ đối với yêu cầu này: CAST, HASHTABLE_LOOKUP, LSH_PROJECTION, PAD_V2QUANTIZED_16BIT_LSTM. Toán tử QUANTIZED_16BIT_LSTM không hỗ trợ toán hạng đã ký và bốn toán tử còn lại hỗ trợ việc lấy mẫu đã ký nhưng không yêu cầu kết quả phải giống nhau.
  • Hỗ trợ các quá trình thực thi có hàng rào, trong đó khung gọi phương thức IPreparedModel::executeFenced để khởi chạy một quá trình thực thi không đồng bộ, có hàng rào trên một mô hình đã chuẩn bị với một vectơ hàng rào đồng bộ hoá để chờ. Để biết thêm thông tin, hãy xem phần Thực thi có hàng rào.
  • Hỗ trợ luồng điều khiển. Thêm các toán tử IFWHILE. Các toán tử này lấy các mô hình khác làm đối số và thực thi các mô hình đó theo điều kiện (IF) hoặc lặp lại (WHILE). Để biết thêm thông tin, hãy xem phần Luồng điều khiển.
  • Cải thiện chất lượng dịch vụ (QoS) vì các ứng dụng có thể cho biết các mức độ ưu tiên tương đối của các mô hình, khoảng thời gian tối đa dự kiến cần để chuẩn bị một mô hình nhất định và thời lượng tối đa dự kiến cần để hoàn tất một quá trình thực thi. Để biết thêm thông tin, hãy xem nội dung Chất lượng dịch vụ.
  • 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 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. Để biết thêm thông tin, hãy xem phần Miền bộ nhớ.

Android 10

Android 10 ra mắt NN HAL 1.2, bao gồm các thay đổi đáng chú ý sau.

  • Cấu trúc Capabilities bao gồm tất cả các loại dữ liệu, bao gồm cả các loại dữ liệu vô hướng và biểu thị hiệu suất không thư giãn bằng cách sử dụng vectơ thay vì các trường được đặt tên.
  • Phương thức getVersionStringgetType cho phép khung truy xuất loại thiết bị (DeviceType) và thông tin phiên bản. Xem phần Khám phá và chỉ định thiết bị.
  • Theo mặc định, phương thức executeSynchronously được gọi để thực hiện một quá trình thực thi đồng bộ. Phương thức execute_1_2 yêu cầu khung thực hiện một quá trình thực thi không đồng bộ. Xem phần Thực thi.
  • Thông số MeasureTiming cho executeSynchronously, execute_1_2 và quá trình thực thi theo đợt chỉ định liệu trình điều khiển có đo lường thời lượng thực thi hay không. Kết quả được báo cáo trong cấu trúc Timing. Xem phần Thời gian.
  • Hỗ trợ các lần thực thi mà một hoặc nhiều toán hạng đầu ra có kích thước hoặc thứ hạng không xác định. Xem phần Hình dạng đầu ra.
  • Hỗ trợ tiện ích của nhà cung cấp, là tập hợp các thao tác và loại dữ liệu do nhà cung cấp xác định. Trình điều khiển báo cáo các tiện ích được hỗ trợ thông qua phương thức IDevice::getSupportedExtensions. Xem phần Tiện ích của nhà cung cấp.
  • Khả năng đối tượng bắn phá kiểm soát một tập hợp các lần thực thi bắn phá bằng cách sử dụng hàng đợi thông báo nhanh (FMQ) để giao tiếp giữa các quy trình ứng dụng và trình điều khiển, giảm độ trễ. Xem phần Thực thi hàng loạt và hàng đợi tin nhắn nhanh.
  • Hỗ trợ AHardwareBuffer để cho phép trình điều khiển thực hiện các lệnh thực thi mà không cần sao chép dữ liệu. Xem AHardwareBuffer.
  • Cải thiện khả năng hỗ trợ lưu các cấu phần phần mềm biên dịch vào bộ nhớ đệm để giảm thời gian biên dịch khi ứng dụng khởi động. Xem phần Lưu biên dịch vào bộ nhớ đệm.

Android 10 giới thiệu các loại toán hạng và thao tác sau.

  • Loại toán hạng

    • ANEURALNETWORKS_BOOL
    • ANEURALNETWORKS_FLOAT16
    • ANEURALNETWORKS_TENSOR_BOOL8
    • ANEURALNETWORKS_TENSOR_FLOAT16
    • ANEURALNETWORKS_TENSOR_QUANT16_ASYMM
    • ANEURALNETWORKS_TENSOR_QUANT16_SYMM
    • ANEURALNETWORKS_TENSOR_QUANT8_SYMM
    • ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL
  • Thao tác

    • ANEURALNETWORKS_ABS
    • ANEURALNETWORKS_ARGMAX
    • ANEURALNETWORKS_ARGMIN
    • ANEURALNETWORKS_AXIS_ALIGNED_BBOX_TRANSFORM
    • ANEURALNETWORKS_BIDIRECTIONAL_SEQUENCE_LSTM
    • ANEURALNETWORKS_BIDIRECTIONAL_SEQUENCE_RNN
    • ANEURALNETWORKS_BOX_WITH_NMS_LIMIT
    • ANEURALNETWORKS_CAST
    • ANEURALNETWORKS_CHANNEL_SHUFFLE
    • ANEURALNETWORKS_DETECTION_POSTPROCESSING
    • ANEURALNETWORKS_EQUAL
    • ANEURALNETWORKS_EXP
    • ANEURALNETWORKS_EXPAND_DIMS
    • ANEURALNETWORKS_GATHER
    • ANEURALNETWORKS_GENERATE_PROPOSALS
    • ANEURALNETWORKS_GREATER
    • ANEURALNETWORKS_GREATER_EQUAL
    • ANEURALNETWORKS_GROUPED_CONV_2D
    • ANEURALNETWORKS_HEATMAP_MAX_KEYPOINT
    • ANEURALNETWORKS_INSTANCE_NORMALIZATION
    • ANEURALNETWORKS_LESS
    • ANEURALNETWORKS_LESS_EQUAL
    • ANEURALNETWORKS_LOG
    • ANEURALNETWORKS_LOGICAL_AND
    • ANEURALNETWORKS_LOGICAL_NOT
    • ANEURALNETWORKS_LOGICAL_OR
    • ANEURALNETWORKS_LOG_SOFTMAX
    • ANEURALNETWORKS_MAXIMUM
    • ANEURALNETWORKS_MINIMUM
    • ANEURALNETWORKS_NEG
    • ANEURALNETWORKS_NOT_EQUAL
    • ANEURALNETWORKS_PAD_V2
    • ANEURALNETWORKS_POW
    • ANEURALNETWORKS_PRELU
    • ANEURALNETWORKS_QUANTIZE
    • ANEURALNETWORKS_QUANTIZED_16BIT_LSTM
    • ANEURALNETWORKS_RANDOM_MULTINOMIAL
    • ANEURALNETWORKS_REDUCE_ALL
    • ANEURALNETWORKS_REDUCE_ANY
    • ANEURALNETWORKS_REDUCE_MAX
    • ANEURALNETWORKS_REDUCE_MIN
    • ANEURALNETWORKS_REDUCE_PROD
    • ANEURALNETWORKS_REDUCE_SUM
    • ANEURALNETWORKS_RESIZE_NEAREST_NEIGHBOR
    • ANEURALNETWORKS_ROI_ALIGN
    • ANEURALNETWORKS_ROI_POOLING
    • ANEURALNETWORKS_RSQRT
    • ANEURALNETWORKS_SELECT
    • ANEURALNETWORKS_SIN
    • ANEURALNETWORKS_SLICE
    • ANEURALNETWORKS_SPLIT
    • ANEURALNETWORKS_SQRT
    • ANEURALNETWORKS_TILE
    • ANEURALNETWORKS_TOPK_V2
    • ANEURALNETWORKS_TRANSPOSE_CONV_2D
    • ANEURALNETWORKS_UNIDIRECTIONAL_SEQUENCE_LSTM
    • ANEURALNETWORKS_UNIDIRECTIONAL_SEQUENCE_RNN

Android 10 ra mắt các bản cập nhật cho nhiều thao tác hiện có. Các bản cập nhật này chủ yếu liên quan đến những nội dung sau:

  • Hỗ trợ bố cục bộ nhớ NCHW
  • Hỗ trợ các tensor có thứ hạng khác với 4 trong các phép toán softmax và chuẩn hoá
  • Hỗ trợ các phép tích chập mở rộng
  • Hỗ trợ đầu vào có lượng tử hoá kết hợp trong ANEURALNETWORKS_CONCATENATION

Danh sách dưới đây cho thấy các thao tác được sửa đổi trong Android 10. Để biết thông tin chi tiết đầy đủ về các thay đổi, hãy xem OperationCode trong tài liệu tham khảo NNAPI.

  • ANEURALNETWORKS_ADD
  • ANEURALNETWORKS_AVERAGE_POOL_2D
  • ANEURALNETWORKS_BATCH_TO_SPACE_ND
  • ANEURALNETWORKS_CONCATENATION
  • ANEURALNETWORKS_CONV_2D
  • ANEURALNETWORKS_DEPTHWISE_CONV_2D
  • ANEURALNETWORKS_DEPTH_TO_SPACE
  • ANEURALNETWORKS_DEQUANTIZE
  • ANEURALNETWORKS_DIV
  • ANEURALNETWORKS_FLOOR
  • ANEURALNETWORKS_FULLY_CONNECTED
  • ANEURALNETWORKS_L2_NORMALIZATION
  • ANEURALNETWORKS_L2_POOL_2D
  • ANEURALNETWORKS_LOCAL_RESPONSE_NORMALIZATION
  • ANEURALNETWORKS_LOGISTIC
  • ANEURALNETWORKS_LSH_PROJECTION
  • ANEURALNETWORKS_LSTM
  • ANEURALNETWORKS_MAX_POOL_2D
  • ANEURALNETWORKS_MEAN
  • ANEURALNETWORKS_MUL
  • ANEURALNETWORKS_PAD
  • ANEURALNETWORKS_RELU
  • ANEURALNETWORKS_RELU1
  • ANEURALNETWORKS_RELU6
  • ANEURALNETWORKS_RESHAPE
  • ANEURALNETWORKS_RESIZE_BILINEAR
  • ANEURALNETWORKS_RNN
  • ANEURALNETWORKS_ROI_ALIGN
  • ANEURALNETWORKS_SOFTMAX
  • ANEURALNETWORKS_SPACE_TO_BATCH_ND
  • ANEURALNETWORKS_SPACE_TO_DEPTH
  • ANEURALNETWORKS_SQUEEZE
  • ANEURALNETWORKS_STRIDED_SLICE
  • ANEURALNETWORKS_SUB
  • ANEURALNETWORKS_SVDF
  • ANEURALNETWORKS_TANH
  • ANEURALNETWORKS_TRANSPOSE

Android 9

NN HAL 1.1 được giới thiệu trong Android 9 và bao gồm các thay đổi đáng chú ý sau.

  • IDevice::prepareModel_1_1 bao gồm một tham số ExecutionPreference. Trình điều khiển có thể sử dụng thông tin này để điều chỉnh quá trình chuẩn bị, biết rằng ứng dụng ưu tiên tiết kiệm pin hoặc sẽ thực thi mô hình trong các lệnh gọi liên tiếp nhanh chóng.
  • Thêm 9 toán tử mới: BATCH_TO_SPACE_ND, DIV, MEAN, PAD, SPACE_TO_BATCH_ND, SQUEEZE, STRIDED_SLICE, SUB, TRANSPOSE.
  • Ứng dụng có thể chỉ định rằng các phép tính số thực 32 bit có thể chạy bằng cách sử dụng phạm vi và/hoặc độ chính xác của số thực 16 bit bằng cách đặt Model.relaxComputationFloat32toFloat16 thành true. Cấu trúc Capabilities có thêm trường relaxedFloat32toFloat16Performance để trình điều khiển có thể báo cáo hiệu suất thư giãn của nó cho khung.

Android 8.1

HAL (1.0) của mạng nơron ban đầu được phát hành trong Android 8.1. Để biết thêm thông tin, hãy xem /neuralnetworks/1.0/.