모델 서버 (서빙 프레임워크)

준비된 모델을 실제 서비스 환경에 배포할 때 모델을 GRPC나 REST API를 통하는 경우가 일반적이다. 이런 유스케이스를 위해 FuriosaAI SDK는 KServe Predict Protocol Version 2 를 지원하는 모델 서버를 제공한다.

모델 서버는 다음 주요 기능을 제공한다.

  • REST API 지원

  • 다수의 NPU 디바이스 및 다수의 모델를 하나의 서버로 서빙 지원

모델 서버 설치

모델 서버 설치를 위한 최소 요구사항은 다음과 같다.

Python 실행환경 준비가 필요하다면 Python 실행 환경 구성 를 참고한다.

간단하게 다음 커맨드를 실행해주세요.

$ pip install 'furiosa-sdk[server]'

모델 서버 실행

모델 서버는 명령행 도구 furiosa server 커맨드를 통해 실행 할 수 있다. furiosa server --help 을 실행하면 아래와 같은 도움말을 볼 수 있다.

$ furiosa server --help
Usage: furiosa server [OPTIONS]

    Start serving models from FuriosaAI model server

Options:
    --log-level [ERROR|INFO|WARN|DEBUG|TRACE]
                                    [default: LogLevel.INFO]
    --model-path TEXT               Path to Model file (tflite, onnx are
                                    supported)
    --model-name TEXT               Model name used in URL path
    --model-version TEXT            Model version used in URL path  [default:
                                    default]
    --host TEXT                     IP address to bind  [default: 0.0.0.0]
    --http-port INTEGER             HTTP port to listen to requests  [default:
                                    8080]
    --model-config FILENAME         Path to a config file about models with
                                    specific configurations
    --server-config FILENAME        Path to Model file (tflite, onnx are
                                    supported)
    --install-completion [bash|zsh|fish|powershell|pwsh]
                                    Install completion for the specified shell.
    --show-completion [bash|zsh|fish|powershell|pwsh]
                                    Show completion for the specified shell, to
                                    copy it or customize the installation.
    --help                          Show this message and exit.

간단한 모델 서빙은 커맨드로 tflite, onnx 포맷의 모델 이미지의 패스와 모델 이름을 지정하면 실행할 수 있다.

$ cd furiosa-sdk
$ furiosa server \
--model-path examples/assets/quantized_models/MNISTnet_uint8_quant_without_softmax.tflite \
--model-name mnist

--model-path 옵션으로 로컬 파일 시스템에 저장된 모델을 지정할 수 있다. 또한 모델 서버가 지정한 호스트 이름과 포트로 연결 요청을 대기하기 원하는 경우 --host, --host-port 로 각각 설정할 수 있다.

모델 설정을 이용한 모델 서버 실행

컴파일 옵션이나 서빙에 대한 더 고급 설정이 필요한 경우 또는 반복적으로 같은 옵션을 사용하는 경우 모델 설정을 활용할 수 있다.

model_config_list:
  - name: mnist
    model: "samples/data/MNISTnet_uint8_quant.tflite"
    version: "1"
    platform: npu
    npu_device: warboy(1)*1
    compiler_config:
      keep_unsignedness: true
      split_unit: 0
  - name: ssd
    model: "samples/data/SSD512_MOBILENET_V2_BDD_int_without_reshape.tflite"
    version: "1"
    platform: npu
    npu_device: warboy(1)*1

위와 같은 설정을 준비한 뒤에 아래와 같이 --model-config 옵션을 이용하여 설정 파일의 패스를 지정하여 실행할 수 있다. 위 예제 실행을 위해서는 모델이 필요한데 위 모델은 Furiosa Server Github 저장소samples 디렉토리에서 찾을 수 있다. 모델과 모델 설정이 준비되어 있다면 아래 예제를 실행해볼 수 있다.

