درایورهای API شبکه های عصبی

این صفحه مروری بر نحوه پیاده‌سازی درایور API شبکه‌های عصبی (NNAPI) ارائه می‌دهد. برای جزئیات بیشتر، به مستندات موجود در فایل‌های تعریف HAL ​​در hardware/interfaces/neuralnetworks مراجعه کنید. یک نمونه پیاده‌سازی درایور در frameworks/ml/nn/driver/sample قرار دارد.

برای اطلاعات بیشتر در مورد API شبکه‌های عصبی، به API شبکه‌های عصبی مراجعه کنید.

شبکه‌های عصبی HAL

HAL شبکه‌های عصبی (NN) انتزاعی از دستگاه‌های مختلف، مانند واحدهای پردازش گرافیکی (GPU) و پردازنده‌های سیگنال دیجیتال (DSP)، که در یک محصول (به عنوان مثال، یک تلفن یا تبلت) وجود دارند را تعریف می‌کند. درایورهای این دستگاه‌ها باید با HAL شبکه عصبی مطابقت داشته باشند. رابط در فایل‌های تعریف HAL ​​در hardware/interfaces/neuralnetworks مشخص شده است.

جریان کلی رابط بین چارچوب و یک درایور در شکل 1 نشان داده شده است.

جریان شبکه‌های عصبی

شکل ۱. جریان شبکه‌های عصبی

مقداردهی اولیه

در هنگام مقداردهی اولیه، چارچوب با استفاده از IDevice::getCapabilities_1_3 از درایور، قابلیت‌های آن را جستجو می‌کند. ساختار @1.3::Capabilities شامل تمام انواع داده‌ها است و عملکرد غیرریلکس شده را با استفاده از یک بردار نشان می‌دهد.

برای تعیین نحوه تخصیص محاسبات به دستگاه‌های موجود، این چارچوب از قابلیت‌هایی برای درک سرعت و میزان بهره‌وری انرژی هر درایور برای انجام یک اجرا استفاده می‌کند. برای ارائه این اطلاعات، درایور باید اعداد عملکرد استاندارد شده‌ای را بر اساس اجرای بارهای کاری مرجع ارائه دهد.

برای تعیین مقادیری که درایور در پاسخ به IDevice::getCapabilities_1_3 برمی‌گرداند، از برنامه بنچمارک NNAPI برای اندازه‌گیری عملکرد انواع داده‌های مربوطه استفاده کنید. مدل‌های MobileNet v1 و v2، asr_float و tts_float برای اندازه‌گیری عملکرد برای مقادیر ممیز شناور ۳۲ بیتی و مدل‌های کوانتیزه MobileNet v1 و v2 برای مقادیر کوانتیزه ۸ بیتی توصیه می‌شوند. برای اطلاعات بیشتر، به مجموعه تست یادگیری ماشین اندروید مراجعه کنید.

در اندروید ۹ و پایین‌تر، ساختار Capabilities فقط شامل اطلاعات عملکرد درایور برای تانسورهای ممیز شناور و کوانتیزه شده است و انواع داده‌های اسکالر را شامل نمی‌شود.

به عنوان بخشی از فرآیند مقداردهی اولیه، چارچوب ممکن است با استفاده از IDevice::getType ، IDevice::getVersionString ، IDevice:getSupportedExtensions و IDevice::getNumberOfCacheFilesNeeded اطلاعات بیشتری را جستجو کند.

بین راه‌اندازی‌های مجدد محصول، چارچوب انتظار دارد که تمام پرس‌وجوهای شرح داده شده در این بخش، همیشه مقادیر یکسانی را برای یک درایور مشخص گزارش دهند. در غیر این صورت، برنامه‌ای که از آن درایور استفاده می‌کند، ممکن است عملکرد کاهش یافته یا رفتار نادرستی از خود نشان دهد.

گردآوری

این چارچوب تعیین می‌کند که هنگام دریافت درخواست از یک برنامه، از کدام دستگاه‌ها استفاده کند. در اندروید ۱۰، برنامه‌ها می‌توانند دستگاه‌هایی را که چارچوب از آنها انتخاب می‌کند، کشف و مشخص کنند. برای اطلاعات بیشتر، به بخش کشف و تخصیص دستگاه مراجعه کنید.

در زمان کامپایل مدل، چارچوب با فراخوانی IDevice::getSupportedOperations_1_3 ، مدل را به هر درایور کاندید ارسال می‌کند. هر درایور آرایه‌ای از مقادیر بولی را برمی‌گرداند که نشان می‌دهد کدام عملیات مدل پشتیبانی می‌شوند. یک درایور می‌تواند تشخیص دهد که به دلایل مختلف نمی‌تواند از یک عملیات خاص پشتیبانی کند. به عنوان مثال:

  • درایور از نوع داده پشتیبانی نمی‌کند.
  • این درایور فقط از عملیات با پارامترهای ورودی خاص پشتیبانی می‌کند. برای مثال، یک درایور ممکن است از عملیات کانولوشن ۳x۳ و ۵x۵ پشتیبانی کند، اما از عملیات کانولوشن ۷x۷ پشتیبانی نکند.
  • این درایور محدودیت‌های حافظه دارد که مانع از مدیریت نمودارها یا ورودی‌های بزرگ می‌شود.

