教學課程:使用 自訂視覺 Service 在邊緣執行影像分類

適用於:IoT Edge 1.4 checkmark IoT Edge 1.4

重要

支援的版本是 IoT Edge 1.4。 如果您是舊版,請參閱更新 IoT Edge

Azure IoT Edge 可將工作負載移出雲端和邊緣,讓您的IoT解決方案更有效率。 這項功能非常適合處理大量數據的服務,例如計算機視覺模型。 Azure AI 自訂視覺 可讓您建置自定義映像分類器,並將其部署至裝置作為容器。 這兩項服務可讓您從影像或視訊串流中尋找深入解析,而不需要先在月臺外傳輸所有數據。 自訂視覺 提供分類器,可比較影像與定型模型以產生見解。

例如,IoT Edge 裝置上的 自訂視覺 可以判斷高速公路是否遇到高於或低於正常流量,或停車庫是否連續有可用的停車點。 這些深入解析可以與其他服務共用以採取動作。

在本教學課程中,您會了解如何:

  • 使用 自訂視覺 建置映像分類器。
  • 開發IoT Edge模組,以查詢裝置上的 自訂視覺網頁伺服器。
  • 將影像分類器的結果傳送至 IoT 中樞。

Diagram - Tutorial architecture, stage and deploy classifier

如果您沒有 Azure 訂閱,請在開始之前,先建立 Azure 免費帳戶

必要條件

提示

本教學課程是Raspberry Pi 3範例專案上 自訂視覺和 Azure IoT Edge 的簡化版本。 本教學課程的設計目的是在雲端 VM 上執行,並使用靜態映射來定型和測試映像分類器,這對剛開始在 IoT Edge 上評估 自訂視覺 的人來說很有用。 範例專案會使用實體硬體,並設定即時相機摘要來定型和測試影像分類器,這對想要嘗試更詳細、真實生活案例的人來說很有用。

使用 自訂視覺 建置映像分類器

若要建置映像分類器,您必須建立 自訂視覺 專案並提供定型影像。 如需本節中採取之步驟的詳細資訊,請參閱如何使用 自訂視覺 建置分類器。

建置並定型映射分類器之後,您可以將它匯出為 Docker 容器,並將其部署至 IoT Edge 裝置。

建立新專案

  1. 在您的網頁瀏覽器中,流覽至 自訂視覺 網頁

  2. 選取 [ 登入],並使用您用來存取 Azure 資源的相同帳戶登入。

  3. 選取 [新增專案]

  4. 使用下列值建立您的專案:

    欄位
    名稱 提供項目的名稱,例如 EdgeTreeClassifier
    描述 選擇性專案描述。
    資源 選取其中一個 Azure 資源群組,其中包含 自訂視覺 服務資源,或如果您尚未新增資源,請建立新的資源群組。
    專案類型 分類
    分類類型 多類別 (每個影像的單一標記)
    網域 一般(精簡)
    匯出功能 基本平臺 (Tensorflow、CoreML、ONNX、...)
  5. 選取建立專案

上傳影像並定型分類器

建立影像分類器需要一組定型影像和測試影像。

  1. 將認知-CustomVision-Windows 存放庫的範例映像複製或下載到本機開發計算機。

    git clone https://github.com/Microsoft/Cognitive-CustomVision-Windows.git
    
  2. 返回您的 自訂視覺 項目,然後選取 [新增影像]。

  3. 流覽至您在本機複製的 git 存放庫,並流覽至第一個 image 資料夾 Cognitive-CustomVision-Windows / Samples / Images / Hemlock。 選取資料夾中的所有 10 個影像,然後 選取 [開啟]。

  4. 將標記 hemlock 新增至此影像群組,然後按 Enter 以套用標記。

  5. 選取 [ 上傳 10 個檔案]。

    Upload hemlock tagged files to Custom Vision

  6. 成功上傳影像時,請選取 [ 完成]。

  7. 再次選取 [ 新增映射 ]。

  8. 流覽至第二個影像資料夾 Cognitive-CustomVision-Windows / Samples / Images / Japanese Cherry。 選取資料夾中的所有 10 個影像,然後 選取 [開啟]。

  9. 將標籤 櫻桃 新增至此影像群組,然後按 Enter 以套用標籤。

  10. 選取 [ 上傳 10 個檔案]。 成功上傳影像時,請選取 [ 完成]。

  11. 當這兩組影像都標記並上傳時,請選取 [定 型] 以定型分類器。