$ cd furiosa-sdk/python/furiosa-server
$ furiosa server --model-config samples/model_config_example.yaml
libfuriosa_hal.so --- v0.11.0, built @ 43c901f
2023-08-02T07:42:42.263133Z  INFO furiosa_rt_core::driver::event_driven::device: DeviceManager has detected 1 NPUs
2023-08-02T07:42:42.267247Z  INFO furiosa_rt_core::driver::event_driven::device: [1] npu:6:1 (warboy-b0, 64dpes)
2023-08-02T07:42:42.267264Z  INFO furiosa_rt_core::driver::event_driven::coord: furiosa-rt (v0.10.0-rc6, rev: d021ff71d, built_at: 2023-07-31T19:05:26Z) is being initialized
2023-08-02T07:42:42.267269Z  INFO furiosa_rt_core::npu::async_impl::threaded: npu:6:1-io-thread-0 thread has started
2023-08-02T07:42:42.267398Z  INFO furiosa_rt_core::npu::async_impl::threaded: npu:6:1-commit-thread thread has started
2023-08-02T07:42:42.267405Z  INFO furiosa_rt_core::npu::async_impl::threaded: npu:6:1-io-thread-1 thread has started
2023-08-02T07:42:42.270837Z  INFO furiosa_rt_core::driver::event_driven::coord: Loaded libcompiler 0.10.0 (rev: f8f05c built: 2023-07-26T09:49:17Z)
2023-08-02T07:42:42.270851Z  INFO furiosa_rt_core::driver::event_driven::coord: Loaded libhal-warboy 0.11.0 (rev: 43c901f built: 2023-04-19T14:04:55Z)
2023-08-02T07:42:42.271144Z  INFO furiosa_rt_core::driver::event_driven::coord: [NONAME] Runtime has started
2023-08-02T07:42:42.273772Z  INFO furiosa_rt_core::driver::event_driven::coord: Model#0001 is being loaded to npu:6:1
2023-08-02T07:42:42.283260Z  INFO furiosa_rt_core::driver::event_driven::coord: Compiling Model#0001 (target: warboy-b0, 64dpes, file: MNISTnet_uint8_quant.tflite, size: 18.2 kiB)
2023-08-02T07:42:42.299091Z  INFO furiosa_rt_core::driver::event_driven::coord: Model#0001 has been compiled successfully (took 0 secs)
2023-08-02T07:42:42.299293Z  INFO furiosa_rt_core::dag: Task Statistics: TaskStats { cpu: 5, npu: 1, alias: 0, coalesce: 0 }
2023-08-02T07:42:42.300701Z  INFO furiosa_rt_core::driver::event_driven::coord: NpuApi (AsyncNpuApiImpl) has started..
2023-08-02T07:42:42.300721Z  INFO furiosa_rt_core::driver::event_driven::coord: Creating 1 Contexts on npu:6:1 (DRAM usage: 6.0 kiB / 16.0 GiB, SRAM usage: 124.0 kiB / 64.0 MiB)
2023-08-02T07:42:42.300789Z  INFO furiosa_rt_core::driver::event_driven::coord: npu:6:1 has scheduled to Model#0001
2023-08-02T07:42:42.304216Z  WARN furiosa_rt_core::consts::envs: NPU_DEVNAME will be deprecated. Use FURIOSA_DEVICES instead.
2023-08-02T07:42:42.313084Z  INFO furiosa_rt_core::driver::event_driven::device: DeviceManager has detected 1 NPUs
2023-08-02T07:42:42.315470Z  INFO furiosa_rt_core::driver::event_driven::device: [1] npu:6:0 (warboy-b0, 64dpes)
2023-08-02T07:42:42.315483Z  INFO furiosa_rt_core::driver::event_driven::coord: furiosa-rt (v0.10.0-rc6, rev: d021ff71d, built_at: 2023-07-31T19:05:26Z) is being initialized
2023-08-02T07:42:42.315560Z  INFO furiosa_rt_core::npu::async_impl::threaded: npu:6:0-io-thread-1 thread has started
2023-08-02T07:42:42.315610Z  INFO furiosa_rt_core::npu::async_impl::threaded: npu:6:0-io-thread-0 thread has started
2023-08-02T07:42:42.315657Z  INFO furiosa_rt_core::npu::async_impl::threaded: npu:6:0-commit-thread thread has started
2023-08-02T07:42:42.319127Z  INFO furiosa_rt_core::driver::event_driven::coord: Loaded libcompiler 0.10.0 (rev: f8f05c built: 2023-07-26T09:49:17Z)
2023-08-02T07:42:42.319141Z  INFO furiosa_rt_core::driver::event_driven::coord: Loaded libhal-warboy 0.11.0 (rev: 43c901f built: 2023-04-19T14:04:55Z)
2023-08-02T07:42:42.319364Z  INFO furiosa_rt_core::driver::event_driven::coord: [NONAME] Runtime has started
2023-08-02T07:42:42.324283Z  INFO furiosa_rt_core::driver::event_driven::coord: Model#0002 is being loaded to npu:6:0
2023-08-02T07:42:42.333521Z  INFO furiosa_rt_core::driver::event_driven::coord: Compiling Model#0002 (target: warboy-b0, 64dpes, file: SSD512_MOBILENET_V2_BDD_int_without_reshape.tflite, size: 5.2 MiB)
2023-08-02T07:42:42.814260Z  INFO furiosa_rt_core::driver::event_driven::coord: Model#0002 has been compiled successfully (took 0 secs)
2023-08-02T07:42:42.815406Z  INFO furiosa_rt_core::dag: Task Statistics: TaskStats { cpu: 26, npu: 1, alias: 0, coalesce: 0 }
2023-08-02T07:42:42.893745Z  INFO furiosa_rt_core::driver::event_driven::coord: NpuApi (AsyncNpuApiImpl) has started..
2023-08-02T07:42:42.893772Z  INFO furiosa_rt_core::driver::event_driven::coord: Creating 1 Contexts on npu:6:0 (DRAM usage: 1.0 MiB / 16.0 GiB, SRAM usage: 14.8 MiB / 64.0 MiB)
2023-08-02T07:42:42.894265Z  INFO furiosa_rt_core::driver::event_driven::coord: npu:6:0 has scheduled to Model#0002
INFO:     Started server process [2448540]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)

