با میکروکنترلرها شروع کنید

با مجموعه‌ها، منظم بمانید ذخیره و دسته‌بندی محتوا براساس اولویت‌های شما.

این سند نحوه آموزش یک مدل و اجرای استنتاج با استفاده از یک میکروکنترلر را توضیح می دهد.

مثال سلام جهان

مثال Hello World برای نشان دادن اصول اولیه استفاده از TensorFlow Lite برای میکروکنترلرها طراحی شده است. ما مدلی را آموزش می‌دهیم و اجرا می‌کنیم که یک تابع سینوسی را تکرار می‌کند، یعنی یک عدد را به عنوان ورودی می‌گیرد و مقدار سینوسی عدد را خروجی می‌کند. هنگامی که روی میکروکنترلر مستقر می شود، پیش بینی های آن برای چشمک زدن LED ها یا کنترل یک انیمیشن استفاده می شود.

گردش کار انتها به انتها شامل مراحل زیر است:

  1. آموزش یک مدل (در پایتون): یک نوت بوک jupyter برای آموزش، تبدیل و بهینه سازی یک مدل برای استفاده در دستگاه.
  2. اجرای استنتاج (در C++ 11): یک تست واحد سرتاسری که استنتاج را روی مدل با استفاده از کتابخانه C++ اجرا می‌کند.

یک دستگاه پشتیبانی شده دریافت کنید

برنامه نمونه ای که ما استفاده خواهیم کرد در دستگاه های زیر آزمایش شده است:

درباره پلتفرم های پشتیبانی شده در TensorFlow Lite برای میکروکنترلرها بیشتر بیاموزید.

یک مدل تربیت کنید

از Google Colaboratory برای آموزش مدل خود استفاده کنید . برای جزئیات بیشتر، به README.md مراجعه کنید:

سلام آموزش جهانی README.md

استنتاج را اجرا کنید

برای اجرای مدل بر روی دستگاه شما، دستورالعمل‌های موجود در README.md را بررسی می‌کنیم:

سلام جهان README.md

بخش‌های زیر نمونه‌ای از تست واحد hello_world_test.cc را بررسی می‌کنند که نحوه اجرای استنتاج با استفاده از TensorFlow Lite برای میکروکنترلرها را نشان می‌دهد. مدل را بارگذاری می کند و استنتاج را چندین بار اجرا می کند.

1. سرصفحه های کتابخانه را وارد کنید

برای استفاده از کتابخانه TensorFlow Lite برای میکروکنترلرها، باید فایل‌های هدر زیر را اضافه کنیم:

#include "tensorflow/lite/micro/all_ops_resolver.h"
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "tensorflow/lite/version.h"
  • all_ops_resolver.h عملیات مورد استفاده توسط مفسر برای اجرای مدل را فراهم می کند.
  • micro_error_reporter.h اطلاعات اشکال زدایی را خروجی می دهد.
  • micro_interpreter.h حاوی کدی برای بارگیری و اجرای مدل ها است.
  • schema_generated.h شامل طرحی برای قالب فایل مدل FlatBuffer Lite FlatBuffer است.
  • version.h اطلاعات نسخه‌سازی را برای طرح TensorFlow Lite فراهم می‌کند.

2. هدر مدل را وارد کنید

مفسر TensorFlow Lite برای میکروکنترلرها انتظار دارد که مدل به صورت یک آرایه ++C ارائه شود. مدل در فایل های model.h و model.cc تعریف شده است. هدر با خط زیر همراه است:

#include "tensorflow/lite/micro/examples/hello_world/model.h"

3. سربرگ چارچوب تست واحد را وارد کنید

برای ایجاد یک تست واحد، چارچوب تست واحد TensorFlow Lite برای میکروکنترلرها را با گنجاندن خط زیر اضافه می کنیم:

#include "tensorflow/lite/micro/testing/micro_test.h"

