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 trong các tệp định nghĩa HAL trong hardware/interfaces/neuralnetworks. Một ví dụ về cách triển khai trình điều khiển nằm 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 cho Mạng nơron

HAL Mạng nơ-ron (NN) xác định một lớp trừu tượng 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 số (DSP), có 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.

Luồng Mạng nơron

Hình 1. Luồng Mạng nơron

Khởi chạy

Khi khởi động, khung 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 bị hạn chế bằng cách sử dụng một vectơ.

Để xác định cách phân bổ các phép tính cho các thiết bị hiện có, khung này sử dụng các chức năng để tìm hiểu tốc độ và mức tiêu thụ năng lượng của từng trình điều khiển khi thực hiện một lệnh. Để cung cấp thông tin này, trình điều khiển phải cung cấp các số liệu hiệu suất tiêu chuẩn dựa trên việc thực thi các 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 kiểu dữ liệu tương ứng. Bạn nên dùng các mô hình MobileNet phiên bản 1 và 2, asr_floattts_float để đo lường hiệu suất cho các giá trị dấu phẩy động 32 bit, đồng thời nên dùng các mô hình được lượng tử hoá MobileNet phiên bản 1 và 2 cho các giá trị được lượng tử hoá 8 bit. Để biết thêm thông tin, hãy xem Bộ kiểm thử học máy trên 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 các tensor dấu phẩy động và lượng tử hoá, đồng thời không bao gồm các kiểu dữ liệu vô hướng.

Trong quá trình khởi tạo, 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 mong đợi tất cả các truy vấn được mô tả trong phần này 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, một ứng dụng sử dụng trình điều khiển đó có thể hoạt động kém hiệu quả hoặc có hành vi không chính xác.

Biên dịch

Khung này xác định những thiết bị cần dùng khi nhận được yêu cầu từ một ứng dụng. Trong Android 10, các ứng dụng có thể khám phá và chỉ định những thiết bị mà khung chọn. Để biết thêm thông tin, hãy xem phần Phát hiện 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 gồm các giá trị boolean cho biết những 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 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 này.
  • 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ợ các hoạt động tích chập 3x3 và 5x5, nhưng không hỗ trợ các hoạt động tích chập 7x7.
  • 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 biểu đồ hoặc dữ liệu đầu vào lớn.

Trong quá trình biên dịch, các 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ó thứ hạng hoặc kích thước 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 riêng mình. Ví dụ: trình điều khiển có thể tạo mã hoặc tạo bản sao được sắp xếp lại của các trọng số. Vì có thể có 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 các tài nguyên như các khối lớn bộ nhớ thiết bị không được chỉ định trong quá trình biên dịch.

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

Để giảm thời gian dùng cho quá trình biên dịch khi một ứng dụng khởi động, trình điều khiển có thể lưu vào bộ nhớ đệm các cấu phần phần mềm biên dịch. Để biết thêm thông tin, hãy xem phần Lưu vào bộ nhớ đệm khi 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 một 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 không đồng bộ bằng phương thức execute_1_3, phương thức executeFenced (xem phần Thực thi có rào chắn) hoặc thực thi bằng thực thi hàng loạt.

Các lệnh gọi thực thi đồng bộ giúp cải thiện hiệu suất và giảm chi phí luồng so với các 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 chiều đầu tiên lặp lại chậm nhất và không có khoảng đệm ở cuối 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ề cho khung. Trong quá trình thực thi, các toán hạng đầu ra hoặc 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ứ nguyên hoặc hạng 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, chỉ trạng thái lỗi được trả về 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 chiều không xác định, nhưng phải có hạng được chỉ định.

Đối với các yêu cầu của người dùng 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 cho từng trình điều khiển.

Bạn có thể bắt đầu 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ượt 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 (được mô tả trong phần Dọn dẹp) m1 và phát hành m2.

