

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# Estenda uma imagem de contêiner predefinida
<a name="prebuilt-containers-extend"></a>

Se um contêiner de SageMaker IA pré-construído não atender a todos os seus requisitos, você poderá estender a imagem existente para acomodar suas necessidades. Mesmo que haja suporte direto para seu ambiente ou estrutura, talvez você queira adicionar mais funcionalidades ou configurar seu ambiente de contêiner de forma diferente. Quando estender uma imagem predefinida, você pode aproveitar as bibliotecas e configurações de aprendizado profundo incluídas sem precisar criar uma imagem do zero. Estenda o contêiner para adicionar bibliotecas, modificar configurações e instalar dependências adicionais. 

O tutorial a seguir mostra como estender uma SageMaker imagem pré-criada e publicá-la no Amazon ECR.

**Topics**
+ [

## Requisitos para estender um contêiner predefinido
](#prebuilt-containers-extend-required)
+ [

## Estenda os contêineres de SageMaker IA para executar um script Python
](#prebuilt-containers-extend-tutorial)

## Requisitos para estender um contêiner predefinido
<a name="prebuilt-containers-extend-required"></a>

Para estender uma SageMaker imagem pré-criada, você precisa definir as seguintes variáveis de ambiente em seu Dockerfile. Para obter mais informações sobre variáveis de ambiente com contêineres de SageMaker IA, consulte o repositório do [SageMaker Training Toolkit GitHub ](https://github.com/aws/sagemaker-training-toolkit/blob/master/ENVIRONMENT_VARIABLES.md).
+ `SAGEMAKER_SUBMIT_DIRECTORY`: o diretório dentro do contêiner no qual o script Python para treinamento está localizado.
+ `SAGEMAKER_PROGRAM`: o script Python que deve ser invocado e usado como ponto de entrada no treinamento.

Você também pode instalar mais bibliotecas incluindo o seguinte em seu Dockerfile:

```
RUN pip install <library>
```

O tutorial a seguir mostra como usar essas variáveis de ambiente.

## Estenda os contêineres de SageMaker IA para executar um script Python
<a name="prebuilt-containers-extend-tutorial"></a>

Neste tutorial, você aprende como estender o PyTorch contêiner de SageMaker IA com um arquivo Python que usa o conjunto de dados CIFAR-10. Ao estender o PyTorch contêiner de SageMaker IA, você utiliza a solução de treinamento existente feita para trabalhar com SageMaker IA. Este tutorial estende uma imagem de treinamento, mas as mesmas etapas podem ser tomadas para estender uma imagem de inferência. Para obter uma lista completa das imagens disponíveis, consulte [Imagens de contêineres de aprendizado profundo](https://github.com/aws/deep-learning-containers/blob/master/available_images.md).

Para executar seu próprio modelo de treinamento usando os contêineres de SageMaker IA, crie um contêiner Docker por meio de uma instância do SageMaker Notebook. 

### Etapa 1: criar uma instância de SageMaker notebook
<a name="extend-step1"></a>

1. Abra o [console de SageMaker IA](https://console.aws.amazon.com/sagemaker/). 

1. No painel de navegação, escolha **Caderno**, e depois **Instâncias do caderno** e selecione **Criar instância de cadernos**. 

1. Na página **Create notebook instance (Criar instância de bloco de anotações)**, forneça as seguintes informações: 

   1. Para **Notebook instance name (Nome da instância de bloco de anotações)**, insira **RunScriptNotebookInstance**.

   1. Em **Notebook Instance type (Tipo de instância de bloco de anotações)**, escolha **ml.t2.medium**.

   1. Na seção **Permissões e criptografia)** e faça o seguinte:

      1. Em **Perfil do IAM**, selecione **Criar uma nova função**.

      1. Na página **Create an IAM role (Criar uma função do IAM)**, escolha **Specific S3 buckets (Buckets do S3 específicos)**, especifique um bucket do Amazon S3 chamado **sagemaker-run-script** e depois escolha **Create role (Criar função)**.

         SageMaker A IA cria uma função do IAM chamada`AmazonSageMaker-ExecutionRole-YYYYMMDDTHHmmSS`, como`AmazonSageMaker-ExecutionRole-20190429T110788`. Observe que a convenção de nomenclatura de função de execução usa a data e a hora em que a função foi criada, separada por um `T`.

   1. Em **Root Access (Acesso raiz)**, escolha **Enable (Habilitar)**.

   1. Escolha **Create notebook instance (Criar instância de bloco de anotações)**. 

1. Na página de **Instâncias de cadernos**, o **status** é **Pendente**. Pode levar alguns minutos para que a Amazon SageMaker AI lance uma instância de computação de aprendizado de máquina — nesse caso, ela lança uma instância de notebook — e anexe um volume de armazenamento de ML a ela. A instância de caderno conta com a pré-configuração de um servidor de cadernos Jupyter e de um conjunto de bibliotecas da Anaconda. Para obter mais informações, consulte [ CreateNotebookInstance](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateNotebookInstance.html). 

   

1. Na seção **Permissões e criptografia**, copie **o número ARN do perfil do IAM** e cole-o em um arquivo do bloco de notas para salvá-lo temporariamente. Posteriormente, você usa esse número ARN da função do IAM para configurar um estimador de treinamento local na instância de cadernos. **The IAM role ARN number (O número do ARN da função do IAM) ** é semelhante ao seguinte: `'arn:aws:iam::111122223333:role/service-role/AmazonSageMaker-ExecutionRole-20190429T110788'` 

1. Depois que o status da instância do notebook mudar para **InService**, escolha **Abrir JupyterLab**.

### Etapa 2: Como criar e fazer upload do Dockerfile e dos scripts de treinamento do Python
<a name="extend-step2"></a>

1. Depois de JupyterLab abrir, crie uma nova pasta no diretório inicial do seu JupyterLab. No canto superior esquerdo, escolha o ícone **Nova pasta** e insira o nome da pasta `docker_test_folder`. 

1.  Crie um arquivo de texto `Dockerfile` no diretório `docker_test_folder`. 

   1. Escolha o ícone **Novo inicializador** (\$1) no canto superior esquerdo. 

   1. No painel à direita, na seção **Outro**, selecione **Arquivo de texto**.

   1.  Cole o código de amostra `Dockerfile` a seguir no seu arquivo de texto. 

      ```
      # 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
      ```

      O script do Dockerfile executa as seguintes tarefas:
      + `FROM 763104351884.dkr.ecr.us-east-1.amazonaws.com/pytorch-training:1.5.1-cpu-py36-ubuntu16.04`— Faz o download da imagem PyTorch base da SageMaker IA. Você pode substituí-la por qualquer imagem base de SageMaker IA que você queira trazer para criar contêineres.
      + `ENV SAGEMAKER_SUBMIT_DIRECTORY /opt/ml/code`: define `/opt/ml/code` como o diretório do script de treinamento.
      + `COPY cifar10.py /opt/ml/code/cifar10.py`— Copia o script para o local dentro do contêiner que é esperado pela SageMaker IA. O script deve estar localizado nessa pasta.
      + `ENV SAGEMAKER_PROGRAM cifar10.py`: define seu script de treinamento `cifar10.py` como o script do ponto de entrada.

   1.  No painel de navegação do diretório à esquerda, o nome do arquivo de texto é nomeado automaticamente como `untitled.txt`. Para renomear o arquivo, clique com o botão direito do mouse no arquivo, escolha **Rename (Renomear)**, renomeie o arquivo como `Dockerfile` sem a extensão `.txt` e pressione `Ctrl+s` ou `Command+s` para salvar o arquivo.

1. Crie ou faça upload de um script de treinamento `cifar10.py` no `docker_test_folder`. Você pode usar o seguinte script de exemplo neste exercício: 

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

### Etapa 3: Definir o Contêiner
<a name="extend-step3"></a>

1. No diretório JupyterLab inicial, abra um notebook Jupyter. Para abrir um novo bloco de anotações, escolha o ícone **New Launch (Novo lançamento)** e depois **conda\$1pytorch\$1p39** na seção **Notebook**. 

1. Execute o comando a seguir na primeira célula do notebook para mudar para o diretório `docker_test_folder`:

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

   Isso retorna o diretório atual da seguinte forma:

   ```
   ! pwd
   ```

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

1. Faça login no Docker para acessar o contêiner de base:

   ```
   ! aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 763104351884.dkr.ecr.us-east-1.amazonaws.com
   ```

1. Para criar o contêiner do Docker, execute o seguinte comando de criação do Docker, incluindo o espaço, seguido por ponto final.

   ```
   ! docker build -t pytorch-extended-container-test .
   ```

   O comando de criação do Docker deve ser executado no diretório que você criou, neste caso, o `docker_test_folder`.
**nota**  
Se você receber a mensagem de erro a seguir informando que o Docker não consegue encontrar o Dockerfile, verifique se o Dockerfile tem o nome correto e foi salvo no diretório.  

   ```
   unable to prepare context: unable to evaluate symlinks in Dockerfile path: 
   lstat /home/ec2-user/SageMaker/docker/Dockerfile: no such file or directory
   ```
Lembre-se de que `docker` procura um arquivo chamado especificamente `Dockerfile` sem nenhuma extensão no diretório atual. Se você deu outro nome, poderá transmitir o nome de arquivo manualmente com a bandeira `-f`. Por exemplo, se você chamou o Dockerfile de `Dockerfile-text.txt`, execute o seguinte comando:  

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

### Etapa 4: Testar o Contêiner
<a name="extend-step4"></a>

1. Para testar o contêiner no local na instância do bloco de anotações, abra um bloco de anotações do Jupyter. Escolha **New Launcher (Novo inicializador)** e depois **Notebook (Bloco de anotações)** na estrutura de trabalho **`conda_pytorch_p39`**. O restante dos trechos de código deve ser executado na instância do bloco de anotações Jupyter.

1. Baixe o conjunto de dados 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')
   ```

1. Defina `role` no perfil usado para criar seu caderno Jupyter. Isso é usado para configurar seu Estimador de SageMaker IA.

   ```
   from sagemaker import get_execution_role
   
   role=get_execution_role()
   ```

1. Cole o script de exemplo a seguir na célula de código do notebook para configurar um Estimador de SageMaker IA usando seu contêiner estendido.

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

1. Execute a célula de código. Esse teste mostra a configuração do ambiente de treinamento, os valores usados para as variáveis de ambiente, a fonte dos dados e a perda e precisão obtidas durante o treinamento.

### Etapa 5: Envie o contêiner para o Amazon Elastic Container Registry (Amazon ECR)
<a name="extend-step5"></a>

1. Depois de executar com êxito este teste de modo local, você pode enviar a imagem para o [Amazon ECR](https://docs.aws.amazon.com/AmazonECR/latest/userguide/what-is-ecr.html) e usá-la para executar trabalhos de treinamento. 

   É possível executar as linhas de comandos a seguir em uma célula do bloco de anotações.

   ```
   %%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}
   ```

1. Depois de enviar o contêiner, você pode chamar a imagem do Amazon ECR de qualquer lugar no ambiente de SageMaker IA. Execute o exemplo de código a seguir na próxima célula do bloco de anotações. 

   Se quiser usar esse contêiner de treinamento com o SageMaker Studio para usar seus recursos de visualização, você também pode executar o código a seguir em uma célula de notebook do Studio para chamar a imagem Amazon ECR do seu contêiner de treinamento.

   ```
   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
   ```

1. Use o `ecr_image` recuperado da etapa anterior para configurar um objeto estimador de SageMaker IA. O exemplo de código a seguir configura um PyTorch estimador de SageMaker IA.

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

### Etapa 6: Limpar os Recursos
<a name="extend-step6"></a>

**Para limpar recursos quando terminar com o exemplo de Get Started (introdução)**

1. Abra o [console de SageMaker IA](https://console.aws.amazon.com/sagemaker/), escolha a instância do notebook **RunScriptNotebookInstance**, escolha **Ações** e escolha **Parar**. Pode demorar alguns minutos para que a instância pare. 

1. Depois que o **status** da instância mudar para **Interrompido**, escolha **Ações**, escolha **Excluir** e, em seguida, escolha **Excluir** na caixa de diálogo. Pode demorar alguns minutos para a exclusão da instância. A instância dos blocos de anotações desaparece da tabela quando é excluída. 

1. Abra o [console do Amazon S3](https://console.aws.amazon.com/s3/) e exclua o bucket criado para armazenar artefatos do modelo e o conjunto de dados de treinamento. 

1. Abra o [console do IAM](https://console.aws.amazon.com/iam/) e exclua a função do IAM. Se você criou políticas de permissões, poderá excluí-las também. 
**nota**  
 O contêiner do Docker é desligado automaticamente depois de ser executado. Você não precisa excluí-lo.