در طول کامپایل، ورودی، خروجی و عملوندهای داخلی مدل، همانطور که در OperandLifeTime توضیح داده شده است، می‌توانند ابعاد یا رتبه ناشناخته‌ای داشته باشند. برای اطلاعات بیشتر، به Output shape مراجعه کنید.

این چارچوب به هر درایور انتخاب شده دستور می‌دهد تا با فراخوانی IDevice::prepareModel_1_3 ، برای اجرای زیرمجموعه‌ای از مدل آماده شود. سپس هر درایور زیرمجموعه خود را کامپایل می‌کند. برای مثال، یک درایور ممکن است کدی تولید کند یا یک کپی مرتب‌شده از وزن‌ها ایجاد کند. از آنجا که ممکن است زمان قابل توجهی بین کامپایل مدل و اجرای درخواست‌ها وجود داشته باشد، منابعی مانند بخش‌های بزرگی از حافظه دستگاه نباید در طول کامپایل اختصاص داده شوند.

در صورت موفقیت، درایور یک هندل @1.3::IPreparedModel برمی‌گرداند. اگر درایور هنگام آماده‌سازی زیرمجموعه مدل خود، کد خرابی (failure code) برگرداند، فریم‌ورک کل مدل را روی CPU اجرا می‌کند.

برای کاهش زمان مورد استفاده برای کامپایل هنگام شروع یک برنامه، یک درایور می‌تواند مصنوعات کامپایل را ذخیره کند. برای اطلاعات بیشتر، به ذخیره سازی کامپایل مراجعه کنید.

اعدام

وقتی یک برنامه از فریم‌ورک می‌خواهد که یک درخواست را اجرا کند، فریم‌ورک به طور پیش‌فرض متد IPreparedModel::executeSynchronously_1_3 HAL را برای انجام اجرای همزمان روی یک مدل آماده شده فراخوانی می‌کند. یک درخواست همچنین می‌تواند به صورت غیرهمزمان با استفاده از متد execute_1_3 ، متد executeFenced (به بخش اجرای حصارکشی شده مراجعه کنید) یا با استفاده از اجرای پشت سر هم اجرا شود.

فراخوانی‌های اجرای همزمان در مقایسه با فراخوانی‌های غیرهمزمان، عملکرد را بهبود بخشیده و سربار نخ‌بندی را کاهش می‌دهند، زیرا کنترل تنها پس از اتمام اجرا به فرآیند برنامه بازگردانده می‌شود. این بدان معناست که درایور به مکانیسم جداگانه‌ای برای اطلاع‌رسانی به فرآیند برنامه مبنی بر اتمام اجرا نیاز ندارد.

با متد execute_1_3 ناهمزمان، کنترل پس از شروع اجرا به فرآیند برنامه بازمی‌گردد و درایور باید پس از اتمام اجرا، با استفاده از @1.3::IExecutionCallback ، فریم‌ورک را مطلع کند.

پارامتر Request که به متد execute ارسال می‌شود، عملوندهای ورودی و خروجی مورد استفاده برای اجرا را فهرست می‌کند. حافظه‌ای که داده‌های عملوند را ذخیره می‌کند باید از ترتیب سطر-اصلی استفاده کند، به طوری که اولین بُعد، کندترین تکرار را داشته باشد و در انتهای هیچ سطری، فاصله‌گذاری نداشته باشد. برای اطلاعات بیشتر در مورد انواع عملوندها، به Operands مراجعه کنید.

برای درایورهای NN HAL نسخه ۱.۲ یا بالاتر، هنگامی که یک درخواست تکمیل می‌شود، وضعیت خطا، شکل خروجی و اطلاعات زمان‌بندی به چارچوب بازگردانده می‌شوند. در حین اجرا، خروجی یا عملوندهای داخلی مدل می‌توانند یک یا چند بعد یا رتبه ناشناخته داشته باشند. هنگامی که حداقل یک عملوند خروجی دارای بعد یا رتبه ناشناخته باشد، درایور باید اطلاعات خروجی با اندازه پویا را بازگرداند.

برای درایورهایی با NN HAL 1.1 یا پایین‌تر، فقط وضعیت خطا هنگام تکمیل درخواست برگردانده می‌شود. ابعاد عملوندهای ورودی و خروجی باید به طور کامل مشخص شوند تا اجرا با موفقیت انجام شود. عملوندهای داخلی می‌توانند یک یا چند بعد ناشناخته داشته باشند، اما باید رتبه مشخصی داشته باشند.

برای درخواست‌های کاربر که شامل چندین درایور می‌شوند، چارچوب مسئول رزرو حافظه میانی و ترتیب فراخوانی‌ها به هر درایور است.

چندین درخواست می‌توانند به صورت موازی روی یک @1.3::IPreparedModel آغاز شوند. درایور می‌تواند درخواست‌ها را به صورت موازی اجرا کند یا اجراها را سریالی کند.

