표준 TensorFlow ModelServer 구축

이 튜토리얼에서는 TensorFlow Serving 구성 요소를 사용하여 학습된 TensorFlow 모델의 새 버전을 동적으로 검색하고 제공하는 표준 TensorFlow ModelServer를 구축하는 방법을 보여줍니다. 표준 서버를 사용하여 모델을 제공하려면 TensorFlow Serving 기본 튜토리얼을 참조하세요.

이 튜토리얼에서는 필기 이미지(MNIST 데이터) 분류를 위해 TensorFlow 튜토리얼에 소개된 간단한 Softmax 회귀 모델을 사용합니다. TensorFlow 또는 MNIST가 무엇인지 모르는 경우 ML 초보자를 위한 MNIST 튜토리얼을 참조하세요.

이 튜토리얼의 코드는 두 부분으로 구성됩니다.

  • 여러 버전의 모델을 학습하고 내보내는 Python 파일 mnist_saved_model.py .

  • 새로 내보낸 모델을 검색하고 이를 제공하기 위해 gRPC 서비스를 실행하는 표준 TensorFlow ModelServer인 C++ 파일 main.cc 입니다.

이 튜토리얼에서는 다음 작업을 단계별로 진행합니다.

  1. TensorFlow 모델을 학습하고 내보냅니다.
  2. TensorFlow Serving ServerCore 사용하여 모델 버전 관리를 관리하세요.
  3. SavedModelBundleSourceAdapterConfig 사용하여 일괄 처리를 구성합니다.
  4. TensorFlow Serving ServerCore 사용하여 요청을 처리합니다.
  5. 서비스를 실행하고 테스트합니다.

시작하기 전에 먼저 Docker를 설치하세요.

TensorFlow 모델 학습 및 내보내기

먼저, 아직 복제하지 않았다면 이 저장소를 로컬 머신에 복제하세요.

git clone https://github.com/tensorflow/serving.git
cd serving

내보내기 디렉터리가 이미 있으면 지우십시오.

rm -rf /tmp/models

학습(100회 반복) 및 모델의 첫 번째 버전 내보내기:

tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
  --training_iteration=100 --model_version=1 /tmp/mnist

2000번의 반복을 통해 학습하고 두 번째 버전의 모델을 내보냅니다.

tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
  --training_iteration=2000 --model_version=2 /tmp/mnist

mnist_saved_model.py 에서 볼 수 있듯이 학습 및 내보내기는 TensorFlow Serving 기본 튜토리얼 과 동일한 방식으로 수행됩니다. 시연을 위해 의도적으로 첫 번째 실행을 위해 훈련 반복을 줄이고 이를 v1로 내보내는 반면, 두 번째 실행을 위해 정상적으로 훈련하고 동일한 상위 디렉터리에 v2로 내보냅니다. 후자에서 달성할 것으로 예상됩니다. 더 집중적인 훈련으로 인해 분류 정확도가 향상됩니다. /tmp/mnist 디렉터리에서 각 훈련 실행에 대한 훈련 데이터를 볼 수 있습니다:

$ ls /tmp/mnist
1  2

서버코어

이제 새로운 알고리즘이 실험되거나 모델이 새로운 데이터 세트로 훈련될 때 모델의 v1과 v2가 런타임에 동적으로 생성된다고 상상해 보세요. 프로덕션 환경에서는 v1을 제공하는 동안 v2를 검색, 로드, 실험, 모니터링 또는 되돌릴 수 있는 점진적인 롤아웃을 지원할 수 있는 서버를 구축할 수 있습니다. 또는 v2를 시작하기 전에 v1을 해제할 수도 있습니다. TensorFlow Serving은 두 가지 옵션을 모두 지원합니다. 하나는 전환 중에 가용성을 유지하는 데 좋고, 다른 하나는 리소스 사용량(예: RAM)을 최소화하는 데 좋습니다.

TensorFlow Serving Manager 바로 그 일을 합니다. 버전 전환은 물론 모델 로드, 제공, 언로드를 포함하여 TensorFlow 모델의 전체 수명 주기를 처리합니다. 이 튜토리얼에서는 내부적으로 AspiredVersionsManager 래핑하는 TensorFlow Serving ServerCore 위에 서버를 구축합니다.

int main(int argc, char** argv) {
  ...

  ServerCore::Options options;
  options.model_server_config = model_server_config;
  options.servable_state_monitor_creator = &CreateServableStateMonitor;
  options.custom_model_config_loader = &LoadCustomModelConfig;

  ::google::protobuf::Any source_adapter_config;
  SavedModelBundleSourceAdapterConfig
      saved_model_bundle_source_adapter_config;
  source_adapter_config.PackFrom(saved_model_bundle_source_adapter_config);
  (*(*options.platform_config_map.mutable_platform_configs())
      [kTensorFlowModelPlatform].mutable_source_adapter_config()) =
      source_adapter_config;

  std::unique_ptr<ServerCore> core;
  TF_CHECK_OK(ServerCore::Create(options, &core));
  RunServer(port, std::move(core));

  return 0;
}