تست با استفاده از ماکروهای زیر تعریف می شود:

TF_LITE_MICRO_TESTS_BEGIN

TF_LITE_MICRO_TEST(LoadModelAndPerformInference) {
  . // add code here
  .
}

TF_LITE_MICRO_TESTS_END

اکنون در مورد کد موجود در ماکرو بالا بحث می کنیم.

4. ورود به سیستم را تنظیم کنید

برای تنظیم گزارش، یک tflite::ErrorReporter با استفاده از یک اشاره گر به یک نمونه tflite::MicroErrorReporter می شود:

tflite::MicroErrorReporter micro_error_reporter;
tflite::ErrorReporter* error_reporter = &micro_error_reporter;

این متغیر به مفسر ارسال می‌شود که به آن اجازه می‌دهد لاگ بنویسد. از آنجایی که میکروکنترلرها اغلب مکانیسم های مختلفی برای ورود به سیستم دارند، پیاده سازی tflite::MicroErrorReporter به گونه ای طراحی شده است که برای دستگاه خاص شما سفارشی شود.

5. یک مدل را بارگذاری کنید

در کد زیر، مدل با استفاده از داده های آرایه char ، g_model که در model.h تعریف شده است، نمونه سازی شده است. سپس مدل را بررسی می کنیم تا مطمئن شویم که نسخه طرحواره آن با نسخه ای که استفاده می کنیم سازگار است:

const tflite::Model* model = ::tflite::GetModel(g_model);
if (model->version() != TFLITE_SCHEMA_VERSION) {
  TF_LITE_REPORT_ERROR(error_reporter,
      "Model provided is schema version %d not equal "
      "to supported version %d.\n",
      model->version(), TFLITE_SCHEMA_VERSION);
}

6. حل کننده عملیات آنی

یک نمونه AllOpsResolver اعلام شده است. این توسط مفسر برای دسترسی به عملیاتی که توسط مدل استفاده می شود استفاده می شود:

tflite::AllOpsResolver resolver;

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

این کار با استفاده از کلاس دیگری، MicroMutableOpResolver انجام می شود. می‌توانید نحوه استفاده از آن را در مثال micro_speech_test.cc micro_speech_test.cc کنید.

7. تخصیص حافظه

ما باید مقدار مشخصی از حافظه را برای ورودی، خروجی و آرایه های میانی تخصیص دهیم. این به عنوان یک آرایه uint8_t با اندازه tensor_arena_size شده است:

const int tensor_arena_size = 2 * 1024;
uint8_t tensor_arena[tensor_arena_size];

اندازه مورد نیاز به مدلی که استفاده می کنید بستگی دارد و ممکن است نیاز باشد با آزمایش تعیین شود.

8. مترجم فوری

ما یک نمونه tflite::MicroInterpreter ایجاد می کنیم که متغیرهای ایجاد شده قبلی را منتقل می کند:

tflite::MicroInterpreter interpreter(model, resolver, tensor_arena,
                                     tensor_arena_size, error_reporter);

9. تانسورها را اختصاص دهید

ما به مفسر می گوییم که حافظه را از tensor_arena برای تانسورهای مدل اختصاص دهد:

interpreter.AllocateTensors();

10. شکل ورودی را اعتبارسنجی کنید

نمونه MicroInterpreter می تواند با فراخوانی .input(0) یک اشاره گر به تانسور ورودی مدل در اختیار ما قرار دهد، جایی که 0 نشان دهنده اولین (و تنها) تانسور ورودی است:

  // Obtain a pointer to the model's input tensor
  TfLiteTensor* input = interpreter.input(0);

سپس این تانسور را بررسی می کنیم تا تأیید کنیم که شکل و نوع آن همان چیزی است که ما انتظار داریم:

