Amazon SageMaker AI에 대한 자체 추론 컨테이너 조정 - Amazon SageMaker AI

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

Amazon SageMaker AI에 대한 자체 추론 컨테이너 조정

사전 구축된 SageMaker AI Docker 이미지 Amazon SageMaker AI에 나열된 이미지를 사용 사례에 사용할 수 없는 경우 자체 Docker 컨테이너를 빌드하고 SageMaker AI 내에서 훈련 및 추론에 사용할 수 있습니다. SageMaker AI와 호환되려면 컨테이너에 다음과 같은 특성이 있어야 합니다.

  • 컨테이너에는 포트 8080에 웹 서버 목록이 있어야 합니다.

  • 컨테이너는 /invocations/ping 실시간 엔드포인트에 대한 POST 요청을 수락해야 합니다. 이러한 엔드포인트에 보내는 요청은 60초 이내에 반환되어야 하며 최대 크기는 6MB입니다.

SageMaker AI를 사용한 훈련 및 추론을 위해 자체 Docker 컨테이너를 빌드하는 방법에 대한 자세한 내용과 예제는 자체 알고리즘 컨테이너 빌드를 참조하세요.

다음 가이드에서는 Amazon SageMaker Studio Classic과 함께 JupyterLab스페이스를 사용하여 SageMaker AI 호스팅으로 작동하도록 추론 컨테이너를 조정하는 방법을 보여줍니다. 이 예제에서는 NGINX 웹 서버, Python 웹 서버 게이트웨이 인터페이스로서 Gunicorn 및 웹 애플리케이션 프레임워크로서 Flask를 사용합니다. 컨테이너가 이전에 나열된 요구 사항을 충족하는 한 다른 애플리케이션을 사용하여 컨테이너를 조정할 수 있습니다. 자체 추론 코드 사용에 대한 자세한 내용은 호스팅 서비스를 사용한 사용자 지정 추론 코드 섹션을 참조하세요.

추론 컨테이너 조정

다음 단계에 따라 SageMaker AI 호스팅을 사용하도록 자체 추론 컨테이너를 조정합니다. 다음 단계에 표시된 예제에서는 다음 및 Python에 대해 spaCy 자연어 처리(NLP) 라이브러리를 사용하는 사전 훈련된 NER(명명된 개체 인식) 모델을 사용합니다.

  • NER 모델을 포함하는 컨테이너를 빌드하기 위한 Dockerfile입니다.

  • NER 모델을 지원하는 추론 스크립트입니다.