ServerCore::Create() ServerCore::Options 매개변수를 사용합니다. 다음은 일반적으로 사용되는 몇 가지 옵션입니다.

  • 로드할 모델을 지정하는 ModelServerConfig 입니다. 모델은 모델의 정적 목록을 선언하는 model_config_list 통해 선언되거나 런타임에 업데이트될 수 있는 모델 목록을 선언하는 사용자 지정 방법을 정의하는 custom_model_config 통해 선언됩니다.
  • PlatformConfigMap 플랫폼 이름(예: tensorflow )에서 SourceAdapter 생성하는 데 사용되는 PlatformConfig 로 매핑됩니다. SourceAdapter StoragePath (모델 버전이 검색되는 경로)를 모델 Loader (스토리지 경로에서 모델 버전을 로드하고 Manager 에 상태 전환 인터페이스 제공)에 적용합니다. PlatformConfig SavedModelBundleSourceAdapterConfig 포함되어 있으면 SavedModelBundleSourceAdapter 가 생성되며 이에 대해서는 나중에 설명하겠습니다.

SavedModelBundle 은 TensorFlow Serving의 핵심 구성요소입니다. 이는 지정된 경로에서 로드된 TensorFlow 모델을 나타내며 추론을 실행하기 위해 TensorFlow와 동일한 Session::Run 인터페이스를 제공합니다. SavedModelBundleSourceAdapter 모델 수명을 Manager 에서 관리할 수 있도록 Loader<SavedModelBundle> 에 대한 저장소 경로를 조정합니다. SavedModelBundle 은 더 이상 사용되지 않는 SessionBundle 의 후속 버전입니다. SessionBundle 에 대한 지원이 곧 제거될 예정이므로 사용자는 SavedModelBundle 사용하는 것이 좋습니다.

이러한 모든 기능을 통해 ServerCore 내부적으로 다음을 수행합니다.

  • model_config_list 에 선언된 모델 내보내기 경로를 모니터링하는 FileSystemStoragePathSource 인스턴스화합니다.
  • model_config_list 에 선언된 모델 플랫폼과 함께 PlatformConfigMap 을 사용하여 SourceAdapter 인스턴스화하고 FileSystemStoragePathSource 여기에 연결합니다. 이렇게 하면 내보내기 경로에서 새 모델 버전이 발견될 때마다 SavedModelBundleSourceAdapter 이를 Loader<SavedModelBundle> 에 맞게 조정합니다.
  • SavedModelBundleSourceAdapter 에 의해 생성된 모든 Loader 인스턴스를 관리하는 AspiredVersionsManager 라는 Manager 의 특정 구현을 인스턴스화합니다. ServerCore AspiredVersionsManager 에 대한 호출을 위임하여 Manager 인터페이스를 내보냅니다.

새 버전을 사용할 수 있을 때마다 이 AspiredVersionsManager 새 버전을 로드하고 기본 동작에 따라 이전 버전을 언로드합니다. 사용자 정의를 시작하려면 내부적으로 생성되는 구성 요소와 구성 방법을 이해하는 것이 좋습니다.

TensorFlow Serving은 처음부터 매우 유연하고 확장 가능하도록 설계되었다는 점은 언급할 가치가 있습니다. ServerCoreAspiredVersionsManager 와 같은 일반 핵심 구성 요소를 활용하면서 다양한 플러그인을 구축하여 시스템 동작을 맞춤 설정할 수 있습니다. 예를 들어 로컬 저장소 대신 클라우드 저장소를 모니터링하는 데이터 소스 플러그인을 구축하거나 다른 방식으로 버전 전환을 수행하는 버전 정책 플러그인을 구축할 수 있습니다. TensorFlow가 아닌 ​​모델. 이러한 주제는 이 튜토리얼의 범위를 벗어납니다. 그러나 자세한 내용은 사용자 정의 소스사용자 정의 제공 가능 튜토리얼을 참조할 수 있습니다.

일괄 처리

프로덕션 환경에서 원하는 또 다른 일반적인 서버 기능은 일괄 처리입니다. 기계 학습 추론을 수행하는 데 사용되는 최신 하드웨어 가속기(GPU 등)는 일반적으로 추론 요청이 대규모 배치로 실행될 때 최고의 계산 효율성을 달성합니다.

SavedModelBundleSourceAdapter 생성할 때 적절한 SessionBundleConfig 제공하면 일괄 처리를 켤 수 있습니다. 이 경우에는 거의 기본값으로 BatchingParameters 설정합니다. 사용자 정의 시간 초과, 배치_크기 등의 값을 설정하여 일괄 처리를 미세 조정할 수 있습니다. 자세한 내용은 BatchingParameters 를 참조하세요.

SessionBundleConfig session_bundle_config;
// Batching config
if (enable_batching) {
  BatchingParameters* batching_parameters =
      session_bundle_config.mutable_batching_parameters();
  batching_parameters->mutable_thread_pool_name()->set_value(
      "model_server_batch_threads");
}
*saved_model_bundle_source_adapter_config.mutable_legacy_config() =
    session_bundle_config;

전체 배치에 도달하면 추론 요청이 내부적으로 하나의 대규모 요청(텐서)으로 병합되고 tensorflow::Session::Run() 이 호출됩니다(GPU의 실제 효율성 향상은 여기서 비롯됩니다).

