Adaptez votre propre conteneur d'inférence pour Amazon SageMaker - Amazon SageMaker

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Adaptez votre propre conteneur d'inférence pour Amazon SageMaker

Si vous ne pouvez utiliser aucune des images répertoriées Images SageMaker Docker prédéfinies sur Amazon SageMaker pour votre cas d'utilisation, vous pouvez créer votre propre conteneur Docker et l'utiliser à des SageMaker fins d'entraînement et d'inférence. Pour être compatible avec SageMaker, votre contenant doit présenter les caractéristiques suivantes :

  • Votre conteneur doit avoir une liste de serveurs Web sur le port8080.

  • Votre conteneur doit accepter les POST demandes adressées aux points de terminaison /invocations et /ping en temps réel. Les demandes que vous envoyez à ces points de terminaison doivent être renvoyées dans les 60 secondes et avoir une taille maximale de 6 Mo.

Pour plus d'informations et un exemple de création de votre propre conteneur Docker à des fins d'entraînement et d'inférence SageMaker, consultez la section Création de votre propre conteneur d'algorithmes.

Le guide suivant explique comment utiliser un JupyterLab espace avec Amazon SageMaker Studio Classic pour adapter un conteneur d'inférence afin qu'il fonctionne avec l' SageMaker hébergement. L'exemple utilise un NGINX serveur Web, Gunicorn en tant que Python interface de passerelle de serveur Web, et Flask en tant que framework d'application Web. Vous pouvez utiliser différentes applications pour adapter votre conteneur à condition qu'il réponde aux exigences répertoriées précédemment. Pour plus d'informations sur l'utilisation de votre propre code d'inférence, consultezCode d'inférence personnalisé avec services d'hébergement.

Adaptez votre conteneur d'inférence

Suivez les étapes ci-dessous pour adapter votre propre conteneur d'inférence afin qu'il fonctionne avec l' SageMaker hébergement. L'exemple présenté dans les étapes suivantes utilise un modèle Named Entity Recognition (NER) préentraîné qui utilise la bibliothèque de traitement du langage spaCynaturel (NLP) pour Python les opérations suivantes :

  • A Dockerfile pour créer le conteneur qui contient le NER modèle.

  • Scripts d'inférence destinés à servir le NER modèle.