// Make sure the input has the properties we expect
TF_LITE_MICRO_EXPECT_NE(nullptr, input);
// The property "dims" tells us the tensor's shape. It has one element for
// each dimension. Our input is a 2D tensor containing 1 element, so "dims"
// should have size 2.
TF_LITE_MICRO_EXPECT_EQ(2, input->dims->size);
// The value of each element gives the length of the corresponding tensor.
// We should expect two single element tensors (one is contained within the
// other).
TF_LITE_MICRO_EXPECT_EQ(1, input->dims->data[0]);
TF_LITE_MICRO_EXPECT_EQ(1, input->dims->data[1]);
// The input is a 32 bit floating point value
TF_LITE_MICRO_EXPECT_EQ(kTfLiteFloat32, input->type);

مقدار enum kTfLiteFloat32 ارجاع به یکی از انواع داده های TensorFlow Lite است و به صورت common.h تعریف می شود.

11. یک مقدار ورودی ارائه دهید

برای ارائه یک ورودی به مدل، محتویات تانسور ورودی را به صورت زیر تنظیم می کنیم:

input->data.f[0] = 0.;

در این مورد، یک مقدار ممیز شناور به نمایندگی از 0 وارد می کنیم.

12. مدل را اجرا کنید

برای اجرای مدل، می‌توانیم Invoke() را در نمونه tflite::MicroInterpreter فراخوانی کنیم:

TfLiteStatus invoke_status = interpreter.Invoke();
if (invoke_status != kTfLiteOk) {
  TF_LITE_REPORT_ERROR(error_reporter, "Invoke failed\n");
}

ما می‌توانیم مقدار بازگشتی، یک TfLiteStatus را بررسی کنیم تا مشخص کنیم که آیا اجرا با موفقیت انجام شده است یا خیر. مقادیر ممکن TfLiteStatus که در common.h تعریف شده اند kTfLiteOk و kTfLiteError هستند.

کد زیر بیان می کند که مقدار kTfLiteOk است، به این معنی که استنتاج با موفقیت اجرا شد.

TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, invoke_status);

13. خروجی را بدست آورید

تانسور خروجی مدل را می توان با فراخوانی output(0) در tflite::MicroInterpreter به دست آورد، جایی که 0 نشان دهنده اولین (و تنها) تانسور خروجی است.

در مثال، خروجی مدل یک مقدار ممیز شناور منفرد است که در یک تانسور دو بعدی قرار دارد:

TfLiteTensor* output = interpreter.output(0);
TF_LITE_MICRO_EXPECT_EQ(2, output->dims->size);
TF_LITE_MICRO_EXPECT_EQ(1, input->dims->data[0]);
TF_LITE_MICRO_EXPECT_EQ(1, input->dims->data[1]);
TF_LITE_MICRO_EXPECT_EQ(kTfLiteFloat32, output->type);

می‌توانیم مقدار را مستقیماً از تانسور خروجی بخوانیم و ادعا کنیم که همان چیزی است که انتظار داریم:

// Obtain the output value from the tensor
float value = output->data.f[0];
// Check that the output value is within 0.05 of the expected value
TF_LITE_MICRO_EXPECT_NEAR(0., value, 0.05);

14. استنتاج را دوباره اجرا کنید

بقیه کد چندین بار استنتاج را اجرا می کند. در هر نمونه، یک مقدار به تانسور ورودی اختصاص می دهیم، مفسر را فراخوانی می کنیم و نتیجه را از تانسور خروجی می خوانیم:

input->data.f[0] = 1.;
interpreter.Invoke();
value = output->data.f[0];
TF_LITE_MICRO_EXPECT_NEAR(0.841, value, 0.05);

input->data.f[0] = 3.;
interpreter.Invoke();
value = output->data.f[0];
TF_LITE_MICRO_EXPECT_NEAR(0.141, value, 0.05);

input->data.f[0] = 5.;
interpreter.Invoke();
value = output->data.f[0];
TF_LITE_MICRO_EXPECT_NEAR(-0.959, value, 0.05);

15. کد برنامه را بخوانید

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