다음을 통해 공유


자습서: Custom Vision Service를 사용하여 에지에서 이미지 분류 수행

적용 대상:IoT Edge 1.5 확인 표시 IoT Edge 1.5

중요합니다

IoT Edge 1.5 LTS는 지원되는 릴리스입니다. IoT Edge 1.4 LTS는 2024년 11월 12일부터 수명이 종료됩니다. 이전 릴리스에 있는 경우 IoT Edge 업데이트를 참조하세요.

Azure IoT Edge는 클라우드에서 에지로 워크로드를 이동하여 IoT 솔루션을 보다 효율적으로 만듭니다. 이 기능은 Computer Vision 모델과 같이 대량의 데이터를 처리하는 서비스에 적합합니다. Azure AI Custom Vision을 사용하면 사용자 지정 이미지 분류자를 빌드하고 이를 디바이스에 컨테이너로 배포할 수 있습니다. 이러한 두 서비스를 함께 사용하면 사용자가 먼저 모든 데이터를 오프사이트로 전송하지 않고 이미지 또는 비디오 스트림에서 인사이트를 찾을 수 있습니다. Custom Vision은 이미지를 학습된 모델과 비교하여 인사이트를 생성하는 분류자를 제공합니다.

예를 들어 IoT Edge 디바이스의 Custom Vision은 고속도로의 트래픽이 평소보다 높거나 낮은지 또는 주차장에 연속으로 사용 가능한 주차장이 있는지 여부를 결정할 수 있습니다. 작업을 수행하기 위해 다른 서비스와 이러한 정보를 공유할 수 있습니다.

이 자습서에서는 다음을 하는 방법을 알아볼 수 있습니다.

  • Custom Vision을 사용하여 이미지 분류자 빌드
  • 디바이스에서 Custom Vision 웹 서버를 쿼리하는 IoT Edge 모듈을 개발합니다.
  • 이미지 분류자 결과를 IoT Hub로 보냅니다.

다이어그램 - 자습서 아키텍처, 분류자 준비 및 배포

Azure 계정이 없는 경우 시작하기 전에 체험 계정을 만듭니다.

필수 조건

이 자습서는 Raspberry Pi 3의 Custom Vision 및 Azure IoT Edge 샘플 프로젝트의 단순화된 버전입니다. 클라우드 VM에서 실행되며, 정적 이미지를 사용하여 이미지 분류자를 학습하고 테스트합니다. 이는 IoT Edge의 Custom Vision을 새로운 사용자에게 도움이 됩니다. 샘플 프로젝트는 물리적 하드웨어를 사용하고 라이브 카메라 피드를 설정하여 이미지 분류자를 학습 및 테스트합니다. 이는 보다 상세하고 실제 시나리오를 탐색하는 사람에게 유용합니다.

Custom Vision을 사용하여 이미지 분류자 빌드

이미지 분류자를 빌드하려면 Custom Vision 프로젝트를 만들고 학습 이미지를 제공합니다. 이 섹션에서 수행하는 단계에 대한 자세한 내용은 Custom Vision을 사용하여 분류자를 빌드하는 방법을 참조하세요.

이미지 분류자를 빌드하고 학습한 후 Docker 컨테이너로 내보내고 IoT Edge 디바이스에 배포합니다.

새 프로젝트 만들기

  1. 웹 브라우저에서 Custom Vision 웹 페이지로 이동합니다.

  2. 로그인을 선택하고 Azure 리소스에 액세스하는 데 사용하는 동일한 계정으로 로그인합니다.

  3. 새 프로젝트를 선택합니다.

  4. 다음 값을 사용하여 프로젝트를 만듭니다.

    필드
    속성 EdgeTreeClassifier와 같은 프로젝트의 이름을 제공합니다.
    설명 선택적인 프로젝트 설명입니다.
    리소스 Custom Vision Service 리소스를 포함하는 Azure 리소스 그룹 중 하나를 선택하거나 아직 추가하지 않은 경우 새로 만듭니다.
    프로젝트 형식: 분류
    분류 형식: 다중 클래스(이미지당 단일 태그)
    도메인 일반(압축)
    기능 내보내기 기본 플랫폼(TensorFlow, CoreML, ONNX, ...)
  5. 프로젝트 만들기를 선택합니다.

