TorchServe 배치 추론

TorchServe 배치 추론

모델을 서빙하다 보면 요청 하나씩 처리하는 것보다 여러 요청을 모아 한 번에 추론하면 자원을 훨씬 효율적으로 쓸 수 있는데요, 대부분의 ML/DL 프레임워크가 배치 요청에 최적화돼 있기 때문이에요. TorchServe는 이런 배치 추론(batch inference)을 네이티브로 지원해요. 이 문서에서는 로컬 서빙과 도커 컨테이너 두 환경에서 배치 추론을 설정하고 사용하는 방법을 예시로 살펴볼게요.

출처: Batch Inference with TorchServe — PyTorch/Serve

배치 추론이 필요한 이유

배치 추론은 추론 요청들을 모아 한꺼번에 ML/DL 프레임워크로 보내는 과정이에요. TorchServe는 들어오는 추론 요청의 배칭을 기본으로 지원하도록 설계됐어요. 프레임워크가 배치 요청에 최적화돼 있으므로 호스트 자원을 최적으로 사용할 수 있고, 결과적으로 TorchServe로 추론 서비스를 운영하는 비용을 줄여줘요.

사전 준비

이 문서를 읽기 전에 다음을 먼저 확인해 주세요.

  • TorchServe가 무엇인지
  • 커스텀 서비스 코드(custom service code)가 무엇인지

기본 핸들러로 배치 추론하기

TorchServe의 기본 핸들러는 text_classifier 핸들러를 제외하고 모두 배치 추론을 기본 지원해요.

ResNet-152 모델로 배치 추론 설정하기

배치 추론을 지원하려면 TorchServe에 두 가지가 필요해요.

  1. TorchServe 모델 설정: Management API의 POST /models나 config.properties에서 batch_sizemax_batch_delay를 설정해요. TorchServe는 모델이 처리할 수 있는 최대 배치 크기와 배치 요청을 채울 때까지 기다릴 최대 시간을 알아야 해요.
  2. 모델 핸들러 코드: 배치 추론 요청을 처리할 수 있는 핸들러가 필요해요. 배치 처리하는 커스텀 모델 핸들러의 전체 예시는 Hugging Face transformer generalized handler를 참고해요.

TorchServe 모델 설정

TorchServe 0.4.1부터 배칭 기능을 설정하는 방법은 두 가지예요.

  • POST /models API로 배치 설정 정보를 넘기기
  • config.properties 설정 파일로 넘기기

여기서 관심 있는 설정 속성은 두 가지예요.

  • batch_size: 모델이 처리할 수 있는 최대 배치 크기
  • max_batch_delay: TorchServe가 batch_size 개의 요청을 받을 때까지 기다리는 최대 지연(ms). 이 타이머가 끝나기 전에 batch_size 개의 요청을 채우지 못하면, 지금까지 받은 요청을 모델 핸들러로 보내요.

Management API로 설정하는 예시는 이래요.

# resnet-152.mar 모델을 등록하면서 batch_size=8, max_batch_delay=50ms로 설정
curl -X POST "localhost:8081/models?url=resnet-152.mar&batch_size=8&max_batch_delay=50"

config.properties로 설정하는 예시는 이래요.

models={
  "resnet-152": {
    "1.0": {
        "defaultVersion": true,
        "marName": "resnet-152.mar",
        "minWorkers": 1,
        "maxWorkers": 1,
        "batchSize": 8,
        "maxBatchDelay": 50,
        "responseTimeout": 120
    }
  }
}

이 설정은 TorchServe와 모델의 커스텀 서비스 코드(핸들러 코드) 양쪽에서 쓰여요. TorchServe는 배치 관련 설정을 모델별로 연결하고, 프론트엔드는 batch_size 개의 요청을 모아 백엔드로 보내려고 시도해요.

ResNet-152 배치 추론 데모

여기서는 기본 image_classifier 핸들러를 쓰는 ResNet-152 모델로 배치 추론을 해볼게요.

TorchServe와 Torch Model Archiver 설치

먼저 메인 Readme를 따라 torchserve를 포함한 필요한 패키지를 모두 설치해요.

Management API로 설정한 ResNet-152 배치 추론

모델 서버를 시작해요. 이 예시에서는 추론 포트 8080, 관리 포트 8081로 시작해요.

$ cat config.properties
...
inference_address=http://127.0.0.1:8080
management_address=http://127.0.0.1:8081
...
$ torchserve --start --model-store model_store

TorchServe가 정상 동작하는지 확인해요.

$ curl localhost:8080/ping
{
  "status": "Healthy"
}