匯出分類器

  1. 訓練分類器之後,請在分類器的 [效能] 頁面上選取 [匯出 ]。

    Export your trained image classifier

  2. 針對平台選取 [DockerFile ]。

  3. 針對版本選取 [Linux ]。

  4. 選取匯出

    Export as DockerFile with Linux containers

  5. 匯出完成時,請選取 [ 下載 ],然後將.zip套件儲存在本機計算機上。 從套件擷取所有檔案。 您可以使用這些檔案來建立包含影像分類伺服器的 IoT Edge 模組。

當您到達此點時,您已完成建立和定型 自訂視覺 專案。 您將在下一節中使用導出的檔案,但您已完成 自訂視覺 網頁。

建立IoT Edge解決方案

現在,您已在開發計算機上擁有映像分類器的容器版本檔案。 在本節中,您會將映射分類器容器設定為以IoT Edge模組的形式執行。 您也會建立與映像分類器一起部署的第二個模組。 第二個模組會將要求張貼至分類器,並將結果當做訊息傳送至 IoT 中樞。

建立新的解決方案

解決方案是針對單一 IoT Edge 部署開發和組織多個模組的邏輯方式。 解決方案包含一或多個模組的程序代碼,以及宣告如何在IoT Edge裝置上設定它們的部署指令清單。

  1. 在 Visual Studio Code 中,選取 [檢視>命令選擇區] 以開啟 Visual Studio Code 命令選擇區。

  2. 在命令選擇區中,輸入並執行命令 Azure IoT Edge:新的 IoT Edge 解決方案。 在命令選擇區中,提供下列資訊來建立您的解決方案:

    欄位
    選取資料夾 選擇 Visual Studio Code 開發電腦上的位置,以建立方案檔。
    提供解決方案名稱 輸入解決方案的描述性名稱,例如 CustomVisionSolution,或接受預設值。
    選取模組範本 選擇 [Python 模組]。
    提供模組名稱 將模組 分類器命名為 。

    此模組名稱必須小寫。 當參考模組時,IoT Edge 會區分大小寫,而此解決方案會使用連結庫來格式化小寫中的所有要求。
    提供模組的 Docker 映像存放庫 映像存放庫包含容器登錄的名稱和容器映像的名稱。 您的容器映像會從最後一個步驟預先填入。 將localhost:5000取代為您的 Azure 容器登錄中的登入伺服器值。 您可以從容器登錄的 [概觀] 頁面,擷取 Azure 入口網站 中的登入伺服器。

    最後一個字串看起來像 <登錄名稱>.azurecr.io/classifier

    Provide Docker image repository

Visual Studio Code 視窗會載入 IoT Edge 解決方案工作區。

新增登錄認證

環境檔案會儲存容器登錄的認證,並與IoT Edge運行時間共用認證。 運行時間需要這些認證,才能將私人映像提取到IoT Edge裝置。

IoT Edge 擴充功能會嘗試從 Azure 提取容器登錄認證,並在環境檔案中填入這些認證。 檢查是否已包含您的認證。 如果沒有,請立即新增它們:

  1. 在 Visual Studio Code 總管中,開啟 .env 檔案。
  2. 使用您從 Azure 容器登錄複製的使用者名稱和密碼值來更新欄位。
  3. 儲存此檔案。

注意

本教學課程使用適用於 Azure Container Registry 的管理員登入認證,這對開發和測試案例而言很方便。 當您準備好進行生產案例時,建議您使用最低許可權驗證選項,例如服務主體。 如需詳細資訊,請參閱 管理容器登錄的存取權。

選取您的目標架構

