為 Amazon 調整您自己的推論容器 SageMaker - Amazon SageMaker

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

為 Amazon 調整您自己的推論容器 SageMaker

如果您無法將 Amazon 預先建置的 SageMaker Docker 映像 中列出的任何映像 SageMaker 用於您的使用案例,則可以建置自己的 Docker 容器,並在內部將其用於 SageMaker 訓練和推論。若要與 相容 SageMaker,您的容器必須具有下列特性:

  • 您的容器必須具有連接埠 上的 Web 伺服器清單8080

  • 您的容器必須接受 /invocations/ping 即時端點的POST請求。您傳送至這些端點的請求必須以 60 秒傳回,且大小上限為 6 MB。

如需使用 建置自己的 Docker 容器以進行訓練和推論的詳細資訊和範例 SageMaker,請參閱建置自己的演算法容器

下列指南說明如何搭配 Amazon SageMaker Studio Classic 使用JupyterLab空間來調整推論容器,以使用 SageMaker 託管。此範例使用 NGINX Web 伺服器、Gunicorn 作為 Python Web 伺服器閘道介面,以及 Flask 作為 Web 應用程式架構。您可以使用不同的應用程式來調整容器,只要其符合先前列出的需求即可。如需使用您自己的推論程式碼的詳細資訊,請參閱 使用 Hosting Services 的自訂推論程式碼

調整推論容器

使用下列步驟來調整您自己的推論容器,以使用 SageMaker 託管。下列步驟中顯示的範例使用預先訓練的具名實體識別 (NER) 模型,該模型使用 spaCy 的自然語言處理 (NLP) 程式庫Python和下列項目:

  • A Dockerfile 建置包含 的容器 NER 模型。

  • 提供 的推論指令碼 NER 模型。

如果您針對使用案例調整此範例,則必須使用 Dockerfile 部署和服務模型所需的 和推論指令碼。

  1. 使用 Amazon SageMaker Studio Classic 建立 JupyterLab 空間 (選用)。

    您可以使用任何筆記本來執行指令碼,透過 SageMaker 託管來調整推論容器。此範例示範如何使用 JupyterLab Amazon SageMaker Studio Classic 中的空間,以啟動 JupyterLab 隨附分佈 SageMaker映像的應用程式。如需詳細資訊,請參閱SageMaker JupyterLab

  2. 上傳 Docker 檔案和推論指令碼。

    1. 在主目錄中建立新資料夾。如果您使用的是 JupyterLab,在左上角,選擇新資料夾圖示,然後輸入資料夾名稱以包含您的 Dockerfile。 在此範例中,資料夾稱為 docker_test_folder

    2. 上傳 Dockerfile 文字檔案到新資料夾。以下是範例 Dockerfile 建立 Docker 容器具有來自 的預先訓練的具名實體識別 (NER) 模型spaCy,執行範例所需的應用程式和環境變數:

      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 – A Python 指令碼,其中包含使用模型載入和執行推論的邏輯。

      • nginx.conf – 用來設定 Web 伺服器的指令碼。

      • serve – 啟動推論伺服器的指令碼。

      • wsgi.py – 協助程式指令碼,用於提供模型。

      重要

      如果您將推論指令碼複製到結尾為 的筆記本.ipynb中並重新命名,則指令碼可能包含格式字元,以防止端點部署。相反地,請建立文字檔案並重新命名。

    4. 上傳指令碼,讓您的模型可供推論。以下是名為 的範例指令碼predictor.py,其使用 Flask 提供 /ping/invocations 端點:

      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')

      如果正確載入模型,以及錯誤404載入模型200,上一個指令碼範例中的/ping端點會傳回 的狀態碼。/invocations 端點會處理格式化為 的請求 JSON,擷取輸入欄位,並使用 NER 模型,以識別和儲存變數實體中的實體。所以此 Flask 應用程式會傳回包含這些實體的回應。如需這些必要運作狀態請求的詳細資訊,請參閱 容器對運作狀態檢查 (Ping) 請求應有的回應方式

    5. 上傳指令碼以啟動推論伺服器。下列指令碼範例serve使用 呼叫 Gunicorn 作為應用程式伺服器,以及 Nginx 作為 Web 伺服器:

      #!/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_handler,該函數會關閉 Nginx 以及 Gunicorn 會在收到SIGTERM訊號時處理子程序。start_server 函數會啟動訊號處理常式、啟動和監控 Nginx 以及 Gunicorn 子程序,並擷取日誌串流。

    6. 上傳指令碼以設定 Web 伺服器。下列指令碼範例稱為 nginx.conf,可設定 Nginx 使用 的 Web 伺服器 Gunicorn 作為應用程式伺服器,為您的模型提供推論服務:

      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. 上傳為模型提供服務所需的任何其他指令碼。此範例需要下列名為 的範例指令碼wsgi.py來協助 Gunicorn 尋找您的應用程式:

      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.confservepredictor.pywsgi.py ,如下所示:

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

  3. 建置您自己的容器。

    從 資料夾 中docker_test_folder,建置您的 Docker 容器。下列範例命令將建置 Docker 在您的 中設定的容器 Dockerfile:

    ! 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,建置您的 Docker 容器使用-f旗標,後面接著您的檔案,如下所示:

    ! docker build -t byo-container-test -f Dockerfile-text.txt .
  4. 推送您的 Docker Amazon Elastic Container Registry (Amazon ECR) 的影像

    在筆記本儲存格中,推送您的 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. serve 檔案位於 NER 資料夾可執行檔。

    3. 設定 AWS 區域。

    4. ECR 如果尚未存在,請建立 。

    5. 登入 ECR。

    6. 建置 Docker 容器。

    7. 推送 Docker 映像到 ECR。

  5. 設定 SageMaker 用戶端

    如果您想要使用 SageMaker 託管服務進行推論,則必須建立模型 、建立端點組態建立端點 。若要從端點取得推論,您可以使用 SageMaker boto3 執行期用戶端以叫用您的端點。下列程式碼說明如何使用 boto3 用戶端 設定 SageMaker用戶端和 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 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 Role Manager。如需將許可新增至目前角色的詳細資訊,請參閱 AWS Amazon 的受管政策 SageMaker

  6. 建立模型。

    如果您想要使用 SageMaker 託管服務進行推論,您必須在 中建立模型 SageMaker。下列程式碼範例示範如何建立 spaCy NER 中的模型 SageMaker:

    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'])

    先前的程式碼範例顯示s3_bucket,如果您要使用步驟 5 中註解中的 Amazon S3 儲存貯體,如何使用 model_url 定義 ,以及定義容器映像ECRURI的 。先前的程式碼範例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 託管進行推論,您還必須設定和建立端點。 SageMaker 將使用此端點進行推論。下列組態範例顯示如何使用您先前定義的執行個體類型和模型名稱來產生和設定端點:

      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'])

      在先前的組態範例中, 會將 model_name與使用時間戳記endpoint_config_name建立的唯一端點組態名稱create_endpoint_config_response建立關聯。

      上一個指令碼的範例輸出如下:

      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 端點會進入失敗狀態?

    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 Resource Name。此describe_endpoint方法會傳回端點及其狀態的相關資訊。 SageMaker 服務生等待端點處於服務狀態。

  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.dumps序列化request_body為格式化為 的字串,JSON並將其儲存在變數承載中。然後 SageMaker ,執行期用戶端會使用叫用端點方法將承載傳送至您的端點。結果包含擷取輸出欄位後來自端點的回應。

    先前的程式碼範例應傳回下列輸出:

    [['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