배치 추론을 처리하도록 만든 resnet-152 모델을 띄워요. 이 예시에선 워커 1개가 batch_size=3, max_batch_delay=10ms로 처리해요.

$ curl -X POST "localhost:8081/models?url=https://torchserve.pytorch.org/mar_files/resnet-152-batch_v2.mar&batch_size=3&max_batch_delay=10&initial_workers=1"
{
  "status": "Processing worker updates..."
}

워커가 제대로 시작됐는지 확인해요.

curl http://localhost:8081/models/resnet-152-batch_v2
[
  {
    "modelName": "resnet-152-batch_v2",
    "modelVersion": "2.0",
    "modelUrl": "https://torchserve.pytorch.org/mar_files/resnet-152-batch_v2.mar",
    "runtime": "python",
    "minWorkers": 1,
    "maxWorkers": 1,
    "batchSize": 3,
    "maxBatchDelay": 10,
    "loadedAtStartup": false,
    "workers": [
      {
        "id": "9000",
        "startTime": "2021-06-14T23:18:21.793Z",
        "status": "READY",
        "memoryUsage": 1726554112,
        "pid": 19946,
        "gpu": true,
        "gpuUsage": "gpuId::0 utilization.gpu [%]::0 % utilization.memory [%]::0 % memory.used [MiB]::678 MiB"
      }
    ]
  }
]

이제 서비스를 테스트해요. 먼저 테스트에 쓸 이미지를 받아요.

$ curl -LJO https://github.com/pytorch/serve/raw/master/examples/image_classifier/kitten.jpg

모델 추론을 실행해요.

$ curl http://localhost:8080/predictions/resnet-152-batch_v2 -T kitten.jpg
{
    "tiger_cat": 0.5798614621162415,
    "tabby": 0.38344162702560425,
    "Egyptian_cat": 0.0342114195227623,
    "lynx": 0.0005819813231937587,
    "quilt": 0.000273319921689108
}

config.properties로 설정한 ResNet-152 배치 추론

이번엔 config.properties에 batch_size와 max_batch_delay를 먼저 설정해요. mar 파일이 model-store에 있고 models 설정의 버전이 만든 mar 파일 버전과 일치하는지 확인해야 해요. 설정에 대한 자세한 내용은 관련 문서를 참고해요.

load_models=resnet-152-batch_v2.mar
models={
  "resnet-152-batch_v2": {
    "2.0": {
        "defaultVersion": true,
        "marName": "resnet-152-batch_v2.mar",
        "minWorkers": 1,
        "maxWorkers": 1,
        "batchSize": 3,
        "maxBatchDelay": 5000,
        "responseTimeout": 120
    }
  }
}

--ts-config 플래그로 config.properties를 넘겨 TorchServe를 시작해요.

torchserve --start --model-store model_store --ts-config config.properties

서버와 워커 시작 확인, 이미지 추론 테스트는 앞선 예시와 동일하게 진행하면 돼요.

도커로 ResNet-152 배치 추론 설정하기

도커 컨테이너로 모델을 서빙할 때 배치 추론을 지원하는 모델을 등록하는 방법이에요. dockered_entrypoint.sh가 쓰는 config.properties에 앞선 예시처럼 batch_size와 max_batch_delay를 설정해요.

inference_address=http://127.0.0.1:8080
management_address=http://127.0.0.1:8081
metrics_address=http://127.0.0.1:8082
number_of_netty_threads=32
job_queue_size=1000
model_store=/home/model-server/model-store
load_models=resnet-152-batch_v2.mar
models={
  "resnet-152-batch_v2": {
    "1.0": {
        "defaultVersion": true,
        "marName": "resnet-152-batch_v2.mar",
        "minWorkers": 1,
        "maxWorkers": 1,
        "batchSize": 3,
        "maxBatchDelay": 100,
        "responseTimeout": 120
    }
  }
}

여기서는 GPU 이미지를 쓰는 대상 도커 이미지를 빌드해요.

./build_image.sh -g -cv cu102

컨테이너로 모델을 서빙하고 config.properties를 컨테이너에 넘겨요.

docker run --rm -it --gpus all -p 127.0.0.1:8080:8080 -p 127.0.0.1:8081:8081 --name mar -v /home/ubuntu/serve/model_store:/home/model-server/model-store -v $path to config.properties:/home/model-server/config.properties pytorch/torchserve:latest-gpu

이후 워커 시작 확인과 이미지 추론 테스트는 앞선 예시와 동일해요.

더 알아보기 (Learn more)