Bewerken

Delen via


Machine Learning-deductie inschakelen op een Azure IoT Edge-apparaat

Azure IoT Edge
Azure IoT Hub

AI aan de rand is een van de populairste edge-scenario's. Implementaties van dit scenario omvatten afbeeldingsclassificatie, objectdetectie, hoofdtekst, gezichts- en gebarenanalyse en afbeeldingsmanipulatie. In deze architectuurhandleiding wordt beschreven hoe u Azure IoT Edge gebruikt om deze scenario's te ondersteunen.

U kunt de nauwkeurigheid van AI verbeteren door het AI-model bij te werken, maar in sommige scenario's is de edge-apparaatnetwerkomgeving niet goed. In de wind- en olieindustrie kan apparatuur zich bijvoorbeeld in de woestijn of de oceaan bevinden.

IoT Edge-moduledubbels worden gebruikt om het dynamisch geladen AI-model te implementeren. IoT Edge-modules zijn gebaseerd op Docker. Een afbeelding voor een IoT Edge-module in een AI-omgeving heeft doorgaans een grootte van ten minste 1 GB, dus incrementeel bijwerken van het AI-model is belangrijk in een netwerk met beperkte bandbreedte. Deze overweging is de belangrijkste focus van dit artikel. Het idee is om een IoT Edge AI-module te maken die LiteRT-objectdetectiemodellen (voorheen TensorFlow Lite) of Open Neural Network Exchange (ONNX) kan laden. U kunt de module ook inschakelen als een web-API, zodat u deze kunt gebruiken voor andere toepassingen of modules.

De oplossing die in dit artikel wordt beschreven, kan u op deze manieren helpen:

  • AI-deductie inschakelen op edge-apparaten.
  • Minimaliseer de netwerkkosten voor het implementeren en bijwerken van AI-modellen aan de rand. De oplossing kan geld besparen voor u of uw klanten, met name in een netwerkomgeving met beperkte bandbreedte.
  • Een AI-modelopslagplaats maken en beheren in de lokale opslag van een IoT Edge-apparaat.
  • Bijna nul downtime bereiken wanneer het edge-apparaat AI-modellen overschakelt.

TensorFlow en LiteRT zijn een handelsmerk van Google Inc. Er wordt geen goedkeuring geïmpliceerd door het gebruik van dit merk.

Architectuur

Diagram met een architectuur die ondersteuning biedt voor machine learning-deductie.

Een Visio-bestand van deze architectuur downloaden.

Gegevensstroom

  1. Het AI-model wordt geüpload naar Azure Blob Storage of een webservice. Het model kan een vooraf getraind LiteRT- of ONNX-model of een model zijn dat is gemaakt in Azure Machine Learning. De IoT Edge-module heeft toegang tot dit model en downloadt het later naar het edge-apparaat. Als u betere beveiliging nodig hebt, kunt u overwegen om privé-eindpuntverbindingen tussen Blob Storage en het edge-apparaat te gebruiken.
  2. Azure IoT Hub synchroniseert apparaatmoduledubbels automatisch met AI-modelgegevens. De synchronisatie vindt zelfs plaats als IoT Edge offline is geweest. (In sommige gevallen zijn IoT-apparaten verbonden met netwerken op geplande tijden per uur, dagelijks of wekelijks om stroom te besparen of netwerkverkeer te verminderen.)
  3. De loadermodule bewaakt de updates van de moduledubbels via API. Wanneer een update wordt gedetecteerd, wordt het SAS-token voor het machine learning-model opgehaald en vervolgens het AI-model gedownload.
    • Zie SAS-token maken voor een container of blob voor meer informatie.
    • U kunt de eigenschap ExpiresOn gebruiken om de vervaldatum van resources in te stellen. Als uw apparaat lange tijd offline is, kunt u de verlooptijd verlengen.
  4. De loadermodule slaat het AI-model op in de gedeelde lokale opslag van de IoT Edge-module. U moet de gedeelde lokale opslag configureren in het JSON-bestand van de IoT Edge-implementatie.
  5. De loadermodule laadt het AI-model vanuit lokale opslag via de LiteRT- of ONNX-API.
  6. De loadermodule start een web-API die de binaire foto via POST-aanvraag ontvangt en de resultaten retourneert in een JSON-bestand.

Als u het AI-model wilt bijwerken, kunt u de nieuwe versie uploaden naar Blob Storage en de apparaatmoduledubbels opnieuw synchroniseren voor een incrementele update. U hoeft de volledige installatiekopieën van de IoT Edge-module niet bij te werken.

Scenariodetails

In deze oplossing wordt een IoT Edge-module gebruikt om een AI-model te downloaden en vervolgens machine learning-deductie in te schakelen. U kunt vooraf getrainde LiteRT- of ONNX-modellen in deze oplossing gebruiken.

