Mengaktifkan inferensi pembelajaran mesin pada perangkat Azure IoT Edge

Azure IoT Edge
Azure IoT Hub

AI di tepi adalah salah satu skenario tepi paling populer. Implementasi skenario ini termasuk klasifikasi gambar, deteksi objek, isi, wajah, dan analisis gerakan, dan manipulasi gambar. Panduan arsitektur ini menjelaskan cara menggunakan Azure IoT Edge untuk mendukung skenario ini.

Anda dapat meningkatkan akurasi AI dengan memperbarui model AI, tetapi dalam beberapa skenario lingkungan jaringan perangkat edge tidak baik. Misalnya, dalam industri tenaga angin dan minyak, peralatan mungkin terletak di gurun atau laut.

Kembar modul IoT Edge digunakan untuk mengimplementasikan model AI yang dimuat secara dinamis. Modul IoT Edge didasarkan pada Docker. Gambar untuk modul IoT Edge di lingkungan AI biasanya memiliki ukuran setidaknya 1 GB, sehingga memperbarui model AI secara bertahap penting dalam jaringan bandwidth sempit. Pertimbangan itu adalah fokus utama artikel ini. Idenya adalah membuat modul AI IoT Edge yang dapat memuat model deteksi objek LiteRT (sebelumnya TensorFlow Lite) atau Open Neural Network Exchange (ONNX). Anda juga dapat mengaktifkan modul sebagai API web sehingga Anda dapat menggunakannya untuk menguntungkan aplikasi atau modul lain.

Solusi yang dijelaskan dalam artikel ini dapat membantu Anda dengan cara berikut:

  • Aktifkan inferensi AI pada perangkat edge.
  • Minimalkan biaya jaringan untuk menyebarkan dan memperbarui model AI di tepi. Solusinya dapat menghemat uang untuk Anda atau pelanggan Anda, terutama di lingkungan jaringan bandwidth sempit.
  • Membuat dan mengelola repositori model AI di penyimpanan lokal perangkat edge IoT.
  • Mencapai waktu henti hampir nol saat perangkat edge mengalihkan model AI.

TensorFlow dan LiteRT adalah merek dagang Dari Google Inc. Tidak ada dukungan yang tersirat oleh penggunaan tanda ini.

Sistem

Diagram yang menunjukkan arsitektur yang mendukung inferensi pembelajaran mesin.

Unduh file Visio arsitektur ini.

Aliran data

  1. Model AI diunggah ke Azure Blob Storage atau layanan web. Model ini dapat menjadi model LiteRT atau ONNX yang telah dilatih sebelumnya atau model yang dibuat di Azure Pembelajaran Mesin. Modul IoT Edge dapat mengakses model ini dan mengunduhnya ke perangkat edge nanti. Jika Anda memerlukan keamanan yang lebih baik, pertimbangkan untuk menggunakan koneksi titik akhir privat antara Blob Storage dan perangkat edge.
  2. Azure IoT Hub menyinkronkan kembar modul perangkat secara otomatis dengan informasi model AI. Sinkronisasi terjadi bahkan jika IoT Edge telah offline. (Dalam beberapa kasus, perangkat IoT terhubung ke jaringan pada waktu per jam, harian, atau mingguan terjadwal untuk menghemat daya atau mengurangi lalu lintas jaringan.)
  3. Modul loader memantau pembaruan modul kembar melalui API. Ketika mendeteksi pembaruan, ia mendapatkan token SAS model pembelajaran mesin dan kemudian mengunduh model AI.
    • Untuk informasi selengkapnya, lihat Membuat token SAS untuk kontainer atau blob.
    • Anda dapat menggunakan properti ExpiresOn untuk mengatur tanggal kedaluwarsa sumber daya. Jika perangkat Anda akan offline untuk waktu yang lama, Anda dapat memperpanjang waktu kedaluwarsa.
  4. Modul loader menyimpan model AI di penyimpanan lokal bersama modul IoT Edge. Anda perlu mengonfigurasi penyimpanan lokal bersama dalam file JSON penyebaran IoT Edge.
  5. Modul loader memuat model AI dari penyimpanan lokal melalui LITERT atau ONNX API.
  6. Modul loader memulai API web yang menerima foto biner melalui permintaan POST dan mengembalikan hasilnya dalam file JSON.

Untuk memperbarui model AI, Anda dapat mengunggah versi baru ke Blob Storage dan menyinkronkan kembar modul perangkat lagi untuk pembaruan tambahan. Tidak perlu memperbarui seluruh gambar modul IoT Edge.

Detail skenario

Dalam solusi ini, modul IoT Edge digunakan untuk mengunduh model AI lalu mengaktifkan inferensi pembelajaran mesin. Anda dapat menggunakan model LiteRT atau ONNX yang telah dilatih sebelumnya dalam solusi ini.