Để tránh lần thực thi đầu tiên diễn ra 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 nên thực hiện hầu hết các hoạt động khởi tạo trong giai đoạn biên dịch. Quá trình khởi chạy trong lần thực thi đầu tiên chỉ nên giới hạn ở những 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 các bộ đệm tạm thời lớn hoặc tăng tốc độ xung nhịp của thiết bị. Những 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 thực hiện quá trình khởi tạo khi thực thi lần đầu.

Trong Android 10 trở lên, trong trường hợp nhiều lượt thực thi có cùng một mô hình đã chuẩn bị được thực thi liên tiếp, ứng dụng có thể chọn sử dụng một đối tượng thực thi hàng loạt để 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 bài viết Thực thi hàng loạ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 các vùng đệm tạm thời hoặc tăng tốc độ xung nhịp. Bạn nên tạo một luồng giám 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 phương diện được chỉ định, trình điều khiển phải cung cấp một danh sách các hình dạng đầu ra chứa thông tin về phương diện cho từng 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 quá trình thực thi không thành công do bộ đệm đầu ra có kích thước quá nhỏ, thì 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 các hình dạng đầu ra và nên báo cáo nhiều thông tin về kích thước nhất có thể, sử dụng giá trị 0 cho những kích thước chưa xác định.

Thời gian

Trong Android 10, một ứ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 MeasureTimingKhá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 gian thực thi hoặc báo cáo UINT64_MAX (để cho biết thời gian không có sẵn) khi thực thi một yêu cầu. Trình điều khiển phải giảm thiểu mọi mức phạt 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 theo 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, chẳng hạn như khi quá trình thực thi bị các tác vụ khác chiếm quyền hoặc khi quá trình này đang chờ một tài nguyên có sẵn.

Khi trình điều khiển chưa được yêu cầu đo thời gian 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 là UINT64_MAX. Ngay cả khi trình điều khiển được yêu cầu đo lường thời lượng thực thi, trình điều khiển vẫn 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 là một giá trị khác UINT64_MAX, thời gian thực thi trong trình điều khiển phải bằng hoặc vượt quá thời gian trên thiết bị.

Thực thi có rào chắn

Trong Android 11, NNAPI cho phép các hoạt động thực thi chờ danh sách các đối tượng 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 chi phí cho các mô hình chuỗi nhỏ và trường hợp sử dụng truyền phát trực tiếp. Hoạt động thực thi có rào chắn 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 Khung đồng bộ hoá.

Trong quá trình thực thi có hàng rào, khung sẽ gọi phương thức IPreparedModel::executeFenced để chạy một quy 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ộ để 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 giá trị nhận dạng 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 2 giá trị thời gian sau đây để đo lường thời lượng thực thi thông qua IFencedExecutionCallback::getExecutionInfo.

  • timingLaunched: Khoảng thời gian từ khi executeFenced được gọi cho đến khi executeFenced báo hiệu syncFence đã trả về.
  • timingFenced: Khoảng thời gian 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 2 thao tác luồng điều khiển, IFWHILE, lấy các mô hình khác làm đối số và thực thi chúng có đ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 thao tác 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 một ứ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 và thời lượng tối đa dự kiến cần để hoàn tất một hoạt động thực thi. Để 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 dùng xong một mô hình đã chuẩn bị, khung sẽ giải phóng tham chiếu của mô hình đó đế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 đó. Các tài nguyên dành riêng cho mô hình có thể được thu hồi vào thời điểm này trong quá trình triển khai trình 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 tự động bị huỷ khi không còn cần thiết cho ứng dụng, thì dịch vụ đó 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 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 phân bổ công việc một cách chính xác của khung. Trình điều khiển nên báo cáo những 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 một quy trình 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 bài viết Tiện ích của nhà cung cấp.

