Le Blog Amazon Web Services

Création d’un workflow TensorFlow 2 complet avec Amazon SageMaker

La gestion du cycle de vie complet d’un projet de Deep Learning peut s’avérer difficile, surtout si vous utilisez plusieurs outils et services distincts. Par exemple, vous pouvez utiliser différents outils pour la préparation des données, pour le prototypage, les essais d’entraînement et le code d’inférence, l’entraînement et l’optimisation des modèles à grande échelle, les déploiements des modèles et l’automatisation des workflows pour orchestrer tout ce qui permet d’arriver à l’utilisation du modèle en production. Cet article illustre comment gérer efficacement le cycle de vie complet des projets de Deep Learning avec Amazon SageMaker.

Nous utilisons un exemple de modèle construit avec le framework TensorFlow 2; les concepts décrits sont tout à fait généralisables à d’autres frameworks. Cet article s’accompagne également d’un exemple de bloc-notes Jupyter, que vous pouvez exécuter en moins d’une heure pour découvrir toutes les fonctionnalités abordées ci-dessous. Pour plus d’informations, consultez le projet GitHub (en anglais).

Présentation d’un workflow Amazon SageMaker

Chaque projet de data science utilisant TensorFlow 2 ou tout autre framework de Machine Learning commence par l’exploitation d’un jeu de données : c’est à dire sa réplication dans son environnement de travail, son exploration et son pré-traitement/préparation. Dans le contexte d’un workflow Amazon SageMaker, l’exploration des données se fait généralement dans un bloc-notes. Ce bloc-notes est de préférence déployé sur des types d’instance relativement moins puissantes et peu coûteuses, car elles restent généralement allumées pendant plusieurs heures de travail.

Par la suite, à moins que le jeu de données représente un très faible volume de données, un bloc-notes n’est pas le meilleur endroit pour effectuer des traitements sur des données à grande échelle, l’entraînement du modèle ou l’inférence. En effet, ces tâches nécessitent généralement d’importantes ressources informatiques et des besoins en parallélisation. Il est alors beaucoup plus pratique et économique d’utiliser la fonctionnalité Amazon SageMaker Processing pour créer différents clusters d’instances plus puissantes et de taille appropriée qui peuvent exécuter ces tâches plus rapidement en fonction de vos besoins. Tous ces travaux sont facturés à la seconde, et, en fin de traitement, Amazon SageMaker arrête automatiquement les instances. Pour cette raison, pour un projet Amazon SageMaker typique, les frais les plus fréquents se concentrent sur des blocs-notes relativement peu coûteux supportant l’exploration et le prototypage des données. Les frais plus importants liés à la mobilisation d’instances GPU ou accélérées n’arrivent que bien plus tard, une fois ce travail d’exploration fructueux, afin de supporter les tâches d’entraînement du modèle retenu en vue de sa mise en production.

Une fois que l’exploration & le prototypage sont terminés, vous pouvez aller au-delà des blocs-notes grâce à l’automatisation du workflow. Un pipeline automatisé est en effet nécessaire pour orchestrer le workflow complet permettant le déploiement de modèles de manière robuste et reproductible. Amazon SageMaker fournit une solution native pour cela et les sections suivantes de cet article présentent les diverses fonctionnalités d’Amazon SageMaker que vous pouvez utiliser pour implémenter les étapes ce cycle de vie du projet.

Transformation des données avec Amazon SageMaker Processing

Amazon SageMaker Processing vous aide à pré-traiter des jeux de données volumineux dans un cluster dont la traille est adapté à la charge et distinct d’un poste local ou d’un simple bloc-notes. Amazon SageMaker Processing inclut la prise en charge standard de Scikit-Learn ainsi que toute autre technologie conteneurisée. Par exemple, vous pouvez lancer des clusters Apache Spark temporaires pour les jobs de transformation et de préparation sur de larges volumes de données.

