TensorRT 5 및 NVIDIA T4 GPU를 이용하여 규모에 맞게 TensorFlow 추론 실행

이 가이드에서는 NVIDIA TensorRT 5 및 T4 GPU에서 대규모로 추론을 실행하는 방법을 설명합니다. NVIDIA TensorRT™는 고성능 딥 러닝 추론을 위한 플랫폼입니다. 여기에는 딥 러닝 추론 애플리케이션에 짧은 지연 시간과 높은 처리량을 제공하는 딥 러닝 추론 최적화 도구와 런타임이 포함되어 있습니다.

이 가이드에서는 GPU 사용률에 따라 자동 확장 그룹을 사용하여 추론을 실행하기 위한 다중 영역 클러스터를 설정합니다.

개요

이 가이드는 다음을 소개합니다.

  • 개발 환경에 적합한 확장 가능한 머신러닝 추론 시스템을 Google Cloud에서 구현하기 위한 참조 아키텍처. 인프라 및 보안 요구사항은 환경마다 다르므로 이 가이드에 설명된 구성을 적절히 조정할 수 있습니다.
  • 가이드에서 TensorFlow 모델 및 기타 필수 구성요소를 설치하는 데 사용하는 스크립트가 포함된 GitHub 저장소.
  • TensorRT를 사용하여 TensorFlow 모델을 양자화하는 방법, 스크립트 배포 방법, 참조 아키텍처 배포 방법 안내
  • Cloud Load Balancing을 구성하는 방법 안내

이 가이드를 마치면 Cloud Storage에 선행 학습된 양자화된 모델과 웹 트래픽을 위해 앞쪽에 Cloud Load Balancing이 배치된 서로 다른 리전에 2개의 클러스터형 Compute Engine 인스턴스 그룹을 갖게 됩니다. 다음 다이어그램에서 이 아키텍처를 볼 수 있습니다.

이 가이드에 사용된 아키텍처

목표

  • 선행 학습된 그래프부터 시작합니다.
  • TensorRT로 모델을 최적화하고 다양한 최적화에서 모델 속도가 얼마나 향상되는지 확인합니다.
  • 모델을 완성한 후 TensorFlow, TensorFlow Serving, TensorRT 5가 사전 설치된 Compute Engine 딥 러닝 VM을 기반으로 클러스터를 만듭니다.

비용

이 가이드에서는 비용이 청구될 수 있는 다음과 같은 Google Cloud 구성요소를 사용합니다.

  • Compute Engine
  • Persistent Disk
  • Cloud Storage
  • 네트워킹
  • NVIDIA T4 GPU

프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요. Google Cloud를 처음 사용하는 사용자는 무료 체험판을 사용할 수 있습니다.

시작하기 전에

  1. Cloud Console에서 프로젝트 선택기 페이지로 이동합니다.

    프로젝트 선택기 페이지로 이동

  2. Cloud 프로젝트를 선택하거나 만듭니다.

  3. Google Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다. 프로젝트에 결제가 사용 설정되어 있는지 확인하는 방법을 알아보세요.

  4. Compute Engine and Cloud Logging API를 사용 설정합니다.

    API 사용 설정

  5. VM을 만들기 위한 GPU 할당량이 충분한지 확인합니다.

이 가이드를 마치면 만든 리소스를 삭제하여 비용이 계속 청구되지 않게 할 수 있습니다. 자세한 내용은 삭제를 참조하세요.

환경 준비

이 섹션에서는 리전, 영역과 같이 가이드 전반에 사용되는 값의 기본 설정을 수행합니다. 이 가이드에서는 us-central1을 기본 리전으로, us-central1-b를 기본 영역으로 사용합니다.