이 예제를 사용 사례에 맞게 조정하는 경우 모델을 배포하고 제공하는 데 필요한 Dockerfile 및 추론 스크립트를 사용해야 합니다.

  1. Amazon SageMaker Studio Classic을 사용하여 JupyterLab 공간을 생성합니다(선택 사항).

    모든 노트북을 사용하여 스크립트를 실행하여 추론 컨테이너를 SageMaker AI 호스팅으로 조정할 수 있습니다. 이 예제에서는 Amazon SageMaker Studio Classic 내에서 JupyterLab스페이스를 사용하여 SageMaker AI 배포 이미지와 함께 제공되는 JupyterLab 애플리케이션을 시작하는 방법을 보여줍니다. 자세한 내용은 SageMaker JupyterLab 단원을 참조하십시오.

  2. Docker 파일 및 추론 스크립트를 업로드합니다.

    1. 홈 디렉터리에 새 폴더를 생성합니다. JupyterLab을 사용하는 경우 왼쪽 상단 모서리에서 새 폴더 아이콘을 선택하고 Dockerfile를 포함할 폴더 이름을 입력합니다. 이 예에서 폴더 이름은 docker_test_folder입니다.

    2. 새 폴더에 Dockerfile 텍스트 파일을 업로드합니다. 다음은 spaCy에서 사전 훈련된 NER(명명된 엔터티 인식) 모델, 예제를 실행하는 데 필요한 애플리케이션 및 환경 변수를 사용하여 Docker 컨테이너를 생성하는 Dockerfile 예제입니다.

      FROM python:3.8 RUN apt-get -y update && apt-get install -y --no-install-recommends \ wget \ python3 \ nginx \ ca-certificates \ && rm -rf /var/lib/apt/lists/* RUN wget https://bootstrap.pypa.io/get-pip.py && python3 get-pip.py && \ pip install flask gevent gunicorn && \ rm -rf /root/.cache #pre-trained model package installation RUN pip install spacy RUN python -m spacy download en # Set environment variables ENV PYTHONUNBUFFERED=TRUE ENV PYTHONDONTWRITEBYTECODE=TRUE ENV PATH="/opt/program:${PATH}" COPY NER /opt/program WORKDIR /opt/program

      이전 코드 예제에서 PYTHONUNBUFFERED 환경 변수는 표준 Python이 출력 스트림을 버퍼링하지 못하도록 하므로 사용자에게 로그를 더 빠르게 전송할 수 있습니다. PYTHONDONTWRITEBYTECODE 환경 변수는 이 Python컴파일된 바이트코드 .pyc 파일을 쓰지 못하게 하므로 이 사용 사례에서는 필요하지 않습니다. PATH 환경 변수는 컨테이너를 호출할 때 trainserve 프로그램의 위치를 식별하는 데 사용됩니다.

    3. 새 폴더 내에 새 디렉터리를 생성하여 모델에 사용할 스크립트를 포함합니다. 이 예제에서는 이 예제를 실행하는 데 필요한 다음 스크립트가 포함된 NER이라는 디렉터리를 사용합니다.

      • predictor.py - 모델을 로드하고 추론을 수행하는 로직이 포함된 Python 스크립트입니다.

      • nginx.conf - 웹 서버를 구성하는 스크립트입니다.

      • serve - 추론 서버를 시작하는 스크립트입니다.

      • wsgi.py - 모델을 제공하는 헬퍼 스크립트입니다.

      중요

      .ipynb로 끝나는 노트북에 추론 스크립트를 복사하고 이름을 바꾸는 경우 스크립트에 엔드포인트 배포를 방지하는 서식 문자가 포함될 수 있습니다. 대신 텍스트 파일을 생성하고 이름을 변경합니다.

    4. 모델을 추론에 사용할 수 있도록 스크립트를 업로드합니다. 다음은 /ping/invocations 엔드포인트를 제공하는 데 Flask를 사용하는 predictor.py라는 예제 스크립트입니다.

      from flask import Flask import flask import spacy import os import json import logging #Load in model nlp = spacy.load('en_core_web_sm') #If you plan to use a your own model artifacts, #your model artifacts should be stored in /opt/ml/model/ # The flask app for serving predictions app = Flask(__name__) @app.route('/ping', methods=['GET']) def ping(): # Check if the classifier was loaded correctly health = nlp is not None status = 200 if health else 404 return flask.Response(response= '\n', status=status, mimetype='application/json') @app.route('/invocations', methods=['POST']) def transformation(): #Process input input_json = flask.request.get_json() resp = input_json['input'] #NER doc = nlp(resp) entities = [(X.text, X.label_) for X in doc.ents] # Transform predictions to JSON result = { 'output': entities } resultjson = json.dumps(result) return flask.Response(response=resultjson, status=200, mimetype='application/json')

      이전 스크립트 예제의 /ping 엔드포인트는 모델이 올바르게 로드되면 200의 상태 코드를, 모델이 잘못 로드되면 404의 상태 코드를 반환합니다. /invocations 엔드포인트는 JSON에서 형식이 지정된 요청을 처리하고, 입력 필드를 추출하고, NER 모델을 사용하여 변수 엔터티에서 엔터티를 식별하고 저장합니다. Flask 애플리케이션은 이러한 엔터티가 포함된 응답을 반환합니다. 이러한 필수 상태 요청에 대한 자세한 내용은 컨테이너의 상태 확인(핑) 요청 응답 방법 섹션을 참조하세요.

    5. 추론 서버를 시작하려면 스크립트를 업로드합니다. 다음 스크립트 예제는 애플리케이션 서버로 Gunicorn을 사용하는 serve를, 웹 서버로 Nginx를 호출합니다.

      #!/usr/bin/env python # This file implements the scoring service shell. You don't necessarily need to modify it for various # algorithms. It starts nginx and gunicorn with the correct configurations and then simply waits until # gunicorn exits. # # The flask server is specified to be the app object in wsgi.py # # We set the following parameters: # # Parameter Environment Variable Default Value # --------- -------------------- ------------- # number of workers MODEL_SERVER_WORKERS the number of CPU cores # timeout MODEL_SERVER_TIMEOUT 60 seconds import multiprocessing import os import signal import subprocess import sys cpu_count = multiprocessing.cpu_count() model_server_timeout = os.environ.get('MODEL_SERVER_TIMEOUT', 60) model_server_workers = int(os.environ.get('MODEL_SERVER_WORKERS', cpu_count)) def sigterm_handler(nginx_pid, gunicorn_pid): try: os.kill(nginx_pid, signal.SIGQUIT) except OSError: pass try: os.kill(gunicorn_pid, signal.SIGTERM) except OSError: pass sys.exit(0) def start_server(): print('Starting the inference server with {} workers.'.format(model_server_workers)) # link the log streams to stdout/err so they will be logged to the container logs subprocess.check_call(['ln', '-sf', '/dev/stdout', '/var/log/nginx/access.log']) subprocess.check_call(['ln', '-sf', '/dev/stderr', '/var/log/nginx/error.log']) nginx = subprocess.Popen(['nginx', '-c', '/opt/program/nginx.conf']) gunicorn = subprocess.Popen(['gunicorn', '--timeout', str(model_server_timeout), '-k', 'sync', '-b', 'unix:/tmp/gunicorn.sock', '-w', str(model_server_workers), 'wsgi:app']) signal.signal(signal.SIGTERM, lambda a, b: sigterm_handler(nginx.pid, gunicorn.pid)) # Exit the inference server upon exit of either subprocess pids = set([nginx.pid, gunicorn.pid]) while True: pid, _ = os.wait() if pid in pids: break sigterm_handler(nginx.pid, gunicorn.pid) print('Inference server exiting') # The main routine to invoke the start function. if __name__ == '__main__': start_server()

      이전 스크립트 예제에서는 SIGTERM 신호를 수신할 때 Nginx 및 Gunicorn 하위 프로세스를 종료하는 sigterm_handler 신호 핸들러 함수를 정의합니다. start_server 함수는 신호 핸들러를 시작하고, Nginx 및 Gunicorn 하위 프로세스를 시작하고 모니터링하며, 로그 스트림을 캡처합니다.

    6. 스크립트를 업로드하여 웹 서버를 구성합니다. nginx.conf라는 다음 스크립트 예제는 애플리케이션 서버로 Gunicorn을 사용하여 추론용 모델을 제공하는 Nginx 웹 서버를 구성합니다.

      worker_processes 1; daemon off; # Prevent forking pid /tmp/nginx.pid; error_log /var/log/nginx/error.log; events { # defaults } http { include /etc/nginx/mime.types; default_type application/octet-stream; access_log /var/log/nginx/access.log combined; upstream gunicorn { server unix:/tmp/gunicorn.sock; } server { listen 8080 deferred; client_max_body_size 5m; keepalive_timeout 5; proxy_read_timeout 1200s; location ~ ^/(ping|invocations) { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; proxy_pass http://gunicorn; } location / { return 404 "{}"; } } }

      이전 스크립트 예제는 포그라운드에서 실행되도록 Nginx를 구성하고, error_log를 캡처할 위치를 설정하고, upstream을 Gunicorn 서버의 소켓 삭스로 정의합니다. 서버는 포트 8080에서 수신하도록 서버 블록을 구성하고 클라이언트 요청 본문 크기 및 제한 시간 값에 대한 제한을 설정합니다. 서버 블록은 /ping 또는 /invocations 경로가 포함된 요청을 Gunicorn server http://gunicorn에 전달하고 다른 경로에 대한 404 오류를 반환합니다.

    7. 모델을 제공하는 데 필요한 다른 스크립트를 업로드합니다. 이 예제에서는 Gunicorn이 애플리케이션을 찾는 데 도움이 되도록 wsgi.py라는 다음 예제 스크립트가 필요합니다.

      import predictor as myapp # This is just a simple wrapper for gunicorn to find your app. # If you want to change the algorithm file, simply change "predictor" above to the # new file. app = myapp.app

    docker_test_folder 폴더에서 디렉터리 구조에는 Dockerfile 및 NER 폴더가 포함되어야 합니다. NER 폴더에는 다음과 같이 nginx.conf, predictor.py, serve, 및 wsgi.py 파일이 포함되어야 합니다.

    The Dockerfile structure has inference scripts under the NER directory next to the Dockerfile.

  3. 자체 컨테이너를 빌드합니다.

    폴더 docker_test_folder에서 Docker 컨테이너를 빌드합니다. 다음 예제 명령은 Dockerfile에 구성된 Docker 컨테이너를 빌드합니다.

    ! docker build -t byo-container-test .

    이전 명령은 현재 작업 디렉터리에서 byo-container-test라는 컨테이너를 빌드합니다. Docker 빌드 파라미터에 대한 자세한 내용은 인수 빌드를 참조하세요.

    참고

    Docker가 Dockerfile을 찾을 수 없다는 내용의 다음 오류 메시지가 나타날 경우, Dockerfile의 이름이 정확하고 해당 디렉터리에 저장되었는지 확인하세요.

    unable to prepare context: unable to evaluate symlinks in Dockerfile path: lstat /home/ec2-user/SageMaker/docker_test_folder/Dockerfile: no such file or directory

    Docker가 현재 디렉터리 내에서 어떤 확장자도 없이 특별히 호출된 Dockerfile 파일을 찾는다는 점을 기억해 두세요. 다른 이름을 지정한 경우에는 -f 플래그로 파일 이름을 수동으로 전달할 수 있습니다. 예를 들어 Dockerfile을 Dockerfile-text.txt로 명명한 경우 다음과 같이 -f 플래그와 파일을 사용하여 Docker 컨테이너를 빌드합니다.

    ! docker build -t byo-container-test -f Dockerfile-text.txt .
  4. Amazon Elastic Container Registry(Amazon ECR)에 Docker 이미지 푸시

    노트북 셀에서 Docker 이미지를 ECR로 푸시합니다. 다음 코드 예제에서는 로컬에서 컨테이너를 빌드하고 로그인한 다음 ECR에 푸시하는 방법을 보여줍니다.

    %%sh # Name of algo -> ECR algorithm_name=sm-pretrained-spacy #make serve executable chmod +x NER/serve account=$(aws sts get-caller-identity --query Account --output text) # Region, defaults to us-west-2 region=$(aws configure get region) region=${region:-us-east-1} fullname="${account}.dkr.ecr.${region}.amazonaws.com/${algorithm_name}:latest" # If the repository doesn't exist in ECR, create it. aws ecr describe-repositories --repository-names "${algorithm_name}" > /dev/null 2>&1 if [ $? -ne 0 ] then aws ecr create-repository --repository-name "${algorithm_name}" > /dev/nullfi # Get the login command from ECR and execute it directly aws ecr get-login-password --region ${region}|docker login --username AWS --password-stdin ${fullname} # Build the docker image locally with the image name and then push it to ECR # with the full name. docker build -t ${algorithm_name} . docker tag ${algorithm_name} ${fullname} docker push ${fullname}

    이전 예제에서는 예제 Docker 컨테이너를 ECR로 푸시하는 데 필요한 다음 단계를 수행하는 방법을 보여줍니다.

    1. 알고리즘 이름을 sm-pretrained-spacy로 정의합니다.

    2. NER 폴더 실행 파일 내에 serve 파일을 만듭니다.

    3. 를 설정합니다 AWS 리전.

    4. 아직 존재하지 않으면 ECR을 만듭니다.

    5. ECR에 로그인합니다.

    6. 로컬에서 Docker 컨테이너를 구축합니다.

    7. Docker 이미지를 ECR로 푸시합니다.

  5. SageMaker AI 클라이언트 설정

    추론에 SageMaker AI 호스팅 서비스를 사용하려면 모델을 생성하고, 엔드포인트 구성을 생성하고, 엔드포인트를 생성해야 합니다. 엔드포인트에서 추론을 가져오려면 SageMaker AI boto3 런타임 클라이언트를 사용하여 엔드포인트를 호출할 수 있습니다. 다음 코드는 SageMaker AI boto3 클라이언트를 사용하여 SageMaker AI 클라이언트와 SageMaker 런타임 클라이언트를 모두 설정하는 방법을 보여줍니다. SageMaker

    import boto3 from sagemaker import get_execution_role sm_client = boto3.client(service_name='sagemaker') runtime_sm_client = boto3.client(service_name='sagemaker-runtime') account_id = boto3.client('sts').get_caller_identity()['Account'] region = boto3.Session().region_name #used to store model artifacts which SageMaker AI will extract to /opt/ml/model in the container, #in this example case we will not be making use of S3 to store the model artifacts #s3_bucket = '<S3Bucket>' role = get_execution_role()

    이전 코드 예제에서는 Amazon S3 버킷이 사용되지 않지만 모델 아티팩트를 저장하는 방법을 보여주는 주석으로 삽입됩니다.

    이전 코드 예제를 실행한 후 권한 오류가 발생하면 IAM 역할에 권한을 추가해야 할 수 있습니다. IAM 역할에 대한 자세한 내용은 Amazon SageMaker 역할 관리자 섹션을 참조하세요. 현재 역할에 권한을 추가하는 방법에 대한 자세한 내용은 AWS Amazon SageMaker AI에 대한 관리형 정책 섹션을 참조하세요.

  6. 모델을 생성합니다.

    추론에 SageMaker AI 호스팅 서비스를 사용하려면 SageMaker AI에서 모델을 생성해야 합니다. 다음 코드 예제는 SageMaker AI 내에서 spaCy NER 모델을 생성하는 방법을 보여줍니다.

    from time import gmtime, strftime model_name = 'spacy-nermodel-' + strftime("%Y-%m-%d-%H-%M-%S", gmtime()) # MODEL S3 URL containing model atrifacts as either model.tar.gz or extracted artifacts. # Here we are not #model_url = 's3://{}/spacy/'.format(s3_bucket) container = '{}.dkr.ecr.{}.amazonaws.com/sm-pretrained-spacy:latest'.format(account_id, region) instance_type = 'ml.c5d.18xlarge' print('Model name: ' + model_name) #print('Model data Url: ' + model_url) print('Container image: ' + container) container = { 'Image': container } create_model_response = sm_client.create_model( ModelName = model_name, ExecutionRoleArn = role, Containers = [container]) print("Model Arn: " + create_model_response['ModelArn'])

    이전 코드 예제에서는 5단계의 설명에서 Amazon S3 버킷을 사용할 경우 s3_bucket을 사용하여 model_url를 정의하는 방법과 컨테이너 이미지에 대한 ECR URI를 정의합니다. 이전 코드 예제에서는 ml.c5d.18xlarge를 인스턴스 유형으로 정의합니다. 다른 인스턴스 유형을 선택할 수도 있습니다. 인스턴스 유형에 대한 자세한 내용은 Amazon EC2 인스턴스 유형을 참조하세요.

    이전 코드 예제에서 Image 키는 컨테이너 이미지 URI를 가리킵니다. create_model_response 정의는 create_model method를 사용하여 모델을 생성하고 모델 이름, 역할 및 컨테이너 정보가 포함된 목록을 반환합니다.

    이전 스크립트의 예제 출력은 다음과 같습니다.

    Model name: spacy-nermodel-YYYY-MM-DD-HH-MM-SS Model data Url: s3://spacy-sagemaker-us-east-1-bucket/spacy/ Container image: 123456789012.dkr.ecr.us-east-2.amazonaws.com/sm-pretrained-spacy:latest Model Arn: arn:aws:sagemaker:us-east-2:123456789012:model/spacy-nermodel-YYYY-MM-DD-HH-MM-SS
    1. 엔드포인트 구성 및 생성

      추론에 SageMaker AI 호스팅을 사용하려면 엔드포인트도 구성하고 생성해야 합니다. SageMaker AI는 추론에이 엔드포인트를 사용합니다. 다음 구성 예제에서는 이전에 정의한 인스턴스 유형 및 모델 이름으로 엔드포인트를 생성하고 구성하는 방법을 보여줍니다.

      endpoint_config_name = 'spacy-ner-config' + strftime("%Y-%m-%d-%H-%M-%S", gmtime()) print('Endpoint config name: ' + endpoint_config_name) create_endpoint_config_response = sm_client.create_endpoint_config( EndpointConfigName = endpoint_config_name, ProductionVariants=[{ 'InstanceType': instance_type, 'InitialInstanceCount': 1, 'InitialVariantWeight': 1, 'ModelName': model_name, 'VariantName': 'AllTraffic'}]) print("Endpoint config Arn: " + create_endpoint_config_response['EndpointConfigArn'])

      이전 구성 예제에서 create_endpoint_config_response는 타임스탬프로 생성된 고유한 엔드포인트 구성 이름 endpoint_config_namemodel_name를 연결합니다.

      이전 스크립트의 예제 출력은 다음과 같습니다.

      Endpoint config name: spacy-ner-configYYYY-MM-DD-HH-MM-SS Endpoint config Arn: arn:aws:sagemaker:us-east-2:123456789012:endpoint-config/spacy-ner-config-MM-DD-HH-MM-SS

      엔드포인트 오류에 대한 자세한 내용은 엔드포인트를 생성하거나 업데이트할 때 Amazon SageMaker AI 엔드포인트가 실패 상태가 되는 이유는 무엇입니까?를 참조하세요.

    2. 엔드포인트를 생성하고 엔드포인트가 서비스될 때까지 기다립니다.

      다음 코드 예제는 이전 구성 예제의 구성을 사용하여 엔드포인트를 생성하고 모델을 배포합니다.

      %%time import time endpoint_name = 'spacy-ner-endpoint' + strftime("%Y-%m-%d-%H-%M-%S", gmtime()) print('Endpoint name: ' + endpoint_name) create_endpoint_response = sm_client.create_endpoint( EndpointName=endpoint_name, EndpointConfigName=endpoint_config_name) print('Endpoint Arn: ' + create_endpoint_response['EndpointArn']) resp = sm_client.describe_endpoint(EndpointName=endpoint_name) status = resp['EndpointStatus'] print("Endpoint Status: " + status) print('Waiting for {} endpoint to be in service...'.format(endpoint_name)) waiter = sm_client.get_waiter('endpoint_in_service') waiter.wait(EndpointName=endpoint_name)

      이전 코드 예제에서 create_endpoint 메서드는 이전 코드 예제에서 생성된 엔드포인트 이름으로 엔드포인트를 생성하고 엔드포인트의 Amazon 리소스 이름을 인쇄합니다. describe_endpoint 메서드는 엔드포인트 및 해당 상태에 대한 정보를 반환합니다. SageMaker AI 웨이터는 엔드포인트가 서비스될 때까지 기다립니다.

  7. 엔드포인트를 테스트합니다.

    엔드포인트가 사용 중이면 엔드포인트에 호출 요청을 보냅니다. 다음 코드 예제는 엔드포인트에 테스트 요청을 보내는 방법을 보여줍니다.

    import json content_type = "application/json" request_body = {"input": "This is a test with NER in America with \ Amazon and Microsoft in Seattle, writing random stuff."} #Serialize data for endpoint #data = json.loads(json.dumps(request_body)) payload = json.dumps(request_body) #Endpoint invocation response = runtime_sm_client.invoke_endpoint( EndpointName=endpoint_name, ContentType=content_type, Body=payload) #Parse results result = json.loads(response['Body'].read().decode())['output'] result

    이전 코드 예제에서 메서드 json.dumpsrequest_body를 JSON 형식의 문자열로 직렬화하고 이를 변수 페이로드에 저장합니다. 그런 다음 SageMaker AI 런타임 클라이언트는 엔드포인트 호출 방법을 사용하여 엔드포인트에 페이로드를 전송합니다. 결과에는 출력 필드를 추출한 후 엔드포인트의 응답이 포함됩니다.

    이전 코드 예제는 다음 출력을 반환해야 합니다.

    [['NER', 'ORG'], ['America', 'GPE'], ['Amazon', 'ORG'], ['Microsoft', 'ORG'], ['Seattle', 'GPE']]
  8. 엔드포인트 삭제

    호출을 완료한 후 엔드포인트를 삭제하여 리소스를 보존합니다. 다음 코드 예제는 엔드포인트를 삭제하는 방법을 보여줍니다.

    sm_client.delete_endpoint(EndpointName=endpoint_name) sm_client.delete_endpoint_config(EndpointConfigName=endpoint_config_name) sm_client.delete_model(ModelName=model_name)

    이 예제의 코드가 포함된 전체 노트북은 BYOC-Single-Model 을 참조하세요.