本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
延伸預先建置的容器。
如果預先建置的 SageMaker 容器無法滿足您的所有需求,您可以擴充現有映像以符合您的需求。即使為您的環境或架構提供直接支援,您可能想要新增其他功能,或以不同方式設定容器環境。透過延伸預先建置的映像,您可以利用內含的深度學習程式庫和設定,無需從頭開始建立映像。您可以延伸容器,以新增程式庫、修改設定和安裝其他相依性。
下列教學課程說明如何擴充預先建立的 SageMaker 映像並將其發佈到 Amazon ECR。
延伸預先建置容器的需求
要擴展預構建的 SageMaker 圖像,您需要在 Dockerfile 中設置以下環境變量。如需有關使用 SageMaker容器之環境變數的詳細資訊,請參閱SageMaker 訓練工具組 GitHub 存放庫
SAGEMAKER_SUBMIT_DIRECTORY
:容器中用於訓練的 Python 指令碼所在的目錄。SAGEMAKER_PROGRAM
:應調用並用作訓練進入點的 Python 指令碼。
您還可以透過在 Dockerfile 中包含下列內容來安裝其他程式庫:
RUN pip install
<library>
下列教學課程將介紹如何使用這些環境變數。
擴充 SageMaker容器以執行 Python 指令碼
在本教學課程中,您將學習如何使用使用 CIFAR-10 資料集的 Python 檔案來擴充 SageMaker PyTorch 容器。藉由擴充 SageMaker PyTorch 容器,您可以利用現有的訓練解決方案 SageMaker。本教程為延伸訓練影像,但也可以採取相同步驟來延伸推論影像。有關可用映像的完整清單,請參閱可用的深度學習容器映像
若要使用 SageMaker 容器執行您自己的訓練模型,請透過 SageMaker Notebook 執行個體建置 Docker 容器。
步驟 1:建立 SageMaker 記事本執行個體
-
開啟 SageMaker 主控台
。 -
從左邊導覽窗格中,選擇 筆記本,選擇筆記本執行個體,然後選擇建立筆記本執行個體。
-
在建立筆記本執行個體頁面上,提供下列資訊:
-
對於筆記本執行個體名稱,輸入
RunScriptNotebookInstance
。 -
對於筆記本執行個體類型,選擇
ml.t2.medium
。 -
在 許可與加密區段內執行下列動作:
-
對於IAM 角色,選擇建立新角色。
-
在建立 IAM 角色頁面上,選擇特定的 S3 儲存貯體、指定名為
sagemaker-run-script
的Amazon S3 儲存貯體,然後選擇建立角色。SageMaker 會建立名為的 IAM 角色
AmazonSageMaker-ExecutionRole-
,例如YYYYMMDD
THHmmSS
AmazonSageMaker-ExecutionRole-20190429T110788
。請注意,執行角色命名慣例會使用角色建立時的日期和時間,並以T
分隔。
-
-
對於根存取,選擇已啟用。
-
選擇建立筆記本執行個體。
-
-
在記事本執行個體頁面上,狀態為待定。Amazon CloudWatch Internet Monitor 可能需要幾分鐘的時間才能啟動機器學習運算執行個體 (在此情況下,它會啟動筆記型電腦執行個體,並將 ML 儲存磁碟區附加至其中)。筆記本執行個體具備預先設定的 Jupyter 筆記本伺服器和一組 Anaconda 程式庫。如需詳細資訊,請參閱 CreateNotebookInstance。
在許可與加密區段中,複製 IAM 角色 ARN 編號,然後將它貼到記事本檔案中暫存。稍後您可以使用此 IAM 角色 ARN 編號,在筆記本執行個體中設定本機訓練估算器。IAM 角色 ARN 編號如下所示:
'arn:aws:iam::111122223333:role/service-role/AmazonSageMaker-ExecutionRole-20190429T110788'
-
記事本實例的狀態變更為之後 InService,請選擇「開啟」 JupyterLab。
步驟 2:建立並上傳 Dockerfile 和 Python 訓練指令碼
-
JupyterLab 開啟後,在您的主目錄中建立一個新資料夾 JupyterLab。在左上角選擇新增資料夾圖示,然後輸入檔案夾名稱
docker_test_folder
。 -
在
docker_test_folder
目錄中,建立一個Dockerfile
文字檔案。-
選擇左上角的新增啟動器圖示 (+)。
-
在其他區段下右邊的窗格中,選擇文字檔案。
-
將下列
Dockerfile
範例程式碼貼到您的文字檔中。# SageMaker PyTorch image FROM 763104351884.dkr.ecr.us-east-1.amazonaws.com/pytorch-training:1.5.1-cpu-py36-ubuntu16.04 ENV PATH="/opt/ml/code:${PATH}" # this environment variable is used by the SageMaker PyTorch container to determine our user code directory. ENV SAGEMAKER_SUBMIT_DIRECTORY /opt/ml/code # /opt/ml and all subdirectories are utilized by SageMaker, use the /code subdirectory to store your user code. COPY cifar10.py /opt/ml/code/cifar10.py # Defines cifar10.py as script entrypoint ENV SAGEMAKER_PROGRAM cifar10.py
此 Dockerfile 指令碼會執行以下任務:
-
FROM 763104351884.dkr.ecr.us-east-1.amazonaws.com/pytorch-training:1.5.1-cpu-py36-ubuntu16.04
-下載 SageMaker PyTorch 基本圖像。您可以將其替換為您想要用於構建容器的任何 SageMaker 基本映像。 -
ENV SAGEMAKER_SUBMIT_DIRECTORY /opt/ml/code
– 將/opt/ml/code
設定為訓練指令碼目錄。 -
COPY cifar10.py /opt/ml/code/cifar10.py
— 將指令碼複製到容器內預期的位置 SageMaker。此指令碼必須位於此資料夾。 -
ENV SAGEMAKER_PROGRAM cifar10.py
– 將您的cifar10.py
訓練指令碼設定為進入點指令碼。
-
-
在左側目錄導覽窗格中,文字檔案名稱會自動命名為
untitled.txt
。若要重新命名檔案,請在該檔案上按一下滑鼠右鍵,選擇重新命名,將檔案重新命名為Dockerfile
(不要納入.txt
副檔名),然後按下Ctrl+s
或Command+s
以儲存檔案。
-
-
在
docker_test_folder
中建立或上傳訓練指令碼cifar10.py
。您可以為此練習使用下列範例指令碼。import ast import argparse import logging import os import torch import torch.distributed as dist import torch.nn as nn import torch.nn.parallel import torch.optim import torch.utils.data import torch.utils.data.distributed import torchvision import torchvision.models import torchvision.transforms as transforms import torch.nn.functional as F logger=logging.getLogger(__name__) logger.setLevel(logging.DEBUG) classes=('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck') # https://github.com/pytorch/tutorials/blob/master/beginner_source/blitz/cifar10_tutorial.py#L118 class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1=nn.Conv2d(3, 6, 5) self.pool=nn.MaxPool2d(2, 2) self.conv2=nn.Conv2d(6, 16, 5) self.fc1=nn.Linear(16 * 5 * 5, 120) self.fc2=nn.Linear(120, 84) self.fc3=nn.Linear(84, 10) def forward(self, x): x=self.pool(F.relu(self.conv1(x))) x=self.pool(F.relu(self.conv2(x))) x=x.view(-1, 16 * 5 * 5) x=F.relu(self.fc1(x)) x=F.relu(self.fc2(x)) x=self.fc3(x) return x def _train(args): is_distributed=len(args.hosts) > 1 and args.dist_backend is not None logger.debug("Distributed training - {}".format(is_distributed)) if is_distributed: # Initialize the distributed environment. world_size=len(args.hosts) os.environ['WORLD_SIZE']=str(world_size) host_rank=args.hosts.index(args.current_host) dist.init_process_group(backend=args.dist_backend, rank=host_rank, world_size=world_size) logger.info( 'Initialized the distributed environment: \'{}\' backend on {} nodes. '.format( args.dist_backend, dist.get_world_size()) + 'Current host rank is {}. Using cuda: {}. Number of gpus: {}'.format( dist.get_rank(), torch.cuda.is_available(), args.num_gpus)) device='cuda' if torch.cuda.is_available() else 'cpu' logger.info("Device Type: {}".format(device)) logger.info("Loading Cifar10 dataset") transform=transforms.Compose( [transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]) trainset=torchvision.datasets.CIFAR10(root=args.data_dir, train=True, download=False, transform=transform) train_loader=torch.utils.data.DataLoader(trainset, batch_size=args.batch_size, shuffle=True, num_workers=args.workers) testset=torchvision.datasets.CIFAR10(root=args.data_dir, train=False, download=False, transform=transform) test_loader=torch.utils.data.DataLoader(testset, batch_size=args.batch_size, shuffle=False, num_workers=args.workers) logger.info("Model loaded") model=Net() if torch.cuda.device_count() > 1: logger.info("Gpu count: {}".format(torch.cuda.device_count())) model=nn.DataParallel(model) model=model.to(device) criterion=nn.CrossEntropyLoss().to(device) optimizer=torch.optim.SGD(model.parameters(), lr=args.lr, momentum=args.momentum) for epoch in range(0, args.epochs): running_loss=0.0 for i, data in enumerate(train_loader): # get the inputs inputs, labels=data inputs, labels=inputs.to(device), labels.to(device) # zero the parameter gradients optimizer.zero_grad() # forward + backward + optimize outputs=model(inputs) loss=criterion(outputs, labels) loss.backward() optimizer.step() # print statistics running_loss += loss.item() if i % 2000 == 1999: # print every 2000 mini-batches print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 2000)) running_loss=0.0 print('Finished Training') return _save_model(model, args.model_dir) def _save_model(model, model_dir): logger.info("Saving the model.") path=os.path.join(model_dir, 'model.pth') # recommended way from http://pytorch.org/docs/master/notes/serialization.html torch.save(model.cpu().state_dict(), path) def model_fn(model_dir): logger.info('model_fn') device="cuda" if torch.cuda.is_available() else "cpu" model=Net() if torch.cuda.device_count() > 1: logger.info("Gpu count: {}".format(torch.cuda.device_count())) model=nn.DataParallel(model) with open(os.path.join(model_dir, 'model.pth'), 'rb') as f: model.load_state_dict(torch.load(f)) return model.to(device) if __name__ == '__main__': parser=argparse.ArgumentParser() parser.add_argument('--workers', type=int, default=2, metavar='W', help='number of data loading workers (default: 2)') parser.add_argument('--epochs', type=int, default=2, metavar='E', help='number of total epochs to run (default: 2)') parser.add_argument('--batch-size', type=int, default=4, metavar='BS', help='batch size (default: 4)') parser.add_argument('--lr', type=float, default=0.001, metavar='LR', help='initial learning rate (default: 0.001)') parser.add_argument('--momentum', type=float, default=0.9, metavar='M', help='momentum (default: 0.9)') parser.add_argument('--dist-backend', type=str, default='gloo', help='distributed backend (default: gloo)') # The parameters below retrieve their default values from SageMaker environment variables, which are # instantiated by the SageMaker containers framework. # https://github.com/aws/sagemaker-containers#how-a-script-is-executed-inside-the-container parser.add_argument('--hosts', type=str, default=ast.literal_eval(os.environ['SM_HOSTS'])) parser.add_argument('--current-host', type=str, default=os.environ['SM_CURRENT_HOST']) parser.add_argument('--model-dir', type=str, default=os.environ['SM_MODEL_DIR']) parser.add_argument('--data-dir', type=str, default=os.environ['SM_CHANNEL_TRAINING']) parser.add_argument('--num-gpus', type=int, default=os.environ['SM_NUM_GPUS']) _train(parser.parse_args())
步驟 3:建置容器
-
在 JupyterLab 主目錄中,開啟 Jupyter 筆記本。若要開啟新筆記本,請選擇新的啟動圖示,然後在筆記本區段中選擇 conda_pytorch_p39。
-
在第一個筆記本儲存格中執行下列命令,以切換至
docker_test_folder
目錄:% cd ~/SageMaker/docker_test_folder
這樣會返回目前的目錄,如下所示:
! pwd
output: /home/ec2-user/SageMaker/docker_test_folder
-
登入 Docker 以存取基礎容器:
! aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 763104351884.dkr.ecr.us-east-1.amazonaws.com
-
若要建置 Docker 容器,請執行下列 Docker 建置命令 (包含結尾句點後的空格)。
! docker build -t pytorch-extended-container-test .
必須從您建立的 Docker 目錄中執行 Docker build 命令,在此案例中為
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
標記手動貼入檔案名稱。例如,如果您將 Docerfile 命名為Dockerfile-text.txt
,請執行下列命令:! docker build -t tf-custom-container-test -f Dockerfile-text.txt .
步驟 4:測試容器
-
若要在筆記本執行個體內本機測試容器,請開啟 Jupyter 筆記本。選擇新啟動器,然後在
conda_pytorch_p39
架構中選擇筆記本。其餘的程式碼片段必須從 Jupyter 筆記本執行個體中執行。 -
下載 CIFAR-10 資料集。
import torch import torchvision import torchvision.transforms as transforms def _get_transform(): return transforms.Compose( [transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]) def get_train_data_loader(data_dir='/tmp/pytorch/cifar-10-data'): transform=_get_transform() trainset=torchvision.datasets.CIFAR10(root=data_dir, train=True, download=True, transform=transform) return torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2) def get_test_data_loader(data_dir='/tmp/pytorch/cifar-10-data'): transform=_get_transform() testset=torchvision.datasets.CIFAR10(root=data_dir, train=False, download=True, transform=transform) return torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=2) trainloader=get_train_data_loader('/tmp/pytorch-example/cifar-10-data') testloader=get_test_data_loader('/tmp/pytorch-example/cifar-10-data')
-
將
role
設定為用於建立 Jupyter 筆記本的角色。這是用來配置您的 SageMaker 估算器。from sagemaker import get_execution_role role=get_execution_role()
-
將下列範例指令碼貼到筆記本程式碼儲存格中,以使用延伸容器設 SageMaker 定估算程式。
from sagemaker.estimator import Estimator hyperparameters={'epochs': 1} estimator=Estimator( image_uri='pytorch-extended-container-test', role=role, instance_count=1, instance_type='local', hyperparameters=hyperparameters ) estimator.fit('file:///tmp/pytorch-example/cifar-10-data')
-
執行程式碼儲存格。此測試會輸出環境組態、用於環境變數的值、資料的來源,以及訓練期間獲得的損失和準確率。
步驟 5:將容器推送至 Amazon Elastic Container Registry (Amazon ECR)
成功執行本機模式測試之後,您可以將 Docker 容器推送至 Amazon ECR,並使用它執行訓練任務。
您可以在筆記本儲存格中,手動執行如下 Git 命令。
%%sh # Specify an algorithm name algorithm_name=pytorch-extended-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) 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 # Log into Docker 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}
-
推送容器之後,您可以從 SageMaker 環境中的任何位置呼叫 Amazon ECR 映像。在下一個筆記本儲存格中執行下列程式碼範例。
如果您想要搭配 SageMaker Studio 使用此訓練容器來使用其視覺化功能,也可以在 Studio 筆記本儲存格中執行下列程式碼,以呼叫訓練容器的 Amazon ECR 映像。
import boto3 client=boto3.client('sts') account=client.get_caller_identity()['Account'] my_session=boto3.session.Session() region=my_session.region_name algorithm_name="
pytorch-extended-container-test
" ecr_image='{}.dkr.ecr.{}.amazonaws.com/{}:latest'.format(account, region, algorithm_name) ecr_image # This should return something like # 12-digits-of-your-account.dkr.ecr.us-east-2.amazonaws.com/tf-2.2-test:latest 使用從上一個步驟
ecr_image
擷取的來配置 SageMaker 估算器物件。下列程式碼範例會設定估算器 SageMaker PyTorch。import sagemaker from sagemaker import get_execution_role from sagemaker.estimator import Estimator estimator=Estimator( image_uri=ecr_image, role=get_execution_role(), base_job_name='
pytorch-extended-container-test
', instance_count=1, instance_type='ml.p2.xlarge' ) # start training estimator.fit() # deploy the trained model predictor=estimator.deploy(1, instance_type)
步驟 6:清除資源
若要在入門範例使用完畢後清除資源
-
開啟SageMaker 主控台
,選擇筆記本執行個體 RunScriptNotebookInstance,選擇 [動作],然後選擇 [停止]。停止執行個體可能需要幾分鐘。 -
執行個體狀態變更為已停止後,選擇動作,選擇刪除,然後在對話方塊中選擇刪除。刪除執行個體可能需要幾分鐘。當記事本執行個體被刪除,會從表格中消失。
-
開啟 Amazon S3 主控台
,刪除您為了儲存模型成品和訓練資料集而建立的儲存貯體。 -
開啟 IAM 主控台
並刪除該 IAM 角色。如果已建立許可政策,也可一併刪除。 注意
Docker 容器執行之後會自動關閉。您不需要刪除它。