Si vous adaptez cet exemple à votre cas d'utilisation, vous devez utiliser un Dockerfile et les scripts d'inférence nécessaires au déploiement et au service de votre modèle.

  1. Créez de JupyterLab l'espace avec Amazon SageMaker Studio Classic (facultatif).

    Vous pouvez utiliser n'importe quel bloc-notes pour exécuter des scripts afin d'adapter votre conteneur d'inférence à l' SageMaker hébergement. Cet exemple vous montre comment utiliser un JupyterLab espace dans Amazon SageMaker Studio Classic pour lancer un JupyterLab application fournie avec une image SageMaker de distribution. Pour de plus amples informations, veuillez consulter SageMaker JupyterLab.

  2. Téléchargez un Docker scripts de fichiers et d'inférence.

    1. Créez un nouveau dossier dans votre répertoire personnel. Si vous utilisez JupyterLab, dans le coin supérieur gauche, cliquez sur l'icône Nouveau dossier et entrez le nom du dossier qui contiendra votre Dockerfile. Dans cet exemple, le dossier est appelédocker_test_folder.

    2. Téléchargez un Dockerfile fichier texte dans votre nouveau dossier. Ce qui suit est un exemple Dockerfile qui crée un Docker conteneur avec un modèle Named Entity Recognition (NER) préentraîné à partir spaCydes applications et des variables d'environnement nécessaires pour exécuter l'exemple :

      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

      Dans l'exemple de code précédent, la variable d'environnement PYTHONUNBUFFERED conserve Python de la mise en mémoire tampon du flux de sortie standard, ce qui permet de livrer plus rapidement les journaux à l'utilisateur. La variable d'environnement PYTHONDONTWRITEBYTECODE conserve Python de l'écriture de .pyc fichiers de bytecode compilés, qui ne sont pas nécessaires pour ce cas d'utilisation. La variable d'environnement PATH est utilisée pour identifier l'emplacement des serve programmes train et lorsque le conteneur est invoqué.

    3. Créez un nouveau répertoire dans votre nouveau dossier pour contenir les scripts destinés à servir votre modèle. Cet exemple utilise un répertoire appeléNER, qui contient les scripts suivants nécessaires pour exécuter cet exemple :

      • predictor.py— UN Python script contenant la logique permettant de charger et d'effectuer des inférences avec votre modèle.

      • nginx.conf— Script pour configurer un serveur Web.

      • serve— Script qui démarre un serveur d'inférence.

      • wsgi.py— Un script d'assistance destiné à servir un modèle.

      Important

      Si vous copiez vos scripts d'inférence dans un bloc-notes se terminant par .ipynb et que vous les renommez, votre script peut contenir des caractères de mise en forme qui empêcheront le déploiement de votre terminal. Créez plutôt un fichier texte et renommez-le.

    4. Téléchargez un script pour rendre votre modèle disponible à des fins d'inférence. Voici un exemple de script appelé predictor.py qui utilise Flask pour fournir les /invocations points de terminaison /ping et :

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

      Dans l'exemple de script précédent, le point de /ping terminaison renvoie un code d'état indiquant 200 si le modèle est chargé correctement et 404 s'il n'est pas chargé correctement. Le /invocations point de terminaison traite une demande formatée en JSON, extrait le champ de saisie et utilise NER modèle pour identifier et stocker les entités dans les entités variables. Le Flask l'application renvoie la réponse qui contient ces entités. Pour plus d'informations sur ces demandes de santé obligatoires, consultezComment votre conteneur doit-il répondre aux requêtes de surveillance de l'état (Ping) ?.

    5. Téléchargez un script pour démarrer un serveur d'inférence. L'exemple de script suivant appelle à serve l'aide de Gunicorn en tant que serveur d'applications, et Nginx en tant que serveur 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()

      L'exemple de script précédent définit une fonction sigterm_handler de gestion de signal qui arrête le Nginx and Gunicorn sous-traite lorsqu'il reçoit un SIGTERM signal. Une start_server fonction démarre le gestionnaire de signaux, démarre et surveille le Nginx and Gunicorn sous-traite et capture les flux de journaux.

    6. Téléchargez un script pour configurer votre serveur Web. L'exemple de script suivantnginx.conf, appelé, configure un Nginx serveur Web utilisant Gunicorn en tant que serveur d'applications pour servir votre modèle à des fins d'inférence :

      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 "{}"; } } }

      L'exemple de script précédent configure Nginx pour courir au premier plan, définit l'emplacement pour capturer leerror_log, et définit upstream comme Gunicorn socket sock du serveur. Le serveur configure le bloc serveur pour qu'il écoute sur le port8080, fixe des limites à la taille du corps de la demande du client et aux valeurs de délai d'expiration. Le bloc serveur transmet les demandes contenant l'un /ping ou l'autre /invocations des chemins au Gunicorn server http://gunicorn, et renvoie une 404 erreur pour les autres chemins.

    7. Téléchargez tous les autres scripts nécessaires pour servir votre modèle. Cet exemple nécessite l'exemple de script suivant appelé wsgi.py pour vous aider Gunicorn trouvez votre application :

      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

    À partir du dossierdocker_test_folder, la structure de votre répertoire doit contenir un Dockerfile et le dossier NER. Le NER le dossier doit contenir les fichiers nginx.confpredictor.py,serve, et wsgi.py comme suit :

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

  3. Construisez votre propre conteneur.

    À partir du dossierdocker_test_folder, créez votre Docker contenant. L'exemple de commande suivant créera le Docker conteneur configuré dans votre Dockerfile:

    ! docker build -t byo-container-test .

    La commande précédente créera un conteneur appelé byo-container-test dans le répertoire de travail actuel. Pour plus d'informations sur le Docker paramètres de construction, voir Arguments de construction.

    Note

    Si le message d'erreur suivant s'affiche Docker Impossible de trouver le Dockerfile, assurez-vous que Dockerfile porte le nom correct et a été enregistré dans le répertoire.

    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 recherche un fichier spécifiquement appelé Dockerfile sans aucune extension dans le répertoire en cours. Si vous lui avez donné un autre nom, vous pouvez transmettre le nom du fichier manuellement à l'aide de l'indicateur -f. Par exemple, si vous avez nommé votre Dockerfile comme Dockerfile-text.txt, construisez votre Docker conteneur en utilisant le -f drapeau suivi de votre fichier comme suit :

    ! docker build -t byo-container-test -f Dockerfile-text.txt .
  4. Poussez votre Docker Image vers un Amazon Elastic Container Registry (AmazonECR)

    Dans une cellule d'ordinateur portable, appuyez sur Docker image vers unECR. L'exemple de code suivant vous montre comment créer votre conteneur localement, vous connecter et le transférer vers un 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}

    Dans l'exemple précédent, il montre comment effectuer les étapes suivantes nécessaires pour transférer l'exemple de conteneur Docker vers un ECR :

    1. Définissez le nom de l'algorithme commesm-pretrained-spacy.

    2. Créez le serve fichier à l'intérieur du NER dossier exécutable.

    3. Réglez le Région AWS.

    4. Créez un ECR s'il n'existe pas déjà.

    5. Connectez-vous auECR.

    6. Construisez le Docker conteneur local.

    7. Appuyez sur le Docker image vers leECR.

  5. Configurer le SageMaker client

    Si vous souhaitez utiliser les services SageMaker d'hébergement à des fins d'inférence, vous devez créer un modèle, créer une configuration de point de terminaison et créer un point de terminaison. Pour obtenir des déductions à partir de votre point de terminaison, vous pouvez utiliser le SageMaker boto3 Client d'exécution pour appeler votre point de terminaison. Le code suivant explique comment configurer à la fois le SageMaker client et le client SageMaker Runtime à l'aide du client SageMaker boto3 :

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

    Dans l'exemple de code précédent, le compartiment Amazon S3 n'est pas utilisé, mais il est inséré en tant que commentaire pour montrer comment stocker les artefacts du modèle.

    Si vous recevez une erreur d'autorisation après avoir exécuté l'exemple de code précédent, vous devrez peut-être ajouter des autorisations à votre IAM rôle. Pour plus d'informations sur IAM les rôles, consultezAmazon SageMaker Role Manager. Pour plus d'informations sur l'ajout d'autorisations à votre rôle actuel, consultezAWS Politiques gérées pour Amazon SageMaker.

  6. Créez votre modèle.

    Si vous souhaitez utiliser les services SageMaker d'hébergement à des fins d'inférence, vous devez créer un modèle dans SageMaker. L'exemple de code suivant vous montre comment créer spaCy NER modèle intérieur de 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'])

    L'exemple de code précédent montre comment définir un compartiment à model_url l'aide du compartiment Amazon S3 s3_bucket si vous deviez utiliser le compartiment Amazon S3 à partir des commentaires de l'étape 5, et définit l'ECRURIimage du conteneur. Les exemples de code précédents définissent ml.c5d.18xlarge le type d'instance. Vous pouvez également choisir un autre type d'instance. Pour plus d'informations sur les types d'instances disponibles, consultez la section Types d'EC2instances Amazon.

    Dans l'exemple de code précédent, la Image clé pointe vers l'image du conteneurURI. La create_model_response définition utilise le create_model method pour créer un modèle et renvoie le nom du modèle, le rôle et une liste contenant les informations sur le conteneur.

    Voici un exemple de sortie du script précédent :

    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. Configuration et création d'un point de terminaison

      Pour utiliser l' SageMaker hébergement à des fins d'inférence, vous devez également configurer et créer un point de terminaison. SageMaker utilisera ce point de terminaison pour l'inférence. L'exemple de configuration suivant montre comment générer et configurer un point de terminaison avec le type d'instance et le nom de modèle que vous avez définis précédemment :

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

      Dans l'exemple de configuration précédent, create_endpoint_config_response model_name associe le à un nom endpoint_config_name de configuration de point de terminaison unique créé avec un horodatage.

      Voici un exemple de sortie du script précédent :

      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

      Pour plus d'informations sur les erreurs de point de terminaison, consultez Pourquoi mon point de SageMaker terminaison Amazon passe en état d'échec lorsque je crée ou mets à jour un point de terminaison ?

    2. Créez un point de terminaison et attendez qu'il soit en service.

      L'exemple de code suivant crée le point de terminaison en utilisant la configuration de l'exemple de configuration précédent et déploie le modèle :

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

      Dans l'exemple de code précédent, la create_endpoint méthode crée le point de terminaison avec le nom de point de terminaison généré dans l'exemple de code précédent, et imprime le nom de ressource Amazon du point de terminaison. La describe_endpoint méthode renvoie des informations sur le point de terminaison et son état. Un SageMaker serveur attend que le terminal soit en service.

  7. Testez votre terminal.

    Une fois que votre terminal est en service, envoyez-lui une demande d'invocation. L'exemple de code suivant montre comment envoyer une demande de test à votre terminal :

    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

    Dans l'exemple de code précédent, la méthode json.dumps sérialise le request_body dans une chaîne formatée JSON et l'enregistre dans la charge utile variable. Le client SageMaker Runtime utilise ensuite la méthode d'appel du point de terminaison pour envoyer la charge utile à votre point de terminaison. Le résultat contient la réponse de votre point de terminaison après avoir extrait le champ de sortie.

    L'exemple de code précédent doit renvoyer le résultat suivant :

    [['NER', 'ORG'], ['America', 'GPE'], ['Amazon', 'ORG'], ['Microsoft', 'ORG'], ['Seattle', 'GPE']]
  8. Supprimer votre point de terminaison

    Une fois que vous avez terminé vos appels, supprimez votre point de terminaison pour économiser les ressources. L'exemple de code suivant vous montre comment supprimer votre point de terminaison :

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

    Pour un bloc-notes complet contenant le code de cet exemple, voir BYOC-Single-Model.