이미지 업로드 및 분류자 학습

이미지 분류자를 만들려면 학습 이미지와 테스트 이미지 집합이 필요합니다.

  1. Cognitive-CustomVision-Windows 리포지토리의 샘플 이미지를 로컬 개발 머신으로 복제 또는 다운로드합니다.

    git clone https://github.com/Microsoft/Cognitive-CustomVision-Windows.git
    
  2. Custom Vision 프로젝트로 돌아가고 이미지 추가를 선택합니다.

  3. 로컬로 복제한 git 리포지토리를 찾고, 첫 번째 이미지 폴더, Cognitive-CustomVision-Windows / Samples / Images / Hemlock으로 이동합니다. 폴더에서 10개의 이미지를 모두 선택한 다음 열기를 선택합니다.

  4. 이 이미지 그룹에 태그 헴록 을 추가한 다음 Enter 키를 눌러 태그를 적용합니다.

  5. 10개의 파일 업로드를 선택합니다.

    Custom Vision에 hemlock 태그가 지정된 파일 업로드

  6. 이미지가 성공적으로 업로드되면 완료를 선택합니다.

  7. 이미지 추가를 다시 선택합니다.

  8. 두 번째 이미지 폴더, Cognitive-CustomVision-Windows / Samples / Images / Japanese Cherry를 찾습니다. 폴더에서 10개의 모든 이미지를 선택한 다음, 열기를 선택합니다.

  9. 태그 japanese cherry를 이 이미지 그룹에 추가하고 입력 키를 눌러 태그를 적용합니다.

  10. 10개의 파일 업로드를 선택합니다. 이미지가 성공적으로 업로드되면 완료를 선택합니다.

  11. 두 이미지 집합에 태그를 지정하고 업로드한 후 학습 을 선택하여 분류자를 학습합니다.

분류자 내보내기

  1. 분류자를 학습한 후 분류자의 성능 페이지에서 내보내기를 선택합니다.

    학습된 이미지 분류자 내보내기

  2. 플랫폼에 대해 DockerFile을 선택합니다.

  3. 버전에 대해 Linux를 선택합니다.

  4. 내보내기를 선택합니다.

  5. 내보내기가 완료되면 다운로드 를 선택하고 컴퓨터에 로컬로 .zip 패키지를 저장합니다. 패키지에서 모든 파일을 추출합니다. 이러한 파일을 사용하여 이미지 분류 서버를 포함하는 IoT Edge 모듈을 만듭니다.

이 시점에 도달하면 Custom Vision 프로젝트 만들기 및 학습을 완료했습니다. 다음 섹션에서는 내보낸 파일을 사용하지만 Custom Vision 웹 페이지 사용은 완료했습니다.

IoT Edge 솔루션 만들기

이제 개발 머신에 이미지 분류자의 컨테이너 버전에 대한 파일이 있습니다. 이 섹션에서는 IoT Edge 모듈로 실행되도록 이미지 분류자 컨테이너를 설정합니다. 또한 요청을 분류자로 게시하고 결과를 IoT Hub에 메시지로 보내는 두 번째 모듈을 만듭니다.

새 솔루션 만들기

솔루션은 단일 IoT Edge 배포에 대해 여러 모듈을 개발 및 구성하는 논리적 방법입니다. 솔루션에는 하나 이상의 모듈에 대한 코드와 IoT Edge 디바이스에서 모듈을 구성하는 방법을 선언하는 배포 매니페스트가 포함되어 있습니다. Azure IoT Edge CLI(Dev Tool 명령줄) 개발 도구를 사용하여 솔루션을 만듭니다. 이 도구를 사용하는 가장 간단한 방법은 Docker를 사용하여 IoT Edge 개발자 컨테이너를 실행하는 것입니다.

  1. 분류자라는 디렉터리를 만들고 디렉터리로 변경합니다.

    mkdir CustomVisionSolution
    cd CustomVisionSolution
    
  2. iotedgedev tool init 명령을 실행하여 새 IoT Edge 솔루션을 만듭니다. IoT Edge Dev Docker 컨테이너에서 다음 명령을 입력합니다.

    iotedgedev solution init --template python --module classifier
    

    iotedgedev solution init 스크립트는 다음을 포함한 여러 단계를 완료하라는 메시지를 표시합니다.

    • Azure에 대한 인증
    • Azure 구독 선택
    • 리소스 그룹 선택 또는 만들기
    • Azure IoT Hub 선택 또는 만들기
    • Azure IoT Edge 디바이스 선택 또는 만들기

    이 명령은 현재 작업 디렉터리에 분류자 라는 모듈을 사용하여 새 IoT Edge 솔루션을 만듭니다.

  3. Visual Studio Code에서 솔루션을 엽니다.

