Sdílet prostřednictvím


Povolení odvození strojového učení na zařízení Azure IoT Edge

Azure IoT Edge
Azure IoT Hub

AI na hraničních zařízeních je jedním z nejoblíbenějších hraničních scénářů. Implementace tohoto scénáře zahrnují klasifikaci obrázků, detekci objektů, tělo, tvář a analýzu gest a manipulaci s obrázky. Tato příručka k architektuře popisuje, jak používat Azure IoT Edge k podpoře těchto scénářů.

Přesnost AI můžete zlepšit aktualizací modelu AI, ale v některých scénářích není síťové prostředí hraničního zařízení dobré. Například v odvětví větrné energie a ropy mohou být zařízení umístěna v poušti nebo oceánu.

Dvojčata modulů IoT Edge se používají k implementaci dynamicky načteného modelu AI. Moduly IoT Edge jsou založené na Dockeru. Image modulu IoT Edge v prostředí AI má obvykle velikost nejméně 1 GB, takže přírůstková aktualizace modelu AI je důležitá v síti s úzkou šířkou pásma. Tento článek je hlavním cílem tohoto článku. Cílem je vytvořit modul IoT Edge AI, který může načíst modely detekce objektů LiteRT (dříve TensorFlow Lite) nebo Open Neural Network Exchange (ONNX). Modul můžete také povolit jako webové rozhraní API, abyste ho mohli použít k výhodě jiných aplikací nebo modulů.

Řešení popsané v tomto článku vám může pomoct těmito způsoby:

  • Povolte odvození AI na hraničních zařízeních.
  • Minimalizujte náklady na síť při nasazování a aktualizaci modelů AI na hraničních zařízeních. Řešení vám nebo vašim zákazníkům může ušetřit peníze, zejména v prostředí sítě s úzkou šířkou pásma.
  • Vytvořte a spravujte úložiště modelu AI v místním úložišti zařízení IoT Edge.
  • Téměř nulový výpadek dosáhnete, když hraniční zařízení přepne modely AI.

TensorFlow a LiteRT jsou ochrannou známkou společnosti Google Inc. Použití této značky nevyžaduje žádné doporučení.

Architektura

Diagram znázorňující architekturu podporující odvození strojového učení

Stáhněte si soubor aplikace Visio s touto architekturou.

Tok dat

  1. Model AI se nahraje do služby Azure Blob Storage nebo webové služby. Modelem může být předem natrénovaný model LiteRT nebo ONNX nebo model vytvořený ve službě Azure Machine Learning. Modul IoT Edge má přístup k tomuto modelu a později ho stáhnout do hraničního zařízení. Pokud potřebujete lepší zabezpečení, zvažte použití připojení privátních koncových bodů mezi službou Blob Storage a hraničním zařízením.
  2. Azure IoT Hub automaticky synchronizuje dvojčata modulů zařízení s informacemi o modelu AI. K synchronizaci dochází i v případě, že je IoT Edge offline. (V některých případech jsou zařízení IoT připojená k sítím v naplánovaných hodinách, denně nebo týdně, aby se ušetřila energie nebo snížil síťový provoz.)
  3. Modul zavaděče monitoruje aktualizace dvojčat modulů prostřednictvím rozhraní API. Když zjistí aktualizaci, získá token SAS modelu strojového učení a pak stáhne model AI.
    • Další informace najdete v tématu Vytvoření tokenu SAS pro kontejner nebo objekt blob.
    • Pomocí vlastnosti ExpiresOn můžete nastavit datum vypršení platnosti prostředků. Pokud se očekává, že vaše zařízení bude po dlouhou dobu offline, můžete prodloužit dobu vypršení platnosti.
  4. Modul zavaděče uloží model AI do sdíleného místního úložiště modulu IoT Edge. Potřebujete nakonfigurovat sdílené místní úložiště v souboru JSON nasazení IoT Edge.
  5. Modul zavaděče načte model AI z místního úložiště prostřednictvím rozhraní LITERT nebo ONNX API.
  6. Modul zavaděče spustí webové rozhraní API, které obdrží binární fotku prostřednictvím požadavku POST a vrátí výsledky v souboru JSON.