Pour utiliser Amazon SageMaker Processing avec Scikit-Learn, vous devez fournir un script de pré-traitement des données Python avec le code Scikit-Learn standard. Il n’y a qu’une condition nécessaire pour ce script : les données d’entrée et de sortie doivent être placées à des emplacements spécifiés (voir exemples de code ci-dessous). Amazon SageMaker Processing charge automatiquement les données d’entrée depuis Amazon Simple Storage Service (Amazon S3) et télécharge les données transformées vers Amazon S3 une fois le traitement terminé.

Avant de démarrer une tâche Amazon SageMaker Processing, instanciez un objet SkLearnProcessor comme illustré dans l’exemple de code suivant. Dans cet objet, vous spécifiez le type d’instance à utiliser pour le traitement et le nombre d’instances.

from sagemaker import get_execution_role
from sagemaker.sklearn.processing import SKLearnProcessor

sklearn_processor = SKLearnProcessor(framework_version='0.20.0',
                                     role=get_execution_role(),
                                     instance_type='ml.m5.xlarge',
                                     instance_count=2)

Pour répartir les fichiers de données de manière égale entre les instances de cluster de traitement, spécifiez le type de distribution ShardedByS3Key dans l’objet ProcessingInput. Cela permet de s’assurer que s’il y a n instances, chaque instance recevant 1/n fichiers du compartiment S3 spécifié. La possibilité de créer facilement un vaste cluster d’instances pour les transformations de données sans état n’est qu’un des nombreux avantages qu’offre Amazon SageMaker Processing.

from sagemaker.processing import ProcessingInput, ProcessingOutput
from time import gmtime, strftime 

processing_job_name = "tf-2-workflow-{}".format(strftime("%d-%H-%M-%S", gmtime()))
output_destination = 's3://{}/{}/data'.format(bucket, s3_prefix)

sklearn_processor.run(code='preprocessing.py',
                      job_name=processing_job_name,
                      inputs=[ProcessingInput(
                        source=raw_s3,
                        destination='/opt/ml/processing/input',
                        s3_data_distribution_type='ShardedByS3Key')],
                      outputs=[ProcessingOutput(output_name='train',
                                                destination='{}/train'.format(output_destination),
                                                source='/opt/ml/processing/train'),
                               ProcessingOutput(output_name='test',
                                                destination='{}/test'.format(output_destination),
                                                source='/opt/ml/processing/test')])

Prototypage du code d’entraînement et d’inférence avec le mode Local

Une fois que le jeu de données est prêt pour l’entraînement, l’étape suivante consiste à prototyper le code d’entraînement. Pour TensorFlow 2, le workflow le plus pratique consiste à fournir un script d’entraînement pour l’ingestion par le conteneur TensorFlow 2 préconstruit fourni par Amazon SageMaker. Cette fonctionnalité est nommée mode script et fonctionne de manière transparente avec la fonctionnalité d’entraînement en mode Local de Amazon SageMaker.

Le mode Local est un moyen pratique de s’assurer que le code fonctionne localement sur un bloc-notes avant de passer à un entraînement hébergé à grande échelle dans un cluster distinct géré par Amazon SageMaker. En mode local, vous entraînez votre modèle généralement pendant une courte période seulement pour quelques itérations (“epochs” dans le langage du Machine Learning), peut-être uniquement sur un sous-échantillon de l’ensemble des données, afin de confirmer que le code fonctionne correctement et d’éviter de perdre du temps sur un entraînement à grande échelle. Spécifiez également le type d’instance en tant que local_gpu ou local, selon que le bloc-notes se trouve sur une instance GPU ou CPU.

from sagemaker.tensorflow import TensorFlow

git_config = {'repo': 'https://github.com/aws-samples/amazon-sagemaker-script-mode', 
              'branch': 'master'}

