Bu belgede bir modelin nasıl eğitileceği ve mikrodenetleyici kullanılarak çıkarımın nasıl çalıştırılacağı açıklanmaktadır.
Merhaba Dünya örneği
Merhaba Dünya örneği, Mikrodenetleyiciler için TensorFlow Lite kullanımının mutlak temellerini göstermek üzere tasarlanmıştır. Bir sinüs fonksiyonunu kopyalayan, yani girişi olarak tek bir sayıyı alan ve sayının sinüs değerini çıkaran bir modeli eğitiyor ve çalıştırıyoruz. Mikrodenetleyiciye dağıtıldığında tahminleri LED'leri yakıp söndürmek veya bir animasyonu kontrol etmek için kullanılır.
Uçtan uca iş akışı aşağıdaki adımları içerir:
- Bir modeli eğitin (Python'da): Bir modeli cihaz üzerinde kullanım için eğitmek, dönüştürmek ve optimize etmek için kullanılan bir python dosyası.
- Çıkarımı çalıştır (C++ 17'de): C++ kitaplığını kullanarak model üzerinde çıkarım çalıştıran uçtan uca birim testi.
Desteklenen bir cihaz edinin
Kullanacağımız örnek uygulama aşağıdaki cihazlarda test edilmiştir:
- Arduino Nano 33 BLE Sense (Arduino IDE kullanarak)
- SparkFun Edge (doğrudan kaynaktan oluşturma)
- STM32F746 Keşif kiti (Mbed kullanılarak)
- Adafruit EdgeBadge (Arduino IDE kullanarak)
- Mikrodenetleyiciler Kiti için Adafruit TensorFlow Lite (Arduino IDE kullanarak)
- Adafruit Circuit Playground Bluefruit (Arduino IDE kullanarak)
- Espressif ESP32-DevKitC (ESP IDF kullanarak)
- Espressif ESP-EYE (ESP IDF kullanarak)
Mikrodenetleyiciler için TensorFlow Lite'ta desteklenen platformlar hakkında daha fazla bilgi edinin.
Bir modeli eğitin
Günah dalgası tanımaya yönelik merhaba dünya modeli eğitimi için train.py'yi kullanın
Çalıştır: 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/
Çıkarımı çalıştır
Modeli cihazınızda çalıştırmak için README.md
dosyasındaki talimatları izleyeceğiz:
Aşağıdaki bölümlerde, Mikrodenetleyiciler için TensorFlow Lite kullanılarak çıkarımın nasıl çalıştırılacağını gösteren evaluate_test.cc
birim testi açıklanmaktadır. Modeli yükler ve birkaç kez çıkarım yapar.
1. Kitaplık başlıklarını ekleyin
Mikrodenetleyiciler için TensorFlow Lite kitaplığını kullanmak için aşağıdaki başlık dosyalarını eklemeliyiz:
#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
yorumlayıcının modeli çalıştırmak için kullandığı işlemleri sağlar. -
micro_error_reporter.h
hata ayıklama bilgilerini verir. -
micro_interpreter.h
modelleri yüklemek ve çalıştırmak için kod içerir. -
schema_generated.h
TensorFlow LiteFlatBuffer
model dosya formatının şemasını içerir. -
version.h
TensorFlow Lite şeması için sürüm oluşturma bilgilerini sağlar.
2. Model başlığını ekleyin
Mikrodenetleyiciler için TensorFlow Lite yorumlayıcısı, modelin bir C++ dizisi olarak sağlanmasını bekler. Model model.h
ve model.cc
dosyalarında tanımlanır. Başlık aşağıdaki satıra eklenmiştir:
#include "tensorflow/lite/micro/examples/hello_world/model.h"
3. Birim testi çerçeve başlığını ekleyin
Birim testi oluşturmak için aşağıdaki satırı ekleyerek Mikrodenetleyiciler için TensorFlow Lite birim test çerçevesini dahil ediyoruz:
#include "tensorflow/lite/micro/testing/micro_test.h"
Test aşağıdaki makrolar kullanılarak tanımlanır:
TF_LITE_MICRO_TESTS_BEGIN
TF_LITE_MICRO_TEST(LoadModelAndPerformInference) {
. // add code here
.
}
TF_LITE_MICRO_TESTS_END
Şimdi yukarıdaki makroda yer alan kodu tartışacağız.
4. Günlüğe kaydetmeyi ayarlayın
Günlüğe kaydetmeyi ayarlamak için, bir tflite::ErrorReporter
örneğine yönelik bir işaretçi kullanılarak bir tflite::MicroErrorReporter
ErrorReporter işaretçisi oluşturulur:
tflite::MicroErrorReporter micro_error_reporter;
tflite::ErrorReporter* error_reporter = µ_error_reporter;
Bu değişken yorumlayıcıya iletilecek ve bu da onun günlük yazmasına olanak tanıyacaktır. Mikrodenetleyiciler genellikle günlük kaydı için çeşitli mekanizmalara sahip olduğundan, tflite::MicroErrorReporter
uygulaması, cihazınıza göre özelleştirilecek şekilde tasarlanmıştır.
5. Bir model yükleyin
Aşağıdaki kodda model, model.h
dosyasında bildirilen g_model
char
dizisindeki veriler kullanılarak başlatılır. Daha sonra şema sürümünün kullandığımız sürümle uyumlu olduğundan emin olmak için modeli kontrol ederiz:
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. İşlem çözümleyicisini somutlaştırın
Bir MicroMutableOpResolver
örneği bildirildi. Bu, yorumlayıcı tarafından model tarafından kullanılan işlemleri kaydetmek ve bunlara erişmek için kullanılacaktır:
using HelloWorldOpResolver = tflite::MicroMutableOpResolver<1>;
TfLiteStatus RegisterOps(HelloWorldOpResolver& op_resolver) {
TF_LITE_ENSURE_STATUS(op_resolver.AddFullyConnected());
return kTfLiteOk;
MicroMutableOpResolver
kaydedilecek işlem sayısını belirten bir şablon parametresine ihtiyaç duyar. RegisterOps
işlevi, işlemleri çözümleyiciye kaydeder.
HelloWorldOpResolver op_resolver;
TF_LITE_ENSURE_STATUS(RegisterOps(op_resolver));
7. Belleği ayırın
Giriş, çıkış ve ara diziler için belirli miktarda belleği önceden ayırmamız gerekir. Bu, tensor_arena_size
boyutunda bir uint8_t
dizisi olarak sağlanır:
const int tensor_arena_size = 2 * 1024;
uint8_t tensor_arena[tensor_arena_size];
Gerekli boyut, kullandığınız modele bağlı olacaktır ve deneylerle belirlenmesi gerekebilir.
8. Tercümanı somutlaştırın
Daha önce oluşturulan değişkenleri ileterek bir tflite::MicroInterpreter
örneği oluşturuyoruz:
tflite::MicroInterpreter interpreter(model, resolver, tensor_arena,
tensor_arena_size, error_reporter);
9. Tensörleri tahsis edin
Yorumlayıcıya tensor_arena
modelin tensörleri için bellek ayırmasını söyleriz:
interpreter.AllocateTensors();
10. Giriş şeklini doğrulayın
MicroInterpreter
örneği .input(0)
öğesini çağırarak bize modelin giriş tensörünü gösteren bir işaretçi sağlayabilir; burada 0
, ilk (ve tek) giriş tensörünü temsil eder:
// Obtain a pointer to the model's input tensor
TfLiteTensor* input = interpreter.input(0);
Daha sonra şeklinin ve türünün beklediğimiz gibi olduğunu doğrulamak için bu tensörü inceliyoruz:
// 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);
kTfLiteFloat32
enum değeri, TensorFlow Lite veri türlerinden birine bir referanstır ve common.h
dosyasında tanımlanır.
11. Bir giriş değeri girin
Modele bir girdi sağlamak için giriş tensörünün içeriğini aşağıdaki gibi ayarlıyoruz:
input->data.f[0] = 0.;
Bu durumda 0
temsil eden bir kayan nokta değeri giriyoruz.
12. Modeli çalıştırın
Modeli çalıştırmak için tflite::MicroInterpreter
örneğimizde Invoke()
öğesini çağırabiliriz:
TfLiteStatus invoke_status = interpreter.Invoke();
if (invoke_status != kTfLiteOk) {
TF_LITE_REPORT_ERROR(error_reporter, "Invoke failed\n");
}
Çalıştırmanın başarılı olup olmadığını belirlemek için dönüş değerini TfLiteStatus
) kontrol edebiliriz. common.h
tanımlanan TfLiteStatus
olası değerleri kTfLiteOk
ve kTfLiteError
.
Aşağıdaki kod, değerin kTfLiteOk
olduğunu ileri sürer; bu, çıkarımın başarıyla çalıştırıldığı anlamına gelir.
TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, invoke_status);
13. Çıktıyı alın
Modelin çıkış tensörü, tflite::MicroInterpreter
üzerinde output(0)
çağrılarak elde edilebilir; burada 0
, ilk (ve tek) çıkış tensörünü temsil eder.
Örnekte, modelin çıktısı bir 2B tensör içinde yer alan tek bir kayan nokta değeridir:
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);
Değeri doğrudan çıkış tensöründen okuyabilir ve beklediğimiz gibi olduğunu iddia edebiliriz:
// 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. Çıkarımı tekrar çalıştırın
Kodun geri kalanı çıkarımı birkaç kez daha çalıştırır. Her durumda, giriş tensörüne bir değer atarız, yorumlayıcıyı çağırırız ve sonucu çıkış tensöründen okuruz:
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);