Pokud chcete aktualizovat model AI, můžete novou verzi nahrát do služby Blob Storage a znovu synchronizovat dvojčata modulu zařízení pro přírůstkovou aktualizaci. Není nutné aktualizovat celou image modulu IoT Edge.

Podrobnosti scénáře

V tomto řešení se modul IoT Edge používá ke stažení modelu AI a následnému povolení odvozování strojového učení. V tomto řešení můžete použít předem natrénované modely LiteRT nebo ONNX.

LiteRT

  • Soubor .tflite je předem natrénovaný model AI. Můžete si ho stáhnout z TensorFlow.org. Jedná se o obecný model AI, který můžete použít v multiplatformních aplikacích, jako je iOS a Android. LiteRT podporuje modely z TensorFlow, PyTorch, JAX a Keras. Další informace o metadatech a přidružených polích (například labels.txt) najdete v tématu Čtení metadat z modelů.

  • Model detekce objektů je natrénovaný tak, aby zjistil přítomnost a umístění více tříd objektů. Model může být například natrénován obrázky, které obsahují různé kusy ovoce, spolu s popiskem, který určuje třídu ovoce, kterou představují (například jablko) a data určující, kde se každý objekt na obrázku zobrazuje.

    Když je k modelu k dispozici obrázek, vypíše seznam objektů, které detekuje, umístění ohraničujícího rámečku pro každý objekt a skóre, které označuje spolehlivost detekce.

  • Pokud chcete vytvořit nebo vyladit model AI, přečtěte si téma LiteRT Model Maker.

  • V Zoo detekce můžete získat více bezplatných předem natrénovaných modelů detekce s různými charakteristikami latence a přesnosti. Každý model používá vstupní a výstupní podpisy uvedené v následujících ukázkách kódu.

ONNX

ONNX je open-standard formát pro reprezentaci modelů strojového učení. Podporuje ji komunita partnerů, kteří ji implementovali v mnoha architekturách a nástrojích.

  • ONNX podporuje nástroje pro sestavování a nasazování modelů a pro provádění dalších úloh. Další informace najdete v tématu Podporované nástroje ONNX.
  • Modul runtime ONNX můžete použít ke spouštění předem natrénovaných modelů ONNX. Informace o předem natrénovaných modelech najdete v tématu ONNX Model Zoo.
  • V tomto scénáři můžete použít model rozpoznávání objektů a segmentace obrázků: Tiny YOLOv3.

Komunita ONNX poskytuje nástroje , které vám pomůžou vytvořit a nasadit model hlubokého učení.

Stažení natrénovaných modelů AI

Pokud chcete stáhnout natrénované modely AI, doporučujeme používat dvojčata zařízení k přijímání oznámení, když je nový model připravený. I když je zařízení offline, může se zpráva ukládat do mezipaměti ve službě IoT Hub, dokud se hraniční zařízení nevrátí do online režimu. Zpráva se synchronizuje automaticky.

Následující příklad kódu Pythonu zaregistruje oznámení pro dvojčata zařízení a pak stáhne model AI v souboru ZIP. Provádí také další operace se staženým souborem.

Kód provádí tyto úlohy:

  1. Obdrží oznámení dvojčat zařízení. Oznámení obsahuje název souboru, adresu pro stažení souboru a ověřovací token MD5. (V názvu souboru můžete zahrnout informace o verzi, například 1.0.)
  2. Stáhněte si model AI jako soubor ZIP do místního úložiště.
  3. Volitelně můžete provést kontrolní součet MD5. Ověření MD5 pomáhá zabránit manipulaci se soubory ZIP během přenosu sítě.
  4. Rozbalte soubor ZIP a uložte ho místně.
  5. Odešlete oznámení do IoT Hubu nebo do zprávy směrování, která oznámí, že je nový model AI připravený.