모델 서버가 시작되고 나면 일반적인 HTTP 요청을 보내 모델의 추론 작업을 해볼 수 있다. 모델 설정에서 모델 이름이 mnist 이고 버전이 1 인 모델에 추론 요청을 보낼 때는 http://<host>:<port>/v2/models/mnist/version/1/inferPOST 요청을 보내면 된다.

아래 예제는 위와 동일한 요청을 Python 코드를 통해 보내는 예제이다.

import requests
import mnist
import numpy as np

mnist_images = mnist.train_images().reshape((60000, 1, 28, 28)).astype(np.uint8)
url = 'http://localhost:8080/v2/models/mnist/versions/1/infer'

data = mnist_images[0:1].flatten().tolist()
request = {
    "inputs": [{
        "name":
        "mnist",
        "datatype": "UINT8",
        "shape": (1, 1, 28, 28),
        "data": data
    }]
}

response = requests.post(url, json=request)
print(response.json())

엔드포인트(Endpoint) 정보

다음 테이블은 모델 서버가 제공하는 주요 REST API 엔드포인트 정보이다. 모델 서버는 KServe Predict Protocol Version 2 - HTTP/REST 를 따르고 있으므로 더 자세한 정보는 링크에서 찾아볼 수 있다.

Endpoints of KServe Predict Protocol Version 2

Method and Endpoint

Description

GET /v2/health/live

서버가 요청을 처리할 수 있는 상태면 HTTP 상태 Ok 리턴 (Kubernetes livenessProbe에 해당)

GET /v2/health/ready

모든 모델이 추론 작업을 위한 준비가 되면 HTTP 상태 Ok 리턴 (Kubernetes readinessProbe에 해당)

GET /v2/models/${MODEL_NAME}/versions/${MODEL_VERSION}

모델 메타데이터 반환

GET /v2/models/${MODEL_NAME}/versions/${MODEL_VERSION}/ready

특정 버전의 모델이 추론 요청을 처리할 준비가 되었다면 HTTP 상태 Ok 리턴

POST /v2/models/${MODEL_NAME}[/versions/${MODEL_VERSION}]/infer

추론 요청