目前,Visual Studio Code 可以開發適用於 Linux AMD64 和 Linux ARM32v7 裝置的模組。 您必須選取每個解決方案的目標架構,因為容器會針對每個架構類型建置和執行方式不同。 默認值為Linux AMD64,這是我們在本教學課程中使用的。

  1. 開啟命令選擇區並搜尋 Azure IoT Edge:設定 Edge 解決方案的預設目標平臺,或選取視窗底部側邊列中的快捷方式圖示。

  2. 在命令選擇區中,從選項清單中選取目標架構。 在本教學課程中,我們會使用Ubuntu虛擬機作為IoT Edge裝置,因此請保留預設 amd64

新增影像分類器

Visual Studio Code 中的 Python 模組範本包含一些您可以執行以測試 IoT Edge 的範例程式代碼。 在此案例中,您不會使用該程序代碼。 請改用本節中的步驟,將範例程式代碼取代為您先前導出的映射分類器容器。

  1. 在檔案總管中,流覽至您下載並解壓縮的 自訂視覺 套件。 從擷取的套件複製所有內容。 它應該是兩個資料夾、 應用程式和azureml,以及兩個檔案 DockerfileREADME

  2. 在檔案總管中,流覽至您告訴Visual StudioCode建立IoT Edge解決方案的目錄。

  3. 開啟分類器模組資料夾。 如果您在上一節中使用建議的名稱,資料夾結構看起來像 CustomVisionSolution / modules / classifier

  4. 將檔案貼到 分類器 資料夾中。

  5. 返回 Visual Studio Code 視窗。 您的解決方案工作區現在應該會在模組資料夾中顯示影像分類器檔案。

    Solution workspace with image classifier files

  6. 開啟分類器資料夾中的module.json檔案。

  7. 更新 platform 參數以指向您新增的新 Dockerfile,並移除 AMD64 以外的所有選項,這是我們在本教學課程中唯一使用的架構。

    "platforms": {
        "amd64": "./Dockerfile"
    }
    
  8. 儲存您的變更。

建立模擬相機模組

在實際的 自訂視覺 部署中,您會有提供即時影像或視訊串流的相機。 在此案例中,您會建置將測試影像傳送至影像分類器的模組來模擬相機。

新增和設定新模組

