Ampliar una contenedor precompilado - Amazon SageMaker

Ampliar una contenedor precompilado

Si un contenedor de Sagemaker precompilado 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.

En el siguiente tutorial se muestra cómo ampliar una imagen de SageMaker precompilada y publicarla en Amazon ECR.

Requisitos para ampliar un contenedor precompilado

Para ampliar una imagen de SageMaker precompilada, debe establecer las siguientes variables de entorno en su Dockerfile. Para obtener más información sobre información sobre las variables de entorno con contenedores de SageMaker, consulte el repositorio de GitHub de SageMaker Training Toolkit.

  • 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.

Ampliar los contenedores de Sagemaker para ejecutar un script de Python

En este tutorial, aprenderá a ampliar el contenedor de PyTorch de SageMaker con un archivo de Python que utilice el conjunto de datos CIFAR-10. Al ampliar el contenedor de PyTorch de SageMaker, se utiliza la solución de entrenamiento existente diseñada para funcionar con SageMaker. 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.

Para ejecutar su propio modelo de entrenamiento mediante los contenedores de SageMaker, cree un contenedor de Docker a través de una instancia de cuaderno de SageMaker.

Paso 1: Crear una instancia con cuaderno de SageMaker

  1. Abra la consola de SageMaker.

  2. 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).

  3. 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.

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

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

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

      2. 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 crea un rol de IAM denominado AmazonSageMaker-ExecutionRole-YYYYMMDDTHHmmSS, como 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.

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

    5. Elija Crear instancia de bloc de notas.

  4. En la página Notebook instances (Instancias de cuaderno), Status (Estado) es Pemnding (Pendiente). Amazon CloudWatch Internet Monitor puede tardar unos minutos en lanzar una instancia de procesamiento de machine learning (en este caso, lanza una instancia de cuaderno) y le asocia un volumen de almacenamiento de ML. 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 Crear una instancia de cuaderno.

  5. 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'.

  6. Cuando el estado de la instancia del cuaderno cambie a InService, seleccione Open JupyterLab (Abrir JupyterLab).

Paso 2: Crear y cargar scripts de entrenamiento de Dockerfile y Python

  1. Cuando se abra JupyterLab, 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.

  2. Cree un archivo de texto Dockerfile en el directorio docker_test_folder.

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

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

    3. 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 base de PyTorch de SageMaker. Puede sustituirla por cualquier imagen base de Sagemaker que desee utilizar para crear 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 script en la ubicación dentro del contenedor esperado por SageMaker. 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.

    4. 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.

  3. 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

  1. En el directorio principal de JupyterLab, abra 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).

  2. 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

  3. 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
  4. 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

  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.

  2. 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')
  3. Defina role en el rol utilizado para crear su cuaderno de Jupyter. Se utiliza para configurar su estimador de SageMaker.

    from sagemaker import get_execution_role role=get_execution_role()
  4. Pegue el siguiente script de ejemplo en la celda de código del cuaderno para configurar un estimador de SageMaker 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')
  5. 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)

  1. Después de ejecutar correctamente la prueba de modo local, puede insertar el contenedor de Docker en Amazon ECR 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}
  2. Después de insertar el contenedor, puede llamar a la imagen de Amazon ECR desde cualquier lugar del entorno de SageMaker. Ejecute el siguiente ejemplo de código en la siguiente celda del cuaderno.

    Si desea utilizar este contenedor de entrenamiento con Sagemaker Studio para utilizar sus características de visualización, también puede ejecutar el siguiente código en una celda de un cuaderno de Studio para llamar a la imagen de Amazon ECR de su 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
  3. Utilice la ecr_image obtenida en el paso anterior para configurar un objeto de estimador de SageMaker. En el siguiente ejemplo de código se configura un estimador de PyTorch de Sagemaker.

    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

Para eliminar recursos una vez que haya terminado con el ejemplo de inicio
  1. Abra la consola de SageMaker, seleccione la instancia de cuaderno RunScriptNotebookInstance, elija Actions (Acciones) y elija Stop (Detener). Puede que transcurran unos minutos hasta que la instancia se detenga.

  2. 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.

  3. Abra la consola de Amazon S3 y elimine el bucket que creó para almacenar los artefactos del modelo y los conjuntos de datos de entrenamiento.

  4. Abra la consola de 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.