또한 모든 설정이 포함된 파일을 만들어 Cloud Shell을 다시 열고 설정을 다시 초기화해야 하는 경우에 자동으로 변수를 로드할 수 있도록 합니다.

  1. Cloud Shell을 엽니다.

    Cloud Shell 열기

  2. 기본 리전 및 영역을 설정합니다.

    gcloud compute project-info add-metadata \
        --metadata google-compute-default-region=us-central1,google-compute-default-zone=us-central1-a
    
  3. 셸을 다시 초기화합니다.

    gcloud init --console-only
    
  4. 처음 3개의 질문에 1을 누른 다음 마지막 질문에서 프로젝트 ID를 입력합니다.

TensorRT로 모델 최적화

  1. Cloud Shell에서 모델 준비에 사용할 수 있는 인스턴스를 만듭니다.

    export IMAGE_FAMILY="tf-latest-cu100"
    export INSTANCE_NAME="model-prep"
    
    gcloud compute instances create $INSTANCE_NAME \
        --image-family=$IMAGE_FAMILY \
        --machine-type=n1-standard-8 \
        --image-project=deeplearning-platform-release \
        --maintenance-policy=TERMINATE \
        --accelerator="type=nvidia-tesla-t4,count=1" \
        --metadata="install-nvidia-driver=True"
    

    GPU는 하나만 있어도 다양한 TensorRT 최적화 모델을 비교하고 단일 GPU가 얼마나 빠른지 파악하기에 충분합니다.

  2. VM 인스턴스를 만든 후 ssh를 사용하여 VM에 연결합니다.

  3. 공식 TensorFlow 저장소에서 인스턴스에 resnetv2 모델을 다운로드하여 TensorRT 최적화를 테스트합니다.

    wget -q http://download.tensorflow.org/models/official/resnetv2_imagenet_frozen_graph.pb
    

TensorRT는 추론 속도를 개선할 수 있지만 그 외의 개선은 양자화가 필요합니다. 선형 모델 양자화는 가중치와 활성화를 부동 소수점에서 정수로 변환합니다. 예를 들어 모델의 초기 가중치가 FP32(부동 소수점 32비트)인 경우 정밀도를 줄이면 INT8을 사용할 수 있습니다. 그러나 양자화에는 단점도 있습니다. 저장소 표현을 줄이면 모델의 정확도가 약간 줄어들 수 있습니다. 그러나 FP32에서 FP16으로 전환하는 것은 사실상 손실이 없습니다.

속도(정밀도를 우선시)와 정확도 간의 적절한 절충안을 선택하려면 어떻게 해야 할까요? 이 작업을 처리하는 기존 코드가 있습니다. 이 코드는 속도와 다른 측정항목 대비 정확도를 측정할 수 있습니다. 이 테스트는 이미지 인식 모델로 제한되지만, 이러한 코드 기반의 커스텀 테스트를 실시하기는 어렵지 않습니다.

  1. Cloud Shell에서 커스텀 테스트를 다운로드하여 구현합니다.

    git clone https://github.com/tensorflow/models.git
    cd models
    git checkout f0e10716160cd048618ccdd4b6e18336223a172f
    touch research/__init__.py
    touch research/tensorrt/__init__.py
    cp research/tensorrt/labellist.json .
    cp research/tensorrt/image.jpg .
    
  2. 실행할 테스트를 준비합니다.

    python -m research.tensorrt.tensorrt \
        --frozen_graph=$HOME/resnetv2_imagenet_frozen_graph.pb \
        --image_file=$HOME/models/image.jpg \
        --native --fp32 --fp16 --int8 \
        --output_dir=$HOME
    

    이 테스트를 실행하려면 고정 그래프(앞에서 다운로드한 resnetv2 모델)와 테스트할 다른 양자화 모드에 대한 인수가 필요합니다. 이 명령어를 완료하는 데는 다소 시간이 걸립니다.

    실행이 완료되면 추론 결과를 다른 버전의 그래프로 비교한 결과가 출력됩니다.

    다른 버전의 그래프로 추론 결과 비교

    FP32의 결과와 FP16의 결과가 동일하여 같은 정확도를 나타냅니다. 따라서 TensorRT 사용에 문제가 없다면 FP16을 바로 사용할 수 있습니다. 반대로 INT8은 약간 덜 정확한 결과를 표시합니다.

  3. 정확도 수치를 표시합니다.

    cat $HOME/log.txt
    

    이 명령어는 다음 출력을 생성합니다.

    규모에 맞게 로그 추론