این چارچوب می‌تواند از یک درایور بخواهد که بیش از یک مدل آماده را نگه دارد. برای مثال، آماده‌سازی مدل m1 ، آماده‌سازی m2 ، اجرای درخواست r1 روی m1 ، اجرای r2 روی m2 ، اجرای r3 روی m1 ، اجرای r4 روی m2 ، رهاسازی (در پاکسازی توضیح داده شده است) m1 ، و رهاسازی m2 .

برای جلوگیری از اجرای کند اولیه که می‌تواند منجر به تجربه کاربری ضعیف شود (مثلاً کندی فریم اول)، درایور باید بیشتر مقداردهی اولیه را در مرحله کامپایل انجام دهد. مقداردهی اولیه در اولین اجرا باید به اقداماتی محدود شود که هنگام انجام زودهنگام بر سلامت سیستم تأثیر منفی می‌گذارند، مانند رزرو بافرهای موقت بزرگ یا افزایش سرعت کلاک یک دستگاه. درایورهایی که می‌توانند فقط تعداد محدودی از مدل‌های همزمان را آماده کنند، ممکن است مجبور شوند مقداردهی اولیه خود را در اولین اجرا انجام دهند.

در اندروید ۱۰ یا بالاتر، در مواردی که چندین اجرا با مدل آماده‌شده‌ی یکسان، پشت سر هم و سریع اجرا می‌شوند، کلاینت می‌تواند از یک شیء اجرای پشت سر هم برای ارتباط بین فرآیندهای برنامه و درایور استفاده کند. برای اطلاعات بیشتر، به بخش اجراهای پشت سر هم و صف‌های پیام سریع مراجعه کنید.

برای بهبود عملکرد برای چندین اجرا پشت سر هم، درایور می‌تواند بافرهای موقت را نگه دارد یا نرخ کلاک را افزایش دهد. ایجاد یک نخ نگهبان (watchdog thread) برای آزاد کردن منابع در صورت عدم ایجاد درخواست جدید پس از یک دوره زمانی ثابت توصیه می‌شود.

شکل خروجی

برای درخواست‌هایی که در آن‌ها یک یا چند عملوند خروجی تمام ابعاد مشخص‌شده را ندارند، درایور باید فهرستی از شکل‌های خروجی حاوی اطلاعات ابعاد برای هر عملوند خروجی پس از اجرا ارائه دهد. برای اطلاعات بیشتر در مورد ابعاد، به OutputShape مراجعه کنید.

اگر اجرایی به دلیل کمبود بافر خروجی با شکست مواجه شود، درایور باید در لیست شکل‌های خروجی، مشخص کند که کدام عملوندهای خروجی اندازه بافر ناکافی دارند و باید تا حد امکان اطلاعات ابعادی را گزارش دهد و برای ابعاد ناشناخته از صفر استفاده کند.

زمان‌بندی

در اندروید ۱۰، یک برنامه می‌تواند در صورتی که یک دستگاه واحد را برای استفاده در طول فرآیند کامپایل مشخص کرده باشد، زمان اجرا را درخواست کند. برای جزئیات بیشتر، به MeasureTiming و Device Discovery and Assignment مراجعه کنید. در این حالت، یک درایور NN HAL 1.2 باید هنگام اجرای یک درخواست، مدت زمان اجرا را اندازه‌گیری کند یا UINT64_MAX را گزارش دهد (برای نشان دادن اینکه مدت زمان در دسترس نیست). درایور باید هرگونه جریمه عملکردی ناشی از اندازه‌گیری مدت زمان اجرا را به حداقل برساند.

درایور مدت زمان‌های زیر را بر حسب میکروثانیه در ساختار Timing گزارش می‌دهد:

  • زمان اجرا روی دستگاه: شامل زمان اجرا در درایور که روی پردازنده میزبان اجرا می‌شود، نمی‌شود.
  • زمان اجرا در درایور: شامل زمان اجرا در دستگاه می‌شود.

این مدت زمان‌ها باید شامل زمانی باشند که اجرا به حالت تعلیق در می‌آید، برای مثال، زمانی که اجرا توسط وظایف دیگر به تعویق افتاده است یا زمانی که منتظر در دسترس قرار گرفتن یک منبع است.

وقتی از درایور خواسته نشده باشد که مدت زمان اجرا را اندازه‌گیری کند، یا وقتی خطایی در اجرا وجود دارد، درایور باید مدت زمان‌ها را به صورت UINT64_MAX گزارش دهد. حتی وقتی از درایور خواسته شده باشد که مدت زمان اجرا را اندازه‌گیری کند، می‌تواند به جای آن UINT64_MAX برای زمان روی دستگاه، زمان در درایور یا هر دو گزارش دهد. وقتی درایور هر دو مدت زمان را به صورت مقداری غیر از UINT64_MAX گزارش می‌دهد، زمان اجرا در درایور باید برابر یا بیشتر از زمان روی دستگاه باشد.

اجرای حصارکشی شده

در اندروید ۱۱، NNAPI به اجراها اجازه می‌دهد تا منتظر لیستی از دستگیره‌های sync_fence بمانند و به صورت اختیاری یک شیء sync_fence را برگردانند که با اتمام اجرا، سیگنالی ارسال می‌شود. این امر سربار مدل‌های توالی کوچک و موارد استفاده از جریان را کاهش می‌دهد. اجرای محصور شده همچنین امکان همکاری کارآمدتر با سایر مؤلفه‌هایی را که می‌توانند سیگنال ارسال کنند یا منتظر sync_fence باشند، فراهم می‌کند. برای اطلاعات بیشتر در مورد sync_fence ، به چارچوب همگام‌سازی مراجعه کنید.