이미지 분류자 추가

Visual Studio Code의 Python 모듈 템플릿은 IoT Edge를 테스트하도록 실행할 수 있는 몇 가지 샘플 코드를 포함합니다. 이 시나리오에서는 해당 코드를 사용하지 않습니다. 대신 이 섹션의 단계를 사용하여 샘플 코드를 이전에 내보낸 이미지 분류자 컨테이너로 바꿉니다.

  1. 파일 탐색기에서 다운로드 및 추출한 Custom Vision 패키지를 찾습니다. 추출된 패키지에서 모든 콘텐츠를 복사합니다. 두 개의 폴더, appazureml과 두 개의 파일, DockerfileREADME여야 합니다.

  2. 파일 탐색기에서 Visual Studio Code에서 IoT Edge 솔루션을 만들도록 설정한 디렉터리를 찾습니다.

  3. 분류자 모듈 폴더를 엽니다. 이전 섹션에서 제안된 이름을 사용한 경우 폴더 구조는 CustomVisionSolution / modules / classifier와 같습니다.

  4. 파일을 분류자 폴더로 붙여넣습니다.

  5. Visual Studio Code 창으로 돌아갑니다. 솔루션 작업 영역은 이제 모듈 폴더에 이미지 분류자 파일을 표시해야 합니다.

  6. 원래 Dockerfile.amd64 파일을 삭제한 후, 사용자 지정 비전 패키지의 Dockerfile 파일을 Dockerfile.amd64로 이름을 변경하여 교체하십시오.

  7. 변경 내용을 저장합니다.

시뮬레이션된 카메라 모듈 만들기

실제 사용자 지정 비전 배포에서 카메라는 라이브 이미지 또는 비디오 스트림을 제공합니다. 이 시나리오의 경우 이미지 분류자에 테스트 이미지를 전송하는 모듈을 작성하여 카메라를 시뮬레이션합니다.

이 섹션에서는 동일한 CustomVisionSolution에 새 모듈을 추가하고 시뮬레이션된 카메라를 만드는 코드를 제공합니다.

  1. iotedgedev 도구를 사용하여 솔루션에 새 모듈을 추가합니다. 이 명령은 솔루션의 모듈 폴더에 cameracapture라는 새 폴더를 만듭니다.

    iotedgedev solution add --template python cameracapture
    
  2. 모듈 / 폴더에서 main.py 파일을 엽니다.

  3. 전체 파일을 다음 코드로 바꿉니다. 이 샘플 코드는 분류자 모듈에서 실행되는 이미지 처리 서비스에 POST 요청을 보냅니다. 이 모듈 컨테이너를 요청에 사용할 샘플 이미지로 제공합니다. 그런 다음, IoT Hub 메시지로 응답을 패키지하고 출력 큐에 보냅니다.

    # 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 / Samples / Images / Test에 위치한 테스트 이미지로 이동합니다.

  2. test_image.jpg 복사

  3. IoT Edge 솔루션 디렉터리로 이동하여 테스트 이미지를 모듈 / 폴더에 붙여넣습니다. 이미지는 이전 섹션에서 편집한 main.py 파일과 동일한 폴더에 있어야 합니다.

  4. Visual Studio Code에서 cameracapture 모듈에 대한 Dockerfile.amd64 파일을 엽니다.

  5. 작업 디렉터리, WORKDIR /app을 설정하는 줄 뒤에 다음 코드 줄을 추가합니다.

    ADD ./test_image.jpg .
    
  6. Dockerfile을 저장합니다.