在本節中,您會將新模組新增至相同的 CustomVisionSolution,並提供程式碼來建立模擬相機。

  1. 在相同的 Visual Studio Code 視窗中,使用命令選擇區來執行 Azure IoT Edge:新增 IoT Edge 模組。 在命令選擇區中,為您的新模組提供下列資訊:

    提示
    選取部署範本檔案 選取 CustomVisionSolution 資料夾中的 deployment.template.json檔案。
    選取模組範本 選取 Python 模組
    提供模組名稱 將模組 命名為cameraCapture
    提供模組的 Docker 映像存放庫 將localhost:5000取代為 Azure 容器登錄的登入伺服器值。

    最後一個字串看起來像 registryname.azurecr.io/cameracapture>。<

    Visual Studio Code 視窗會在解決方案工作區中載入您的新模組,並更新deployment.template.json檔案。 現在您應該會看到兩個模組資料夾:分類器和cameraCapture。

  2. 開啟modules / cameraCapture資料夾中的 main.py 檔案。

  3. 以下列程式代碼取代整個檔案。 此範例程式代碼會將POST要求傳送至分類器模組中執行的影像處理服務。 我們會提供此模組容器,其中包含要用於要求中的範例映像。 然後,它會將回應封裝為 IoT 中樞 訊息,並將其傳送至輸出佇列。

    # Copyright (c) Microsoft. All rights reserved.
    # Licensed under the MIT license. See LICENSE file in the project root for
    # full license information.
    
    import time
    import sys
    import os
    import requests
    import json
    from azure.iot.device import IoTHubModuleClient, Message
    
    # global counters
    SENT_IMAGES = 0
    
    # global client
    CLIENT = None
    
    # Send a message to IoT Hub
    # Route output1 to $upstream in deployment.template.json
    def send_to_hub(strMessage):
        message = Message(bytearray(strMessage, 'utf8'))
        CLIENT.send_message_to_output(message, "output1")
        global SENT_IMAGES
        SENT_IMAGES += 1
        print( "Total images sent: {}".format(SENT_IMAGES) )
    
    # Send an image to the image classifying server
    # Return the JSON response from the server with the prediction result
    def sendFrameForProcessing(imagePath, imageProcessingEndpoint):
        headers = {'Content-Type': 'application/octet-stream'}
    
        with open(imagePath, mode="rb") as test_image:
            try:
                response = requests.post(imageProcessingEndpoint, headers = headers, data = test_image)
                print("Response from classification service: (" + str(response.status_code) + ") " + json.dumps(response.json()) + "\n")
            except Exception as e:
                print(e)
                print("No response from classification service")
                return None
    
        return json.dumps(response.json())
    
    def main(imagePath, imageProcessingEndpoint):
        try:
            print ( "Simulated camera module for Azure IoT Edge. Press Ctrl-C to exit." )
    
            try:
                global CLIENT
                CLIENT = IoTHubModuleClient.create_from_edge_environment()
            except Exception as iothub_error:
                print ( "Unexpected error {} from IoTHub".format(iothub_error) )
                return
    
            print ( "The sample is now sending images for processing and will indefinitely.")
    
            while True:
                classification = sendFrameForProcessing(imagePath, imageProcessingEndpoint)
                if classification:
                    send_to_hub(classification)
                time.sleep(10)
    
        except KeyboardInterrupt:
            print ( "IoT Edge module sample stopped" )
    
    if __name__ == '__main__':
        try:
            # Retrieve the image location and image classifying server endpoint from container environment
            IMAGE_PATH = os.getenv('IMAGE_PATH', "")
            IMAGE_PROCESSING_ENDPOINT = os.getenv('IMAGE_PROCESSING_ENDPOINT', "")
        except ValueError as error:
            print ( error )
            sys.exit(1)
    
        if ((IMAGE_PATH and IMAGE_PROCESSING_ENDPOINT) != ""):
            main(IMAGE_PATH, IMAGE_PROCESSING_ENDPOINT)
        else: 
            print ( "Error: Image path or image-processing endpoint missing" )
    
  4. 儲存 main.py 檔案。

  5. 開啟requirements.txt檔案。

  6. 為要包含在容器中的連結庫新增一行。

    requests
    
  7. 儲存 requirements.txt 檔案。

將測試映像新增至容器

我們將使用單一測試影像,而不是使用真實相機來提供此案例的影像摘要。 您在本教學課程稍早為定型映射下載的 GitHub 存放庫中會包含測試映像。

  1. 流覽至位於 Cognitive-CustomVision-Windows / 範例 / 影像測試的測試影像。 /

  2. 複製 test_image.jpg

  3. 流覽至您的IoT Edge解決方案目錄,並將測試影像貼到modules / cameraCapture資料夾中。 影像應該與您在上一節中編輯的 main.py 檔案位於相同的資料夾中。

  4. 在 Visual Studio Code 中,開啟 cameraCapture 模組的 Dockerfile.amd64 檔案。

  5. 在建立工作目錄的行之後, WORKDIR /app新增下列程式代碼行:

    ADD ./test_image.jpg .
    
  6. 儲存 Dockerfile。

準備部署指令清單

到目前為止,在本教學課程中,您已將 自訂視覺 模型定型,以分類樹狀結構影像,並將該模型封裝為IoT Edge模組。 然後,您已建立第二個模組來查詢影像分類伺服器,並將其結果回報給 IoT 中樞。 現在,您已準備好建立部署指令清單,告知 IoT Edge 裝置如何一起啟動並執行這兩個模組。

