TensorFlow Lite Micro, TinyML projelerinin çoğunun mikrodenetleyicilerde sinir ağı çalıştırmak için kullandığı çalışma zamanıdır ve dört nesneyi anladığınızda API'si oldukça küçüktür: model, op resolver, tensör arenası ve yorumlayıcı (interpreter). Bu başlangıç rehberi her birini açıklıyor, bir ESP32-S3 kartında eksiksiz bir örneği adım adım anlatıyor ve tahminlerin bir MQTT broker'a, doğrudan Wi-Fi üzerinden ya da ağ bağlantısı olmayan kartlar için bir seri köprü aracılığıyla nasıl gönderileceğini gösteriyor.
TensorFlow Lite Micro Nedir
TensorFlow Lite for Microcontrollers (genellikle TFLM olarak kısaltılır ve artık Google'ın LiteRT ailesinin bir parçasıdır), işletim sistemi olmayan, çıkarım sırasında dinamik bellek ayırma yapmayan ve çok az RAM'e sahip cihazlar için tasarlanmış bir C++ çıkarım motorudur. Telefonlardaki TensorFlow Lite ile aynı .tflite flatbuffer formatını okur, ancak daha küçük bir operatör kümesini destekler ve doğrudan firmware'inize derlenmek üzere tasarlanmıştır.
TFLM yalnızca çıkarım yapar. Eğitim bir bilgisayarda TensorFlow ile gerçekleşir; mikrodenetleyici dönüştürülmüş, genellikle int8 nicemlenmiş bir model alır. Bu kadar küçük çiplerde neden ML çalıştırıldığına dair büyük resmi görmek istiyorsanız TinyML nedir yazısına bakın.
Dört Temel Kavram
| Nesne | Nedir | Ne ters gider |
|---|---|---|
tflite::Model |
Flash'a bayt dizisi olarak gömülmüş flatbuffer | Kütüphaneyle şema sürümü uyuşmazlığı |
MicroMutableOpResolver<N> |
Firmware'e bağlanan operatör çekirdeklerinin listesi | Çalışma zamanında eksik op; şablon N çok küçük |
| Tensör arenası | Girdiler, çıktılar ve ara tensörler için statik bir bayt tamponu | Çok küçük olduğunda AllocateTensors() başarısız olur |
MicroInterpreter |
Modeli, resolver'ı ve arenayı birbirine bağlar ve Invoke() çalıştırır |
Model int8 beklerken girdinin float olarak yazılması |
Tipik bir program başlangıçta bir kez şunları yapar: modeli eşler, kullandığı op'ları kaydeder, yorumlayıcıyı oluşturur, tensörleri ayırır. Ardından her çıkarım için: girdi tensörünü yazar, Invoke() çağırır, çıktı tensörünü okur. Çoğu proje için ihtiyaç duyacağınız çalışma zamanı API'sinin tamamı budur.
Adım 1: Bir Model Eğitin ve Dönüştürün
Klasik ilk TFLM modeli sin(x) fonksiyonunu öğrenir. Küçüktür, gözle doğrulanması kolaydır ve nicemlenmiş girdi ile çıktıyı test eder. Bu betik onu eğitir, tam int8'e dönüştürür ve firmware için C++ kaynak dosyalarını yazar.
pip install tensorflow numpy
# train_sine.py
import numpy as np
import tensorflow as tf
rng = np.random.default_rng(1)
x = rng.uniform(0, 2 * np.pi, 3000).astype(np.float32)
y = (np.sin(x) + 0.05 * rng.standard_normal(x.size)).astype(np.float32)
model = tf.keras.Sequential([
tf.keras.Input(shape=(1,)),
tf.keras.layers.Dense(16, activation="relu"),
tf.keras.layers.Dense(16, activation="relu"),
tf.keras.layers.Dense(1),
])
model.compile(optimizer="adam", loss="mse")
model.fit(x, y, epochs=200, batch_size=64, validation_split=0.2, verbose=0)
print("val mse:", model.evaluate(x[:500], y[:500], verbose=0))
def rep():
for v in np.linspace(0, 2 * np.pi, 300, dtype=np.float32):
yield [np.array([[v]], dtype=np.float32)]
conv = tf.lite.TFLiteConverter.from_keras_model(model)
conv.optimizations = [tf.lite.Optimize.DEFAULT]
conv.representative_dataset = rep
conv.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
conv.inference_input_type = tf.int8
conv.inference_output_type = tf.int8
tfl = conv.convert()
print("model bytes:", len(tfl))
with open("tflm_sine/main/model_data.cc", "w") as f:
f.write('#include "model_data.h"\n')
f.write("alignas(16) const unsigned char g_model[] = {%s};\n" % ", ".join(f"0x{b:02x}" for b in tfl))
f.write(f"const unsigned int g_model_len = {len(tfl)};\n")
with open("tflm_sine/main/model_data.h", "w") as f:
f.write("#pragma once\nextern const unsigned char g_model[];\nextern const unsigned int g_model_len;\n")
Firmware yazmadan önce dönüştürülmüş modeldeki operatörleri inceleyin. .tflite dosyasını Netron gibi bir model görüntüleyicide açmak veya tf.lite.experimental.Analyzer.analyze(model_content=tfl) kullanmak, bu modelin yalnızca FULLY_CONNECTED operatörleri içerdiğini gösterir. Bu liste, resolver'a kaydedeceğiniz şeyin ta kendisidir.
TensorFlow Lite Micro İçin Neden Nicemleme Yapılır
Mikrodenetleyiciler tam sayı aritmetiğinde kayan noktaya göre çok daha hızlıdır ve birçoğunda hiç kayan nokta birimi yoktur. Tam int8 nicemleme her ağırlığı dört bayt yerine bir baytta saklar ve her katmanı tam sayı çekirdekleriyle çalıştırır; bu da flash kullanımını ve tensör arenasını küçültür ve CMSIS-NN ya da Espressif'in çekirdekleri gibi optimize edilmiş kütüphanelerin işini yapmasına olanak tanır. Bedeli küçük bir hassasiyet kaybı ve girdi ile çıktıları her tensörün scale ve zero_point değerleriyle dönüştürme gibi ek bir adımdır; aşağıdaki firmware bunu açıkça yapar.
Flash ve RAM: Model Nerede Yaşar
Model dizisi const olarak bildirilir; böylece bağlayıcı (linker) onu flash'a yerleştirir ve RAM maliyeti olmaz. RAM maliyeti tensör arenasıdır: girdiler, çıktılar, ara aktivasyonlar ve yorumlayıcının bir miktar kayıt tutma verisi. ESP32 ailesinde hızlı seçenek dahili RAM'dir; çok büyük arenalar, PSRAM'e sahip kartlarda biraz hız kaybıyla PSRAM'e yerleştirilebilir. Bu sinüs modeli için arena, aşağıda ayrılan 4 KB'ın epey altında yer gerektirir; bunu firmware'in yazdırdığı günlük satırından doğrulayabilirsiniz.
Adım 2: Kart Projesini Kurun
Bu rehber, Arduino IDE'den de programlanabilen bir ESP32-S3 geliştirme kartı kullanır, ancak derlemeyi ESP-IDF ile yapar; çünkü Espressif'in esp-tflite-micro bileşeni upstream TFLM API'sini takip eder ve optimize edilmiş çekirdekler ekler. Diğer kartlarda bir sonraki adımdaki C++ kodu aynı kalır; yalnızca derleme sistemi değişir.
tflm_sine/
CMakeLists.txt
main/
CMakeLists.txt
main.cc
model_data.cc (generated)
model_data.h (generated)
# tflm_sine/CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(tflm_sine)
# tflm_sine/main/CMakeLists.txt
idf_component_register(SRCS "main.cc" "model_data.cc" INCLUDE_DIRS ".")
cd tflm_sine
idf.py set-target esp32s3
idf.py add-dependency "espressif/esp-tflite-micro"
Adım 3: TensorFlow Lite Micro ile Çıkarım Çalıştırın
Firmware x değerini 0'dan 2π'ye kadar ilerletir, her değeri girdi tensörünün ölçeği ve sıfır noktasıyla nicemler, modeli çalıştırır ve seri konsolda her tahmin için bir JSON satırı yazdırır.
// tflm_sine/main/main.cc
#include <algorithm>
#include <cmath>
#include <cstdio>
#include "esp_log.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "model_data.h"
static const char *TAG = "tflm";
static constexpr int kArenaSize = 4 * 1024;
alignas(16) static uint8_t tensor_arena[kArenaSize];
extern "C" void app_main(void) {
// 1. Modeli eşle
const tflite::Model *model = tflite::GetModel(g_model);
if (model->version() != TFLITE_SCHEMA_VERSION) {
ESP_LOGE(TAG, "model schema %lu != runtime %d", (unsigned long)model->version(), TFLITE_SCHEMA_VERSION);
return;
}
// 2. Yalnızca modelin kullandığı operatörleri kaydet
static tflite::MicroMutableOpResolver<3> resolver;
resolver.AddFullyConnected();
resolver.AddQuantize();
resolver.AddDequantize();
// 3. Yorumlayıcıyı statik bir arena üzerinde oluştur ve tensörleri ayır
static tflite::MicroInterpreter interpreter(model, resolver, tensor_arena, kArenaSize);
if (interpreter.AllocateTensors() != kTfLiteOk) {
ESP_LOGE(TAG, "AllocateTensors failed, increase kArenaSize");
return;
}
ESP_LOGI(TAG, "arena used %u of %d bytes", (unsigned)interpreter.arena_used_bytes(), kArenaSize);
TfLiteTensor *input = interpreter.input(0);
TfLiteTensor *output = interpreter.output(0);
const float two_pi = 2.0f * (float)M_PI;
int step = 0;
while (true) {
float x = two_pi * (step % 40) / 40.0f;
// 4. Girdiyi nicemle: q = x / scale + zero_point
int q = (int)lroundf(x / input->params.scale) + input->params.zero_point;
input->data.int8[0] = (int8_t)std::min(127, std::max(-128, q));
int64_t t0 = esp_timer_get_time();
if (interpreter.Invoke() != kTfLiteOk) {
ESP_LOGE(TAG, "Invoke failed");
break;
}
int us = (int)(esp_timer_get_time() - t0);
// 5. Çıktının nicemlemesini geri al: y = (q - zero_point) * scale
float y = (output->data.int8[0] - output->params.zero_point) * output->params.scale;
printf("{\"x\":%.3f,\"y\":%.3f,\"ref\":%.3f,\"us\":%d}\n", x, y, sinf(x), us);
step++;
vTaskDelay(pdMS_TO_TICKS(500));
}
}
python train_sine.py
cd tflm_sine
idf.py build flash monitor
Monitör {"x":1.571,"y":0.98,"ref":1.000,"us":...} gibi satırlar gösterir. Tahmin edilen y, nicemlemeden kaynaklanan küçük hatalarla ref değerini yakından takip etmelidir. Her çıktı aynı değerse, girdi neredeyse kesinlikle nicemlenmeden yazılıyordur.
Adım 4: Tahminleri MQTT Üzerinden Gönderin
Bu tahminleri bir broker'a ulaştırmanın iki yolu vardır.
Doğrudan Wi-Fi üzerinden. ESP32-S3 gibi Wi-Fi'li kartlarda ESP-IDF MQTT istemcisini ekleyin ve her JSON satırını yazdırmak yerine yayınlayın. ESP32 üzerinde TinyML eğitimi, Last Will ve değişiklikte yayın mantığı dahil olmak üzere tam olarak bunu yapan eksiksiz bir firmware içeriyor.
Seri köprü. Dahili sensörlere sahip Cortex-M kartları gibi birçok popüler TFLM kartında Wi-Fi yoktur. Bu kartlar JSON'u USB seri port üzerinden yazdırabilir ve bir bilgisayar veya Raspberry Pi onu iletir. Bu köprü, yukarıdaki firmware ile hiçbir değişiklik yapılmadan çalışır:
pip install pyserial "paho-mqtt>=2.0"
# serial_to_mqtt.py kullanım: python serial_to_mqtt.py COM5 (veya /dev/ttyACM0)
import json
import sys
import uuid
import paho.mqtt.client as mqtt
import serial
port = sys.argv[1]
run = uuid.uuid4().hex[:8]
topic = f"connectmq/demo/{run}/lab/tflm-board/inference"
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=f"tflm-bridge-{run}")
client.will_set(f"connectmq/demo/{run}/lab/tflm-board/status", "offline", qos=1, retain=True)
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_start()
client.publish(f"connectmq/demo/{run}/lab/tflm-board/status", "online", qos=1, retain=True)
print("publishing to", topic)
with serial.Serial(port, 115200, timeout=2) as ser:
while True:
line = ser.readline().decode("utf-8", errors="ignore").strip()
if not line.startswith("{"):
continue # açılış ve günlük satırlarını atla
try:
json.loads(line) # yalnızca geçerli JSON'u ilet
except json.JSONDecodeError:
continue
client.publish(topic, line, qos=0)
print(line)
Seri portu yalnızca tek bir program tutabildiğinden önce idf.py monitor oturumunu kapatın. Ardından akışı herhangi bir makineden izleyin:
mosquitto_sub -h broker.connectmq.com -p 1883 -i tflm-viewer-12 -t 'connectmq/demo/+/lab/tflm-board/#' -v
Herkese açık alanı herkesin okuyabildiğini unutmadığınız sürece ücretsiz herkese açık MQTT broker bunun için uygundur. Üretim cihazları özel kimlik bilgileri ve 8883 portunda TLS kullanmalıdır; köprüde bu, ConnectMQ broker'ınızdaki değerlerle client.tls_set() ve client.username_pw_set() çağırmak ve verilen client ID'yi kullanmak anlamına gelir.
Köprü deseninin faydalı bir yan etkisi vardır: kart firmware'i ağ kodundan, sertifikalardan ve kimlik bilgilerinden arınmış kalır; böylece hiçbir şeye yeniden yazılım yüklemeden ağ geçidinde broker değiştirebilir, TLS ekleyebilir veya topic'leri değiştirebilirsiniz. Bedeli, çalışır tutulması gereken bir cihazın daha olmasıdır. Tek bir bilgisayara bağlı birkaç laboratuvar kartı için idealdir; sahadaki bir filo içinse doğrudan yayın yapan yerleşik Wi-Fi'li kartları işletmek genellikle daha basittir.
Neyin Yayınlanacağını Seçmek
Bunun gibi bir regresyon modeli her çağrıda bir değer üretir, ancak çoğu gerçek uygulama olaylarla ilgilenir: bir değerin bir sınırı aşması, bir sınıfın değişmesi veya bir güven değerinin düşmesi. Neyin olay sayılacağına cihazda veya köprüde karar verin ve bunları, artı yavaş bir kalp atışını yayınlayın. Bu, trafiği istemci başına hız sınırlarının epey içinde tutar ve sonraki tüketicileri basitleştirir.
TensorFlow Lite Micro Sorun Giderme
Didn't find op for builtin opcode: eksik operatörü kaydedin ve resolver'ın şablon sayısını artırın.AllocateTensors()başarısız oluyor: arenayı büyütün, çalıştıktan sonraarena_used_bytes()artı biraz paya kadar küçültün.Invoke()içinde hard fault veya çökme: model dizisi hizalanmamış ya da arena başka bir bellekle çakışıyor. Her ikisinde dealignas(16)kullanmaya devam edin.- Doğruluk PC'dekinden çok daha kötü: temsili veri kümesi gerçek girdi aralığını kapsamadığı için nicemleme değerleri kırptı.
representative_datasetiçinde gerçek örnekler kullanın. MicroErrorReporterveyaAllOpsResolverile ilgili derleme hataları: eski örnek kodu daha yeni bir TFLM sürümüyle karıştırıyorsunuz. Güncel sürümler yukarıda gösterilen yapıcıyı veMicroMutableOpResolverkullanır.
Sonra Nereye
Sinüs modelini, ESP32 üzerinde TinyML yazısındaki gibi gerçek sensör öznitelikleriyle beslenen bir sınıflandırıcıyla değiştirin veya Edge Impulse MQTT eğitimi ile işlem hattını bir platformun sizin için oluşturmasına izin verin. Resmi TensorFlow Lite Micro deposu, desteklenen operatörleri ve yeni kartlara taşımayı belgeliyor. Mimari bağlam için yapay zeka ve IoT rehberi, mikrodenetleyici modellerinin bulut analitiğiyle birlikte nasıl konumlandığını ele alıyor.
ConnectMQ ile Başlayın
Tahminler kartınızdan ister Wi-Fi ister bir köprü üzerinden çıksın, güvenilir bir hedefe ihtiyaç duyar. ConnectMQ, TLS, MQTT 3.1.1 ve 5.0 ile mesajları geldikçe kontrol etmek için tarayıcı içi bir MQTT istemcisi sunan tam yönetilen bir MQTT hizmetidir. app.connectmq.com adresinde ücretsiz Serverless planında kredi kartı gerektirmeden bir broker oluşturun.
Sık Sorulan Sorular
TensorFlow Lite ile TensorFlow Lite Micro arasındaki fark nedir?
TensorFlow Lite, işletim sistemi ve dinamik belleği olan telefonları ve Linux cihazlarını hedefler. TensorFlow Lite Micro ise statik bir arena, azaltılmış bir operatör kümesi kullanan ve işletim sistemi bağımlılığı olmayan, mikrodenetleyiciler için sadeleştirilmiş bir çalışma zamanıdır.
Tensör arenası boyutunu nasıl seçerim?
Cömert bir boyutla başlayın, AllocateTensors() çağırın, ardından arena_used_bytes() değerini okuyun ve arenayı bu değer artı bir güvenlik payına ayarlayın. Gereksinim, modelin en büyük ara tensörlerine bağlıdır.
TensorFlow Lite Micro float modelleri destekler mi?
Evet, birçok operatörün float çekirdekleri vardır, ancak int8 modeller çoğu mikrodenetleyicide daha küçük ve çok daha hızlıdır. Üretim için olağan seçim tam tam sayı nicemlemedir.
TensorFlow Lite Micro verileri kendisi MQTT üzerinden gönderebilir mi?
Hayır. TFLM yalnızca çıkarım yapar. Sonuçları ESP-IDF MQTT istemcisi, PubSubClient veya bir ağ geçidindeki seri köprü gibi ayrı bir MQTT istemcisiyle yayınlarsınız.



