Mikrodenetleyicileri kullanmaya başlayın

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:

  1. 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ı.
  2. Çı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:

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:

Merhaba Dünya README.md

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"

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 = &micro_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);