model_dir = '/opt/ml/model'
train_instance_type = 'local'
hyperparameters = {'epochs': 5, 'batch_size': 128, 'learning_rate': 0.01}
local_estimator = TensorFlow(git_config=git_config,
                             source_dir='tf-2-workflow/train_model',
                             entry_point='train.py',
                             model_dir=model_dir,
                             train_instance_type=train_instance_type,
                             train_instance_count=1,
                             hyperparameters=hyperparameters,
                             role=sagemaker.get_execution_role(),
                             base_job_name='tf-2-workflow',
                             framework_version='2.1',
                             py_version='py3',
                             script_mode=True)

Bien que l’entraînement en mode local soit très utile pour s’assurer que le code fonctionne avant de passer à l’entraînement à grande échelle, il est également pratique d’avoir un moyen facile de prototyper le code d’inférence localement. Une possibilité est de récupérer un artefact TensorFlow SavedModel ou un checkpoint du modèle enregistré dans Amazon S3 et de le charger dans un bloc-notes pour effectuer des tests. Un moyen encore plus simple consiste à utiliser les endpoints en mode local.

Vous pouvez donc déployer un modèle dans un endpoint en mode local, qui contient un conteneur Amazon SageMaker TensorFlow Serving, à l’aide de l’objet estimator du job d’entraînement opéré en mode local. Ce code est le même que le code de déploiement d’un modèle vers un endpoint hébergé de manière distincte. Vous devez simplement appeler la méthode de déploiement de l’estimator local, puis spécifiez à nouveau le type d’instance en tant que local_gpu ou local, selon que le bloc-notes se trouve sur une instance GPU ou CPU.

local_predictor = local_estimator.deploy(initial_instance_count=1, instance_type='local')
local_results = local_predictor.predict(x_test[:10])['predictions']

Avant d’utiliser le mode local, assurez-vous que docker-compose ou nvidia-docker-compose (pour les instances GPU) peut être exécuté sur votre instance en effectuant les commandes suivantes :

!wget -q https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-script-mode/master/local_mode_setup.sh
!wget -q https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-script-mode/master/daemon.json    
!/bin/bash ./local_mode_setup.sh

Optimisation automatique du modèle

Une fois le prototypage terminé, l’étape suivante consiste à utiliser l’entraînement hébergé par Amazon SageMaker et l’optimisation automatique de modèle. L’entraînement hébergé par Sagemaker est préférable pour l’entraînement à grande échelle, en particulier pour distribuer celui-ci sur un grand nombre d’instancs. Contrairement au mode local, pour l’entraînement hébergé, l’entraînement réel ne se produit pas sur l’instance elle-même, mais sur un cluster distinct de machines gérées par Amazon SageMaker. Un objet estimator pour l’entraînement hébergé est similaire à un estimator en mode local, à l’exception des éléments suivants :

  • Le jeu de données doit être dans Amazon S3, Amazon Elastic File System (Amazon EFS) ou Amazon FSx for Lustre,
  • Le type d’instances d’entraînement est défini sur un type d’instance Amazon SageMaker ML correctement dimensionné pour un traitement à grande échelle,
  • En outre, comme le prototypage en mode local a prouvé que le code d’entraînement fonctionne, vous pouvez modifier l’estimateur d’entraînement hébergé pour entraîner sur un plus grand nombre d’itérations (epochs), et sur le jeu de données complet.

Cependant, exécuter des tâches d’entraînement individuelles hébergées et modifier manuellement les hyperparamètres à la recherche du meilleur modèle restent une tâche ardue et fastidieuse. La sélection de la bonne combinaison d’hyperparamètres dépend du jeu de données et de l’algorithme. Certains algorithmes ont de nombreux hyperparamètres différents que vous pouvez modifier, certains sont très sensibles aux valeurs d’hyperparamètres sélectionnées, et la plupart ont une relation non-linéaire entre l’ajustement du modèle et les valeurs d’hyperparamètres. L’optimisation automatique du modèle accélère ce processus : il exécute plusieurs tâches d’entraînement avec différentes combinaisons d’hyperparamètres pour trouver l’ensemble avec les meilleures performances pour un modèle donné.