배포 매니페스트 준비

지금까지 이 자습서에서는 트리 이미지를 분류하는 사용자 지정 비전 모델을 학습하고 해당 모델을 IoT Edge 모듈로 패키징했습니다. 그런 다음 이미지 분류 서버를 쿼리하고 결과를 IoT Hub에 보고하는 두 번째 모듈을 만들었습니다. 이제 이 두 모듈을 함께 시작하고 실행하는 방법을 IoT Edge 디바이스에 알려주는 배포 매니페스트를 만들 준비가 되었습니다.

Visual Studio Code용 IoT Edge 확장은 배포 매니페스트를 만들 수 있도록 각 IoT Edge 솔루션에서 템플릿을 제공합니다.

  1. 솔루션 폴더에서 deployment.template.json 파일을 엽니다.

  2. 배포 매니페스트의 모듈에 대한 레지스트리 자격 증명을 설정합니다.

    "registryCredentials": {
        "<registryName>": {
            "username": "<AcrUsername>",
            "password": "<AcrPassword>",
            "address": "<registryName>.azurecr.io"
        }
    }
    

    registryName<을 Azure Container Registry의 이름으로 바꾸고 AcrUsername 및 AcrPassword를 레지스트리의 사용자 이름 및 암호로 바꿉>다.<><> 이러한 값은 Azure Portal에서 Azure 컨테이너 레지스트리의 액세스 키 섹션에서 찾을 수 있습니다.

  3. 만든 모듈 2개, 분류자카메라 캡처, 기본적으로 포함된 세 번째 모듈인 tempSensor가 포함된 모듈 섹션을 찾습니다.

  4. tempSensor 모듈과 모든 매개 변수를 삭제합니다. 이 모듈은 테스트 시나리오에 대한 샘플 데이터를 제공하지만 이 배포에는 필요하지 않습니다.

  5. 이미지 분류 모듈을 classifier 이외의 이름으로 지정한 경우 이름을 확인하고 모두 소문자인지 확인합니다. cameracapture 모듈은 모든 요청의 형식을 소문자로 지정하는 요청 라이브러리를 사용하여 분류자 모듈을 호출하고 IoT Edge는 대/소문자를 구분합니다.

  6. 각 시스템 모듈 edgeAgentedgeHub에 대해 createOptions 값을 문자열화된 버전으로 변경합니다. 다음은 그 예입니다.

    "createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"
    
  7. 각 시스템 모듈 edgeAgentedgeHub에 대해 이미지 버전을 최신 버전 1.5로 변경합니다. 다음은 그 예입니다.

    "image": "mcr.microsoft.com/azureiotedge-agent:1.5",
    "image": "mcr.microsoft.com/azureiotedge-hub:1.5",
    
  8. 분류자 모듈의 createOptions 매개 변수를 문자열화된 버전으로 업데이트합니다. 다음은 그 예입니다.

    "createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"
    
  9. cameracapture 모듈에 대한 createOptions 매개 변수를 다음 JSON으로 업데이트합니다. 이 정보는 main.py 프로세스에서 검색되는 모듈 컨테이너에 환경 변수를 만듭니다. 배포 매니페스트에 이 정보를 포함하면 모듈 이미지를 다시 빌드하지 않고도 이미지 또는 엔드포인트를 변경할 수 있습니다.

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

    Custom Vision 모듈을 classifier 이외의 이름으로 지정한 경우 이미지 처리 엔드포인트 값을 일치하도록 업데이트합니다.

    예를 들어 분류자cameracapture 구성은 다음과 유사해야 합니다.

    "modules": {
        "classifier": {
            "version": "1.0",
            "type": "docker",
            "status": "running",
            "restartPolicy": "always",
            "settings": {
                "image": "${MODULES.classifier}",
                "createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"
            }
        },
        "cameracapture": {
            "version": "1.0",
            "type": "docker",
            "status": "running",
            "restartPolicy": "always",
            "settings": {
                "image": "${MODULES.cameracapture}",
                "createOptions": "{\"Env\":[\"IMAGE_PATH=test_image.jpg\",\"IMAGE_PROCESSING_ENDPOINT=http://classifier/image\"]}"
            }
        }
    }
    
  10. deployment.template.json 파일을 저장합니다.

