Dokumen ini menjelaskan cara melatih model dan menjalankan inferensi menggunakan mikrokontroler.
Contoh Halo Dunia
Contoh Hello World dirancang untuk mendemonstrasikan dasar-dasar mutlak penggunaan TensorFlow Lite untuk Mikrokontroler. Kami melatih dan menjalankan model yang mereplikasi fungsi sinus, yaitu mengambil satu angka sebagai masukannya, dan mengeluarkan nilai sinus angka tersebut. Saat diterapkan ke mikrokontroler, prediksinya digunakan untuk mengedipkan LED atau mengontrol animasi.
Alur kerja ujung ke ujung melibatkan langkah-langkah berikut:
- Melatih model (dengan Python): File python untuk melatih, mengonversi, dan mengoptimalkan model untuk penggunaan di perangkat.
- Jalankan inferensi (dalam C++ 17): Pengujian unit ujung ke ujung yang menjalankan inferensi pada model menggunakan pustaka C++ .
Dapatkan perangkat yang didukung
Contoh aplikasi yang akan kami gunakan telah diuji pada perangkat berikut:
- Arduino Nano 33 BLE Sense (menggunakan Arduino IDE)
- SparkFun Edge (membangun langsung dari sumber)
- Kit Penemuan STM32F746 (menggunakan Mbed)
- Adafruit EdgeBadge (menggunakan Arduino IDE)
- Adafruit TensorFlow Lite untuk Kit Mikrokontroler (menggunakan Arduino IDE)
- Sirkuit Adafruit Playground Bluefruit (menggunakan Arduino IDE)
- Espressif ESP32-DevKitC (menggunakan ESP IDF)
- Espressif ESP-EYE (menggunakan ESP IDF)
Pelajari lebih lanjut platform yang didukung di TensorFlow Lite untuk Mikrokontroler .
Latih seorang model
Gunakan train.py untuk pelatihan model hello world untuk pengenalan sinwave
Jalankan: bazel build tensorflow/lite/micro/examples/hello_world:train
bazel-bin/tensorflow/lite/micro/examples/hello_world/train --save_tf_model --save_dir=/tmp/model_created/
Jalankan inferensi
Untuk menjalankan model di perangkat Anda, kami akan mengikuti petunjuk di README.md
:
Bagian berikut menjelaskan evaluate_test.cc
contoh, pengujian unit yang menunjukkan cara menjalankan inferensi menggunakan TensorFlow Lite untuk Mikrokontroler. Ini memuat model dan menjalankan inferensi beberapa kali.
1. Sertakan header perpustakaan
Untuk menggunakan pustaka TensorFlow Lite untuk Mikrokontroler, kita harus menyertakan file header berikut:
#include "tensorflow/lite/micro/micro_mutable_op_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"
-
micro_mutable_op_resolver.h
menyediakan operasi yang digunakan oleh penerjemah untuk menjalankan model. -
micro_error_reporter.h
mengeluarkan informasi debug. -
micro_interpreter.h
berisi kode untuk memuat dan menjalankan model. -
schema_generated.h
berisi skema untuk format file model TensorFlow LiteFlatBuffer
. -
version.h
memberikan informasi pembuatan versi untuk skema TensorFlow Lite.
2. Sertakan header model
Interpreter TensorFlow Lite untuk Mikrokontroler mengharapkan model disediakan sebagai array C++. Model didefinisikan dalam file model.h
dan model.cc
. Header disertakan dengan baris berikut:
#include "tensorflow/lite/micro/examples/hello_world/model.h"
3. Sertakan header kerangka pengujian unit
Untuk membuat pengujian unit, kami menyertakan framework pengujian unit TensorFlow Lite untuk Mikrokontroler dengan menyertakan baris berikut:
#include "tensorflow/lite/micro/testing/micro_test.h"
Pengujian ditentukan menggunakan makro berikut:
TF_LITE_MICRO_TESTS_BEGIN
TF_LITE_MICRO_TEST(LoadModelAndPerformInference) {
. // add code here
.
}
TF_LITE_MICRO_TESTS_END
Sekarang kita membahas kode yang disertakan pada makro di atas.
4. Siapkan pencatatan
Untuk menyiapkan logging, penunjuk tflite::ErrorReporter
dibuat menggunakan penunjuk ke instance tflite::MicroErrorReporter
:
tflite::MicroErrorReporter micro_error_reporter;
tflite::ErrorReporter* error_reporter = µ_error_reporter;
Variabel ini akan diteruskan ke penerjemah, yang memungkinkannya menulis log. Karena mikrokontroler sering kali memiliki beragam mekanisme untuk pencatatan, penerapan tflite::MicroErrorReporter
dirancang untuk disesuaikan untuk perangkat khusus Anda.
5. Memuat model
Dalam kode berikut, model dibuat menggunakan data dari array char
, g_model
, yang dideklarasikan dalam model.h
. Kami kemudian memeriksa model untuk memastikan versi skemanya kompatibel dengan versi yang kami gunakan:
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. Membuat instance penyelesai operasi
Contoh MicroMutableOpResolver
dideklarasikan. Ini akan digunakan oleh penerjemah untuk mendaftar dan mengakses operasi yang digunakan oleh model:
using HelloWorldOpResolver = tflite::MicroMutableOpResolver<1>;
TfLiteStatus RegisterOps(HelloWorldOpResolver& op_resolver) {
TF_LITE_ENSURE_STATUS(op_resolver.AddFullyConnected());
return kTfLiteOk;
MicroMutableOpResolver
memerlukan parameter templat yang menunjukkan jumlah operasi yang akan didaftarkan. Fungsi RegisterOps
mendaftarkan operasi dengan penyelesainya.
HelloWorldOpResolver op_resolver;
TF_LITE_ENSURE_STATUS(RegisterOps(op_resolver));
7. Alokasikan memori
Kita perlu mengalokasikan sejumlah memori terlebih dahulu untuk input, output, dan array perantara. Ini disediakan sebagai array uint8_t
dengan ukuran tensor_arena_size
:
const int tensor_arena_size = 2 * 1024;
uint8_t tensor_arena[tensor_arena_size];
Ukuran yang diperlukan akan bergantung pada model yang Anda gunakan, dan mungkin perlu ditentukan melalui eksperimen.
8. Memberi contoh juru bahasa
Kita membuat instance tflite::MicroInterpreter
, meneruskan variabel yang dibuat sebelumnya:
tflite::MicroInterpreter interpreter(model, resolver, tensor_arena,
tensor_arena_size, error_reporter);
9. Alokasikan tensor
Kami meminta interpreter untuk mengalokasikan memori dari tensor_arena
untuk tensor model:
interpreter.AllocateTensors();
10. Validasi bentuk masukan
Instance MicroInterpreter
dapat memberi kita penunjuk ke tensor masukan model dengan memanggil .input(0)
, dengan 0
mewakili tensor masukan pertama (dan satu-satunya):
// Obtain a pointer to the model's input tensor
TfLiteTensor* input = interpreter.input(0);
Kami kemudian memeriksa tensor ini untuk memastikan bahwa bentuk dan tipenya sesuai dengan yang kami harapkan:
// 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);
Nilai enum kTfLiteFloat32
adalah referensi ke salah satu tipe data TensorFlow Lite, dan didefinisikan dalam common.h
.
11. Berikan nilai masukan
Untuk memberikan masukan pada model, kami mengatur isi tensor masukan, sebagai berikut:
input->data.f[0] = 0.;
Dalam hal ini, kita memasukkan nilai floating point yang mewakili 0
.
12. Jalankan modelnya
Untuk menjalankan model, kita dapat memanggil Invoke()
pada instance tflite::MicroInterpreter
kita:
TfLiteStatus invoke_status = interpreter.Invoke();
if (invoke_status != kTfLiteOk) {
TF_LITE_REPORT_ERROR(error_reporter, "Invoke failed\n");
}
Kita dapat memeriksa nilai yang dikembalikan, TfLiteStatus
, untuk menentukan apakah proses berhasil. Nilai yang mungkin dari TfLiteStatus
, yang didefinisikan dalam common.h
, adalah kTfLiteOk
dan kTfLiteError
.
Kode berikut menegaskan bahwa nilainya adalah kTfLiteOk
, artinya inferensi berhasil dijalankan.
TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, invoke_status);
13. Dapatkan hasilnya
Tensor keluaran model dapat diperoleh dengan memanggil output(0)
pada tflite::MicroInterpreter
, dengan 0
mewakili tensor keluaran pertama (dan satu-satunya).
Dalam contoh ini, output model adalah nilai floating point tunggal yang terkandung dalam tensor 2D:
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);
Kita dapat membaca nilainya langsung dari tensor keluaran dan menyatakan bahwa itulah yang kita harapkan:
// 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. Jalankan inferensi lagi
Sisa kode menjalankan inferensi beberapa kali lagi. Dalam setiap instance, kita memberikan nilai pada tensor masukan, memanggil interpreter, dan membaca hasil dari tensor keluaran:
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);