Architettura basata su Container Docker

Il modello di distribuzione di SageMaker prevede l'incapsulamento dei modelli ML/DL in immagini Docker. Semplificando, da un'immagine, è dinamicamente generato un container che è eseguito automaticamente su un'istanza EC2 Amazon Elastic Computer Cloud dedicata e ottimizzata per l'impiego ML Amazon SageMaker ML Instance Types. Il modello è pacchettizzato in modo da essere accessibile attraverso una RESTful API che è automaticamente collegata ad un endpoint HTTPS in grado di offrire un punto di contatto robusto e scalabile verso il modo esterno. Questo tipo di approccio ben si coniuga con uno stile architetturale a microservizi.

Lo stile architetturale a microservizi è un approccio allo sviluppo di una singola applicazione come insieme di piccoli servizi, ciascuno dei quali viene eseguito da un proprio processo e comunica con un meccanismo snello, spesso una HTTP API. Martin Fowler

SageMaker offre anche un insieme di immagini Docker preconfigurate in cui sono incapsulati framework ML/DL e implementazioni di algoritmi base. Utilizzando queste immagini è possibile costruire rapidamente semplici modelli facilmente distribuibili.

Setup Iniziale su SageMaker

Il primo passo consiste nell'accedere alla console di SageMaker e da questa attivare (o creare) una notebook instance. A seguire, facendo click su Open, accediamo all'istanza Jupyter. Dalla finestra di Jupyter, facciamo click su New e apriamo una finestra Terminal nel browser, ossia una shell sulla nostra istanza EC2. Siamo loggati come utenti ec2-user.

Dalla linea di comando digitiamo:

cd SageMaker

Quindi cloniamo (git clone) il package git CNTK_KERAS_SAGEMAKER che ho appositamente predisposto per agevolare le prossime operazioni.

cd CNTK_KERAS_SAGEMAKER/container

Per semplicità, chiamiamo questo punto di accesso cartella base.

Struttura del Progetto

La cartella base è così organizzata:

  • build_and_push_to_ecr.sh: lo script file per la generazione dell'immagine e il pushing sul registro Docker ECR Amazon Elastic Container Registry
  • Dockerfile: il file di testo contenente le istruzioni necessarie per creare una nuova immagine basata su Microsoft CNTK (versione 2.3 con supporto per Py27 e CPU). Il file può essere facilmente modificato per selezionare una versione più recente di CNTK sia con supporto GPU sia Py2 o Py3. Per ulteriori informazioni consultare la pagina CNTK Docker Containers
  • keras.json: il file di testo contente le impostazioni per il framework Keras (versione 2.0.6 o superiore) incluso nell'immagine. Queste impostazioni consentono l'integrazione di Keras con la libreria CNTK. Il file è automaticamente caricato all'interno dell'immagine durante la fase di building
  • context: la cartella che contiene i file dati e di configurazione per la creazione del modello
  • setup: la cartella che contiene i file script che permettono a SageMaker di istanziare un container e attivare un modello richiamando le funzioni di addestramento e predizione
  • evaluation: la cartella con file dati esemplificativi e i notebook jupyter che illustrano come utilizzare il modello basato su CNTK da un notebook in SageMaker

Cartella Context

La cartella context è utilizzata esclusivamente per finalità di test in locale (ossia prima di operare su ECR e con SageMaker) e replica al suo interno una gerarchia che riflette esattamente il funzionamento a regime di SageMaker.

Input files:

  • hyperparameters.json: contiene i parametri di configurazione del nostro modello
  • trainset.csv e testset.csv: contenenti rispettivamente training e testing set

Output folders:

  • model: per il salvataggio del modello addestrato (pesi e architettura)
  • output: per logging

Il popolamento delle cartelle model e output è automatico, a valle della fase di addestramento del modello.

Test in Locale

Per testare in modalità locale il funzionamento del container e del modello in esso incapsulato, è necessario spostarsi nella cartella base e creare un'immagine Docker locale usando il comando:

docker build -t cntkdemo .

Dopo la creazione dell'immagine cntkdemo è possibile spostarsi nella cartella evaluation e digitare uno dei seguenti comandi:

# Per istanziare il modello ed eseguire il training
./run_local.sh train

# Per attivare il modello in modalità serving (in attesa di richieste)
./run_local.sh serve

# Per richiedere una predizione usando un file di dati di validazione
./predict.py eval_data.csv