Comme indiqué dans l’exemple de code suivant, pour utiliser l’optimisation automatique du modèle, spécifiez d’abord les hyperparamètres à optimiser, leurs plages de réglage et une mesure objective à optimiser. Un objet HyperParameterTuner prend ces paramètres en tant qu’entrées. Chaque itération d’optimisation doit également spécifier un nombre maximal de tâches d’entraînement, dans ce cas 15, et le degré de parallélisme à employer, dans ce cas, cinq tâches à la fois. Avec ces paramètres, la tâche d’optimisation est terminée après l’exécution de trois séries de cinq tâches en parallèle. Pour la stratégie d’optimisation bayésienne par défaut, les résultats des batchs précédents d’optimisation sont pris en compte dans la recherche d’optimisation, il est donc préférable de les diviser en groupes de tâches dépendantes plutôt que de les exécuter en parallèle. Il y a donc un compromis à trouver : l’utilisation de tâches parallèles permet de terminer l’optimisation plus vite, mais sacrifie probablement la précision de recherche d’optimisation.

from sagemaker.tuner import IntegerParameter, CategoricalParameter, ContinuousParameter, HyperparameterTuner

hyperparameter_ranges = {
  'learning_rate': ContinuousParameter(0.001, 0.2, scaling_type="Logarithmic"),
  'epochs': IntegerParameter(10, 50),
  'batch_size': IntegerParameter(64, 256),
}

metric_definitions = [{'Name': 'loss',
                       'Regex': ' loss: ([0-9\\.]+)'},
                     {'Name': 'val_loss',
                       'Regex': ' val_loss: ([0-9\\.]+)'}]

objective_metric_name = 'val_loss'
objective_type = 'Minimize'

tuner = HyperparameterTuner(estimator,
                            objective_metric_name,
                            hyperparameter_ranges,
                            metric_definitions,
                            max_jobs=15,
                            max_parallel_jobs=5,
                            objective_type=objective_type)

tuning_job_name = "tf-2-workflow-{}".format(strftime("%d-%H-%M-%S", gmtime()))
tuner.fit(inputs, job_name=tuning_job_name)

Déploiement et automatisation du workflow avec le SDK AWS Step Functions Data Science

Une option pratique pour déployer le meilleur modèle à partir des jobs d’optimisation est d’utiliser un endpoint hébergé par Amazon SageMaker, qui fournit des prédictions en temps réel (les tâches de transformation par lots, ou batch processing, sont également disponibles pour les prédictions asynchrones et hors ligne). Le endpoint récupère le SavedModel TensorFlow et le déploie dans un conteneur Amazon SageMaker TensorFlow Serving. Vous pouvez effectuer cela avec une seule ligne de code en appelant la méthode de déploiement de l’objet HyperParameterTuner :

tuning_predictor = tuner.deploy(initial_instance_count=1, instance_type='ml.m5.xlarge')

Cependant, bien que les blocs-notes soient parfaits pour le prototypage, ils ne sont généralement pas utilisés pour le déploiement dans un environnement de production. Au lieu de cela, un orchestrateur de workflow est préférable pour exécuter un pipeline comportant plusieurs étapes, y compris l’entraînement et le déploiement. Par exemple, un pipeline simple dans Amazon SageMaker se compose de quatre étapes :

  1. Entraînement du modèle,
  2. Création d’un objet Amazon SageMaker Model qui enveloppe l’artefact du modèle pour l’inférence,
  3. Création d’une configuration d’un endpoint Amazon SageMaker spécifiant comment le modèle doit être servi (y compris le type d’instance et le nombre d’instances).
  4. Déploiement du modèle entraîné sur l’endpoint Amazon SageMaker configuré.