TensorRT 5는 모두 네이티브와 비교하여 다음 결과를 표시합니다.

  • FP32의 경우 처리량이 319.1fps에서 428.2fps로 약 34% 향상되었습니다.
  • FP16의 경우 처리량이 319.1fps에서 979.6fps로 약 207% 향상되었습니다.
  • INT8의 경우 처리량이 319.1fps에서 1519.5fps로 약 376% 향상되었습니다.

이러한 결과를 통해 얻을 수 있는 정보는 다음과 같습니다.

  • 네이티브에서 TensorRT로 전환하면 불확실성에 영향을 줍니다. 하지만 약간의 손해가 있어도 문제가 없다면 FP16으로 직접 전환할 수도 습니다.
  • INT8은 매우 빠르지만 정확도 손실이 두드러집니다.

다음 섹션에서는 INT8 모델을 사용합니다.

커스텀 모델을 TensorRT로 변환

모델을 TensorRT 그래프로 변환하려면 SavedModel이 필요합니다.

  1. Cloud Shell에서 다음 선행 학습된 저장 모델을 다운로드합니다.

    wget http://download.tensorflow.org/models/official/20181001_resnet/savedmodels/resnet_v2_fp32_savedmodel_NCHW.tar.gz
    tar -xzvf resnet_v2_fp32_savedmodel_NCHW.tar.gz
    
  2. 고정 모델을 TensorRT 그래프로 변환하는 Python 스크립트를 만듭니다.

    cat <<EOF > convert_to_rt.py
    import tensorflow.contrib.tensorrt as trt
    import argparse
    
    parser = argparse.ArgumentParser(description="Converts TF SavedModel to the TensorRT enabled graph.")
    
    parser.add_argument("--input_model_dir", required=True)
    parser.add_argument("--output_model_dir", required=True)
    parser.add_argument("--batch_size", type=int, required=True)
    parser.add_argument("--precision_mode", choices=["FP32", "FP16", "INT8"], required=True)
    
    args = parser.parse_args()
    
    trt.create_inference_graph(
        None, None, max_batch_size=args.batch_size,
        input_saved_model_dir=args.input_model_dir,
        output_saved_model_dir=args.output_model_dir,
        precision_mode=args.precision_mode)
    EOF
    
  3. 모델을 TensorRT 그래프로 변환합니다.

    python ./convert_to_rt.py \
        --input_model_dir=$HOME/resnet_v2_fp32_savedmodel_NCHW/1538687196 \
        --output_model_dir=$HOME/resnet_v2_int8_NCHW/00001 \
        --batch_size=128 \
        --precision_mode="INT8"
    

    이제 $HOME/resnet_v2_int8_NCHW/00001 폴더에 INT8 모델이 있습니다.

  4. 추론을 실행하여 모든 것이 작동하는지 확인합니다.

    tensorflow_model_server --model_base_path=$HOME/resnet_v2_int8_NCHW/ --rest_api_port=8888
    
  5. 작동하는지 확인하기 위해 다음 샘플 입력을 전송합니다.

    curl -X POST localhost:8888/v1/models/default:predict -d '{"instances": [[[[1,1,1]]]]}'
    
  6. curl 명령어의 결과가 표시되는 경우 Ctrl+C를 눌러 실행되는 추론을 종료합니다.

  7. 클러스터에서 최적화된 모델을 사용하려면 모델을 Cloud Storage에 업로드하고 [GCS_PATH]를 Cloud Storage 버킷 이름으로 바꿉니다.

    tar -zcvf model.tar.gz ./resnet_v2_int8_NCHW/
    export GCS_PATH=[GCS_PATH]
    gsutil cp model.tar.gz $GCS_PATH
    

    다음에 이 모델을 사용할 때 이 전체 프로세스를 반복할 필요가 없습니다. 대신 Cloud Storage 버킷에 있는 INT8 고정 그래프를 사용할 수 있습니다.

    gs://solutions-public-assets/tensorrt-t4-gpu/model.tar.gz
    

