IoT ve Yapay Zekâ

ML Modellerini Edge Cihazlara Dağıtma: Paketleme, Sürümleme ve MQTT Tabanlı Dağıtımlar

Makine öğrenimi modellerini edge cihaz filolarına göndermek için pratik bir rehber; yeni sürümleri duyurmak ve her cihazdan dağıtım durumunu toplamak için MQTT retained mesajlarını kullanır.

Model sürümlerini duyuran bir MQTT broker ve dağıtım durumunu bildiren cihazlarla ML modellerinin edge cihazlara nasıl dağıtılacağını gösteren diyagram
Bunu kendi MQTT broker’ınızda çalıştırınFree planla özel, yönetilen bir MQTT broker alın ve hazır kod örnekleriyle başlayın.
Ücretsiz deneyin Kod örnekleri Kart gerekmez

Bir modeli eğitmek işin yalnızca yarısıdır: değer yaratmak için ML modellerini edge cihazlara dağıtmanız, güncel tutmanız ve her an hangi cihazın hangi sürümü çalıştırdığını bilmeniz gerekir. Bu rehber, modelleri bir filo genelinde paketlemek, sürümlemek ve dağıtmak için kanıtlanmış bir desen gösteriyor; güncellemeleri bildirmek ve durum toplamak için MQTT kullanılırken model dosyalarının kendisi HTTPS üzerinden taşınıyor.

Edge Model Dağıtımı Neden Zordur

Bir modeli sunucuya göndermek tek bir dağıtımdır. Onu yüzlerce ağ geçidine, kameraya veya mikrodenetleyiciye göndermek ise bir dağıtık sistemler problemidir:

  • Cihazlar rastgele zamanlarda çevrimdışı olur ve yeniden bağlandıklarında eksiklerini tamamlamaları gerekir.
  • Donanımlar farklıdır, bu yüzden tek bir model çıktısı her cihaza uymayabilir.
  • Kötü bir model çökmek yerine tahminleri sessizce bozabilir; bu yüzden "süreç çalışıyor" bilgisinin ötesinde sağlık sinyallerine ihtiyacınız vardır.
  • Bant genişliği ve depolama sınırlıdır ve bazı tesisler yalnızca giden bağlantılara izin veren güvenlik duvarlarının arkasındadır.

MQTT bu kısıtlara iyi uyar. Cihazlar bir broker'a tek bir giden bağlantı tutar, retained mesajlar geç katılanlara en son talimatı anında iletir ve bir Last Will mesajı bir cihazın ne zaman düştüğünü size bildirir. Bu sorumluluk ayrımında yeniyseniz, bir MQTT broker'ın ne yaptığına dair genel bakışımız iyi bir başlangıçtır.

Adım 1: Modeli Sürümlenmiş Bir Çıktı Olarak Paketleyin

Her modeli, üzerine yazılan bir dosya olarak değil, değiştirilemez bir sürüm olarak ele alın. Bir model paketi şunları içermelidir:

Dosya Amaç
model.tflite (veya .onnx, _edgetpu.tflite, .engine) Belirli bir çalışma zamanı için derlenmiş model
labels.txt veya classes.json Doğru sırada çıktı sınıf adları
manifest.json Sürüm, çalışma zamanı, girdi şekli, ön işleme, donanım hedefi, sağlama toplamı
preprocess.json (isteğe bağlı) Normalizasyon sabitleri, yeniden boyutlandırma modu, kanal sırası

Ön işleme uyuşmazlıkları, "model dizüstü bilgisayarımda çalışıyor ama cihazda çalışmıyor" durumunun en sık nedenidir. Beklenen girdi boyutunu, renk sırasını ve normalizasyonu manifest'e kaydetmek ve cihazın bunları yükleme sırasında kontrol etmesini sağlamak, bütün bir sessiz hata sınıfını önler.

Formatı hedefe göre seçin:

Hedef donanım Tipik format Notlar
Mikrodenetleyici (ESP32-S3, Cortex-M) TensorFlow Lite Micro, int8 Genellikle firmware'e derlenir; firmware OTA ile güncellenir
Raspberry Pi / ARM ağ geçidi TFLite veya ONNX Runtime Çalışma zamanında dosya olarak değiştirilebilir
Coral Edge TPU _edgetpu.tflite Edge TPU derleyicisiyle derlenmesi gerekir
NVIDIA Jetson TensorRT engine veya ONNX Engine'ler GPU'ya ve TensorRT sürümüne bağlıdır, bu yüzden cihaz türü başına derleyin