Lo script predict.py richiede che un'istanza del modello sia funzionante in modalità serving in una finestra Terminal dedicata. Nella cartella evaluation sono anche memorizzati i file eval_data.csv ed eval_pred.csv contenenti dati di validazione del modello.

Programmazione del Modello

La programmazione del modello è confinata entro specifici file memorizzati all'interno della cartella setup. In particolare, gli unici due punti dove inseriamo i nostri sviluppi custom sono:

File train

All'interno della funzione train() è confinato il codice per:

  • La lettura dei file di training e testing
  • La lettura dei parametri di configurazione
  • La costruzione del modello
  • L'addestramento e la serializzazione delle impostazioni (pesi e architettura)

Nell'esempio fornito, si utilizza Keras per interfacciarsi a CNTK e creare una semplice rete neurale. È possibile utilizzare qualsiasi libreria Python, istanziare più algoritmi ML/DL per la creazione di modelli di qualsiasi complessità.

File predictor.py

All'interno della funzione get_model() è confinato il codice per:

  • L'istanziazione del modello (a partire dai file dei pesi e dell'architettura creati con l'esecuzione di train)
  • L'implementazione della funzione di predizione

Deployment su ECR

Dopo aver verificato, in locale, il corretto funzionamento del container e del modello in esso incapsulato, possiamo generare (build) una nuova immagine e spedirla (push) al registro Docker ECR. Per questa operazione dobbiamo spostarci nella cartella base ed eseguire l'istruzione:

./build_and_push_to_ecr.sh cntkdemo-ecr-4

dove cntkdemo-ecr-4 è un nome che ho arbitrariamente assegnato all'immagine.

Possiamo visualizzare l'elenco delle immagini (sia in locale sia su ECR) digitando l'istruzione:

docker images

Utilizzo con SageMaker

Abbandondiamo la finestra del Terminal e accediamo al Jupyter su SageMaker. Quindi, spostiamoci nella cartella CNTK_KERAS_SAGEMAKER/container/evaluation. In questa cartella sono precaricati tre notebook.

Notebook HowToPrepareModel

Il notebook contiene le istruzioni per:

  • Il caricamento dei dataset di training e testing dalla cartella locale context ad una cartella remota sullo storage S3 Amazon Simple Storage associato all'utenza

  • La predisposizione del container, attraverso l'impiego dell'interfaccia sage.estimator.Estimator (consultare Amazon SageMaker Python SDK per ulteriori dettagli sull'SDK Python per SageMaker) specificando:

    • Il riferimento all'immagine precedentemente caricata su ECR
    • Il tipo di istanza EC2 da attivare
    • Il puntamento alla cartella su S3 creata e popolata al passo precedente
  • La configurazione dei parametri del modello attraverso il metodo set_hyperparameters dell'Estimator (i parametri sono esattamente gli stessi che in locale abbiamo specificato all'interno del file hyperparameters.json)

  • L'addestramento del modello attraverso l'invocazione del metodo fit dell'Estimator

Al termine dell'addestramento, i file dei pesi e dell'architettura saranno automaticamente compressi nell'archivio model.tar.gz che è salvato su S3. L'insieme dei file contenenti pesi e architettura è chiamato model artifact.

Possiamo ottenere l'indirizzo esteso del model artifact memorizzato su S3 eseguendo l'istruzione:

estimator.model_data

### Notebook HowToDeployModel

Il notebook contiene le istruzioni per:

- Istanziare il modello partendo dal model artifact generato nella sezione precedente - Assegnare il container ad un endpoint HTTPS - Attivare l'endpoint (l'attivazione può richiedere qualche minuto)

### Notebook HowToInvokeModel

Il notebook contiene le istruzioni per:

- Caricare i dati di validazione dal file locale eval_data.csv - Accedere all'endpoint HTTPS per invocare la funzione di predizione. L'accesso all'endpoint avviene attraverso il metodo invoke_endpoint comodamente richiamabile attraverso il modulo boto3 (boto3 è l'SDK Python per l'accesso ai servizi AWS)

Il payload dell'invocazione è composto dai dati di validazione che abbiamo opportunamente letto e pre-trattato per l'invio.

Il notebook include istruzioni esemplificative per l'estrazione dei risultati dalla response e la valutazione dell'accuratezza usando i dati ground truth memorizzati in eval_pred.csv, ma questi sono passaggi semplici.