در یک اجرای محصور (fenced execution)، چارچوب، متد IPreparedModel::executeFenced را فراخوانی می‌کند تا یک اجرای محصور و ناهمزمان را روی یک مدل آماده‌شده با برداری از حصارهای همگام‌سازی که باید منتظر بمانند، آغاز کند. اگر وظیفه ناهمزمان قبل از بازگشت فراخوانی به پایان برسد، می‌توان یک هندل خالی برای sync_fence برگرداند. همچنین باید یک شیء IFencedExecutionCallback برگردانده شود تا چارچوب بتواند وضعیت خطا و اطلاعات مدت زمان را پرس‌وجو کند.

پس از اتمام اجرا، دو مقدار زمانی زیر که مدت زمان اجرا را اندازه‌گیری می‌کنند، می‌توانند از طریق IFencedExecutionCallback::getExecutionInfo پرس‌وجو شوند.

  • timingLaunched : مدت زمان از زمانی که executeFenced فراخوانی می‌شود تا زمانی که executeFenced سیگنال syncFence برگشتی را ارسال می‌کند.
  • timingFenced : مدت زمانی که از زمانی که تمام حصارهای همگام‌سازی که اجرا منتظر آنهاست، سیگنال دریافت می‌کنند تا زمانی که executeFenced سیگنال‌های syncFence برگشتی را ارسال می‌کند، آغاز می‌شود.

جریان کنترل

برای دستگاه‌هایی که اندروید ۱۱ یا بالاتر را اجرا می‌کنند، NNAPI شامل دو عملیات جریان کنترل، IF و WHILE ، است که مدل‌های دیگر را به عنوان آرگومان دریافت کرده و آنها را به صورت شرطی ( IF ) یا مکرر ( WHILE ) اجرا می‌کنند. برای اطلاعات بیشتر در مورد نحوه پیاده‌سازی این، به Control flow مراجعه کنید.

کیفیت خدمات

در اندروید ۱۱، NNAPI شامل بهبود کیفیت خدمات (QoS) است که به یک برنامه اجازه می‌دهد اولویت‌های نسبی مدل‌های خود، حداکثر زمان مورد انتظار برای آماده‌سازی یک مدل و حداکثر زمان مورد انتظار برای تکمیل یک اجرا را نشان دهد. برای اطلاعات بیشتر، به بخش کیفیت خدمات مراجعه کنید.

پاکسازی

وقتی استفاده از یک مدل آماده‌شده توسط یک برنامه به پایان می‌رسد، چارچوب، ارجاع خود را به شیء @1.3::IPreparedModel منتشر می‌کند. وقتی شیء IPreparedModel دیگر ارجاع داده نشود، به طور خودکار در سرویس درایوری که آن را ایجاد کرده است، از بین می‌رود. منابع مختص مدل را می‌توان در این زمان در پیاده‌سازی درایور از مخرب، بازیابی کرد. اگر سرویس درایور بخواهد شیء IPreparedModel وقتی دیگر مورد نیاز کلاینت نیست، به طور خودکار از بین برود، نباید هیچ ارجاعی به شیء IPreparedModel پس از برگرداندن شیء IPreparedeModel از طریق IPreparedModelCallback::notify_1_3 داشته باشد.

میزان استفاده از پردازنده

انتظار می‌رود درایورها از CPU برای تنظیم محاسبات استفاده کنند. درایورها نباید از CPU برای انجام محاسبات گراف استفاده کنند زیرا این کار در توانایی چارچوب برای تخصیص صحیح کار اختلال ایجاد می‌کند. درایور باید بخش‌هایی را که نمی‌تواند مدیریت کند به چارچوب گزارش دهد و اجازه دهد چارچوب بقیه را مدیریت کند.

این چارچوب، پیاده‌سازی CPU را برای تمام عملیات NNAPI به جز عملیات تعریف‌شده توسط فروشنده ارائه می‌دهد. برای اطلاعات بیشتر، به Vendor Extensions مراجعه کنید.

عملیات معرفی‌شده در اندروید ۱۰ (سطح API ۲۹) فقط یک پیاده‌سازی CPU مرجع برای تأیید صحت تست‌های CTS و VTS دارند. پیاده‌سازی‌های بهینه‌شده موجود در چارچوب‌های یادگیری ماشین موبایل نسبت به پیاده‌سازی CPU NNAPI ترجیح داده می‌شوند.

توابع کاربردی

کدبیس NNAPI شامل توابع کاربردی است که می‌توانند توسط سرویس‌های درایور مورد استفاده قرار گیرند.