Các thao tác được giới thiệu trong Android 10 (API cấp 29) chỉ có một cá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. Các phương thức triển khai được tối ưu hoá có trong các khung học máy di động được ưu tiên hơn phương thức 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 lại 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 gọi VLOG. Bạn có thể dùng macro VLOG_IS_ON để kiểm tra xem VLOG hiện có được 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 phải là một trong các giá trị sau:

    • Một chuỗi trống, cho biết rằng không có hoạt động ghi nhật ký nào được thực hiện.
    • Mã thông báo 1 hoặc all, cho biết rằng tất cả hoạt động ghi nhật ký sẽ đượ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 hoạt động ghi nhật ký nào sẽ được thực hiện. Các thẻ này là compilation, cpuexe, driver, execution, managermodel.
  • compliantWithV1_*: Trả về true nếu có thể chuyển đổi một đối tượng NN HAL sang cùng 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ụ: việc 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 thao tác được giới thiệu trong NN HAL 1.1 hoặc NN HAL 1.2.

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

  • Chức năng: Bạn có thể 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 một đối tượng NN HAL hợp lệ theo quy cách của phiên bản HAL.

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

Tệp frameworks/ml/nn/common/include/Tracing.h chứa các macro giúp đơn giản hoá việc thêm thông tin systrace 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 một Model ở dạng đồ hoạ cho mục đích gỡ lỗi.

  • graphDump: Ghi nội dung biểu thị mô hình ở định dạng Graphviz (.dot) vào luồng được chỉ định (nếu được cung cấp) 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ử việc triển khai NNAPI, hãy sử dụng các kiểm thử VTS và CTS có trong khung Android. VTS thực thi các trình điều khiển của bạn một cách trực tiếp (không sử dụng khung), trong khi CTS thực thi các trình điều khiển một cách gián tiếp thông qua khung. Các kiểm thử 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 mà trình điều khiển hỗ trợ đều hoạt động đúng cách 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 cho NNAPI:

  • Số thực 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 lệch một (ngoại trừ mobilenet_quantized, sai lệch ba)

  • Boolean: kiểu 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 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, CTS sẽ báo cáo lỗi và kết xuất một tệp đặc 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ử fuzzing là tìm ra các sự cố, khẳng đị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ử fuzzing NNAPI, Android sử dụng các kiểm thử dựa trên libFuzzer. Các kiểm thử này có hiệu quả trong việc fuzzing vì chúng sử dụng mức độ bao phủ dòng của các trường hợp kiểm thử trước đó để tạo đầ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 đề.

Để thực hiện kiểm thử fuzz 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 để thêm mã trình điều khiển. Để biết thêm thông tin về kiểm thử fuzz NNAPI, hãy xem frameworks/ml/nn/runtime/test/android_fuzzing/README.md.

Bảo mật

Vì các quy trình của ứ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. VTS xác minh quy trình xác thực này. Mã xác thực nằm trong frameworks/ml/nn/common/include/ValidateHal.h.

Người lái xe 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 trên Android

Bộ kiểm thử máy học (MLTS) của Android 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 tệ hơn so với việc 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 2 dự án trên 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 định lượng ở nhiều kích thước, chạy trên một tập hợp con nhỏ (1.500 hình ảnh) của Tập dữ liệu hình ảnh mở phiên bản 4.
  • MobileNetV2 có độ chính xác đơn và u8 được định lượng ở nhiều kích thước, chạy trên một tập hợp con nhỏ (1.500 hình ảnh) của Tập dữ liệu hình ảnh mở phiên bản 4.
  • 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 nhóm nhỏ trong bộ dữ liệu 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 nhóm 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 trên 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 bài kiểm thử sự cố đều cung cấp những tính năng sau:

  • Phát hiện trạng thái treo: Nếu ứng dụng NNAPI bị treo trong quá trình kiểm thử, thì quá trình kiểm thử sẽ không thành công với lý do không thành công 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 kiểm thử vẫn hoạt động khi ứng dụng gặp sự cố và các kiểm thử không thành công với lý do thất bại là CRASH.
  • Phát hiện sự cố trình điều khiển: Các kiểm thử có thể phát hiện sự cố trình điều khiển gây ra lỗi trong lệnh gọi NNAPI. Xin lưu ý rằng có thể xảy ra sự cố trong các quy trình của trình điều khiển mà không gây ra lỗi NNAPI và không khiến kiểm thử thất bại. Để 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 đến tất cả các trình tăng tốc có sẵn: Các kiểm thử được chạy trên tất cả các trình điều khiển có sẵn.