IoT Edge 솔루션 빌드 및 푸시

두 모듈을 만들고 배포 매니페스트 템플릿을 구성한 후 컨테이너 이미지를 빌드하고 컨테이너 레지스트리에 푸시합니다.

이미지가 레지스트리에 있으면 솔루션을 IoT Edge 디바이스에 배포할 수 있습니다. IoT Hub를 통해 디바이스에서 모듈을 설정할 수 있습니다. 이 섹션에서는 IoT Hub에 대한 액세스를 설정한 다음, Azure CLI를 사용하여 IoT Edge 디바이스에 솔루션을 배포합니다.

먼저 솔루션을 빌드하고 컨테이너 레지스트리에 푸시합니다.

  1. 보기>터미널을 선택하여 Visual Studio Code 통합 터미널을 엽니다.

  2. Azure Container Registry의 사용자 이름, 암호 및 로그인 서버를 사용하여 터미널에 다음 명령을 입력하여 Docker에 로그인합니다. Azure Portal에서 레지스트리의 액세스 키 섹션에서 이러한 값을 검색할 수 있습니다.

    docker login -u <AcrUsername> -p <AcrPassword> <AcrLoginServer>
    

    --password-stdin 사용을 권장하는 보안 경고가 표시될 수 있습니다. 이 모범 사례는 프로덕션 시나리오에 권장되지만 이 자습서에는 포함되지 않습니다. 자세한 내용은 docker login 참조를 참조하세요.

  3. 모듈의 Dockerfile을 사용하여 모듈 Docker 이미지를 빌드하고 태그를 지정합니다.

    docker build --rm -f "<DockerFilePath>" -t <ImageNameAndTag> "<ContextPath>" 
    

    예를 들어 로컬 레지스트리 또는 Azure 컨테이너 레지스트리에 대한 이미지를 빌드하려면 다음 명령을 사용합니다.

    
    # Build and tag the image for an Azure Container Registry. Replace <AcrRegistryName> with your own registry name.
    
    docker build --rm -f "./modules/classifier/Dockerfile.amd64" -t <AcrRegistryName>.azurecr.io/classifier:0.0.1-amd64 "./modules/classifier"
    docker build --rm -f "./modules/cameracapture/Dockerfile.amd64" -t <AcrRegistryName>.azurecr.io/cameracapture:0.0.1-amd64 "./modules/cameracapture"
    

모듈 Docker 이미지 푸시

레지스트리의 스토리지에 컨테이너 이미지를 푸시할 수 있도록 Docker에 컨테이너 레지스트리 자격 증명을 제공합니다.

  1. ACR(Azure Container Registry) 자격 증명을 사용하여 Docker에 로그인합니다.

    docker login -u <AcrUsername> -p <AcrPassword> <AcrLoginServer>
    

    --password-stdin 사용을 권장하는 보안 경고가 표시될 수 있습니다. 이 모범 사례는 프로덕션 시나리오에 적합하지만 이 자습서의 범위에는 포함되지 않습니다. 자세한 내용은 docker login 참조를 참조하세요.

  2. Azure Container Registry에 로그인합니다. 명령을 사용하려면 az해야 합니다. 이 명령은 설정>액세스 키의 컨테이너 레지스트리에 있는 사용자 이름과 암호를 요청합니다.

    az acr login -n <AcrRegistryName>
    

    이 자습서의 어느 시점에서든 로그아웃한 경우 계속 진행하려면 Docker 및 Azure Container Registry 로그인 단계를 반복하세요.

  3. 모듈 이미지를 로컬 레지스트리 또는 컨테이너 레지스트리에 푸시합니다.

    docker push <ImageName>
    

    다음은 그 예입니다.

    # Push the Docker image to an Azure Container Registry. Replace <AcrRegistryName> with your Azure Container Registry name.
    
    az acr login --name <AcrRegistryName>
    docker push <AcrRegistryName>.azurecr.io/classifier:0.0.1-amd64
    docker push <AcrRegistryName>.azurecr.io/cameracapture:0.0.1-amd64
    