매니저와 함께 봉사하세요

위에서 언급한 것처럼 TensorFlow Serving Manager 임의의 기계 학습 시스템에서 생성된 모델의 로드, 서빙, 언로드 및 버전 전환을 처리할 수 있는 일반 구성 요소로 설계되었습니다. API는 다음과 같은 주요 개념을 기반으로 구축되었습니다.

  • Servable : Servable은 클라이언트 요청을 처리하는 데 사용할 수 있는 불투명 개체입니다. servable의 크기와 세분성은 유연하므로 단일 servable에는 조회 테이블의 단일 샤드부터 단일 기계 학습 모델, 모델 튜플까지 모든 것이 포함될 수 있습니다. servable은 모든 유형과 인터페이스가 될 수 있습니다.

  • Servable 버전 : Servable에는 버전이 지정되며 TensorFlow Serving Manager 하나 이상의 Servable 버전을 관리할 수 있습니다. 버전 관리를 통해 두 개 이상의 서버블 버전을 동시에 로드할 수 있으므로 점진적인 롤아웃 및 실험이 지원됩니다.

  • Servable Stream : servable 스트림은 버전 번호가 증가하는 servable 버전의 시퀀스입니다.

  • Model : 머신러닝 모델은 하나 이상의 servable로 표현됩니다. 제공 가능 항목의 예는 다음과 같습니다.

    • TensorFlow 세션 또는 이를 둘러싼 래퍼(예: SavedModelBundle )
    • 다른 종류의 기계 학습 모델.
    • 어휘 조회 테이블.
    • 조회 테이블 삽입.

    복합 모델은 여러 개의 독립적인 서비스 가능 항목 또는 단일 복합 서비스 가능 항목으로 표현될 수 있습니다. 서비스 가능 항목은 모델의 일부에 해당할 수도 있습니다(예: 여러 Manager 인스턴스에 걸쳐 분할된 대규모 조회 테이블 포함).

이 모든 것을 이 튜토리얼의 맥락에 넣으려면:

  • TensorFlow 모델은 한 종류의 제공 가능 항목( SavedModelBundle )으로 표시됩니다. SavedModelBundle 내부적으로 세션에 로드되는 그래프와 추론을 위해 실행하는 방법에 대한 일부 메타데이터와 쌍을 이루는 tensorflow:Session 으로 구성됩니다.

  • TensorFlow 내보내기 스트림을 포함하는 파일 시스템 디렉터리가 있으며, 각 디렉터리는 이름이 버전 번호인 자체 하위 디렉터리에 있습니다. 외부 디렉터리는 제공되는 TensorFlow 모델에 대한 제공 가능한 스트림의 직렬화된 표현으로 생각할 수 있습니다. 각 내보내기는 로드할 수 있는 servable에 해당합니다.

  • AspiredVersionsManager 내보내기 스트림을 모니터링하고 모든 SavedModelBundle 제공 가능 항목의 수명 주기를 동적으로 관리합니다.

TensorflowPredictImpl::Predict 다음은 다음과 같습니다.

  • 관리자로부터 SavedModelBundle 요청합니다(ServerCore를 통해).
  • generic signatures 사용하여 PredictRequest 의 논리적 텐서 이름을 실제 텐서 이름에 매핑하고 값을 텐서에 바인딩합니다.
  • 추론을 실행합니다.

서버 테스트 및 실행

내보내기의 첫 번째 버전을 모니터링되는 폴더에 복사합니다.

mkdir /tmp/monitored
cp -r /tmp/mnist/1 /tmp/monitored

그런 다음 서버를 시작합니다.

docker run -p 8500:8500 \
  --mount type=bind,source=/tmp/monitored,target=/models/mnist \
  -t --entrypoint=tensorflow_model_server tensorflow/serving --enable_batching \
  --port=8500 --model_name=mnist --model_base_path=/models/mnist &

서버는 "Aspiring version for servable ..."이라는 로그 메시지를 1초마다 내보냅니다. 이는 내보내기를 찾았으며 지속적인 존재를 추적하고 있음을 의미합니다.

--concurrency=10 으로 클라이언트를 실행해 보겠습니다. 이렇게 하면 동시 요청이 서버에 전송되어 일괄 처리 논리가 트리거됩니다.

tools/run_in_docker.sh python tensorflow_serving/example/mnist_client.py \
  --num_tests=1000 --server=127.0.0.1:8500 --concurrency=10

결과는 다음과 같습니다.

...
Inference error rate: 13.1%

그런 다음 내보내기의 두 번째 버전을 모니터링되는 폴더에 복사하고 테스트를 다시 실행합니다.

cp -r /tmp/mnist/2 /tmp/monitored
tools/run_in_docker.sh python tensorflow_serving/example/mnist_client.py \
  --num_tests=1000 --server=127.0.0.1:8500 --concurrency=10

결과는 다음과 같습니다.

...
Inference error rate: 9.5%

이는 서버가 자동으로 새 버전을 검색하고 이를 사용하여 서비스를 제공한다는 것을 확인시켜줍니다.