Le SDK AWS Step Functions Data Science automatise le processus de création et d’exécution de tels pipelines à l’aide d’Amazon SageMaker et d’AWS Step Functions, un service d’orchestration de workflow serverless. Ce SDK permet la création de workflows à l’aide de scripts Python courts et simples qui définissent les étapes du workflow et permettent de les enchaîner. AWS Step Functions coordonne toutes les étapes du workflow sans que vous ayez à gérer l’infrastructure sous-jacente.

Bien que le SDK AWS Step Functions Data Science fournisse plusieurs primitives pour créer des pipelines complexes à partir de zéro, il dispose également de modèles prédéfinis pour les workflows courants, y compris un workflow TrainingPipeline simple pour l’entraînement et le déploiement des modèles. Le code suivant configure un tel pipeline avec seulement quelques paramètres, principalement l’ Estimator pour l’entraînement et les emplacements d’entrée et de sortie dans Amazon S3 :

import stepfunctions
from stepfunctions.template.pipeline import TrainingPipeline

workflow_execution_role = "<StepFunctions-execution-role-arn>"

pipeline = TrainingPipeline(
    estimator=estimator,
    role=workflow_execution_role,
    inputs=inputs,
    s3_bucket=bucket
)

Après avoir défini un pipeline, vous pouvez le visualiser sous forme de graphique, l’instancier et l’exécuter autant de fois que nécessaire. Vous pouvez également exécuter plusieurs workflows en parallèle. Pendant l’exécution d’un workflow, vous pouvez vérifier la progression du workflow dans la console AWS Step Functions ou en appelant la méthode render_progress du pipeline. Le diagramme suivant montre une exécution de workflow arrivée à l’étape d’entraînement :

AWS Step Functions pour Workflow TF2 sur Amazon Sagemaker

Le SDK AWS Step Functions Data Science permet d’implémenter de nombreux workflows de référence pour automatiser des modèles TensorFlow 2 et tout autre autre projet de Machine Learning. Un autre exemple de workflow est par exemple celui permettant d’automatiser périodiquement le re-entraînement des modèles. Un tel workflow pourrait inclure un test de qualité du modèle après son entraînement, avec des branches conditionnelles ultérieures pour les cas de réussite du test de qualité (le modèle est déployé) ou d’échec (pas de déploiement du modèle). Parmi les autres étapes possibles du workflow, mentionnons l’optimisation automatique du modèle, des travaux d’ETL avec AWS Glue, et bien plus encore. Pour plus d’informations sur les workflow de re-entraînement, consultez Automating model retraining and deployment using the AWS Step Functions Data Science SDK for Amazon SageMaker (en anglais).

Conclusion

Nous avons couvert un grand nombre de concepts et services AWS pour répondre à des besoins de Machine Learning : SageMaker Processing pour la transformation des données, le mode Local pour le prototypage du code d’entraînement et d’inférence, l’optimisation automatique du modèle et l’entraînement et l’inférence hébergés par SageMaker. Ce sont des éléments centraux pour la plupart des workflows de Deep Learning dans SageMaker. De plus, nous avons examiné comment le SDK AWS Step Functions Data Science facilite l’automatisation des workflows de Deep Learning après avoir terminé la phase de prototypage d’un projet.

Outre toutes les fonctionnalités de SageMaker décrites ci-dessus, de nombreuses autres fonctionnalités peuvent être appliquées à votre projet. Par exemple, pour gérer les problèmes pendant la phase d’entraînement du modèle de Deep Learning, tels que la disparition ou l’explosion de gradients, SageMaker Debugger peut-être utile. Pour gérer les problèmes courants tels que la dérive des données après la production d’un modèle, SageMaker Model Monitor peut être appliqué.

Article original par Brent Rabowsky, Data Science Solutions Architect pour le secteur “Media & Entertainment”. Traduit de l’anglais par Davide Gallitelli, Solutions Architect au sein des équipes AWS France et assistant les clients français dans l’adoption des solutions basées sur l’intelligence artificielle & le Machine Learning, LinkedIn.