# define behavior for receiving a twin patch
async def twin_patch_handler(patch):
    try:
        print( "######## The data in the desired properties patch was: %s" % patch)
        if "FileName" in patch:
            FileName = patch["FileName"]
        if "DownloadUrl" in patch:
            DownloadUrl = patch["DownloadUrl"]
        if "ContentMD5" in patch:
            ContentMD5 = patch["ContentMD5"]
        FilePath = "/iotedge/storage/" + FileName

        # download AI model
        r = requests.get(DownloadUrl)
        print ("######## download AI Model Succeeded.")
        ffw = open(FilePath, 'wb')
        ffw.write(r.content)
        ffw.close()
        print ("######## AI Model File: " + FilePath)

        # MD5 checksum
        md5str = content_encoding(FilePath)
        if md5str == ContentMD5:
            print ( "######## New AI Model MD5 checksum succeeded")
            # decompressing the ZIP file
            unZipSrc = FilePath
            targeDir = "/iotedge/storage/"
            filenamenoext = get_filename_and_ext(unZipSrc)[0]
            targeDir = targeDir + filenamenoext
            unzip_file(unZipSrc,targeDir)

            # ONNX
            local_model_path = targeDir + "/tiny-yolov3-11.onnx"
            local_labelmap_path = targeDir + "/coco_classes.txt"

            # LiteRT
            # local_model_path = targeDir + "/ssd_mobilenet_v1_1_metadata_1.tflite"
            # local_labelmap_path = targeDir + "/labelmap.txt"

            # message to module
            if client is not None:
                print ( "######## Send AI Model Info AS Routing Message")
                data = "{\"local_model_path\": \"%s\",\"local_labelmap_path\": \"%s\"}" % (filenamenoext+"/tiny-yolov3-11.onnx", filenamenoext+"/coco_classes.txt")
                await client.send_message_to_output(data, "DLModelOutput")
                # update the reported properties
                reported_properties = {"LatestAIModelFileName": FileName }
                print("######## Setting reported LatestAIModelName to {}".format(reported_properties["LatestAIModelFileName"]))
                await client.patch_twin_reported_properties(reported_properties)
        else:
            print ( "######## New AI Model MD5 checksum failed")

    except Exception as ex:
        print ( "Unexpected error in twin_patch_handler: %s" % ex )

Odvozování

Po stažení modelu AI je dalším krokem použití modelu na hraničním zařízení. Model můžete dynamicky načíst a provádět detekci objektů na hraničních zařízeních. Následující příklad kódu ukazuje, jak pomocí modelu LiteRT AI detekovat objekty na hraničních zařízeních.

Kód provádí tyto úlohy:

  1. Dynamicky načtěte model LiteRT AI.
  2. Proveďte standardizaci obrázků.
  3. Rozpozná objekty.
  4. Skóre detekce výpočetních prostředků
class InferenceProcedure():

    def detect_object(self, imgBytes):

        results = []
        try:
            model_full_path = AI_Model_Path.Get_Model_Path()
            if(model_full_path == ""):
                raise Exception ("PLEASE SET AI MODEL FIRST")
            if '.tflite' in model_full_path:
                interpreter = tf.lite.Interpreter(model_path=model_full_path)
                interpreter.allocate_tensors()
                input_details = interpreter.get_input_details()
                output_details = interpreter.get_output_details()
                input_shape = input_details[0]['shape']

                # bytes to numpy.ndarray
                im_arr = np.frombuffer(imgBytes, dtype=np.uint8)
                img = cv2.imdecode(im_arr, flags=cv2.IMREAD_COLOR)
                im_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
                im_rgb = cv2.resize(im_rgb, (input_shape[1], input_shape[2]))
                input_data = np.expand_dims(im_rgb, axis=0)

                interpreter.set_tensor(input_details[0]['index'], input_data)
                interpreter.invoke()
                output_data = interpreter.get_tensor(output_details[0]['index'])
                detection_boxes = interpreter.get_tensor(output_details[0]['index'])
                detection_classes = interpreter.get_tensor(output_details[1]['index'])
                detection_scores = interpreter.get_tensor(output_details[2]['index'])
                num_boxes = interpreter.get_tensor(output_details[3]['index'])

                label_names = [line.rstrip('\n') for line in open(AI_Model_Path.Get_Labelmap_Path())]
                label_names = np.array(label_names)
                new_label_names = list(filter(lambda x : x != '???', label_names))

                for i in range(int(num_boxes[0])):
                    if detection_scores[0, i] > .5:
                        class_id = int(detection_classes[0, i])
                        class_name = new_label_names[class_id]
                        # top, left, bottom, right
                        results_json = "{'Class': '%s','Score': '%s','Location': '%s'}" % (class_name, detection_scores[0, i],detection_boxes[0, i])
                        results.append(results_json)
                        print(results_json)
        except Exception as e:
            print ( "detect_object unexpected error %s " % e )
            raise

        # return results
        return json.dumps(results)