Tất cả các bài kiểm tra va chạm đều có 4 kết quả có thể xảy ra như 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 xảy ra do lỗi khi kiểm thử một mô hình, cho biết rằng trình điều khiển không biên dịch hoặc thực thi được mô hình.
  • HANG: Quá trình kiểm thử không phản hồi.
  • CRASH: Quy trình kiểm thử bị lỗi.

Để biết thêm thông tin về kiểm thử tải và danh sách đầy đủ các kiểm thử sự cố, hãy xem phần 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 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.

Các phiên bản HAL của Mạng nơron

Phần này mô tả những thay đổi được giới thiệu trong các phiên bản HAL của Android và Mạng nơ-ron.

Android 11

Android 11 giới thiệu NN HAL 1.3, trong đó có những thay đổi đáng chú ý sau đây.

  • Hỗ trợ lượng tử hoá 8 bit có dấu trong NNAPI. Thêm kiểu 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 có lượng tử hoá chưa ký cũng phải hỗ trợ các biến thể đã ký của những 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 hoạt động đượ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. Thao tác QUANTIZED_16BIT_LSTM không hỗ trợ toán hạng có dấu và 4 thao tác còn lại hỗ trợ lượng tử hoá có dấu nhưng không yêu cầu kết quả phải giống nhau.
  • Hỗ trợ các lượt thực thi có rào chắn, trong đó khung gọi phương thức IPreparedModel::executeFenced để chạy một lượt thực thi không đồng bộ có rào chắn trên một mô hình đã chuẩn bị với một vectơ rào chắn đồng bộ để chờ. Để biết thêm thông tin, hãy xem phần Thực thi có rào chắn.
  • Hỗ trợ luồng điều khiển. Thêm các thao tác IFWHILE. Các thao tác này lấy những mô hình khác làm đối số và thực thi chúng có đ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 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 và khoảng thời gian tối đa dự kiến cần để hoàn tất một hoạt động thực thi. Để biết thêm thông tin, hãy xem phần 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 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. Để 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, trong đó có những thay đổi đáng chú ý sau đây.

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

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 giới thiệu các bản cập nhật cho nhiều thao tác hiện có. Các nội dung cập nhật chủ yếu liên quan đến những điểm sau:

  • Hỗ trợ bố cục bộ nhớ NCHW
  • Hỗ trợ các tensor có thứ hạng khác 4 trong các thao tác softmax và chuẩn hoá
  • Hỗ trợ tích chập giãn nở
  • Hỗ trợ các đầu vào có lượng tử hoá hỗn 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 đầ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à có những thay đổi đáng chú ý sau đây.

  • IDevice::prepareModel_1_1 bao gồm tham số ExecutionPreference. Trình điều khiển có thể 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.
  • Đã thêm 9 thao tác mới: BATCH_TO_SPACE_ND, DIV, MEAN, PAD, SPACE_TO_BATCH_ND, SQUEEZE, STRIDED_SLICE, SUB, TRANSPOSE.
  • Một ứng dụng có thể chỉ định rằng các phép tính dấu phẩy động 32 bit có thể chạy bằng phạm vi và/hoặc độ chính xác dấu phẩy động 16 bit bằng cách đặt Model.relaxComputationFloat32toFloat16 thành true. Cấu trúc Capabilities có trường bổ sung relaxedFloat32toFloat16Performance để trình điều khiển có thể báo cáo hiệu suất được nới lỏng của mình cho khung.

Android 8.1

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