فایل frameworks/ml/nn/common/include/Utils.h شامل توابع کاربردی متنوعی است، مانند توابعی که برای ثبت وقایع و تبدیل بین نسخه‌های مختلف NN HAL استفاده می‌شوند.

  • VLogging: VLOG یک ماکروی پوششی پیرامون LOG اندروید است که فقط در صورتی پیام را ثبت می‌کند که برچسب مناسب در ویژگی debug.nn.vlog تنظیم شده باشد. initVLogMask() باید قبل از هرگونه فراخوانی VLOG فراخوانی شود. ماکروی VLOG_IS_ON می‌تواند برای بررسی فعال بودن VLOG در حال حاضر استفاده شود و در صورت عدم نیاز، امکان رد شدن از کد ثبت وقایع پیچیده را فراهم کند. مقدار این ویژگی باید یکی از موارد زیر باشد:

    • یک رشته خالی، که نشان می‌دهد هیچ ثبت وقایعی نباید انجام شود.
    • توکن 1 یا all ، نشان می‌دهد که تمام ثبت وقایع باید انجام شود.
    • فهرستی از برچسب‌ها، که با فاصله، کاما یا دونقطه از هم جدا شده‌اند و نشان می‌دهند کدام گزارش‌گیری باید انجام شود. برچسب‌ها عبارتند از compilation ، cpuexe ، driver ، execution ، manager و model .
  • compliantWithV1_* : اگر یک شیء NN HAL بتواند بدون از دست دادن اطلاعات به همان نوع از یک نسخه HAL متفاوت تبدیل شود، مقدار true را برمی‌گرداند. برای مثال، فراخوانی compliantWithV1_0 روی یک V1_2::Model در صورتی false را برمی‌گرداند که مدل شامل انواع عملیاتی باشد که در NN HAL 1.1 یا NN HAL 1.2 معرفی شده‌اند.

  • convertToV1_* : یک شیء NN HAL را از یک نسخه به نسخه دیگر تبدیل می‌کند. اگر تبدیل منجر به از دست رفتن اطلاعات شود (یعنی اگر نسخه جدید نوع نتواند به طور کامل مقدار را نمایش دهد)، یک هشدار ثبت می‌شود.

  • قابلیت‌ها: توابع nonExtensionOperandPerformance و update می‌توانند برای کمک به ساخت فیلد Capabilities::operandPerformance مورد استفاده قرار گیرند.

  • پرس‌وجوی ویژگی‌های انواع: isExtensionOperandType ، isExtensionOperationType ، nonExtensionSizeOfData ، nonExtensionOperandSizeOfData ، nonExtensionOperandTypeIsScalar ، tensorHasUnspecifiedDimensions .

فایل frameworks/ml/nn/common/include/ValidateHal.h شامل توابع کاربردی برای اعتبارسنجی یک شیء NN HAL مطابق با مشخصات نسخه HAL آن است.

  • validate* : اگر شیء NN HAL مطابق مشخصات نسخه HAL خود معتبر باشد، true را برمی‌گرداند. انواع OEM و انواع افزونه‌ها اعتبارسنجی نشده‌اند. برای مثال، validateModel اگر مدل شامل عملیاتی باشد که به یک اندیس عملوند که وجود ندارد اشاره می‌کند، یا عملیاتی که در آن نسخه HAL پشتیبانی نمی‌شود، false را برمی‌گرداند.

فایل frameworks/ml/nn/common/include/Tracing.h حاوی ماکروهایی برای ساده‌سازی افزودن اطلاعات systracing به کد شبکه‌های عصبی است. برای مثال، به فراخوانی‌های ماکروی NNTRACE_* در درایور نمونه مراجعه کنید.

فایل frameworks/ml/nn/common/include/GraphDump.h حاوی یک تابع کاربردی برای نمایش محتوای یک Model به صورت گرافیکی برای اهداف اشکال‌زدایی است.

  • graphDump : نمایشی از مدل را با فرمت Graphviz ( .dot ) در جریان مشخص شده (در صورت ارائه) یا در logcat (در صورت عدم ارائه جریان) می‌نویسد.

اعتبارسنجی

برای آزمایش پیاده‌سازی NNAPI خود، از تست‌های VTS و CTS موجود در چارچوب اندروید استفاده کنید. VTS درایورهای شما را مستقیماً (بدون استفاده از چارچوب) اعمال می‌کند، در حالی که CTS آنها را به طور غیرمستقیم از طریق چارچوب اعمال می‌کند. این تست‌ها هر روش API را آزمایش می‌کنند و تأیید می‌کنند که تمام عملیات پشتیبانی شده توسط درایورها به درستی کار می‌کنند و نتایجی را ارائه می‌دهند که الزامات دقت را برآورده می‌کنند.

الزامات دقت در CTS و VTS برای NNAPI به شرح زیر است:

  • عدد اعشاری: abs(مورد انتظار - واقعی) <= atol + rtol * abs(مورد انتظار)؛ که در آن:

    • برای fp32، atol = 1e-5f، rtol = 5.0f * 1.1920928955078125e-7
    • برای fp16، atol = rtol = 5.0f * 0.0009765625f
  • کوانتیزه شده: خارج از یک (به جز mobilenet_quantized که خارج از سه است)

  • بولی: تطابق دقیق