Mikrodenetleyicilerde model çoğu zaman firmware imajının içinde yaşar; dolayısıyla bir model güncellemesi bir firmware güncellemesidir. TensorFlow Lite Micro eğitimimiz bu durumu ele alıyor; bu rehberin geri kalanı modelleri diskten yükleyen Linux sınıfı cihazlara odaklanıyor.

Adım 2: Anlamsal Sürümleyin ve Her Sürümü İmzalayın

Operatörlere bir şey anlatan bir sürüm dizesi kullanın; örneğin defect-classifier 2.3.0, burada ana sürüm numarası girdiler veya çıktılar uyumsuz biçimde değiştiğinde değişir. Sürümün yanında çıktının SHA-256 sağlama toplamını hesaplayın ve manifest'te yayınlayın. Cihazlar, sağlama toplamı eşleşmeyen bir dosyayı reddetmelidir. Daha yüksek güvence için manifest'i CI sisteminizin tuttuğu özel bir anahtarla imzalayın ve cihazlara yalnızca genel anahtarı gönderin.

Çıktıları HTTPS nesne depolamasında veya dahili bir dosya sunucusunda saklayın. MQTT, çok megabaytlık ikili dosyalar için yanlış kanaldır: broker büyük payload'ları bellekte tutmak zorunda kalır ve birçok plan mesaj boyutunu sınırlar. Örneğin ConnectMQ'nun ücretsiz Serverless planı mesajları 256 KB ile sınırlar; bu bir manifest için fazlasıyla yeterlidir, ancak bir görü modeli için yeterli değildir.

Adım 3: Güncellemeleri MQTT Üzerinden Bildirin

Kontrol düzlemi cihaz başına (veya cihaz grubu başına) üç topic kullanır:

fleet/<site>/<device>/model/desired    retained, written by the deployment service
fleet/<site>/<device>/model/reported   retained, written by the device
fleet/<site>/<device>/model/events     not retained, progress and errors

Dağıtım hizmeti, çevrimdışı olan bir cihazın bağlanır bağlanmaz alabilmesi için retained olarak bir istenen durum (desired state) mesajı yayınlar:

{
  "model": "defect-classifier",
  "version": "2.3.0",
  "url": "https://models.example.com/defect-classifier/2.3.0/model.tflite",
  "sha256": "9f2c4c1d5e8b0a7f3d6e1b2c4a5f6e7d8c9b0a1f2e3d4c5b6a7f8e9d0c1b2a3f",
  "runtime": "tflite",
  "rollout": "canary",
  "issuedAt": "2026-10-16T08:00:00Z"
}

Cihaz istenen durumu çalıştırdığıyla karşılaştırır, indirir, doğrular, değiştirir ve geri bildirir:

{
  "model": "defect-classifier",
  "version": "2.3.0",
  "state": "active",
  "previous": "2.2.1",
  "loadedAt": "2026-10-16T08:03:12Z",
  "selfTest": "passed"
}

Bu desired/reported deseni, cihaz gölgelerinde (device shadow) kullanılan fikrin aynısıdır ve standartlarla uyumlu her broker ile çalışır.

Adım 4: Minimal Bir Cihaz Güncelleme Ajanı

Aşağıdaki ajan bir Linux edge cihazda çalışır. İstenen durum topic'ine abone olur, modeli indirir, sağlama toplamını doğrular, bir duman testi (smoke test) çalıştırır, aktif modeli atomik olarak değiştirir ve geri alma için önceki sürümü saklar.

import hashlib
import json
import os
import shutil
import time
import urllib.request
from pathlib import Path

import paho.mqtt.client as mqtt

DEVICE = "gw-07"
BASE = f"connectmq/demo/a91e4d/fleet/plant1/{DEVICE}/model"
MODELS = Path("/opt/models")
ACTIVE = MODELS / "active"           # aktif sürüm dizinine sembolik bağlantı
STATE_FILE = MODELS / "state.json"


def current_version():
    try:
        return json.loads(STATE_FILE.read_text())["version"]
    except (FileNotFoundError, KeyError, json.JSONDecodeError):
        return None


def report(client, state, **extra):
    body = {"model": extra.pop("model", None), "state": state,
            "version": extra.pop("version", current_version()),
            "ts": int(time.time() * 1000), **extra}
    client.publish(f"{BASE}/reported", json.dumps(body), qos=1, retain=True)


def event(client, msg):
    client.publish(f"{BASE}/events", json.dumps({"msg": msg, "ts": int(time.time() * 1000)}), qos=0)