클러스터 설정

이제 Cloud Storage에 모델이 있으므로 클러스터를 만들 수 있습니다. 첫 번째 단계는 VM 템플릿을 만드는 것입니다. 클러스터는 VM 템플릿을 사용하여 새 인스턴스를 만듭니다.

  1. Cloud Shell에서 클러스터를 설정하는 데 필요한 코드를 다운로드합니다.

    git clone https://github.com/GoogleCloudPlatform/tensorflow-inference-tensorrt5-t4-gpu.git
    
  2. VM 템플릿을 만들고 [PROJECT_NAME]을 프로젝트 이름으로 바꿉니다.

    export PROJECT_NAME=[PROJECT_NAME]
    export INSTANCE_TEMPLATE_NAME="tf-inference-template"
    export IMAGE_FAMILY="tf-latest-cu100"
    
    gcloud beta compute --project=$PROJECT_NAME instance-templates create $INSTANCE_TEMPLATE_NAME \
        --machine-type=n1-standard-16 \
        --maintenance-policy=TERMINATE \
        --accelerator=type=nvidia-tesla-t4,count=4 \
        --min-cpu-platform=Intel\ Skylake \
        --tags=http-server,https-server \
        --image-family=$IMAGE_FAMILY \
        --image-project=deeplearning-platform-release \
        --boot-disk-size=100GB \
        --boot-disk-type=pd-ssd \
        --boot-disk-device-name=$INSTANCE_TEMPLATE_NAME \
        --metadata startup-script-url=gs://solutions-public-assets/tensorrt-t4-gpu/start_agent_and_inf_server.sh
    

    metadata 매개변수는 VM 템플릿으로 만든 모든 인스턴스에 설치되는 시작 스크립트를 지정합니다. 시작 스크립트는 VM 인스턴스가 시작될 때 다음 절차를 수행합니다.

    • NVIDIA 드라이버를 설치합니다.
    • GPU 사용량을 모니터링하는 모니터링 에이전트를 설치합니다.
    • 모델을 다운로드합니다.
    • 추론 서비스를 시작합니다.

    템플릿이 준비되면 관리형 인스턴스 그룹을 만들 수 있습니다. 그룹은 확장 그룹이 아니며 상태 확인을 하지 않습니다. 지정된 영역에 2개의 인스턴스가 실행 중이라는 것만 유일하게 보장하는 그룹을 만듭니다.

  3. 관리형 인스턴스 그룹을 만듭니다.

    gcloud compute instance-groups managed create $INSTANCE_GROUP_NAME \
        --template $INSTANCE_TEMPLATE_NAME \
        --base-instance-name deeplearning-instances \
        --size 2 \
        --zones us-central1-a,us-central1-b
    

    INSTANCE_TEMPLATE_NAME 값은 이전 단계에서 설정한 인스턴스의 이름입니다. GPU의 가용성(모든 GPU를 모든 영역에서 사용할 수 있는 것은 아님)과 할당량을 기준으로 영역을 선택합니다.

    그룹을 만드는 데는 다소 시간이 걸립니다.

  4. 다음 명령어를 실행하여 진행 상황을 확인합니다.

    gcloud compute instance-groups managed list-instances $INSTANCE_GROUP_NAME --region us-central1
    

    출력은 다음과 같이 표시됩니다.

    그룹을 만드는 중

    만들기가 완료되면 다음과 같이 표시됩니다.

    그룹을 만든 후

  5. Cloud Console에서 모니터링 페이지를 엽니다.

    Monitoring 페이지로 이동

  6. 왼쪽 상단을 확인해 올바른 프로젝트 작업공간에 있는지 확인합니다. 이 페이지를 처음 방문하는 경우 새 작업공간을 만들어야 합니다.

  7. 측정항목 탐색기 페이지에서 리소스 유형으로 GCE VM Instance를 선택하고 측정항목으로 custom/gpu_utilization을 선택합니다.

    측정항목 탐색기 페이지

    데이터가 들어오면 다음과 같이 표시됩니다.

    사용량이 0인 측정항목 그래프

  8. Cloud Shell에서 그룹에 자동 확장을 사용 설정합니다.

    gcloud compute instance-groups managed set-autoscaling $INSTANCE_GROUP_NAME \
        --custom-metric-utilization metric=custom.googleapis.com/gpu_utilization,utilization-target-type=GAUGE,utilization-target=85 \
        --max-num-replicas 4 \
        --cool-down-period 360 \
        --region us-central1
    

    여기서 중요한 부분은 측정항목의 전체 경로인 사용률 경로 custom.googleapis.com/gpu_utilization입니다. 또한 대상 레벨을 85로 지정했으므로 GPU 사용률이 85에 도달할 때마다 그룹에 새 인스턴스가 만들어집니다.

