Bu belgede, model eğitme ve mikrodenetleyici kullanarak çıkarım yapma açıklanmaktadır.
Hello World örneği
Hello World örneği, Mikrodenetleyiciler için TensorFlow Lite kullanımının mutlak temellerini göstermek için tasarlanmıştır. Bir sinüs işlevini çoğaltan (yani, girdi olarak tek bir sayı alan ve sayının sinüs değerini veren bir model eğitip çalıştırırız). Mikrodenetleyiciye dağıtıldığında, tahminleri LED'leri yanı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:
- Model eğitme (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ıdır.
- Çıkarım çalıştırma (C++ 17'de): C++ kitaplığını kullanarak model üzerinde çıkarım yapan bir 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 derleme)
- STM32F746 Discovery kiti (Mbed kullanılarak)
- Adafruit EdgeBadge (Arduino IDE kullanarak)
- Mikrodenetleyiciler için Adafruit TensorFlow Lite Seti (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.
Model eğitin
Sinwave tanıma amacıyla hello world modeli eğitimi için train.py uygulamasını kullanın
Çalıştırma: 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
'deki talimatları uygulayacağız:
Aşağıdaki bölümlerde, örneğin evaluate_test.cc
birim testi adım adım açıklamalıdır. Bu test, Mikrodenetleyiciler için TensorFlow Lite'ı kullanarak nasıl çıkarım yapılacağını gösterir. Modeli yükler ve birkaç kez çıkarım yapar.
1. Kitaplık başlıklarını dahil et
Mikrodenetleyiciler için TensorFlow Lite kitaplığını kullanmak için aşağıdaki başlık dosyalarını eklememiz gerekir:
#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
, modeli çalıştırmak için yorumlayıcı tarafından kullanılan işlemleri sağlar.micro_error_reporter.h
hata ayıklama bilgilerini çıkarır.micro_interpreter.h
, modelleri yüklemek ve çalıştırmak için kod içerir.schema_generated.h
, TensorFlow LiteFlatBuffer
model dosya biçimi için şemayı içerir.version.h
, TensorFlow Lite şeması için sürüm oluşturma bilgileri 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ımlı.
Üstbilgi, aşağıdaki satıra eklenir:
#include "tensorflow/lite/micro/examples/hello_world/model.h"
3. Birim test çerçevesi başlığını dahil etme
Birim testi oluşturmak için aşağıdaki satırı ekleyerek Mikrodenetleyiciler için TensorFlow Lite birim test çerçevesini ekliyoruz:
#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 ele alacağız.
4. Günlük kaydını ayarlama
Günlük kaydını ayarlamak amacıyla, tflite::MicroErrorReporter
örneğine işaret eden bir tflite::ErrorReporter
işaretçisi oluşturulur:
tflite::MicroErrorReporter micro_error_reporter;
tflite::ErrorReporter* error_reporter = µ_error_reporter;
Bu değişken, günlük yazmasına olanak tanıyan yorumlayıcıya iletilir. Mikrodenetleyiciler genellikle günlük kaydı için çeşitli mekanizmalara sahip olduğundan tflite::MicroErrorReporter
uygulaması, cihazınıza özel olacak şekilde tasarlanmıştır.
5. Model yükle
Aşağıdaki kodda model, model.h
içinde tanımlanan char
dizisindeki (g_model
) veriler kullanılarak örneklenir. 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. Örnek işlem çözümleyicisi
Bir MicroMutableOpResolver
örneği bildirildi. Çevirmen, modelin kullandığı işlemleri kaydedip bunlara erişmek için bu değeri kullanı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 parametresi gerektirir. RegisterOps
işlevi, işlemleri çözümleyiciye kaydeder.
HelloWorldOpResolver op_resolver;
TF_LITE_ENSURE_STATUS(RegisterOps(op_resolver));
7. Bellek tahsis et
Giriş, çıkış ve ara diziler için belirli bir miktarda belleği önceden ayırmamız gerekir. Bu değer, tensor_arena_size
boyutunda uint8_t
dizisi olarak sağlanır:
const int tensor_arena_size = 2 * 1024;
uint8_t tensor_arena[tensor_arena_size];
Gereken boyut, kullandığınız modele bağlıdır ve denemelerle belirlenmesi gerekebilir.
8. Çevirmeni örneklendirme
Daha önce oluşturulan değişkenleri ileterek bir tflite::MicroInterpreter
örneği oluştururuz:
tflite::MicroInterpreter interpreter(model, resolver, tensor_arena,
tensor_arena_size, error_reporter);
9. Tensör ayır
Çevirmene, modelin tensörleri için tensor_arena
öğesinden bellek ayırmasını söyleriz:
interpreter.AllocateTensors();
10. Giriş şeklini doğrulama
MicroInterpreter
örneği, .input(0)
yöntemini çağırarak bize modelin giriş tensörüne 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ü inceleriz:
// 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
sıralama değeri, TensorFlow Lite veri türlerinden birine referanstır ve common.h
içinde tanımlanır.
11. Giriş değeri girin
Modele giriş sağlamak için giriş tensörünün içeriğini aşağıdaki gibi ayarlarız:
input->data.f[0] = 0.;
Bu örnekte, 0
değerini temsil eden bir kayan nokta değeri giriyoruz.
12. Modeli çalıştırma
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öndürülen değeri (TfLiteStatus
) kontrol edebiliriz. common.h
içinde tanımlanan olası TfLiteStatus
değerleri kTfLiteOk
ve kTfLiteError
'dir.
Aşağıdaki kod, değerin kTfLiteOk
olduğunu, yani çıkarımın başarıyla çalıştırıldığını iddia eder.
TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, invoke_status);
13. Çıkışı alma
Modelin çıkış tensörü, tflite::MicroInterpreter
üzerinde output(0)
çağrısı yapılarak elde edilebilir. Burada 0
, ilk (ve tek) çıkış tensörünü temsil eder.
Bu örnekte, modelin çıkışı, 2D tensör içinde bulunan 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 bunun beklediğimiz 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
Kodun geri kalanı, birkaç kez daha çıkarım yapar. Her örnekte giriş tensörüne bir değer atar, yorumlayıcıyı çağırır 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);