def sha256_of(path):
    h = hashlib.sha256()
    with open(path, "rb") as f:
        for chunk in iter(lambda: f.read(1 << 20), b""):
            h.update(chunk)
    return h.hexdigest()


def smoke_test(model_path):
    # Modeli yükleyin ve saklanan bir örnek girdi üzerinde bir çıkarım çalıştırın.
    # Kendi çalışma zamanınızla değiştirin, örn. tflite_runtime.interpreter.Interpreter.
    return model_path.stat().st_size > 0


def apply_update(client, desired):
    version = desired["version"]
    if version == current_version():
        report(client, "active", model=desired["model"], version=version)
        return
    target = MODELS / version
    target.mkdir(parents=True, exist_ok=True)
    tmp = target / "model.tmp"
    event(client, f"downloading {version}")
    urllib.request.urlretrieve(desired["url"], tmp)
    if sha256_of(tmp) != desired["sha256"]:
        tmp.unlink(missing_ok=True)
        report(client, "failed", model=desired["model"], reason="checksum mismatch")
        return
    final = target / "model.tflite"
    tmp.replace(final)
    if not smoke_test(final):
        report(client, "failed", model=desired["model"], reason="smoke test failed")
        return
    previous = current_version()
    link_tmp = MODELS / "active.tmp"
    if link_tmp.exists() or link_tmp.is_symlink():
        link_tmp.unlink()
    link_tmp.symlink_to(target)
    os.replace(link_tmp, ACTIVE)  # sembolik bağlantının atomik değişimi
    STATE_FILE.write_text(json.dumps({"version": version, "previous": previous}))
    report(client, "active", model=desired["model"], version=version, previous=previous)
    # Diskte yalnızca mevcut ve önceki sürümleri tut
    for d in MODELS.iterdir():
        if d.is_dir() and not d.is_symlink() and d.name not in (version, previous):
            shutil.rmtree(d, ignore_errors=True)


def on_connect(client, userdata, flags, reason_code, properties):
    client.subscribe(f"{BASE}/desired", qos=1)
    report(client, "online")


def on_message(client, userdata, msg):
    try:
        apply_update(client, json.loads(msg.payload))
    except Exception as exc:  # sessizce ölmek yerine her hatayı bildir
        report(client, "failed", reason=str(exc))


MODELS.mkdir(parents=True, exist_ok=True)
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=f"{DEVICE}-a91e4d")
client.on_connect = on_connect
client.on_message = on_message
client.will_set(f"{BASE}/reported", json.dumps({"state": "offline"}), qos=1, retain=True)
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_forever()

İndirmenin mesaj callback'i içinde çalıştığına ve bunun ağ döngüsünü bloke ettiğine dikkat edin. Bu, küçük modeller ve bir test kurulumu için kabul edilebilir; üretimde ise uzun indirmeler sırasında keepalive'ların sürmesi için işi bir çalışan iş parçacığına (worker thread) devredin. Çıkarım süreciniz modeli active sembolik bağlantısı üzerinden açmalı ve bağlantı değiştiğinde, örneğin durum dosyasını izleyerek, yeniden yüklemelidir.

Test sırasında bir dağıtımı tetiklemek için retained bir istenen durum mesajı yayınlayın:

mosquitto_pub -h broker.connectmq.com -p 1883 -i deployer-a91e4d -r -q 1 \
  -t "connectmq/demo/a91e4d/fleet/plant1/gw-07/model/desired" \
  -f desired.json

Herkese açık MQTT test broker'ı akışı denemek için uygundur, ancak herkes tarafından okunabildiğini unutmayın; bu yüzden oraya asla gerçek model URL'leri veya imzalı token'lar koymayın.

Adım 5: Aşamalar Halinde Dağıtın

Yeni bir modeli asla bütün filoya aynı anda göndermeyin. Aşamalı bir dağıtım şöyle görünür:

  1. Gölge modu. Yeni model birkaç cihazda eskisinin yanında çalışır ve her iki çıktı da yayınlanır, ancak eylemleri yalnızca eskisi yönlendirir. Bunları çevrimdışı olarak karşılaştırın.
  2. Kanarya. İstenen durumu küçük bir cihaz grubuna yayınlayın. Bildirilen durumlarını, çıkarım gecikmesini ve tahmin dağılımını izleyin.
  3. Kademeli dalgalar. Dalgalar arasında duraklayarak daha büyük gruplara genişletin. Bir dağıtım betiği yalnızca bir sonraki cihaz grubu için istenen durum topic'ine yazar.
  4. Tam dağıtım. Son dalga sağlıklı olduğunda, yeni sürümü yeni kurulan cihazlar için varsayılan yapın.
  5. Geri alma. Metrikler kötüleşirse önceki sürümü istenen durum olarak yayınlayın. Cihaz son sürümü diskte tuttuğu için geri alma bir indirme bile gerektirmez.