یکی از روش‌های آزمایش NNAPI توسط CTS، تولید گراف‌های شبه‌تصادفی ثابت است که برای آزمایش و مقایسه نتایج اجرای هر درایور با پیاده‌سازی مرجع NNAPI استفاده می‌شود. برای درایورهایی با NN HAL 1.2 یا بالاتر، اگر نتایج معیارهای دقت را برآورده نکنند، CTS خطایی گزارش می‌دهد و یک فایل مشخصات برای مدل ناموفق را در /data/local/tmp برای اشکال‌زدایی ذخیره می‌کند. برای جزئیات بیشتر در مورد معیارهای دقت، به TestRandomGraph.cpp و TestHarness.h مراجعه کنید.

تست فاز

هدف از تست فاز، یافتن خرابی‌ها، ادعاها، نقض حافظه یا رفتار کلی تعریف نشده در کد تحت آزمایش به دلیل عواملی مانند ورودی‌های غیرمنتظره است. برای تست فاز NNAPI، اندروید از تست‌هایی مبتنی بر libFuzzer استفاده می‌کند که در فاز کردن کارآمد هستند زیرا از پوشش خط موارد آزمایش قبلی برای تولید ورودی‌های تصادفی جدید استفاده می‌کنند. به عنوان مثال، libFuzzer از موارد آزمایشی که روی خطوط جدید کد اجرا می‌شوند، حمایت می‌کند. این امر میزان زمان لازم برای یافتن کد مشکل‌ساز را در تست‌ها به میزان زیادی کاهش می‌دهد.

برای انجام تست فاز برای اعتبارسنجی پیاده‌سازی درایور خود، frameworks/ml/nn/runtime/test/android_fuzzing/DriverFuzzTest.cpp را در ابزار تست libneuralnetworks_driver_fuzzer که در AOSP موجود است، تغییر دهید تا کد درایور شما را شامل شود. برای اطلاعات بیشتر در مورد تست فاز NNAPI، به frameworks/ml/nn/runtime/test/android_fuzzing/README.md مراجعه کنید.

امنیت

از آنجا که فرآیندهای برنامه مستقیماً با فرآیند درایور ارتباط برقرار می‌کنند، درایورها باید آرگومان‌های فراخوانی‌های دریافتی خود را اعتبارسنجی کنند. این اعتبارسنجی توسط VTS تأیید می‌شود. کد اعتبارسنجی در frameworks/ml/nn/common/include/ValidateHal.h قرار دارد.

رانندگان همچنین باید اطمینان حاصل کنند که برنامه‌ها هنگام استفاده از همان دستگاه، با برنامه‌های دیگر تداخل نداشته باشند.

مجموعه تست یادگیری ماشین اندروید

مجموعه تست یادگیری ماشین اندروید (MLTS) یک معیار NNAPI است که در CTS و VTS برای اعتبارسنجی دقت مدل‌های واقعی روی دستگاه‌های فروشندگان گنجانده شده است. این معیار، تأخیر و دقت را ارزیابی می‌کند و نتایج درایورها را با نتایج استفاده از TF Lite که روی CPU اجرا می‌شود، برای همان مدل و مجموعه داده‌ها مقایسه می‌کند. این تضمین می‌کند که دقت درایور از پیاده‌سازی مرجع CPU بدتر نباشد.

توسعه‌دهندگان پلتفرم اندروید همچنین از MLTS برای ارزیابی تأخیر و دقت درایورها استفاده می‌کنند.

بنچمارک NNAPI را می‌توان در دو پروژه در AOSP یافت:

مدل‌ها و مجموعه داده‌ها

معیار NNAPI از مدل‌ها و مجموعه داده‌های زیر استفاده می‌کند.

  • MobileNetV1 float و u8 کوانتیزه شده در اندازه‌های مختلف، روی زیرمجموعه کوچکی (۱۵۰۰ تصویر) از مجموعه داده‌های Open Images نسخه ۴ اجرا می‌شوند.
  • MobileNetV2 float و u8 کوانتیزه شده در اندازه‌های مختلف، روی زیرمجموعه کوچکی (۱۵۰۰ تصویر) از مجموعه داده‌های Open Images نسخه ۴ اجرا می‌شوند.
  • مدل آکوستیک مبتنی بر حافظه کوتاه‌مدت بلندمدت (LSTM) برای تبدیل متن به گفتار، که در مقابل زیرمجموعه کوچکی از مجموعه CMU Arctic اجرا می‌شود.
  • مدل آکوستیک مبتنی بر LSTM برای تشخیص خودکار گفتار، اجرا شده بر روی زیرمجموعه کوچکی از مجموعه داده LibriSpeech.

برای اطلاعات بیشتر، به platform/test/mlts/models مراجعه کنید.

تست استرس

مجموعه تست یادگیری ماشین اندروید شامل مجموعه‌ای از تست‌های خرابی است تا میزان تاب‌آوری رانندگان را در شرایط استفاده سنگین یا در موارد جزئی از رفتار کلاینت‌ها، ارزیابی کند.