자동 확장 테스트

이전 섹션에서 설정한 자동 확장을 테스트하기 위해 다음을 수행해야 합니다.

  • SSH를 사용하여 딥 러닝 GPU 인스턴스 중 하나에 연결합니다.
  • 모든 GPU를 100%로 로드합니다.
  • 인스턴스를 한 개 이상 만들어서 자동 확장 그룹이 확장되는 것을 관찰합니다.

  1. ssh를 통해 인스턴스에 연결합니다.
  2. GPU를 600초 동안 100%로 로드합니다.

    git clone https://github.com/GoogleCloudPlatform/tensorflow-inference-tensorrt5-t4-gpu.git
    cd tensorflow-inference-tensorrt5-t4-gpu
    git submodule update --init --recursive
    cd third_party/gpu-burn
    make
    ./gpu_burn 600 > /dev/null &
    

    Cloud Console의 측정항목 탐색기 페이지에서 활동을 확인합니다.

    측정항목 탐색기 페이지 활동 급증

  3. 두 번째 인스턴스를 만듭니다.

  4. GCE 컴퓨팅 페이지 > 인스턴스 그룹 > 모니터링으로 이동하여 활동을 관찰합니다.

    더 높은 모니터링 활동 급증

    이 시점에서 자동 확장 처리가 부하를 줄일 수 있도록 최대한 많은 인스턴스를 가동하려고 시도하지만 부하는 줄어들지 않습니다. 그러면 다음과 같이 됩니다.

    많은 인스턴스 가동

  5. 인스턴스 가동을 중지하고 활동이 어떻게 축소되는지 관찰합니다.

현재 확보한 요소를 알아보세요.

  • TensorRT 5(INT8)로 최적화되고 학습된 모델
  • 딥 러닝 인스턴스의 관리형 그룹
  • GPU 사용률에 기반한 자동 확장

부하 분산기 만들기