배포 템플릿 업데이트

deployment.template.json 파일을 컨테이너 레지스트리 이미지 위치로 업데이트합니다. 이미지 값을 레지스트리에 푸시한 이미지로 변경합니다. 예를 들어 <AcrRegistryName>을 분류자 및 cameracapture 모듈의 이미지 값에서 레지스트리 이름으로 바꿉니다.

"classifier": {
    "version": "1.0",
    "type": "docker",
    "status": "running",
    "restartPolicy": "always",
    "settings": {
        "image": "<AcrRegistryName>.azurecr.io/classifier:0.0.1-amd64",
        "createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"
    },
    "cameracapture": {
        "version": "1.0",
        "type": "docker",
        "status": "running",
        "restartPolicy": "always",
        "settings": {
            "image": "<AcrRegistryName>.azurecr.io/cameracapture:0.0.1-amd64",
            "createOptions": "{\"Env\":[\"IMAGE_PATH=test_image.jpg\",\"IMAGE_PROCESSING_ENDPOINT=http://classifier/image\"]}"
        }
    }
}

최종 배포 매니페스트는 다음과 유사합니다.

{
  "$schema-template": "4.0.0",
  "modulesContent": {
    "$edgeAgent": {
      "properties.desired": {
        "schemaVersion": "1.1",
        "runtime": {
          "type": "docker",
          "settings": {
            "minDockerVersion": "v1.25",
            "loggingOptions": "",
            "registryCredentials": {
              "<AcrRegistryName>": {
                "username": "<AcrUserName>",
                "password": "<AcrPassword>",
                "address": "<AcrRegistryName>.azurecr.io"
              }
            }
          }
        },
        "systemModules": {
          "edgeAgent": {
            "type": "docker",
            "settings": {
              "image": "mcr.microsoft.com/azureiotedge-agent:1.5",
              "createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"
            }
          },
          "edgeHub": {
            "type": "docker",
            "status": "running",
            "restartPolicy": "always",
            "settings": {
              "image": "mcr.microsoft.com/azureiotedge-hub:1.5",
              "createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"
            }
          }
        },
        "modules": {
          "classifier": {
            "version": "1.0",
            "type": "docker",
            "status": "running",
            "restartPolicy": "always",
            "settings": {
              "image": "<AcrRegistryName>.azurecr.io/classifier:0.0.1-amd64",
              "createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"
            }
          },
          "cameracapture": {
            "version": "1.0",
            "type": "docker",
            "status": "running",
            "restartPolicy": "always",
            "settings": {
              "image": "<AcrRegistryName>.azurecr.io/cameracapture:0.0.1-amd64",
              "createOptions": "{\"Env\":[\"IMAGE_PATH=test_image.jpg\",\"IMAGE_PROCESSING_ENDPOINT=http://classifier/image\"]}"
            }
          }
        }
      }
    },
    "$edgeHub": {
      "properties.desired": {
        "schemaVersion": "1.2",
        "routes": {
          "sensorToclassifier": "FROM /messages/modules/tempSensor/outputs/temperatureOutput INTO BrokeredEndpoint(\"/modules/classifier/inputs/input1\")",
          "classifierToIoTHub": "FROM /messages/modules/classifier/outputs/* INTO $upstream",
          "cameracaptureToIoTHub": "FROM /messages/modules/cameracapture/outputs/* INTO $upstream"
        },
        "storeAndForwardConfiguration": {
          "timeToLiveSecs": 7200
        }
      }
    }
  }
}

디바이스에 모듈 배포

빌드된 컨테이너 이미지가 컨테이너 레지스트리에 저장되어 있는지 확인합니다. 그런 다음, 시나리오에 대해 준비된 배포 매니페스트 deployment.template.json 사용하여 디바이스에 배포합니다.

