

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Ampliar una contenedor precompilado
<a name="prebuilt-containers-extend"></a>

Si un contenedor de SageMaker IA prediseñado no cumple con todos sus requisitos, puede ampliar la imagen existente para adaptarla a sus necesidades. Incluso si hay soporte directo para su entorno o marco, es posible que desee añadir funciones adicionales o configurar el entorno de contenedores de forma diferente. Al ampliar una imagen precompilada, puede aprovechar las bibliotecas y configuraciones de aprendizaje profundo incluidas sin tener que crear una imagen desde cero. Puede ampliar el contenedor para añadir bibliotecas, modificar la configuración e instalar dependencias adicionales. 

El siguiente tutorial muestra cómo ampliar una SageMaker imagen prediseñada y publicarla en Amazon ECR.

**Topics**
+ [Requisitos para ampliar un contenedor precompilado](#prebuilt-containers-extend-required)
+ [Amplíe los contenedores de SageMaker IA para ejecutar un script de Python](#prebuilt-containers-extend-tutorial)

## Requisitos para ampliar un contenedor precompilado
<a name="prebuilt-containers-extend-required"></a>

Para ampliar una SageMaker imagen prediseñada, debe configurar las siguientes variables de entorno en su Dockerfile. Para obtener más información sobre las variables de entorno con contenedores de SageMaker IA, consulta el repositorio del [SageMaker Training](https://github.com/aws/sagemaker-training-toolkit/blob/master/ENVIRONMENT_VARIABLES.md) Toolkit. GitHub 
+ `SAGEMAKER_SUBMIT_DIRECTORY`: el directorio dentro del contenedor en el que se encuentra el script de Python para el entrenamiento.
+ `SAGEMAKER_PROGRAM`: el script de Python que debe invocarse y usarse como punto de entrada para el entrenamiento.

También puede instalar bibliotecas adicionales si incluye lo siguiente en su Dockerfile:

```
RUN pip install {{<library>}}
```

En el siguiente tutorial se muestra cómo utilizar estas variables de entorno.

## Amplíe los contenedores de SageMaker IA para ejecutar un script de Python
<a name="prebuilt-containers-extend-tutorial"></a>

En este tutorial, aprenderá a ampliar el PyTorch contenedor de SageMaker IA con un archivo Python que usa el conjunto de datos CIFAR-10. Al ampliar el PyTorch contenedor de SageMaker IA, se utiliza la solución de formación existente diseñada para funcionar con SageMaker la IA. En este tutorial se amplía una imagen de entrenamiento, pero se pueden seguir los mismos pasos para ampliar una imagen de inferencia. Para una lista completa de las Imágenes disponibles, consulte [Imágenes de contenedores de aprendizaje profundo disponibles](https://github.com/aws/deep-learning-containers/blob/master/available_images.md).

Para ejecutar tu propio modelo de entrenamiento con los contenedores de SageMaker IA, crea un contenedor de Docker a través de una instancia de SageMaker Notebook. 

### Paso 1: Crea una instancia de SageMaker Notebook
<a name="extend-step1"></a>

1. Abre la [consola de SageMaker IA](https://console.aws.amazon.com/sagemaker/). 

1. En el panel de navegación, elija **Notebook Cuaderno)**, seleccione **Notebook instances (Instancias de cuaderno)** y, a continuación, seleccione **Create notebook instance (Crear instancia de cuaderno)**. 

1. En la página **Crear instancia de bloc de notas**, proporcione la siguiente información: 

   1. En **Notebook instance name (Nombre de instancia del bloc de notas)**, escriba **RunScriptNotebookInstance**.

   1. En **Tipo de instancia de bloc de notas**, elija **ml.t2.medium**.

   1. En la sección **Permissions and encryption (Permisos y cifrado)**, haga lo siguiente:

      1. En **Rol de IAM**, elija **Crear un nuevo rol**.

      1. En la página **Create an IAM role (Crear un rol de IAM)**, elija **Buckets de S3 específicos**, especifique un bucket de Amazon S3 denominado **sagemaker-run-script** y, a continuación, elija **Create role (Crear rol)**.

         SageMaker La IA crea un rol de IAM denominado`AmazonSageMaker-ExecutionRole-{{YYYYMMDD}}T{{HHmmSS}}`, por ejemplo. `AmazonSageMaker-ExecutionRole-20190429T110788` Tenga en cuenta que la convención de nomenclatura de rol de ejecución utiliza la fecha y la hora en que se creó el rol, separadas por una `T`.

   1. En **Root Access (Acceso raíz)**, elija **Enable (Habilitar)**.

   1. Elija **Crear instancia de bloc de notas**. 

1. **En la página **Notebook instances (Instancias de cuaderno)**, **Status (Estado)** es Pemnding (Pendiente)**. Amazon SageMaker AI puede tardar unos minutos en lanzar una instancia de procesamiento de aprendizaje automático (en este caso, lanza una instancia de notebook) y adjuntarle un volumen de almacenamiento de aprendizaje automático. La instancia de cuaderno cuenta con un servidor de cuaderno de Jupyter configurado previamente y un conjunto de bibliotecas de Anaconda. Para obtener más información, consulte [ CreateNotebookInstance](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateNotebookInstance.html). 

   

1. En la sección **Permissions and encryption (Permisos y cifrado)**, copie el **número de ARN del rol de IAM** y péguelo en un archivo de cuaderno para guardarlo temporalmente. Este número ARN del rol de IAM se utiliza más adelante para configurar un estimador de entrenamiento local en la instancia del cuaderno. **El número de ARN de rol de IAM** tiene el siguiente aspecto: `'arn:aws:iam::111122223333:role/service-role/AmazonSageMaker-ExecutionRole-20190429T110788'`. 

1. Cuando el estado de la instancia del bloc de notas cambie a **InService**, seleccione **Abrir JupyterLab**.

### Paso 2: Crear y cargar scripts de entrenamiento de Dockerfile y Python
<a name="extend-step2"></a>

1. Cuando JupyterLab se abra, cree una nueva carpeta en el directorio principal de su JupyterLab. En la esquina superior izquierda, elija el icono de **nueva carpeta** y, a continuación, escriba el nombre de la carpeta `docker_test_folder`. 

1.  Cree un archivo de texto `Dockerfile` en el directorio `docker_test_folder`. 

   1. Seleccione el icono del **nuevo lanzador** (\+) en la esquina superior izquierda. 

   1. En el panel derecho, en la sección **Other (Otro)**, seleccione **Text file (Archivo de texto)**.

   1.  Pegue el siguiente código de ejemplo `Dockerfile` en el archivo 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
      ```

      El script Dockerfile realiza las siguientes tareas:
      + `FROM 763104351884.dkr.ecr.us-east-1.amazonaws.com/pytorch-training:1.5.1-cpu-py36-ubuntu16.04`— Descarga la imagen PyTorch base de la SageMaker IA. Puedes sustituirla por cualquier imagen base de SageMaker IA que desees utilizar para construir contenedores.
      + `ENV SAGEMAKER_SUBMIT_DIRECTORY /opt/ml/code`: establece `/opt/ml/code` como el directorio de scripts de entrenamiento.
      + `COPY cifar10.py /opt/ml/code/cifar10.py`— Copia el guion en la ubicación prevista por la SageMaker IA dentro del contenedor. El script debe estar ubicado en esta carpeta.
      + `ENV SAGEMAKER_PROGRAM cifar10.py`: establece el script de entrenamiento `cifar10.py` como el script de punto de entrada.

   1.  En la navegación del directorio izquierdo, el nombre del archivo de texto se establece automáticamente como `untitled.txt`. Para cambiar el nombre del archivo, haga clic con el botón derecho en el archivo, seleccione **Rename (Cambiar nombre)**, cámbiele el nombre a `Dockerfile` sin la extensión `.txt` y, a continuación, pulse `Ctrl+s` o `Command+s` para guardar el archivo.

1. Cree o cargue un script de entrenamiento `cifar10.py` en la `docker_test_folder`. Puede utilizar el siguiente script de ejemplo. para este ejercicio. 

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

### Paso 3: Compilar el contenedor
<a name="extend-step3"></a>

1. En el directorio JupyterLab principal, abre un cuaderno de Jupyter. **Para abrir un cuaderno nuevo, seleccionae el icono de **nuevo lanzamiento** y, a continuación, seleccione **conda\_pytorch\_p39** en la sección Notebook (Cuaderno)**. 

1. Ejecute el siguiente comando en la primera celda del cuaderno para cambiar al directorio `docker_test_folder`:

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

   Esto devuelve su directorio actual como se indica a continuación: 

   ```
   ! pwd
   ```

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

1. Inicie sesión en Docker para acceder al contenedor 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 crear el contenedor de Docker, ejecute el siguiente comando de compilación de Docker, incluyendo el espacio seguido del punto final:

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

   El comando de compilación de Docker debe ejecutarse desde el directorio creado, en este caso `docker_test_folder`.
**nota**  
Si aparece el siguiente mensaje de error que indica que Docker no puede encontrar el Dockerfile, asegúrese de que el Dockerfile tenga el nombre correcto y se haya guardado en el directorio.  

   ```
   unable to prepare context: unable to evaluate symlinks in Dockerfile path: 
   lstat /home/ec2-user/SageMaker/docker/Dockerfile: no such file or directory
   ```
Recuerde que `docker` busca un archivo llamado específicamente `Dockerfile` sin ninguna extensión en el directorio actual. Si lo nombró de otra manera, puede pasar el nombre de archivo manualmente con la marca `-f`. Por ejemplo, si asignó el nombre `Dockerfile-text.txt` a su Dockerfile, ejecute el siguiente comando:  

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

### Paso 4: Probar el contenedor
<a name="extend-step4"></a>

1. Para probar el contenedor localmente en la instancia de cuaderno, abra un cuaderno de Jupyter. Elija **New Launcher (Nuevo lanzador)** y seleccione **Notebook (Cuaderno)** en el marco **`conda_pytorch_p39`**. El resto de los fragmentos de código deben ejecutarse desde la instancia del cuaderno de Jupyter.

1. Descargue el conjunto de datos 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` en el rol utilizado para crear su cuaderno de Jupyter. Esto se usa para configurar su SageMaker AI Estimator.

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

1. Pegue el siguiente script de ejemplo en la celda de código del cuaderno para configurar un SageMaker AI Estimator utilizando su contenedor extendido.

   ```
   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. Ejecute la celda de código. Esta prueba devuelve la configuración del entorno de capacitación, los valores utilizados en las variables de entorno, el origen de los datos y la pérdida y precisión obtenidas durante la capacitación.

### Paso 5: Insertar el contenedor en Amazon Elastic Container Registry (Amazon ECR)
<a name="extend-step5"></a>

1. Después de ejecutar correctamente la prueba de modo local, puede insertar el contenedor de Docker en [Amazon ECR](https://docs.aws.amazon.com/AmazonECR/latest/userguide/what-is-ecr.html) para utilizarlo para ejecutar trabajos de entrenamiento. 

   Puede ejecutar manualmente comandos de Git como los siguientes en una celda del cuaderno.

   ```
   %%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. Después de empujar el contenedor, puede llamar a la imagen de Amazon ECR desde cualquier lugar del entorno de SageMaker IA. Ejecute el siguiente ejemplo de código en la siguiente celda del cuaderno. 

   Si quieres usar este contenedor de entrenamiento con SageMaker Studio para usar sus funciones de visualización, también puedes ejecutar el siguiente código en una celda de un cuaderno de Studio para llamar a la imagen de Amazon ECR de tu contenedor de entrenamiento.

   ```
   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. Utilice lo `ecr_image` obtenido en el paso anterior para configurar un objeto estimador de SageMaker IA. El siguiente ejemplo de código configura un SageMaker estimador de IA. 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)
   ```

### Paso 6: Eliminar recursos
<a name="extend-step6"></a>

**Para eliminar recursos una vez que haya terminado con el ejemplo de inicio**

1. **Abre la [consola de SageMaker IA](https://console.aws.amazon.com/sagemaker/), elige la instancia del bloc de notas **RunScriptNotebookInstance**, selecciona **Acciones** y selecciona Detener.** Puede que transcurran unos minutos hasta que la instancia se detenga. 

1. Cuando **State (Estado)** de la instancia cambie a **Stopped (Detenida)**, elija **Actions (Acciones)**, elija **Delete (Eliminar)** y, a continuación, elija **Delete (Eliminar)** en el cuadro de diálogo. Puede que transcurran unos minutos hasta que la instancia se elimine. La instancia del cuaderno desaparece de la tabla cuando se elimina. 

1. Abra la [consola de Amazon S3](https://console.aws.amazon.com/s3/) y elimine el bucket que creó para almacenar los artefactos del modelo y los conjuntos de datos de entrenamiento. 

1. Abra la [consola de IAM](https://console.aws.amazon.com/iam/) y elimine el rol de IAM. Si ha creado políticas de permisos, puede eliminarlas también. 
**nota**  
 El contenedor de Docker se cierra automáticamente después de que se haya ejecutado. No es necesario eliminarlo.