

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

# Estensione di un container predefinito
<a name="prebuilt-containers-extend"></a>

Se un contenitore SageMaker AI preconfigurato non soddisfa tutti i tuoi requisiti, puoi estendere l'immagine esistente per soddisfare le tue esigenze. Anche se è disponibile un supporto diretto per l'ambiente o il framework, è possibile aggiungere funzionalità aggiuntive o configurare l'ambiente del container in modo diverso. Estendendo un'immagine predefinita, è possibile sfruttare le librerie e le impostazioni di deep learning incluse senza dover creare un'immagine da zero. È possibile estendere il container per aggiungere librerie, modificare le impostazioni e installare dipendenze aggiuntive. 

Il seguente tutorial mostra come estendere un' SageMaker immagine predefinita e pubblicarla su Amazon ECR.

**Topics**
+ [Requisiti per estendere un container predefinito](#prebuilt-containers-extend-required)
+ [Estendi i contenitori SageMaker AI per eseguire uno script Python](#prebuilt-containers-extend-tutorial)

## Requisiti per estendere un container predefinito
<a name="prebuilt-containers-extend-required"></a>

Per estendere un' SageMaker immagine predefinita, devi impostare le seguenti variabili di ambiente all'interno del tuo Dockerfile. Per ulteriori informazioni sulle variabili di ambiente con i contenitori SageMaker AI, consulta il repository [SageMaker Training](https://github.com/aws/sagemaker-training-toolkit/blob/master/ENVIRONMENT_VARIABLES.md) Toolkit. GitHub 
+ `SAGEMAKER_SUBMIT_DIRECTORY`: la directory all'interno del container in cui si trova lo script Python per l’addestramento.
+ `SAGEMAKER_PROGRAM`: lo script Python che dovrebbe essere invocato e usato come punto di ingresso per l'addestramento.

È possibile anche installare librerie aggiuntive includendo quanto segue nel Dockerfile:

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

Il tutorial seguente mostra l'utilizzo di queste variabili di ambiente.

## Estendi i contenitori SageMaker AI per eseguire uno script Python
<a name="prebuilt-containers-extend-tutorial"></a>

In questo tutorial, imparerai come estendere il PyTorch contenitore SageMaker AI con un file Python che utilizza il set di dati CIFAR-10. Estendendo il PyTorch contenitore SageMaker AI, utilizzi la soluzione di formazione esistente creata per funzionare con l'IA. SageMaker Questo tutorial estende un'immagine di addestramento, ma è possibile eseguire le stesse fasi per estendere un'immagine di inferenza. Per un elenco completo di immagini disponibili, consulta [Immagini dei container di deep learning disponibili](https://github.com/aws/deep-learning-containers/blob/master/available_images.md).

Per eseguire il tuo modello di formazione utilizzando i contenitori SageMaker AI, crea un contenitore Docker tramite un' SageMaker istanza Notebook. 

### Passaggio 1: creare un'istanza SageMaker Notebook
<a name="extend-step1"></a>

1. Apri la [console SageMaker AI](https://console.aws.amazon.com/sagemaker/). 

1. Nel riquadro di navigazione, scegli **Notebook**, scegli **Istanze del notebook** e quindi scegli **Crea istanza del notebook**. 

1. Nella pagina **Crea istanza del notebook**, inserisci le seguenti informazioni: 

   1. Per **Nome dell’istanza del notebook**, inserisci **RunScriptNotebookInstance**.

   1. Per **Tipo di istanza del notebook**, scegli **ml.t2.medium**.

   1. Espandi la sezione **Autorizzazioni e crittografia** e procedi come segue:

      1. Per **Ruolo IAM**, scegli **Crea un nuovo ruolo**.

      1. Nella pagina **Crea un ruolo IAM**, scegli **Specifica bucket S3**, specifica un bucket S3 Amazon denominato **sagemaker-run-script** e scegli **Crea ruolo**.

         SageMaker L'IA crea un ruolo IAM denominato`AmazonSageMaker-ExecutionRole-{{YYYYMMDD}}T{{HHmmSS}}`, ad esempio`AmazonSageMaker-ExecutionRole-20190429T110788`. Nota che la convenzione di denominazione del ruolo di esecuzione utilizza la data e l'ora in cui il ruolo è stato creato, separati da `T`.

   1. Per **Accesso root**, seleziona **Abilitato**.

   1. Scegli **Crea un'istanza del notebook**. 

1. Nella pagina delle **istanze del notebook**, lo **Stato** è **In sospeso**. Amazon SageMaker AI può impiegare alcuni minuti per avviare un'istanza di calcolo di machine learning (in questo caso, avvia un'istanza notebook) e collegarvi un volume di storage ML. L'istanza del notebook include un server Notebook Jupyter preconfigurato e un set di librerie Anaconda. Per ulteriori informazioni, consulta [ CreateNotebookInstance](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateNotebookInstance.html). 

   

1. Nella sezione **Autorizzazioni e crittografia**, copia **il numero ARN del ruolo IAM** e incollalo in un file di blocco note per salvarlo temporaneamente. Questo numero ARN del ruolo IAM viene utilizzato in seguito per configurare uno strumento di valutazione di addestramento locale nell'istanza del notebook. **Il numero ARN del ruolo IAM** è simile al seguente: `'arn:aws:iam::111122223333:role/service-role/AmazonSageMaker-ExecutionRole-20190429T110788'` 

1. Dopo che lo stato dell'istanza del notebook diventa **InService**, scegli **Apri JupyterLab**.

### Fase 2: creazione e caricamento del Dockerfile e degli script di addestramento Python
<a name="extend-step2"></a>

1. Dopo l' JupyterLab apertura, crea una nuova cartella nella home directory del tuo JupyterLab. Nell’angolo in alto a sinistra, scegli l’icona**Nuova cartella**, quindi inserisci il nome della cartella `docker_test_folder`. 

1.  Crea un `Dockerfile` file di testo nella directory `docker_test_folder`. 

   1. Scegli l'icona **Nuova utilità di avvio** (\+) nell'angolo in alto a sinistra. 

   1. Nel pannello di destra, seleziona **File di testo** nella sezione **Altro**.

   1.  Incolla il seguente codice campione `Dockerfile` nel file di testo. 

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

      Lo script Dockerfile esegue le seguenti attività:
      + `FROM 763104351884.dkr.ecr.us-east-1.amazonaws.com/pytorch-training:1.5.1-cpu-py36-ubuntu16.04`— Scarica l'immagine di PyTorch base SageMaker AI. Puoi sostituirla con qualsiasi immagine di base SageMaker AI che desideri utilizzare per creare contenitori.
      + `ENV SAGEMAKER_SUBMIT_DIRECTORY /opt/ml/code` – imposta `/opt/ml/code` come directory dello script di addestramento.
      + `COPY cifar10.py /opt/ml/code/cifar10.py`— Copia lo script nella posizione all'interno del contenitore prevista dall' SageMaker IA. Lo script si deve trovare in questa cartella.
      + `ENV SAGEMAKER_PROGRAM cifar10.py` – imposta lo script di addestramento `cifar10.py` come script del punto di ingresso.

   1.  Nel riquadro di navigazione a sinistra, il nome del file di testo viene automaticamente denominato `untitled.txt`. Per rinominare il file, fai clic con il pulsante destro del mouse sul file, scegli **Rinomina**, rinomina il file come `Dockerfile` senza l’estensione `.txt`, quindi premi `Ctrl+s` o `Command+s` per salvare il file.

1. Crea o carica uno script di addestramento `cifar10.py` in `docker_test_folder`. Puoi utilizzare il seguente script di esempio per questo esercizio. 

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

### Fase 3: costruzione del container
<a name="extend-step3"></a>

1. Nella JupyterLab home directory, apri un notebook Jupyter. Per aprire un nuovo notebook, scegli l'icona **Nuovo avvio**, quindi scegli **conda\_pytorch\_p39** nella sezione **Notebook**. 

1. Esegui il comando seguente nella prima cella del notebook per passare alla directory `docker_test_folder`:

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

   Viene restituita la directory corrente come segue:

   ```
   ! pwd
   ```

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

1. Effettua il login a Docker per accedere al container di 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. Per compilare il container Docker, esegui il seguente comando di compilazione Docker, incluso lo spazio seguito da un punto finale:

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

   Il comando build Docker deve essere eseguito dalla directory Docker creata, in questo caso `docker_test_folder`.
**Nota**  
Se visualizzi il seguente messaggio di errore che indica che Docker non riesce a trovare il Dockerfile, assicurati che il Dockerfile abbia il nome corretto e che sia stato salvato nella directory.  

   ```
   unable to prepare context: unable to evaluate symlinks in Dockerfile path: 
   lstat /home/ec2-user/SageMaker/docker/Dockerfile: no such file or directory
   ```
Ricorda che `docker` cerca un file chiamato specificamente `Dockerfile` senza alcuna estensione all'interno della directory corrente. Se è stato rinominato, è possibile inserire il nome del file manualmente con il flag `-f`. Ad esempio, se hai inserito un nome per il Dockerfile `Dockerfile-text.txt`, esegui il comando seguente:  

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

### Fase 4: test del container
<a name="extend-step4"></a>

1. Per eseguire il test del container localmente nell’istanza del notebook, apri un notebook Jupyter. Scegli **Nuova utilità di avvio** e seleziona **Notebook** nel framework **`conda_pytorch_p39`**. Il resto dei frammenti di codice deve essere eseguito dall'istanza del notebook Jupyter.

1. Scarica il set di dati 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. Imposta `role` sul ruolo utilizzato per creare il notebook Jupyter. Viene utilizzato per configurare AI Estimator. SageMaker 

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

1. Incolla il seguente script di esempio nella cella di codice del notebook per configurare un SageMaker AI Estimator utilizzando il tuo contenitore esteso.

   ```
   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. Esegui la cella di codice. Questo test genera la configurazione dell'ambiente utilizzato per le variabili di ambiente, l'origine dei dati e la perdita e la precisione ottenuti durante l’addestramento.

### Fase 5: push del container ad Amazon Elastic Container Registry (Amazon ECR)
<a name="extend-step5"></a>

1. Dopo aver eseguito questo test in modalità locale, è possibile eseguire il push del container Docker in [Amazon ECR](https://docs.aws.amazon.com/AmazonECR/latest/userguide/what-is-ecr.html) e utilizzarlo per eseguire processi di addestramento. 

   Esegui le seguenti linee di comando in una cella del notebook.

   ```
   %%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. Dopo aver inviato il container, puoi richiamare l'immagine Amazon ECR da qualsiasi punto dell'ambiente SageMaker AI. Esegui il seguente esempio di codice nella cella successiva del notebook. 

   Se desideri utilizzare questo contenitore di formazione con SageMaker Studio per utilizzare le sue funzionalità di visualizzazione, puoi anche eseguire il codice seguente in una cella notebook Studio per richiamare l'immagine Amazon ECR del tuo contenitore di formazione.

   ```
   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. Usa quanto `ecr_image` recuperato dal passaggio precedente per configurare un oggetto di stima SageMaker AI. Il seguente esempio di codice configura uno SageMaker stimatore AI. 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)
   ```

### Fase 6: eliminazione delle risorse
<a name="extend-step6"></a>

**Per eliminare le risorse al termine dell'esempio sulle Nozioni di base**

1. **Apri la [console SageMaker AI](https://console.aws.amazon.com/sagemaker/), scegli l'istanza del notebook **RunScriptNotebookInstance**, scegli **Azioni** e scegli Stop.** Possono essere necessari alcuni minuti per arrestare l'istanza. 

1. Dopo che lo **Stato** dell'istanza è passato ad **Arrestato**, scegli **Azioni**, seleziona **Elimina**, quindi scegli **Elimina** nella casella di dialogo. Possono essere necessari alcuni minuti per eliminare l'istanza. L'istanza del notebook scompare dalla tabella una volta eliminata. 

1. Apri la [console Amazon S3](https://console.aws.amazon.com/s3/) ed elimina il bucket creato per l'archiviazione degli artefatti del modello e del set di dati di addestramento. 

1. Apri la [console IAM](https://console.aws.amazon.com/iam/) ed elimina il ruolo IAM. Se hai creato policy di autorizzazione, puoi anche eliminarle. 
**Nota**  
 Il container Docker si arresta automaticamente dopo che è stato eseguito. Non è necessario eliminarlo.