IoT Edge Azure CLI set-modules 명령을 사용하여 모듈을 Azure IoT Hub에 배포합니다. 예를 들어 deployment.template.json 파일에 정의된 모듈을 IoT Edge 디바이스 <DeviceName의 IoT Hub >IotHubName<>에 배포하려면 다음 명령을 사용합니다. hub-name, device-idlogin IoT Hub 연결 문자열의 값을 원하는 값으로 바꿉니다.

az iot edge set-modules --hub-name <IotHubName> --device-id <DeviceName> --content ./deployment.template.json --login "HostName=my-iot-hub.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=<SharedAccessKey>"

Azure Portal에서 공유 액세스 키를 포함한 IoT Hub 연결 문자열을 찾을 수 있습니다. IoT Hub >보안 설정>공유 액세스 정책>iothubowner로 이동합니다.

IoT Edge 디바이스가 실행 중인지 확인합니다.

배포되어 실행 중인 모듈의 목록을 보려면 디바이스 아래에서 모듈을 확장합니다. 새로 고침 단추를 선택합니다. $edgeAgent 및 $edgeHub 함께 실행되는 새로운 분류자카메라 캡처 모듈이 표시됩니다.

모든 모듈이 디바이스 자체에서 실행되는지를 확인할 수도 있습니다. IoT Edge 디바이스에서 다음 명령을 실행하여 모듈의 상태를 확인합니다.

iotedge list

모듈이 시작되는 데 몇 분 정도 걸릴 수 있습니다. IoT Edge 런타임은 새 배포 매니페스트를 받고, 컨테이너 런타임에서 모듈 이미지를 끌어온 후 각 새 모듈을 시작해야 합니다.

분류 결과 보기

디바이스에서 cameracapture 모듈의 로그를 확인하여 보낸 메시지를 확인하고 IoT Hub에서 받은 메시지를 확인합니다.

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": ""}

참고 항목

처음에는 배포되는 모듈과 시작 사이의 지연으로 인해 cameracapture 모듈의 출력에 연결 오류가 표시될 수 있습니다.

cameracapture 모듈은 성공할 때까지 자동으로 연결을 다시 시도합니다. 성공적으로 연결되면 예상 이미지 분류 메시지가 표시됩니다.

Cameracapture 모듈에서 메시지로 전송된 Custom Vision 모듈의 결과에는 이미지가 헴록 또는 체리 트리일 가능성이 포함됩니다. 이미지가 헴록이므로 확률은 1.0으로 표시됩니다.

리소스 정리

다음 권장 문서를 계속 진행하려면 만든 리소스 및 구성을 유지하고 다시 사용합니다. 테스트 디바이스와 동일한 IoT Edge 디바이스를 계속 사용해도 됩니다.

그렇지 않으면 요금이 부과되지 않도록 이 문서에서 사용한 로컬 구성 및 Azure 리소스를 삭제합니다.

Azure 리소스 삭제

Azure 리소스와 리소스 그룹을 삭제하면 되돌릴 수 없습니다. 잘못된 리소스 그룹 또는 리소스를 자동으로 삭제하지 않도록 해야 합니다. 유지하려는 리소스가 있는 기존 리소스 그룹 내에 IoT Hub를 만든 경우 리소스 그룹이 아닌 IoT Hub 리소스 자체만 삭제합니다.

리소스를 삭제하려면:

  1. Azure Portal에 로그인한 다음, 리소스 그룹을 선택합니다.

  2. IoT Hub 테스트 리소스가 포함된 리소스 그룹 이름을 선택합니다.

  3. 리소스 그룹에 포함된 리소스 목록을 검토합니다. 모든 항목을 삭제하려는 경우리소스 그룹 삭제를 선택할 수 있습니다. 일부만 삭제하려는 경우 각 리소스를 선택하여 개별적으로 삭제할 수 있습니다.

다음 단계

이 자습서에서는 Custom Vision 모델을 학습하고 이를 모듈로 IoT Edge 디바이스에 배포했습니다. 그런 다음, 이미지 분류 서비스를 쿼리하고 IoT Hub에 결과를 다시 보고할 수 있는 모듈을 빌드했습니다.

Azure IoT Edge에서 데이터를 통해 비즈니스 통찰력을 얻는 데 도움이 되는 다른 방법을 알아보려면 다음 자습서를 진행합니다.