適用於 Visual Studio Code 的 IoT Edge 擴充功能會在每個 IoT Edge 解決方案中提供範本,以協助您建立部署指令清單。

  1. 開啟方案資料夾中的deployment.template.json檔案。

  2. 尋找 modules 區段,其中應該包含三個模組:您建立的兩個模組、分類器和 cameraCapture,以及預設包含的第三個模組 SimulatedTemperatureSensor。

  3. 刪除 SimulatedTemperatureSensor 模組及其所有參數。 此課程模組包含來提供測試案例的範例數據,但我們在此部署中不需要此範例數據。

  4. 如果您將影像分類模組命名為分類器以外的專案,請立即檢查名稱,並確定其全部為小寫。 cameraCapture 模組會使用要求連結庫呼叫分類器模組,以小寫格式化所有要求,而IoT Edge會區分大小寫。

  5. 使用下列 JSON 更新 cameraCapture 模組的 createOptions 參數。 這項資訊會在 main.py 程式中擷取的模組容器中建立環境變數。 藉由在部署指令清單中包含這項資訊,您可以變更映像或端點,而不需要重建模組映像。

    "createOptions": "{\"Env\":[\"IMAGE_PATH=test_image.jpg\",\"IMAGE_PROCESSING_ENDPOINT=http://classifier/image\"]}"
    

    如果您將 自訂視覺 模組命名為分類器以外的專案,請更新影像處理端點值以符合。

  6. 在檔案底部,更新 $edgeHub模組的 routes 參數。 您想要將預測結果從 cameraCapture 路由傳送至 IoT 中樞。

        "routes": {
          "cameraCaptureToIoTHub": "FROM /messages/modules/cameraCapture/outputs/* INTO $upstream"
        },
    

    如果您將第二個模組命名為cameraCapture以外的專案,請更新路由值以符合。

  7. 儲存 deployment.template.json 檔案。

建置並推送IoT Edge解決方案

建立模組並設定部署指令清單範本之後,您就可以建置容器映像,並將其推送至您的容器登錄。

映射進入登錄后,您可以將解決方案部署至 IoT Edge 裝置。 您可以透過 IoT 中樞 在裝置上設定模組,但您也可以透過 Visual Studio Code 存取您的 IoT 中樞 和裝置。 在本節中,您會設定對 IoT 中樞 的存取權,然後使用 Visual Studio Code 將解決方案部署至 IoT Edge 裝置。

首先,建置解決方案並將其推送至容器登錄。

  1. 選取 [檢視>終端機],以開啟Visual StudioCode整合式終端機。

  2. 在終端機中輸入下列命令,以登入 Docker。 使用 Azure 容器登錄的使用者名稱、密碼和登入伺服器登入。 您可以從登錄的 [存取密鑰] 區段擷取這些值,Azure 入口網站。

    docker login -u <ACR username> -p <ACR password> <ACR login server>
    

    您可能會收到建議使用 --password-stdin的安全性警告。 雖然建議針對生產案例使用該最佳做法,但它不在本教學課程的範圍內。 如需詳細資訊,請參閱 docker 登入 參考。

  3. 在 Visual Studio Code 總管中,以滑鼠右鍵按兩下deployment.template.json檔案,然後選取 [建置和推送 IoT Edge 解決方案]。

    建置和推送命令會啟動三個作業。 首先,它會在名為 config 的解決方案中建立新的資料夾,以保存完整的部署指令清單,此指令清單內建在部署範本和其他解決方案檔案中的資訊中。 其次,它會執行 docker build ,根據目標架構的適當 dockerfile 來建置容器映像。 然後,它會執行 docker push ,將映像存放庫推送至容器登錄。

    此程式第一次可能需要幾分鐘的時間,但下次執行命令時會更快。

將模組部署至裝置

使用 Visual Studio Code 總管和 Azure IoT Edge 擴充功能,將模組專案部署至 IoT Edge 裝置。 您已備妥適用於案例的部署指令清單,即 config 資料夾中的 deployment.amd64.json 檔案。 您現在只需要選取要接收部署的裝置。

請確定您的 IoT Edge 裝置已啟動並執行。

  1. 在 Visual Studio Code 總管的 [Azure IoT 中樞] 區段底下,展開 [裝置] 以查看您的 IoT 裝置清單。

  2. 以滑鼠右鍵按兩下IoT Edge裝置的名稱,然後選取 [ 建立單一裝置的部署]。

  3. 選取 config 資料夾中的deployment.amd64.json檔案,然後選取 [Edge 部署指令清單]。 請勿使用deployment.template.json檔案。

  4. 在您的裝置下,展開 [模組 ] 以查看已部署和執行的模組清單。 選取 [重新整理] 按鈕。 您應該會看到新的分類器和 cameraCapture模組與$edgeAgent$edgeHub一起執行。