Grup üyeliği dağıtım hizmetinizde tutulabilir veya topic'lerde kodlanabilir; örneğin fleet/plant1/canary/model/desired, kanarya grubundaki bir cihazın kendi topic'ine ek olarak abone olduğu bir topic'tir.

Her Cihazın Ne Çalıştırdığını İzlemek

Her cihaz retained bir reported mesajı yayınladığı için, fleet/+/+/model/reported üzerine tek bir wildcard abonelik bağlandığı anda eksiksiz bir filo envanteri sağlar. Kaymayı izlemek için bunu tahmin telemetrisiyle birleştirin: bir güncellemeden sonra sınıf dağılımı veya güven skorları keskin biçimde değişirse, model büyük olasılıkla eğitilmediği girdiler görüyordur. IoT MLOps yazımız izleme ve yeniden eğitim döngülerini daha derinlemesine ele alıyor.

Üretim Kontrol Listesi

  1. Çıktılar değiştirilemez, sürümlenmiş ve HTTPS üzerinde saklanıyor.
  2. Her manifest bir SHA-256 sağlama toplamı ve ideal olarak bir imza taşıyor.
  3. Cihazlar doğruluyor, duman testi yapıyor ve atomik olarak değiştiriyor; bir önceki sürümü saklıyor.
  4. İstenen ve bildirilen durum, çevrimdışı tespiti için Last Will ile retained MQTT topic'lerinde tutuluyor.
  5. Dağıtımlar gölge, kanarya, dalgalar, tam sırasıyla ilerliyor ve tek mesajla geri alınabiliyor.
  6. Broker'lar 8883 portunda TLS ve cihaz başına kimlik bilgileri kullanıyor.

Üretim filoları için barındırılan bir MQTT broker sertifikaları, ölçeklendirmeyi ve kimlik doğrulamayı üstlenir; böylece ekibiniz modellere odaklanabilir. ConnectMQ ile her cihaz, client ID'si kendisine bağlı kimlik bilgileri alır ve portaldaki canlı topic gezgini, bir dağıtım ilerledikçe istenen ve bildirilen mesajları gösterir. Modelleri ve bağlantılı cihazları birleştirmenin daha geniş bağlamı için eksiksiz yapay zeka ve IoT rehberimize bakın.

ConnectMQ ile Başlayın

ConnectMQ, TCP, TLS ve WebSocket üzerinden MQTT 3.1.1 ve 5.0'ı destekleyen ve model güncelleme sinyallerinizi taşımaya hazır, yönetilen bir MQTT broker'dır. Kredi kartı gerektirmeden ücretsiz Serverless planına kaydolun ve ilk dağıtımınızı bugün kurun.

Sık Sorulan Sorular

Model dosyasının kendisini MQTT üzerinden gönderebilir miyim?

Küçük dosyaları parçalara bölebilirsiniz, ancak bu nadiren buna değer. Güncelleme sinyali ve durum için MQTT'yi kullanın, çıktıyı ise devam ettirilebilir indirmelerin ve önbelleğe almanın standart olduğu HTTPS üzerinden indirin.

Çevrimdışı olan bir cihaz güncellemeyi nasıl alır?

İstenen durum mesajı retained olduğundan, cihaz yeniden bağlanıp abone olduğunda broker onu hemen iletir. Cihaz ardından sürümleri karşılaştırır ve gerekirse günceller.

Kötü bir modeli nasıl geri alırım?

Önceki sürümü istenen durum olarak yayınlayın. Son sürümünü diskte tutan bir cihaz, hiçbir şey indirmeden anında geri dönebilir.

Mikrodenetleyiciler de aynı yaklaşımı kullanır mı?

Sinyalleşme aynıdır, ancak model genellikle firmware'e derlendiğinden cihaz bir model dosyasını değiştirmek yerine bir firmware OTA güncellemesi yapar.

İlgili yazılar

Tüm yazılar →

Özel MQTT broker’ınız birkaç tık uzağınızda

Hesabınızı oluşturun, broker kimlik bilgilerinizi alın ve ilk cihazınızı bağlayın — kurulacak, yamalanacak ya da ölçeklendirilecek sunucu yok.