تمام تست‌های تصادف ویژگی‌های زیر را ارائه می‌دهند:

  • تشخیص هنگ: اگر کلاینت NNAPI در طول تست هنگ کند، تست با دلیل خرابی HANG با شکست مواجه می‌شود و مجموعه تست به تست بعدی منتقل می‌شود.
  • تشخیص خرابی کلاینت NNAPI: تست‌ها از خرابی‌های کلاینت جان سالم به در می‌برند و تست‌ها با دلیل خرابی CRASH شکست می‌خورند.
  • تشخیص خرابی درایور: تست‌ها می‌توانند خرابی درایوری را که باعث خرابی در فراخوانی NNAPI می‌شود، تشخیص دهند. توجه داشته باشید که ممکن است خرابی‌هایی در فرآیندهای درایور وجود داشته باشد که باعث خرابی NNAPI و خرابی در تست نشوند. برای پوشش این نوع خرابی، توصیه می‌شود دستور tail را در گزارش سیستم برای خطاها یا خرابی‌های مربوط به درایور اجرا کنید.
  • هدف قرار دادن همه شتاب‌دهنده‌های موجود: آزمایش‌ها روی همه درایورهای موجود انجام می‌شوند.

تمام تست‌های تصادف چهار نتیجه‌ی ممکن زیر را دارند:

  • SUCCESS : اجرا بدون خطا انجام شد.
  • FAILURE : اجرا ناموفق بود. معمولاً به دلیل خطا هنگام آزمایش یک مدل ایجاد می‌شود و نشان می‌دهد که درایور نتوانسته مدل را کامپایل یا اجرا کند.
  • HANG : فرآیند تست از کار افتاد.
  • CRASH : فرآیند آزمایش از کار افتاد.

برای اطلاعات بیشتر در مورد تست استرس و لیست کامل تست‌های خرابی، به platform/test/mlts/benchmark/README.txt مراجعه کنید.

از MLTS استفاده کنید

برای استفاده از MLTS:

  1. یک دستگاه هدف را به ایستگاه کاری خود متصل کنید و مطمئن شوید که از طریق adb قابل دسترسی است. اگر بیش از یک دستگاه متصل است، متغیر محیطی ANDROID_SERIAL دستگاه هدف را صادر کنید.
  2. با استفاده از cd به دایرکتوری منبع سطح بالای اندروید بروید.

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

    در پایان اجرای بنچمارک، نتایج به صورت یک صفحه HTML ارائه شده و به xdg-open ارسال می‌شوند.

برای اطلاعات بیشتر، به platform/test/mlts/benchmark/README.txt مراجعه کنید.

شبکه‌های عصبی نسخه‌های HAL

این بخش تغییرات معرفی‌شده در نسخه‌های اندروید و شبکه‌های عصبی HAL را شرح می‌دهد.

اندروید ۱۱

اندروید ۱۱، NN HAL 1.3 را معرفی می‌کند که شامل تغییرات قابل توجه زیر است.

  • پشتیبانی از کوانتیزاسیون ۸ بیتی علامت‌دار در NNAPI. نوع عملوند TENSOR_QUANT8_ASYMM_SIGNED را اضافه می‌کند. درایورهایی با NN HAL 1.3 که از عملیات با کوانتیزاسیون بدون علامت پشتیبانی می‌کنند، باید از انواع علامت‌دار آن عملیات نیز پشتیبانی کنند. هنگام اجرای نسخه‌های علامت‌دار و بدون علامت اکثر عملیات‌های کوانتیزه، درایورها باید نتایج یکسانی را تا آفست ۱۲۸ تولید کنند. پنج استثنا برای این الزام وجود دارد: CAST ، HASHTABLE_LOOKUP ، LSH_PROJECTION ، PAD_V2 و QUANTIZED_16BIT_LSTM . عملیات QUANTIZED_16BIT_LSTM از عملوندهای علامت‌دار پشتیبانی نمی‌کند و چهار عملیات دیگر از کوانتیزاسیون علامت‌دار پشتیبانی می‌کنند اما نیازی به یکسان بودن نتایج ندارند.
  • پشتیبانی از اجراهای حصاربندی‌شده که در آن چارچوب، متد IPreparedModel::executeFenced را برای اجرای یک اجرای حصاربندی‌شده و ناهمزمان روی یک مدل آماده‌شده با برداری از حصارهای همگام‌سازی‌شده که باید منتظر بمانند، فراخوانی می‌کند. برای اطلاعات بیشتر، به اجرای حصاربندی‌شده مراجعه کنید.
  • پشتیبانی از جریان کنترل. عملیات IF و WHILE را اضافه می‌کند که مدل‌های دیگر را به عنوان آرگومان دریافت کرده و آنها را به صورت شرطی ( IF ) یا مکرر ( WHILE ) اجرا می‌کنند. برای اطلاعات بیشتر، به جریان کنترل مراجعه کنید.
  • کیفیت خدمات (QoS) بهبود یافته است، زیرا برنامه‌ها می‌توانند اولویت‌های نسبی مدل‌های خود، حداکثر زمان مورد انتظار برای آماده‌سازی یک مدل و حداکثر زمان مورد انتظار برای تکمیل یک اجرا را نشان دهند. برای اطلاعات بیشتر، به کیفیت خدمات مراجعه کنید.
  • پشتیبانی از دامنه‌های حافظه که رابط‌های تخصیص‌دهنده برای بافرهای مدیریت‌شده توسط درایور را فراهم می‌کنند. این امر امکان انتقال حافظه‌های بومی دستگاه را در طول اجراها فراهم می‌کند و از کپی کردن و تبدیل غیرضروری داده‌ها بین اجراهای متوالی در همان درایور جلوگیری می‌کند. برای اطلاعات بیشتر، به دامنه‌های حافظه مراجعه کنید.

