

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 带有 AI 的自定义 Docker 容 SageMaker 器
<a name="docker-containers-adapt-your-own"></a>

您可以调整现有的 Docker 镜像以与 SageMaker AI 配合使用。当您的容器满足预构建 SageMaker 的 SageMaker AI 镜像当前不支持的功能或安全要求时，您可能需要将现有的外部 Docker 镜像与 AI 配合使用。有两个工具包可以让你自带容器并对其进行调整以与 SageMaker AI 配合使用：
+ [SageMaker 训练工具包](https://github.com/aws/sagemaker-training-toolkit)-使用此工具包使用 SageMaker AI 训练模型。
+ [SageMaker AI 推理工具包](https://github.com/aws/sagemaker-inference-toolkit) — 使用此工具包部署带有 SageMaker AI 的模型。

以下主题介绍如何使用 SageMaker 训练和推理工具包调整现有图像：

**Topics**
+ [单个框架库](#docker-containers-adapt-your-own-frameworks)
+ [SageMaker 训练和推理工具包](amazon-sagemaker-toolkits.md)
+ [调整自己的训练容器](adapt-training-container.md)
+ [调整你自己的推理容器以适应 Amazon AI SageMaker](adapt-inference-container.md)

## 单个框架库
<a name="docker-containers-adapt-your-own-frameworks"></a>

除了 SageMaker 训练工具包和 SageMaker 人工智能推理工具包外，A SageMaker I 还提供专门用于、 TensorFlow MXNet PyTorch、和 Chainer 的工具包。下表提供了指向 GitHub 存储库的链接，这些存储库包含每个框架的源代码及其各自的服务工具包。链接的说明用于使用 Python SDK 在 SageMaker AI 上运行训练算法和托管模型。这些独立库的功能包含在 SageMaker AI 训练工具包和 A SageMaker I 推理工具包中。


| 框架 | 工具包源代码 | 
| --- | --- | 
| TensorFlow |  [SageMaker 人工智能 TensorFlow 训练](https://github.com/aws/sagemaker-tensorflow-training-toolkit) [SageMaker 人工智能 TensorFlow 服务](https://github.com/aws/sagemaker-tensorflow-serving-container)  | 
| MXNet |  [SageMaker 人工智能 MXNet 训练](https://github.com/aws/sagemaker-mxnet-training-toolkit) [SageMaker AI MXNet 推理](https://github.com/aws/sagemaker-mxnet-inference-toolkit)  | 
| PyTorch |  [SageMaker 人工智能 PyTorch 训练](https://github.com/aws/sagemaker-pytorch-training-toolkit) [SageMaker AI PyTorch 推理](https://github.com/aws/sagemaker-pytorch-inference-toolkit)  | 
| Chainer |  [SageMaker AI Chainer SageMaker AI 容器](https://github.com/aws/sagemaker-chainer-container)  | 

# SageMaker 训练和推理工具包
<a name="amazon-sagemaker-toolkits"></a>

[SageMaker 训练](https://github.com/aws/sagemaker-training-toolkit)和 [SageMaker AI 推理](https://github.com/aws/sagemaker-inference-toolkit)工具包实现了调整容器以在 AI 上 SageMaker 运行脚本、训练算法和部署模型所需的功能。安装后，此库会为用户定义以下内容：
+ 用于存储代码和其他资源的位置。
+ 包含要在容器启动时运行的代码的入口点。您的 Dockerfile 必须将需要运行的代码复制到与 SageMaker AI 兼容的容器所期望的位置。
+ 容器管理部署以进行训练和推理所需的其他信息。

## SageMaker AI 工具包容器结构
<a name="sagemaker-toolkits-structure"></a>

当 SageMaker AI 训练模型时，它会在容器的`/opt/ml`目录中创建以下文件文件夹结构。

```
/opt/ml
├── input
│   ├── config
│   │   ├── hyperparameters.json
│   │   └── resourceConfig.json
│   └── data
│       └── <channel_name>
│           └── <input data>
├── model
│
├── code
│
├── output
│
└── failure
```

运行模型*训练*作业时， SageMaker AI 容器使用`/opt/ml/input/`目录，该目录包含配置算法超参数的 JSON 文件以及用于分布式训练的网络布局。该`/opt/ml/input/`目录还包含指定 SageMaker 人工智能访问数据的渠道的文件，这些数据存储在亚马逊简单存储服务 (Amazon S3) Service 中。A SageMaker I 容器库将容器将要运行的脚本放在`/opt/ml/code/`目录中。您的脚本应该将算法生成的模型写入 `/opt/ml/model/` 目录。有关更多信息，请参阅 [带有自定义训练算法的容器](your-algorithms-training-algo.md)。

当您在 SageMaker AI 上*托管*经过训练的模型以进行推断时，可以将模型部署到 HTTP 端点。作为对推理请求的响应，该模型进行实时预测。容器必须包含服务堆栈以处理这些请求。

在托管或批量转换容器中，模型文件所在的文件夹是在训练期间要写入同一个文件夹。

```
/opt/ml/model
│
└── <model files>
```

有关更多信息，请参阅 [具有自定义推理代码的容器](your-algorithms-inference-main.md)。

## 单个容器与多个容器
<a name="sagemaker-toolkits-separate-images"></a>

您可以向训练算法和推理代码提供单独的 Docker 映像，也可以为它们使用相同的 Docker 映像。在创建用于 SageMaker AI 的 Docker 镜像时，请考虑以下几点：
+ 提供两个 Docker 镜像可能会增加存储要求和成本，因为常见的库可能会重复。
+ 通常对于训练和托管而言，容器越小，启动速度越快。模型训练速度更快，并且托管服务可通过更快速地自动扩展对流量增加做出反应。
+ 您或许可以编写一个远小于训练容器的推理容器。当你使用 GPUs训练时，这种情况尤其常见，但你的推理代码已经过优化。 CPUs
+ SageMaker AI 要求 Docker 容器在没有特权访问权限的情况下运行。
+ 您构建的 Docker 容器和 SageMaker AI 提供的容器都可以向`Stdout`和`Stderr`文件发送消息。 SageMaker AI 会将这些消息发送到您 AWS 账户中的 Amazon CloudWatch 日志。

有关如何创建 SageMaker AI 容器以及如何在其中执行脚本的更多信息，请参阅上 GitHub的 [SageMaker AI 训练工具包](https://github.com/aws/sagemaker-training-toolkit)和 [SageMaker AI 推理工具包](https://github.com/aws/sagemaker-inference-toolkit)存储库。它们还提供了重要的环境变量列表和 SageMaker 人工智能容器提供的环境变量。

# 调整自己的训练容器
<a name="adapt-training-container"></a>

要运行您自己的训练模型，请使用[亚马逊 SageMaker 培训工具包通过亚马逊](https://github.com/aws/sagemaker-training-toolkit) SageMaker 笔记本实例构建 Docker 容器。

## 步骤 1：创建 SageMaker 笔记本实例
<a name="byoc-training-step1"></a>

1. 打开 Amazon A SageMaker I 控制台，网址为[https://console.aws.amazon.com/sagemaker/](https://console.aws.amazon.com/sagemaker/)。

1. 在左侧导航窗格中，依次选择**笔记本**、**笔记本实例**和**创建笔记本实例**。

1. 在**创建笔记本实例**页面上提供以下信息：

   1. 对于 **Notebook instance name (笔记本实例名称)**，输入 **RunScriptNotebookInstance**。

   1. 对于**笔记本实例类型**，选择 **ml.t2.medium**。

   1. 展开**权限和加密**部分，执行以下操作：

      1. 对于 **IAM 角色**，选择**创建新角色**。这将打开一个新窗口。

      1. 在**创建 IAM 角色**页面上，选择**特定的 S3 存储桶**，指定一个名为 **sagemaker-run-script** 的 S3 存储桶，然后选择**创建角色**。

         SageMaker AI 创建了一个名为的 IAM 角色`AmazonSageMaker-ExecutionRole-YYYYMMDDTHHmmSS`。例如 `AmazonSageMaker-ExecutionRole-20190429T110788`。请注意，执行角色的命名约定会使用创建角色的日期和时间，由 `T` 分隔。

   1. 对于**根访问**，选择**已启用**。

   1. 选择**创建笔记本实例**。

1. 在**笔记本实例**页面上，**状态**是**待处理**。Amazon A SageMaker I 可能需要几分钟才能启动机器学习计算实例（在本例中为启动笔记本实例）并向其连接 ML 存储卷。笔记本实例有一个预配置的 Jupyter 笔记本服务器和一组 Anaconda 库。有关更多信息，请参阅 [ CreateNotebookInstance](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateNotebookInstance.html)。

   

1. 单击您刚刚创建的笔记本的**名称**。这将打开一个新页面。

1.  在**权限和加密**部分，复制 **IAM 角色 ARN 编号**，然后将其粘贴到记事本文件中以临时保存。稍后，您将使用此 IAM 角色 ARN 编号，在笔记本实例中配置本地训练估算器。**The IAM role ARN number (IAM 角色 ARN 编号)** 如下所示：`'arn:aws:iam::111122223333:role/service-role/AmazonSageMaker-ExecutionRole-20190429T110788'`

1. 笔记本实例的状态更改为后 **InService**，选择**打开 JupyterLab**。

## 步骤 2：创建并上传 Dockerfile 和 Python 训练脚本
<a name="byoc-training-step2"></a>

1.  JupyterLab 打开后，在您的主目录中创建一个新文件夹 JupyterLab。在左上角，选择**新建文件夹**图标，然后输入文件夹名称 `docker_test_folder`。

1. 在 `docker_test_folder` 目录中创建 `Dockerfile` 文本文件。

   1. 选择左上角的**新启动程序**图标 (\$1)。

   1. 在右窗格的**其他**部分下，选择**文本文件**。

   1. 将以下 `Dockerfile` 示例代码粘贴到您的文本文件中。

      ```
      #Download an open source TensorFlow Docker image
      FROM tensorflow/tensorflow:latest-gpu-jupyter
      
      # Install sagemaker-training toolkit that contains the common functionality necessary to create a container compatible with SageMaker AI and the Python SDK.
      RUN pip3 install sagemaker-training
      
      # Copies the training code inside the container
      COPY train.py /opt/ml/code/train.py
      
      # Defines train.py as script entrypoint
      ENV SAGEMAKER_PROGRAM train.py
      ```

      Dockerfile 脚本将执行以下任务：
      + `FROM tensorflow/tensorflow:latest-gpu-jupyter`— 下载最新的 TensorFlow Docker 基础镜像。您可以将其替换为要用于构建容器的任何 Docker 基础镜像以及 AWS 预先构建的容器基础镜像。
      + `RUN pip install sagemaker-training`— 安装 [SageMaker AI 训练工具包](https://github.com/aws/sagemaker-training-toolkit)，其中包含创建与 SageMaker AI 兼容的容器所需的常用功能。
      + `COPY train.py /opt/ml/code/train.py`— 将脚本复制到 SageMaker AI 预期的容器内位置。该脚本必须位于此文件夹中。
      + `ENV SAGEMAKER_PROGRAM train.py` – 以您的训练脚本 `train.py` 作为入口点脚本，复制到容器的 `/opt/ml/code` 文件夹中。这是在您构建自己的容器时唯一必须指定的环境变量。

   1.  在左侧目录导航窗格中，文本文件可能会自动命名为 `untitled.txt`。要重命名文件，请右键单击该文件，然后选择**重命名**，将文件重命名为没有 `.txt` 扩展名的 `Dockerfile`，然后按 `Ctrl+s` 或 `Command+s` 以保存文件。

1. 将训练脚本 `train.py` 上传到 `docker_test_folder`。对于本练习，您可以使用以下示例脚本创建在 [MNIST 数据集](https://en.wikipedia.org/wiki/MNIST_database)上训练的模型来读取手写数字。

   ```
   import tensorflow as tf
   import os
   
   mnist = tf.keras.datasets.mnist
   
   (x_train, y_train), (x_test, y_test) = mnist.load_data()
   x_train, x_test = x_train / 255.0, x_test / 255.0
   
   model = tf.keras.models.Sequential([
   tf.keras.layers.Flatten(input_shape=(28, 28)),
   tf.keras.layers.Dense(128, activation='relu'),
   tf.keras.layers.Dropout(0.2),
   tf.keras.layers.Dense(10, activation='softmax')
   ])
   
   model.compile(optimizer='adam',
   loss='sparse_categorical_crossentropy',
   metrics=['accuracy'])
   
   model.fit(x_train, y_train, epochs=1)
   model_save_dir = f"{os.environ.get('SM_MODEL_DIR')}/1"
   
   model.evaluate(x_test, y_test)
   tf.saved_model.save(model, model_save_dir)
   ```

## 步骤 3：构建容器
<a name="byoc-training-step3"></a>

1. 在 JupyterLab 主目录中，打开 Jupyter 笔记本。要打开新笔记本，请选择**新启动**图标，然后在**笔记本**部分选择 **conda\$1tensorflow2**。

1. 在第一个笔记本单元格中运行以下命令，以便更改到 `docker_test_folder` 目录：

   ```
   cd ~/SageMaker/docker_test_folder
   ```

   这会将您返回到当前目录，如下所示。

   ```
   ! pwd
   ```

   `output: /home/ec2-user/SageMaker/docker_test_folder`

1. 要构建 Docker 容器，请运行以下 Docker 构建命令，包括末尾句点后的空格：

   ```
   ! docker build -t tf-custom-container-test .
   ```

   Docker 构建命令必须从您创建的 Docker 目录运行，在此例中为 `docker_test_folder`。
**注意**  
如果您收到以下错误消息，提示 Docker 找不到 Dockerfile，请确保 Dockerfile 的名称正确并已保存到目录中。  

   ```
   unable to prepare context: unable to evaluate symlinks in Dockerfile path: 
   lstat /home/ec2-user/SageMaker/docker/Dockerfile: no such file or directory
   ```
请记住，`docker` 在当前目录中查找名为 `Dockerfile` 的文件，没有任何扩展名。如果您将其改为其他名称，可以使用 `-f` 标记手动传入文件名。例如，如果您将 Dockerfile 命名为 `Dockerfile-text.txt`，请运行以下命令：  

   ```
   ! docker build -t tf-custom-container-test -f Dockerfile-text.txt .
   ```

## 步骤 4：测试容器
<a name="byoc-training-step4"></a>

1. 要在笔记本实例中本地测试容器，请打开 Jupyter 笔记本。选择**新启动程序**，然后在**笔记本**部分选择 **conda\$1tensorflow2** 的最新版本。

1. 将以下示例脚本粘贴到笔记本代码单元中以配置 A SageMaker I 估算器。

   ```
   import sagemaker
   from sagemaker.estimator import Estimator
   
   estimator = Estimator(image_uri='tf-custom-container-test',
                         role=sagemaker.get_execution_role(),
                         instance_count=1,
                         instance_type='local')
   
   estimator.fit()
   ```

   在前面的代码示例中，指定`role`参数以自动检索`sagemaker.get_execution_role()`为 SageMaker AI 会话设置的角色。您也可以将其替换为在配置笔记本实例时使用的 **IAM 角色 ARN 编号**的字符串值。ARN 应如下所示：`'arn:aws:iam::111122223333:role/service-role/AmazonSageMaker-ExecutionRole-20190429T110788'`。

1. 运行代码单元。该测试输出训练环境配置、用于环境变量的值、数据源以及训练期间获得的损失和准确率。

## 步骤 5：将容器推送至 Amazon Elastic Container Registry (Amazon ECR)
<a name="byoc-training-step5"></a>

1. 成功运行本地模式测试后，您可以将 Docker 容器推送到 [Amazon ECR](https://docs.aws.amazon.com/AmazonECR/latest/userguide/what-is-ecr.html) 并用它来运行训练作业。如果您想使用私有 Docker 注册表而不是 Amazon ECR，请参阅[将您的训练容器推送到私有注册表](https://docs.aws.amazon.com/sagemaker/latest/dg/docker-containers-adapt-your-own-private-registry.html)。

   在笔记本单元格中运行以下命令行。

   ```
   %%sh
   
   # Specify an algorithm name
   algorithm_name=tf-custom-container-test
   
   account=$(aws sts get-caller-identity --query Account --output text)
   
   # Get the region defined in the current configuration (default to us-west-2 if none defined)
   region=$(aws configure get region)
   region=${region:-us-west-2}
   
   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/null
   fi
   
   # 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}
   ```
**注意**  
此 bash shell 脚本可能会引发权限问题，类似于以下错误消息：  

   ```
   "denied: User: [ARN] is not authorized to perform: ecr:InitiateLayerUpload on resource:
   arn:aws:ecr:us-east-1:[id]:repository/tf-custom-container-test"
   ```
如果发生此错误，您需要将 A **mazon EC2 ContainerRegistryFullAccess** 策略附加到您的 IAM 角色。前往 [IAM 控制台](https://console.aws.amazon.com/iam/home)，从左侧导航窗格中选择 “**角色**”，查找 IAMrole 您用于笔记本实例的 “角色”。在 “**权限**” 选项卡下，选择 “**附加政策**” 按钮，然后搜索 **Amazon EC2 ContainerRegistryFullAccess** 政策。选中策略的复选框，选择**附加策略**以完成操作。

1. 在 Studio 笔记本单元格中运行以下代码，调用您的训练容器的 Amazon ECR 映像。

   ```
   import boto3
   
   account_id = boto3.client('sts').get_caller_identity().get('Account')
   ecr_repository = 'tf-custom-container-test'
   tag = ':latest'
   
   region = boto3.session.Session().region_name
   
   uri_suffix = 'amazonaws.com'
   if region in ['cn-north-1', 'cn-northwest-1']:
       uri_suffix = 'amazonaws.com.cn'
   
   byoc_image_uri = '{}.dkr.ecr.{}.{}/{}'.format(account_id, region, uri_suffix, ecr_repository + tag)
   
   byoc_image_uri
   # This should return something like
   # 111122223333.dkr.ecr.us-east-2.amazonaws.com/sagemaker-byoc-test:latest
   ```

1. 使用从上一步中`ecr_image`检索到的来配置 A SageMaker I 估算器对象。以下代码示例使用配置 A SageMaker I 估算器，`byoc_image_uri`并在 Amazon EC2 实例上启动训练作业。

------
#### [ SageMaker Python SDK v1 ]

   ```
   import sagemaker
   from sagemaker import get_execution_role
   from sagemaker.estimator import Estimator
   
   estimator = Estimator(image_uri=byoc_image_uri,
                         role=get_execution_role(),
                         base_job_name='tf-custom-container-test-job',
                         instance_count=1,
                         instance_type='ml.g4dn.xlarge')
   
   #train your model
   estimator.fit()
   ```

------
#### [ SageMaker Python SDK v2 ]

   ```
   import sagemaker
   from sagemaker import get_execution_role
   from sagemaker.estimator import Estimator
   
   estimator = Estimator(image_uri=byoc_image_uri,
                         role=get_execution_role(),
                         base_job_name='tf-custom-container-test-job',
                         instance_count=1,
                         instance_type='ml.g4dn.xlarge')
   
   #train your model
   estimator.fit()
   ```

------

1. 如果您要使用自己的容器部署模型，请参阅[调整自己的推理容器](https://docs.aws.amazon.com/sagemaker/latest/dg/adapt-inference-container.html)。您也可以使用可以部署 TensorFlow 模型的 AWS框架容器。要部署示例模型以读取手写数字，请将以下示例脚本输入到您在上一个子步骤中用于训练模型的同一个笔记本中，以获取部署所需的图像 URIs （通用资源标识符），然后部署模型。

   ```
   import boto3
   import sagemaker
   
   #obtain image uris
   from sagemaker import image_uris
   container = image_uris.retrieve(framework='tensorflow',region='us-west-2',version='2.11.0',
                       image_scope='inference',instance_type='ml.g4dn.xlarge')
   
   #create the model entity, endpoint configuration and endpoint
   predictor = estimator.deploy(1,instance_type='ml.g4dn.xlarge',image_uri=container)
   ```

   通过以下代码示例，使用 MNIST 数据集中的手写数字样本测试您的模型。

   ```
   #Retrieve an example test dataset to test
   import numpy as np
   import matplotlib.pyplot as plt
   from keras.datasets import mnist
   
   # Load the MNIST dataset and split it into training and testing sets
   (x_train, y_train), (x_test, y_test) = mnist.load_data()
   # Select a random example from the training set
   example_index = np.random.randint(0, x_train.shape[0])
   example_image = x_train[example_index]
   example_label = y_train[example_index]
   
   # Print the label and show the image
   print(f"Label: {example_label}")
   plt.imshow(example_image, cmap='gray')
   plt.show()
   ```

   将测试手写数字转换为 TensorFlow 可以提取并进行测试预测的形式。

   ```
   from sagemaker.serializers import JSONSerializer
   data = {"instances": example_image.tolist()}
   predictor.serializer=JSONSerializer() #update the predictor to use the JSONSerializer
   predictor.predict(data) #make the prediction
   ```

有关演示如何在本地测试自定义容器并将其推送到 Amazon ECR 映像的完整示例，请参阅[构建自己的 TensorFlow 容器](https://sagemaker-examples.readthedocs.io/en/latest/advanced_functionality/tensorflow_bring_your_own/tensorflow_bring_your_own.html)示例笔记本。

**提示**  
要分析和调试训练作业以监控系统利用率问题（例如 CPU 瓶颈和 GPU 利用率不足）并识别训练问题（例如过度拟合、过度训练、张量爆炸和梯度消失），请使用 Amazon Debugger。 SageMaker 有关更多信息，请参阅 [使用 Debugger 和自定义训练容器](debugger-bring-your-own-container.md)。

## 步骤 6：清理资源
<a name="byoc-training-step6"></a>

**在完成“开始使用”示例后清理资源**

1. 打开 [SageMaker AI 控制台](https://console.aws.amazon.com/sagemaker/)，选择笔记本实例 **RunScriptNotebookInstance**，选择**操作**，然后选择**停止**。停止实例可能需要几分钟时间。

1. 在实例**状态**更改为**已停止**之后，选择**操作**，选择**删除**，然后在对话框中选择**删除**。删除实例可能需要几分钟时间。删除后，笔记本实例将从表中消失。

1. 打开 [Amazon S3 控制台](https://console.aws.amazon.com/s3/)并删除为存储模型构件和训练数据集创建的存储桶。

1. 打开 [IAM 控制台](https://console.aws.amazon.com/iam/)，然后删除 IAM 角色。如果您已创建权限策略，也可以将其删除。
**注意**  
 Docker 容器在运行后会自动关闭。您不需要删除该容器。

## 博客和案例研究
<a name="byoc-blogs-and-examples"></a>

以下博客讨论了有关在 Amazon A SageMaker I 中使用自定义训练容器的案例研究。
+ [为什么要把自己的容器带到 Amazon SageMaker AI 以及如何正确操作，](https://medium.com/@pandey.vikesh/why-bring-your-own-container-to-amazon-sagemaker-and-how-to-do-it-right-bc158fe41ed1)*中等*（2023 年 1 月 20 日）

# 调整您的训练作业，以访问私有 Docker 注册表中的映像
<a name="docker-containers-adapt-your-own-private-registry"></a>

您可以使用私有 [Docker 注册表来代替亚马逊弹性容器注册表](https://docs.docker.com/registry/) (Amazon ECR) Container Registry 来托管用于人工智能训练的映像。 SageMaker 以下说明向您展示如何创建 Docker 注册表、配置虚拟私有云 (VPC) 和训练作业、存储映像以及如何让 SageMaker AI 访问私有 docker 注册表中的训练映像。这些说明还向您展示了如何使用 SageMaker 训练作业需要身份验证的 Docker 注册表。

## 创建映像并将其存储在私有 Docker 注册表中
<a name="docker-containers-adapt-your-own-private-registry-prerequisites"></a>

创建私有 Docker 注册表来存储您的映像。注册表必须：
+ 使用 [Docker Registry HTTP API](https://docs.docker.com/registry/spec/api/) 协议
+ 可以从 `CreateTrainingJob` API [VpcConfig](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateTrainingJob.html#API_CreateTrainingJob_RequestSyntax)参数中指定的相同 VPC 进行访问。在创建训练作业时输入 `VpcConfig`。
+ 使用来自已知公共证书颁发机构的 [TLS 证书](https://aws.amazon.com/what-is/ssl-certificate/)来保护。

有关创建 Docker 注册表的更多信息，请参阅[部署注册表服务器](https://docs.docker.com/registry/deploying/)。

## 配置您的 VPC 和 SageMaker 训练作业
<a name="docker-containers-adapt-your-own-private-registry-configure"></a>

SageMaker AI 使用您的 VPC 内的网络连接来访问您的 Docker 注册表中的镜像。要将您 Docker 注册表中的映像用于训练，注册表必须可以从您账户中的 Amazon VPC 访问。有关更多信息，请参阅 [使用需要身份验证的 Docker 注册表进行训练](docker-containers-adapt-your-own-private-registry-authentication.md)。

您还必须配置训练作业，将其连接到您的 Docker 注册表有权访问的同一 VPC。有关更多信息，请参阅[为 Amazon VPC 访问配置训练作业](https://docs.aws.amazon.com/sagemaker/latest/dg/train-vpc.html#train-vpc-configure)。

## 使用私有 Docker 注册表中的映像创建训练作业
<a name="docker-containers-adapt-your-own-private-registry-create"></a>

要使用私有 Docker 注册表中的映像进行训练，请使用以下指南配置您的映像、配置和创建训练作业。以下代码示例使用 适用于 Python (Boto3) 的 AWS SDK 客户端。

1. 创建训练映像配置对象，并如下所示为 `TrainingRepositoryAccessMode` 字段输入 `Vpc`。

   ```
   training_image_config = {
       'TrainingRepositoryAccessMode': 'Vpc'
   }
   ```
**注意**  
如果您的私有 Docker 注册表需要身份验证，则必须将 `TrainingRepositoryAuthConfig` 对象添加到训练映像配置对象。您还必须使用对象的`TrainingRepositoryCredentialsProviderArn`字段指定向 A SageMaker I 提供访问凭证的 AWS Lambda 函数的 Amazon 资源名称 (ARN)。`TrainingRepositoryAuthConfig`有关更多信息，请参阅以下示例代码结构。  

   ```
   training_image_config = {
      'TrainingRepositoryAccessMode': 'Vpc',
      'TrainingRepositoryAuthConfig': {
           'TrainingRepositoryCredentialsProviderArn': 'arn:aws:lambda:Region:Acct:function:FunctionName'
      }
   }
   ```

   有关如何创建 Lambda 函数以提供身份验证的信息，请参阅[使用需要身份验证的 Docker 注册表进行训练](docker-containers-adapt-your-own-private-registry-authentication.md)。

1. 使用 Boto3 客户端创建训练作业，并将正确的配置传递给 [create\$1training\$1job](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateTrainingJob.html) API。以下说明向您演示如何配置组件和创建训练作业。

   1. 创建要传递到 `create_training_job` 的 `AlgorithmSpecification` 对象。使用在上一步中创建的训练映像配置对象，如以下代码示例所示。

      ```
      algorithm_specification = {
         'TrainingImage': 'myteam.myorg.com/docker-local/my-training-image:<IMAGE-TAG>',
         'TrainingImageConfig': training_image_config,
         'TrainingInputMode': 'File'
      }
      ```
**注意**  
要使用映像的固定版本而不是更新版本，请引用映像的[摘要](https://docs.docker.com/engine/reference/commandline/pull/#pull-an-image-by-digest-immutable-identifier)，而不是引用名称或标签。

   1. 指定您要传递给 `create_training_job` 的训练作业名称和角色，如以下代码示例中所示。

      ```
      training_job_name = 'private-registry-job'
      execution_role_arn = 'arn:aws:iam::123456789012:role/SageMakerExecutionRole'
      ```

   1. 为您的训练作业的 VPC 配置指定安全组和子网。您的私有 Docker 注册表必须允许来自您指定的安全组的入站流量，如以下代码示例所示。

      ```
      vpc_config = {
          'SecurityGroupIds': ['sg-0123456789abcdef0'],
          'Subnets': ['subnet-0123456789abcdef0','subnet-0123456789abcdef1']
      }
      ```
**注意**  
如果您的子网与私有 Docker 注册表不在同一 VPC 中，则必须在这两 VPCs者之间建立网络连接。 SeeConnect VPCs 使用 [VPC 对等](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-peering.html)连接了解更多信息。

   1. 指定资源配置，包括训练使用的机器学习计算实例和存储卷，如以下代码示例所示。

      ```
      resource_config = {
          'InstanceType': 'ml.m4.xlarge',
          'InstanceCount': 1,
          'VolumeSizeInGB': 10,
      }
      ```

   1. 指定输入和输出数据配置、训练数据集的存储位置以及用于存储模型构件的位置，如以下代码示例所示。

      ```
      input_data_config = [
          {
              "ChannelName": "training",
              "DataSource":
              {
                  "S3DataSource":
                  {
                      "S3DataDistributionType": "FullyReplicated",
                      "S3DataType": "S3Prefix",
                      "S3Uri": "s3://your-training-data-bucket/training-data-folder"
                  }
              }
          }
      ]
      
      output_data_config = {
          'S3OutputPath': 's3://your-output-data-bucket/model-folder'
      }
      ```

   1. 指定模型训练作业可以运行的最大秒数，如以下代码示例所示。

      ```
      stopping_condition = {
          'MaxRuntimeInSeconds': 1800
      }
      ```

   1. 最后，使用在上一步中指定的参数创建训练作业，如以下代码示例所示。

      ```
      import boto3
      sm = boto3.client('sagemaker')
      try:
          resp = sm.create_training_job(
              TrainingJobName=training_job_name,
              AlgorithmSpecification=algorithm_specification,
              RoleArn=execution_role_arn,
              InputDataConfig=input_data_config,
              OutputDataConfig=output_data_config,
              ResourceConfig=resource_config,
              VpcConfig=vpc_config,
              StoppingCondition=stopping_condition
          )
      except Exception as e:
          print(f'error calling CreateTrainingJob operation: {e}')
      else:
          print(resp)
      ```

# 使用 A SageMaker I 估算器来运行训练作业
<a name="docker-containers-adapt-your-own-private-registry-estimator"></a>

您还可以使用 Pyth SageMaker on SDK 中的[估算器](https://sagemaker.readthedocs.io/en/stable/api/training/estimators.html)来处理 SageMaker 训练作业的配置和运行。以下代码示例显示如何使用私有 Docker 注册表中的映像配置和运行估算器。

1. 导入所需的库和依赖项，如以下代码示例中所示。

   ```
   import boto3
   import sagemaker
   from sagemaker.estimator import Estimator
   
   session = sagemaker.Session()
   
   role = sagemaker.get_execution_role()
   ```

1. 向您的训练映像、安全组和子网提供统一资源标识符 (URI)，用于您的训练作业 VPC 配置，如以下代码示例所示。

   ```
   image_uri = "myteam.myorg.com/docker-local/my-training-image:<IMAGE-TAG>"
   
   security_groups = ["sg-0123456789abcdef0"]
   subnets = ["subnet-0123456789abcdef0", "subnet-0123456789abcdef0"]
   ```

   有关`security_group_ids`和的更多信息`subnets`，请参阅 Pyth SageMaker on SDK 的 “[估算器](https://sagemaker.readthedocs.io/en/stable/api/training/estimators.html)” 部分中的相应参数描述。
**注意**  
SageMaker AI 使用您的 VPC 内的网络连接来访问您的 Docker 注册表中的镜像。要将您 Docker 注册表中的映像用于训练，注册表必须可以从您账户中的 Amazon VPC 访问。

1. 或者，如果您的 Docker 注册表需要身份验证，则还必须指定向 AI 提供访问凭证 SageMaker 的函数的 AWS Lambda 亚马逊资源名称 (ARN)。以下示例演示了如何指定 ARN。

   ```
   training_repository_credentials_provider_arn = "arn:aws:lambda:us-west-2:1234567890:function:test"
   ```

   有关使用需要身份验证的 Docker 注册表中的映像的更多信息，请参阅下文中的**使用需要身份验证的 Docker 注册表进行训练**。

1. 使用前面步骤中的代码示例来配置估算器，如以下代码示例所示。

   ```
   # The training repository access mode must be 'Vpc' for private docker registry jobs 
   training_repository_access_mode = "Vpc"
   
   # Specify the instance type, instance count you want to use
   instance_type="ml.m5.xlarge"
   instance_count=1
   
   # Specify the maximum number of seconds that a model training job can run
   max_run_time = 1800
   
   # Specify the output path for the model artifacts
   output_path = "s3://your-output-bucket/your-output-path"
   
   estimator = Estimator(
       image_uri=image_uri,
       role=role,
       subnets=subnets,
       security_group_ids=security_groups,
       training_repository_access_mode=training_repository_access_mode,
       training_repository_credentials_provider_arn=training_repository_credentials_provider_arn,  # remove this line if auth is not needed
       instance_type=instance_type,
       instance_count=instance_count,
       output_path=output_path,
       max_run=max_run_time
   )
   ```

1. 使用您的作业名称和输入路径作为参数来调用 `estimator.fit`，以启动训练作业，如以下代码示例所示。

   ```
   input_path = "s3://your-input-bucket/your-input-path"
   job_name = "your-job-name"
   
   estimator.fit(
       inputs=input_path,
       job_name=job_name
   )
   ```

# 使用需要身份验证的 Docker 注册表进行训练
<a name="docker-containers-adapt-your-own-private-registry-authentication"></a>

如果您的 Docker 注册表需要身份验证，则必须创建一个向 SageMaker AI 提供访问凭据的 AWS Lambda 函数。然后，创建一个训练作业并在 [create\$1training\$1job](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.html#SageMaker.Client.create_training_job) API 中提供此 Lambda 函数的 ARN。最后，您可以选择创建接口 VPC 端点，以便您的 VPC 可以与 Lambda 函数通信，而无需通过互联网发送流量。以下指南演示如何创建 Lambda 函数、为其分配正确的角色以及创建接口 VPC 端点。

## 创建 Lambda 函数
<a name="docker-containers-adapt-your-own-private-registry-authentication-create-lambda"></a>

创建一个将访问凭证传递给 SageMaker AI 并返回响应的 AWS Lambda 函数。以下代码示例创建 Lambda 函数处理程序，如下所示。

```
def handler(event, context):
   response = {
      "Credentials": {"Username": "username", "Password": "password"}
   }
   return response
```

设置私有 Docker 注册表所用的身份验证类型决定了您的 Lambda 函数返回的响应内容，如下所示。
+ 如果您的私有 Docker 注册表使用基本身份验证，则 Lambda 函数将返回所需的用户名和密码，以便向注册表进行身份验证。
+ 如果您的私有 Docker 注册表使用[持有者令牌身份验证](https://docs.docker.com/registry/spec/auth/token/)，则用户名和密码发送到您的授权服务器，该服务器将返回一个持有者令牌。然后，此令牌用于对您的私有 Docker 注册表进行身份验证。

**注意**  
如果您在同一个账户的注册表中有多个 Lambda 函数，并且您的训练作业的执行角色相同，则一个注册表的训练作业可以访问其他注册表的 Lambda 函数。

## 将正确的角色权限授予 Lambda 函数
<a name="docker-containers-adapt-your-own-private-registry-authentication-lambda-role"></a>

您在 [IAMrole](https://docs.aws.amazon.com/sagemaker/latest/dg/sagemaker-roles.html)`create_training_job`API 中使用的必须具有调用 AWS Lambda 函数的权限。以下代码示例演示如何将扩展 IAM 角色的权限，使其能够调用 `myLambdaFunction`。

```
{
    "Effect": "Allow",
    "Action": [
        "lambda:InvokeFunction"
    ],
    "Resource": [
        "arn:aws:lambda:*:*:function:*myLambdaFunction*"
    ]
}
```

有关编辑角色权限策略的信息，请参阅《AWS Identity and Access Management 用户指南》**中的[修改角色权限策略（控制台）](https://docs.aws.amazon.com/IAM/latest/UserGuide/roles-managingrole-editing-console.html#roles-modify_permissions-policy)。

**注意**  
附加了**AmazonSageMakerFullAccess**托管策略的 IAM 角色有权调用名称中带有 “SageMaker AI” 的任何 Lambda 函数。

## 为 Lambda 创建接口 VPC 端点
<a name="docker-containers-adapt-your-own-private-registry-authentication-lambda-endpoint"></a>

通过创建接口端点，您的 Amazon VPC 可以与 Lambda 函数通信而无需通过互联网发送流量。有关更多信息，请参阅《AWS Lambda 开发人员指南》**中的[为 Lambda 配置接口 VPC 终端节点](https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc-endpoints.html)。

创建接口终端节点后， SageMaker 培训将通过您的 VPC 向发送请求，从而调用您的 Lambda 函数。`lambda.region.amazonaws.com`如果您在创建接口端点时选择**启用 DNS 名称**，则 [Amazon Route 53](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/Welcome.html) 会将调用路由到 Lambda 接口端点。如果您使用不同的 DNS 提供商，则必须将 `lambda.region.amazonaws.co`m 映射到您的 Lambda 接口端点。

# 调整你自己的推理容器以适应 Amazon AI SageMaker
<a name="adapt-inference-container"></a>

如果您无法将 [预先构建的 SageMaker AI Docker 镜像](docker-containers-prebuilt.md) Amazon A SageMaker I 中列出的任何图像用于您的用例，则可以构建自己的 Docker 容器，然后在 SageMaker AI 中使用它进行训练和推理。为了与 SageMaker AI 兼容，您的容器必须具有以下特征：
+ 您的容器必须在 `8080` 端口列出网络服务器。
+ 您的容器必须接受向 `/invocations` 和 `/ping` 实时端点发出的 `POST` 请求。您向这些端点发送的请求对于常规响应必须在 60 秒内返回，对于流式响应则必须在 8 分钟内返回，且最大大小为 25 MB。

要了解更多信息以及如何构建自己的 Docker 容器以便使用 SageMaker AI 进行训练和推理的示例，请参阅[构建自己的算法](https://github.com/aws/amazon-sagemaker-examples/blob/main/advanced_functionality/scikit_bring_your_own/scikit_bring_your_own.ipynb)容器。

以下指南向您展示了如何在 Amazon SageMaker Studio Classic 中使用`JupyterLab`空间来调整推理容器以使用 SageMaker AI 托管。此示例使用 NGINX 网络服务器、Gunicorn 作为 Python 网络服务器网关接口，以及 Flask 作为网络应用程序框架。您只要符合前面列出的要求，就可以使用不同的应用程序来调整您的容器。有关使用自己的推理代码的更多信息，请参阅 [自定义托管服务的推理代码](your-algorithms-inference-code.md)。

**调整您的推理容器**

使用以下步骤调整您自己的推理容器以使用 SageMaker AI 托管。以下步骤中的示例使用了预先训练好的[命名实体识别 (NER) 模型](https://spacy.io/universe/project/video-spacys-ner-model-alt)，此模型使用了 [spaCy](https://spacy.io/) 自然语言处理（NLP）库，进行 `Python` 和以下操作：
+ Dockerfile 用于构建包含 NER 模型的容器。
+ 为 NER 模型提供服务的推理脚本。

如果您根据自己的使用场景调整此示例，则必须使用部署和提供模型所需的 Dockerfile 和推理脚本。

1. 使用 Amazon SageMaker Studio Classic（可选）创建 JupyterLab 空间。

   您可以使用任何笔记本来运行脚本，以便通过 SageMaker AI 托管来调整您的推理容器。此示例向您展示如何使用 Amazon SageMaker Studio Classic 中的JupyterLab空间来启动带有 A SageMaker I 分发映像的JupyterLab应用程序。有关更多信息，请参阅 [SageMaker JupyterLab](studio-updated-jl.md)。

1. 上传 Docker 文件和推理脚本。

   1. 在您的主目录中创建一个新文件夹。如果您使用的是 JupyterLab，请在左上角选择**新建文件夹**图标，然后输入包含 Dockerfile 的文件夹名称。在此示例中，文件夹名为 `docker_test_folder`。

   1. 将 Dockerfile 文本文件上传到新文件夹。以下示例 Dockerfile 使用来自 [spaCy](https://spacy.io/) 预训练的[命名实体识别 (NER) 模型](https://spacy.io/universe/project/video-spacys-ner-model)、运行示例所需的应用程序和环境变量来创建 Docker 容器：

      ```
      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` 用于在调用容器时标识 `train` 和 `serve` 程序的位置。

   1. 在新文件夹内创建一个新目录，其中包含为模型提供服务的脚本。本示例使用名为 `NER` 的目录，其中包含运行本示例所需的以下脚本：
      + `predictor.py`：包含用于加载模型并对模型执行推理逻辑的 Python 脚本。
      + `nginx.conf`：用于配置网络服务器的脚本。
      + `serve`：启动推理服务器的脚本。
      + `wsgi.py`：用于为模型提供服务的辅助脚本。
**重要**  
如果您将推理脚本复制到以 `.ipynb` 结尾的笔记本中并重新命名，则脚本中可能会包含格式化字符，从而导致端点无法部署。而是创建一个文本文件并对其进行重命名。

   1. 上传脚本，使您的模型可用于推理。以下是一个名为 `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')
      ```

      如果模型加载正确，前面的脚本示例中的 `/ping` 端点会返回状态代码 `200`；如果模型加载错误，则返回状态代码 `404`。`/invocations` 端点处理以 JSON 为格式的请求，提取输入字段，并使用 NER 模型识别和存储变量实体中的实体。Flask 应用程序会返回包含这些实体的响应。有关这些必要运行状况正常要求的更多信息，请参阅 [容器应如何响应运行状况检查 (Ping) 请求](your-algorithms-inference-code.md#your-algorithms-inference-algo-ping-requests)。

   1. 上传脚本以启动推理服务器。下面的脚本示例使用 Gunicorn 作为应用服务器和 Nginx 作为网络服务器调用 `serve`：

      ```
      #!/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`，此函数在收到 `SIGTERM` 信号时会关闭 Nginx 和 Gunicorn 子进程。`start_server` 函数启动信号处理器，启动和监控 Nginx 和 Gunicorn 子进程，并捕获日志流。

   1. 上传脚本以配置您的网络服务器。下面名为 `nginx.conf` 的脚本示例配置了一个 Nginx 网络服务器，将 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` 错误。

   1. 上传为模型提供服务所需的任何其他脚本。此示例需要以下名为 `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.conf`、`predictor.py`、`serve` 和 `wsgi.py`：

    ![\[The Dockerfile structure has inference scripts under the NER directory next to the Dockerfile.\]](http://docs.aws.amazon.com/zh_cn/sagemaker/latest/dg/images/docker-file-struct-adapt-ex.png) 

1. 构建自己的容器。

   在 `docker_test_folder` 文件夹中，创建 Docker 容器。下面的示例命令将构建在 Dockerfile 中配置的 Docker 容器：

   ```
   ! docker build -t byo-container-test .
   ```

   前面的命令将在当前工作目录下创建一个名为 `byo-container-test` 的容器。有关 Docker 构建参数的更多信息，请参阅[构建参数](https://docs.docker.com/build/guide/build-args/)。
**注意**  
如果您收到以下错误消息，提示 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 .
   ```

1. 将 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`。

   1. 将 NER 文件夹中的 `serve` 文件设为可执行文件。

   1. 设置 AWS 区域.

   1. 如果 ECR 还不存在，则创建 ECR。

   1. 登录 ECR。

   1. 在本地构建 Docker 容器。

   1. 将 Docker 映像推送到 ECR。

1. 设置 SageMaker AI 客户端

   如果要使用 SageMaker AI 托管服务进行推理，则必须[创建模型、创建](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker/client/create_model.html)[终端节点配置并创建终端](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker/client/create_endpoint_config.html#)[节](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker/client/create_endpoint.html#)点。为了从您的终端节点获取推论，您可以使用 SageMaker AI boto3 Runtime 客户端来调用您的终端节点。以下代码向您展示了如何使用 SageMaker AI [boto3 客户端设置 A SageMaker I](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.html) 客户端和 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 角色管理器](role-manager.md)。有关为当前角色添加权限的更多信息，请参阅 [AWS 亚马逊 A SageMaker I 的托管策略](security-iam-awsmanpol.md)。

1. 创建模型。

   如果要使用 SageMaker AI 托管服务进行推理，则必须在 SageMaker AI 中创建模型。以下代码示例向您展示了如何在 SageMaker AI 中创建spaCyNER模型：

   ```
   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 实例类型](https://aws.amazon.com/ec2/instance-types/)。

   在前面的代码示例中，`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. 

   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` 将 `model_name` 与使用时间戳创建的唯一的端点配置名称 `endpoint_config_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
      ```

      有关终端节点错误的更多信息，请参阅[创建或更新终端节点时，为什么我的 SageMaker Amazon AI 终端节点会进入故障状态？](https://repost.aws/knowledge-center/sagemaker-endpoint-creation-fail)

   1. 

**创建端点并等待端点投入使用。**

       下面的代码示例使用前面的配置示例中的配置创建了端点，并部署了模型：

      ```
      %%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` 方法返回有关端点及其状态的信息。A SageMaker I 服务员等待端点投入使用。

1. 测试端点。

   端点投入使用后，向端点发送[调用请求](https://boto3.amazonaws.com/v1/documentation/api/1.9.42/reference/services/sagemaker-runtime.html#SageMakerRuntime.Client.invoke_endpoint)。下面的代码示例说明了如何向端点发送测试请求：

   ```
   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 AI Runtime 客户端使用[调用端点](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker-runtime/client/invoke_endpoint.html)方法向您的终端节点发送有效负载。结果包含端点提取输出字段后的响应。

   前面的代码示例应返回以下输出结果：

   ```
   [['NER', 'ORG'],
    ['America', 'GPE'],
    ['Amazon', 'ORG'],
    ['Microsoft', 'ORG'],
    ['Seattle', 'GPE']]
   ```

1. 删除端点

   完成调用后，请删除端点以节省资源。下面的代码示例说明了如何删除端点：

   ```
   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](https://github.com/aws-samples/sagemaker-hosting/tree/main/Bring-Your-Own-Container/BYOC-Single-Model)。