LiteRT

  • Een .tflite bestand is een vooraf getraind AI-model. U kunt er een downloaden van TensorFlow.org. Het is een algemeen AI-model dat u kunt gebruiken in platformoverschrijdende toepassingen zoals iOS en Android. LiteRT ondersteunt modellen van TensorFlow, PyTorch, JAX en Keras. Zie De metagegevens van modellen lezen voor meer informatie over metagegevens en gekoppelde velden (bijvoorbeeldlabels.txt).

  • Een objectdetectiemodel wordt getraind om de aanwezigheid en locatie van meerdere klassen objecten te detecteren. Een model kan bijvoorbeeld worden getraind met afbeeldingen die verschillende stukjes fruit bevatten, samen met een label dat de klasse van fruit aangeeft die ze vertegenwoordigen (bijvoorbeeld apple) en gegevens die aangeeft waar elk object in de afbeelding wordt weergegeven.

    Wanneer een afbeelding aan het model wordt geleverd, wordt er een lijst uitgevoerd met de objecten die worden gedetecteerd, de locatie van een begrenzingsvak voor elk object en een score die het vertrouwen van de detectie aangeeft.

  • Als u een AI-model wilt bouwen of aanpassen, raadpleegt u LiteRT Model Maker.

  • U kunt bij Detection Zoo meer gratis vooraf getrainde detectiemodellen krijgen, met verschillende latentie- en precisiekenmerken. Elk model gebruikt de invoer- en uitvoerhandtekeningen die worden weergegeven in de volgende codevoorbeelden.

ONNX

ONNX is een open-standaardindeling voor het vertegenwoordigen van machine learning-modellen. Het wordt ondersteund door een community van partners die het in veel frameworks en hulpprogramma's hebben geïmplementeerd.

  • ONNX ondersteunt hulpprogramma's voor het bouwen en implementeren van modellen en voor het uitvoeren van andere taken. Zie ondersteunde ONNX-hulpprogramma's voor meer informatie.
  • U kunt ONNX Runtime gebruiken om vooraf getrainde ONNX-modellen uit te voeren. Zie ONNX Model Zoo voor meer informatie over vooraf getrainde modellen.
  • Voor dit scenario kunt u een objectdetectie- en afbeeldingssegmentatiemodel gebruiken: Tiny YOLOv3.

De ONNX-community biedt hulpprogramma's waarmee u uw Deep Learning-model kunt maken en implementeren.

Getrainde AI-modellen downloaden

Als u getrainde AI-modellen wilt downloaden, raden we u aan apparaatdubbels te gebruiken om meldingen te ontvangen wanneer een nieuw model gereed is. Zelfs als het apparaat offline is, kan het bericht in de cache worden opgeslagen in ioT Hub totdat het edge-apparaat weer online komt. Het bericht wordt automatisch gesynchroniseerd.

Hieronder volgt een voorbeeld van Python-code waarmee meldingen voor de apparaatdubbels worden geregistreerd en vervolgens het AI-model in een ZIP-bestand wordt gedownload. Het voert ook verdere bewerkingen uit op het gedownloade bestand.

De code voert deze taken uit:

  1. Ontvang de melding van de apparaatdubbels. De melding bevat de bestandsnaam, het bestandsdownloadadres en het MD5-verificatietoken. (In de bestandsnaam kunt u versiegegevens opnemen, zoals 1.0.)
  2. Download het AI-model als een ZIP-bestand naar de lokale opslag.
  3. Voer eventueel MD5-controlesom uit. MD5-verificatie helpt zip-bestanden te voorkomen waarmee tijdens de netwerkoverdracht is geknoeid.
  4. Pak het ZIP-bestand uit en sla het lokaal op.
  5. Verzend een melding naar IoT Hub of een routeringsbericht om te rapporteren dat het nieuwe AI-model gereed is.
# 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 )

Deductie

Nadat het AI-model is gedownload, is de volgende stap het gebruik van het model op het edge-apparaat. U kunt het model dynamisch laden en objectdetectie uitvoeren op edge-apparaten. In het volgende codevoorbeeld ziet u hoe u het LiteRT AI-model gebruikt om objecten op edge-apparaten te detecteren.

De code voert deze taken uit:

  1. Laad het LiteRT AI-model dynamisch.
  2. Standaardisatie van installatiekopieën uitvoeren.
  3. Objecten detecteren.
  4. Scores voor berekeningsdetectie.
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)

Hieronder volgt de ONNX-versie van de voorgaande code. De stappen zijn meestal hetzelfde. Het enige verschil is hoe de detectiescore wordt verwerkt, omdat de uitvoerparameters van het Labelmap model verschillen.

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)

Als uw IoT Edge-apparaat de voorgaande code en functies bevat, heeft uw edge-apparaat ai-afbeeldingsobjectdetectie en ondersteunt dynamische updates van AI-modellen. Als u wilt dat de edge-module AI-functionaliteit biedt aan andere toepassingen of modules via een web-API, kunt u een web-API maken in uw module.

Flask-framework is een voorbeeld van een hulpprogramma dat u kunt gebruiken om snel een API te maken. U kunt afbeeldingen ontvangen als binaire gegevens, een AI-model gebruiken voor detectie en vervolgens de resultaten retourneren in een JSON-indeling. Zie Flask: Flask Tutorial in Visual Studio Code voor meer informatie.

Medewerkers

Dit artikel wordt onderhouden door Microsoft. De tekst is oorspronkelijk geschreven door de volgende Inzenders.

Hoofdauteur:

  • Bo Wang | Senior Software Engineer

Andere inzender:

Als u niet-openbare LinkedIn-profielen wilt zien, meldt u zich aan bij LinkedIn.

Volgende stappen