اندروید ۱۰

اندروید ۱۰، NN HAL 1.2 را معرفی می‌کند که شامل تغییرات قابل توجه زیر است.

  • ساختار Capabilities شامل تمام انواع داده از جمله انواع داده اسکالر است و عملکرد غیر وابسته به بردار را به جای فیلدهای نامگذاری شده نشان می‌دهد.
  • متدهای getVersionString و getType به فریم‌ورک اجازه می‌دهند تا نوع دستگاه ( DeviceType ) و اطلاعات نسخه را بازیابی کند. به بخش Device Discovery and Assignment مراجعه کنید.
  • متد executeSynchronously به طور پیش‌فرض برای انجام یک اجرا به صورت همزمان فراخوانی می‌شود. متد execute_1_2 به چارچوب می‌گوید که یک اجرا را به صورت غیرهمزمان انجام دهد. به بخش Execution مراجعه کنید.
  • پارامتر MeasureTiming برای executeSynchronously ، execute_1_2 و اجرای پشت سر هم مشخص می‌کند که آیا درایور قرار است مدت زمان اجرا را اندازه‌گیری کند یا خیر. نتایج در ساختار Timing گزارش می‌شوند. به Timing مراجعه کنید.
  • پشتیبانی از اجراهایی که در آنها یک یا چند عملوند خروجی دارای بُعد یا رتبه نامعلوم هستند. به شکل خروجی مراجعه کنید.
  • پشتیبانی از افزونه‌های فروشنده، که مجموعه‌ای از عملیات و انواع داده تعریف‌شده توسط فروشنده هستند. درایور، افزونه‌های پشتیبانی‌شده را از طریق متد IDevice::getSupportedExtensions گزارش می‌دهد. به افزونه‌های فروشنده مراجعه کنید.
  • قابلیتی برای یک شیء burst برای کنترل مجموعه‌ای از اجراهای burst با استفاده از صف‌های پیام سریع (FMQ) برای ارتباط بین برنامه‌های کاربردی و فرآیندهای درایور، که باعث کاهش تأخیر می‌شود. به Burst Executions و Fast Message Queues مراجعه کنید.
  • پشتیبانی از AHardwareBuffer برای اینکه به درایور اجازه دهد بدون کپی کردن داده‌ها، اجراها را انجام دهد. به AHardwareBuffer مراجعه کنید.
  • پشتیبانی بهبود یافته برای ذخیره‌سازی مصنوعات کامپایل برای کاهش زمان مورد استفاده برای کامپایل هنگام شروع برنامه. به ذخیره‌سازی کامپایل مراجعه کنید.

اندروید ۱۰ انواع عملوندها و عملیات زیر را معرفی می‌کند.

  • انواع عملوند

    • 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
  • عملیات

    • 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

اندروید ۱۰ به‌روزرسانی‌هایی را برای بسیاری از عملیات موجود معرفی می‌کند. این به‌روزرسانی‌ها عمدتاً مربوط به موارد زیر هستند:

  • پشتیبانی از طرح حافظه NCHW
  • پشتیبانی از تانسورهایی با رتبه متفاوت از ۴ در عملیات softmax و نرمال‌سازی
  • پشتیبانی از پیچش‌های متسع‌شده
  • پشتیبانی از ورودی‌های با کوانتیزاسیون مختلط در ANEURALNETWORKS_CONCATENATION

لیست زیر عملیات‌هایی را نشان می‌دهد که در اندروید ۱۰ تغییر یافته‌اند. برای جزئیات کامل تغییرات، به OperationCode در مستندات مرجع 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

اندروید ۹

NN HAL 1.1 در اندروید ۹ معرفی شده و شامل تغییرات قابل توجه زیر است.

  • IDevice::prepareModel_1_1 شامل یک پارامتر ExecutionPreference است. یک درایور می‌تواند از این پارامتر برای تنظیم آماده‌سازی خود استفاده کند، با علم به اینکه برنامه ترجیح می‌دهد باتری را ذخیره کند یا مدل را در فراخوانی‌های سریع و متوالی اجرا خواهد کرد.
  • نه عملیات جدید اضافه شده است: BATCH_TO_SPACE_ND ، DIV ، MEAN ، PAD ، SPACE_TO_BATCH_ND ، SQUEEZE ، STRIDED_SLICE ، SUB ، TRANSPOSE .
  • یک برنامه می‌تواند با تنظیم Model.relaxComputationFloat32toFloat16 روی true ، مشخص کند که محاسبات اعشاری ۳۲ بیتی با استفاده از محدوده و/یا دقت اعشاری ۱۶ بیتی قابل اجرا هستند. struct Capabilities دارای فیلد اضافی relaxedFloat32toFloat16Performance است تا درایور بتواند عملکرد در حالت استراحت خود را به چارچوب گزارش دهد.

اندروید ۸.۱

شبکه عصبی اولیه HAL (1.0) در اندروید ۸.۱ منتشر شد. برای اطلاعات بیشتر، به /neuralnetworks/1.0/ مراجعه کنید.