Následující příklad je verze ONNX předchozího kódu. Kroky jsou většinou stejné. Jediným rozdílem je způsob zpracování skóre detekce, protože Labelmap výstupní parametry modelu se liší.

class InferenceProcedure():

    def letterbox_image(self, image, size):
        '''resize image with unchanged aspect ratio using padding'''
        iw, ih = image.size
        w, h = size
        scale = min(w/iw, h/ih)
        nw = int(iw*scale)
        nh = int(ih*scale)

        image = image.resize((nw,nh), Image.BICUBIC)
        new_image = Image.new('RGB', size, (128,128,128))
        new_image.paste(image, ((w-nw)//2, (h-nh)//2))
        return new_image

    def preprocess(self, img):
        model_image_size = (416, 416)
        boxed_image = self.letterbox_image(img, tuple(reversed(model_image_size)))
        image_data = np.array(boxed_image, dtype='float32')
        image_data /= 255.
        image_data = np.transpose(image_data, [2, 0, 1])
        image_data = np.expand_dims(image_data, 0)
        return image_data

    def detect_object(self, imgBytes):
        results = []
        try:
            model_full_path = AI_Model_Path.Get_Model_Path()
            if(model_full_path == ""):
                raise Exception ("PLEASE SET AI MODEL FIRST")
            if '.onnx' in model_full_path:

                # input
                image_data = self.preprocess(imgBytes)
                image_size = np.array([imgBytes.size[1], imgBytes.size[0]], dtype=np.float32).reshape(1, 2)

                labels_file = open(AI_Model_Path.Get_Labelmap_Path())
                labels = labels_file.read().split("\n")

                # Loading ONNX model
                print("loading Tiny YOLO...")
                start_time = time.time()
                sess = rt.InferenceSession(model_full_path)
                print("loaded after", time.time() - start_time, "s")

                input_name00 = sess.get_inputs()[0].name
                input_name01 = sess.get_inputs()[1].name
                pred = sess.run(None, {input_name00: image_data,input_name01:image_size})

                boxes = pred[0]
                scores = pred[1]
                indices = pred[2]

                results = []
                out_boxes, out_scores, out_classes = [], [], []
                for idx_ in indices[0]:
                    out_classes.append(idx_[1])
                    out_scores.append(scores[tuple(idx_)])
                    idx_1 = (idx_[0], idx_[2])
                    out_boxes.append(boxes[idx_1])
                    results_json = "{'Class': '%s','Score': '%s','Location': '%s'}" % (labels[idx_[1]], scores[tuple(idx_)],boxes[idx_1])
                    results.append(results_json)
                    print(results_json)

        except Exception as e:
            print ( "detect_object unexpected error %s " % e )
            raise

        # return results
        return json.dumps(results)

Pokud vaše hraniční zařízení IoT obsahuje předchozí kód a funkce, má hraniční zařízení detekci objektů obrázků AI a podporuje dynamickou aktualizaci modelů AI. Pokud chcete, aby modul Edge poskytoval funkce AI jiným aplikacím nebo modulům prostřednictvím webového rozhraní API, můžete ve svém modulu vytvořit webové rozhraní API.

Architektura Flask je jedním z příkladů nástroje, který můžete použít k rychlému vytvoření rozhraní API. Obrázky můžete přijímat jako binární data, k detekci použít model AI a výsledky pak vrátit ve formátu JSON. Další informace najdete v tématu Flask: Kurz Flask v editoru Visual Studio Code.

Přispěvatelé

Tento článek spravuje Microsoft. Původně byla napsána následujícími přispěvateli.

Hlavní autor:

  • Bo Wang | Vedoucí softwarový inženýr

Další přispěvatel:

Pokud chcete zobrazit neveřejné profily LinkedIn, přihlaste se na LinkedIn.

Další kroky