첫 번째 단계는 인스턴스 전면에 부하 분산기를 만드는 것입니다.

  1. Cloud Shell에서 상태 확인을 만들어서 백엔드의 특정 호스트가 트래픽을 처리할 수 있는지 결정합니다.

    gcloud compute health-checks create http $HEALTH_CHECK_NAME \
        --request-path /v1/models/default \
        --port 8888
    
  2. 부하 분산기가 포트 80을 통한 추론 요청을 포트 8888을 통해 제공되는 추론 서비스로 전달할 수 있도록 인스턴스 그룹의 이름이 지정된 포트를 구성합니다.

    gcloud compute instance-groups set-named-ports $INSTANCE_GROUP_NAME \
        --named-ports http:8888 \
        --region us-central1
    
  3. 백엔드 서비스를 만듭니다.

    export WEB_BACKED_SERVICE_NAME="tensorflow-backend"
    
    gcloud compute backend-services create $WEB_BACKED_SERVICE_NAME \
        --protocol HTTP \
        --health-checks $HEALTH_CHECK_NAME \
        --global
    

    백엔드 서비스는 상태 확인이 있는 인스턴스 그룹입니다.

  4. 새 백엔드 서비스에 인스턴스 그룹을 추가합니다.

    gcloud compute backend-services add-backend $WEB_BACKED_SERVICE_NAME \
        --balancing-mode UTILIZATION \
        --max-utilization 0.8 \
        --capacity-scaler 1 \
        --instance-group $INSTANCE_GROUP_NAME \
        --instance-group-region us-central1 \
        --global
    
  5. 백엔드 서비스로 전달할 URL을 부하 분산기에 지시합니다.

    export WEB_MAP_NAME="map-all"
    
    gcloud compute url-maps create $WEB_MAP_NAME \
        --default-service $WEB_BACKED_SERVICE_NAME
    
  6. 부하 분산기를 만듭니다.

    export LB_NAME="tf-lb"
    
    gcloud compute target-http-proxies create $LB_NAME \
        --url-map $WEB_MAP_NAME
    
  7. 부하 분산기의 외부 IP 주소를 만듭니다.

    export IP4_NAME="lb-ip4"
    
    gcloud compute addresses create $IP4_NAME \
        --ip-version=IPV4 \
        --global
    
  8. IP 주소가 할당되었는지 확인합니다.

    gcloud compute addresses list
    
  9. Google Cloud가 공개 IP의 모든 요청을 부하 분산기로 전달하는 데 사용하는 전달 규칙을 검토합니다.

    export IP=$(gcloud compute addresses list | grep ${IP4_NAME} | awk '{print $2}')
    export FORWARDING_RULE="lb-fwd-rule"
    
    gcloud compute forwarding-rules create $FORWARDING_RULE \
        --address $IP \
        --global \
        --target-http-proxy $LB_NAME \
        --ports 80
    

    전역 전달 규칙을 만든 후 구성을 적용하기까지 몇 분이 걸릴 수 있습니다.

  10. 외부 인스턴스에 연결하기 위해 프로젝트에서 방화벽을 사용 설정합니다.

    gcloud compute firewall-rules create www-firewall-80 \
        --target-tags http-server --allow tcp:80
    
    gcloud compute firewall-rules create www-firewall-8888 \
        --target-tags http-server --allow tcp:8888
    
  11. 이미지를 서버에 전송할 수 있는 형식으로 변환합니다.

    cat <<EOF > load_and_convert_image.py
    from PIL import Image
    import numpy as np
    import json
    import codecs
    
    img = Image.open("image.jpg").resize((240, 240))
    img_array=np.array(img)
    result = {
        "instances":[img_array.tolist()]
    }
    file_path="/tmp/out.json"
    print(json.dump(result, codecs.open(file_path, 'w', encoding='utf-8'), separators=(',', ':'), sort_keys=True, indent=4))
    EOF
    
  12. 추론을 실행합니다.

    wget https://pixnio.com/free-images/2017/10/31/2017-10-31-10-43-58-1032x825.jpg -O image.jpg
    python load_and_convert_image.py
    curl -X POST $IP/v1/models/default:predict -d @/tmp/out.json
    

    추론이 올바르게 작동하는 경우 다음과 비슷한 결과가 표시됩니다.

    성공적인 추론 실행 결과

삭제

이 가이드를 완료한 후에는 할당량을 차지하지 않고 이후에 요금이 청구되지 않도록 Google Cloud에서 만든 리소스를 삭제할 수 있습니다. 다음 섹션에서는 리소스를 삭제하거나 사용 중지하는 방법을 설명합니다.

  1. Cloud Console에서 리소스 관리 페이지로 이동합니다.

    리소스 관리 페이지로 이동

  2. 프로젝트 목록에서 삭제할 프로젝트를 선택하고 삭제 를 클릭합니다.
  3. 대화상자에서 프로젝트 ID를 입력한 다음 종료를 클릭하여 프로젝트를 삭제합니다.

다음 단계