LiteRT

  • File .tflite adalah model AI yang telah dilatih sebelumnya. Anda dapat mengunduhnya dari TensorFlow.org. Ini adalah model AI generik yang dapat Anda gunakan dalam aplikasi lintas platform seperti iOS dan Android. LiteRT mendukung model dari TensorFlow, PyTorch, JAX, dan Keras. Untuk informasi selengkapnya tentang metadata dan bidang terkait (misalnya, labels.txt) lihat Membaca metadata dari model.

  • Model deteksi objek dilatih untuk mendeteksi keberadaan dan lokasi beberapa kelas objek. Misalnya, model mungkin dilatih dengan gambar yang berisi berbagai potongan buah, bersama dengan label yang menentukan kelas buah yang diwakilinya (misalnya, apel) dan data yang menentukan tempat setiap objek muncul dalam gambar.

    Ketika gambar disediakan untuk model, gambar menghasilkan daftar objek yang dideteksinya, lokasi kotak pembatas untuk setiap objek, dan skor yang menunjukkan keyakinan deteksi.

  • Jika Anda ingin membuat atau menyetel model AI secara kustom, lihat LiteRT Model Maker.

  • Anda bisa mendapatkan model deteksi pra-terlatih yang lebih gratis, dengan berbagai karakteristik latensi dan presisi, di Kebun Binatang Deteksi. Setiap model menggunakan tanda tangan input dan output yang ditunjukkan dalam sampel kode berikut.

ONNX

ONNX adalah format standar terbuka untuk mewakili model pembelajaran mesin. Ini didukung oleh komunitas mitra yang telah menerapkannya dalam banyak kerangka kerja dan alat.

  • ONNX mendukung alat untuk membangun dan menyebarkan model dan untuk menyelesaikan tugas lain. Untuk informasi selengkapnya, lihat, Alat ONNX yang didukung.
  • Anda dapat menggunakan ONNX Runtime untuk menjalankan model onnx yang telah dilatih sebelumnya. Untuk informasi tentang model yang telah dilatih sebelumnya, lihat ONNX Model Zoo.
  • Untuk skenario ini, Anda dapat menggunakan deteksi objek dan model segmentasi gambar: Tiny YOLOv3.

Komunitas ONNX menyediakan alat untuk membantu Anda membuat dan menyebarkan model pembelajaran mendalam Anda.

Mengunduh model AI terlatih

Untuk mengunduh model AI terlatih, kami sarankan Anda menggunakan perangkat kembar untuk menerima pemberitahuan saat model baru siap. Bahkan jika perangkat offline, pesan dapat di-cache di IoT Hub sampai perangkat edge kembali online. Pesan akan disinkronkan secara otomatis.

Berikut ini adalah contoh kode Python yang mendaftarkan pemberitahuan untuk perangkat kembar dan kemudian mengunduh model AI dalam file ZIP. Ini juga melakukan operasi lebih lanjut pada file yang diunduh.

Kode melakukan tugas-tugas ini:

  1. Terima pemberitahuan perangkat kembar. Pemberitahuan mencakup nama file, alamat pengunduhan file, dan token autentikasi MD5. (Dalam nama file, Anda dapat menyertakan informasi versi, seperti 1.0.)
  2. Unduh model AI sebagai file ZIP ke penyimpanan lokal.
  3. Secara opsional, lakukan checksum MD5. Verifikasi MD5 membantu mencegah file ZIP yang telah dirusak selama transmisi jaringan.
  4. Buka zip file ZIP dan simpan secara lokal.
  5. Kirim pemberitahuan ke IoT Hub atau pesan perutean untuk melaporkan bahwa model AI baru sudah siap.
# 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 )

Inferensi

Setelah model AI diunduh, langkah selanjutnya adalah menggunakan model di perangkat edge. Anda dapat memuat model secara dinamis dan melakukan deteksi objek pada perangkat edge. Contoh kode berikut menunjukkan cara menggunakan model AI LiteRT untuk mendeteksi objek di perangkat edge.

Kode melakukan tugas-tugas ini:

  1. Muat model LiteRT AI secara dinamis.
  2. Lakukan standardisasi gambar.
  3. Mendeteksi objek.
  4. Skor deteksi komputasi.
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)

Berikut ini adalah versi ONNX dari kode sebelumnya. Langkah-langkahnya sebagian besar sama. Satu-satunya perbedaan adalah bagaimana skor deteksi ditangani, karena Labelmap parameter output model dan berbeda.

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)

Jika perangkat IoT edge Anda menggabungkan kode dan fitur sebelumnya, perangkat edge Anda memiliki deteksi objek gambar AI dan mendukung pembaruan dinamis model AI. Jika Anda ingin modul edge menyediakan fungsionalitas AI ke aplikasi atau modul lain melalui API web, Anda dapat membuat API web di modul Anda.

Kerangka kerja Flask adalah salah satu contoh alat yang dapat Anda gunakan untuk membuat API dengan cepat. Anda dapat menerima gambar sebagai data biner, menggunakan model AI untuk deteksi, lalu mengembalikan hasilnya dalam format JSON. Untuk informasi selengkapnya, lihat Tutorial Flask: Flask di Visual Studio Code.

Kontributor

Artikel ini dikelola oleh Microsoft. Ini awalnya ditulis oleh kontributor berikut.

Penulis utama:

  • Bo Wang | Insinyur Perangkat Lunak Senior

Kontributor lainnya:

Untuk melihat profil LinkedIn non-publik, masuk ke LinkedIn.

Langkah berikutnya