您也可以檢查所有模組是否已在裝置本身上啟動並執行。 在您的 IoT Edge 裝置上,執行下列命令以查看模組的狀態。

iotedge list

模組可能需要幾分鐘的時間才能啟動。 IoT Edge 執行時間必須接收新的部署指令清單、從容器運行時間提取模組映像,然後啟動每個新模組。

檢視分類結果

有兩種方式可以檢視模組的結果,無論是在裝置本身產生和傳送訊息時,還是從Visual Studio Code,當訊息到達 IoT 中樞 時。

從您的裝置,檢視 cameraCapture 模組的記錄,以查看傳送的訊息,以及 IoT 中樞 收到的確認訊息。

iotedge logs cameraCapture

例如,您應該會看到如下所示的輸出:

admin@vm:~$ iotedge logs cameraCapture
Simulated camera module for Azure IoT Edge. Press Ctrl-C to exit.
The sample is now sending images for processing and will indefinitely.
Response from classification service: (200) {"created": "2023-07-13T17:38:42.940878", "id": "", "iteration": "", "predictions": [{"boundingBox": null, "probability": 1.0, "tagId": "", "tagName": "hemlock"}], "project": ""}

Total images sent: 1
Response from classification service: (200) {"created": "2023-07-13T17:38:53.444884", "id": "", "iteration": "", "predictions": [{"boundingBox": null, "probability": 1.0, "tagId": "", "tagName": "hemlock"}], "project": ""}

您也可以從 Visual Studio Code 檢視訊息。 以滑鼠右鍵按兩下IoT Edge裝置的名稱,然後選取 [ 開始監視內建事件端點]。

[IoTHubMonitor] [2:43:36 PM] Message received from [vision-device/cameraCapture]:
{
  "created": "2023-07-13T21:43:35.697782",
  "id": "",
  "iteration": "",
  "predictions": [
    {
      "boundingBox": null,
      "probability": 1,
      "tagId": "",
      "tagName": "hemlock"
    }
  ],
  "project": ""
}

注意

一開始,您可能會在 cameraCapture 模組的輸出中看到連線錯誤。 這是因為部署和啟動模組之間的延遲。

cameraCapture 模組會自動重新嘗試連線,直到成功為止。 成功連線之後,您會看到預期的影像分類訊息。

從cameraCapture模組傳送為訊息的 自訂視覺 模組結果,包括影像屬於 hemlock 或櫻桃樹的機率。 由於影像是 hemlock,您應該會看到機率為 1.0。

清除資源

如果您打算繼續閱讀下一篇建議的文章,您可以保留您所建立的資源和組態並重複使用它們。 您也可以繼續使用與測試裝置相同的 IoT Edge 裝置。

否則,您可以刪除本文中使用的本機設定和 Azure 資源,以避免產生費用。

刪除 Azure 資源

刪除 Azure 資源和資源群組是無法回復的動作。 請確定您不會不小心刪除錯誤的資源群組或資源。 如果您在現有資源群組內建立IoT中樞,且該資源群組具有您想要保留的資源,請只刪除IoT中樞資源本身,而不是資源群組。

若要刪除資源:

  1. 登入 Azure 入口網站,然後選取 [資源群組]。

  2. 選取包含IoT Edge測試資源的資源群組名稱。

  3. 檢閱資源群組中包含的資源清單。 如果您想要刪除所有資源群組,您可以選取 [ 刪除資源群組]。 如果您想要只刪除其中一些資源,您可以按下每個資源來個別刪除它們。

下一步

在本教學課程中,您已將 自訂視覺 模型定型,並將其部署為模組至 IoT Edge 裝置。 然後,您建置了可查詢影像分類服務的模組,並將其結果回報回 IoT 中樞。

繼續進行下一個教學課程,以瞭解 Azure IoT Edge 可協助您將數據轉換成邊緣商業見解的其他方式。