2e partie - exploitation d'AWS Amazon FSX pour NetApp ONTAP (FSX ONTAP) en tant que source de données pour l'entraînement des modèles dans SageMaker
Cet article est un tutoriel sur l'utilisation d'Amazon FSX pour NetApp ONTAP (FSX ONTAP) pour la formation des modèles PyTorch dans SageMaker, spécialement pour un projet de classification de la qualité des pneus.
Auteur(s):
Jian Jian (Ken), scientifique senior en données et applications, NetApp
Introduction
Ce didacticiel présente un exemple pratique de projet de classification de la vision par ordinateur. Il fournit une expérience pratique de la création de modèles de ML utilisant FSX ONTAP comme source de données dans l'environnement SageMaker. Le projet se concentre sur l'utilisation de PyTorch, un framework de deep learning, pour classer la qualité des pneus en fonction des images. Il insiste sur le développement des modèles de machine learning utilisant FSX ONTAP comme source de données dans Amazon SageMaker.
Qu'est-ce que FSX ONTAP
Amazon FSX ONTAP est une solution de stockage entièrement gérée proposée par AWS. Il exploite le système de fichiers ONTAP de NetApp pour fournir un stockage fiable et haute performance. Grâce à la prise en charge de protocoles comme NFS, SMB et iSCSI, il permet un accès transparent à partir de plusieurs instances de calcul et conteneurs. Ce service est conçu pour fournir des performances exceptionnelles garantissant des opérations de données rapides et efficaces. En outre, il offre une haute disponibilité et une durabilité élevées, assurant l'accessibilité et la protection de vos données. De plus, la capacité de stockage d'Amazon FSX ONTAP est évolutive et vous permet de l'ajuster facilement en fonction de vos besoins.
Condition préalable
Environnement réseau
FSX ONTAP (Amazon FSX ONTAP) est un service de stockage AWS. Elle comprend un système de fichiers s'exécutant sur le système NetApp ONTAP et une machine virtuelle (SVM) gérée par AWS qui se connecte à celui-ci. Dans le diagramme fourni, le serveur NetApp ONTAP géré par AWS se trouve en dehors du VPC. Le SVM sert d'intermédiaire entre SageMaker et le système NetApp ONTAP, en recevant les demandes d'opération de SageMaker et en les transférant vers le stockage sous-jacent. Pour accéder à FSX ONTAP, SageMaker doit être placé dans le même VPC que le déploiement de FSX ONTAP. Cette configuration assure la communication et l'accès aux données entre SageMaker et FSX ONTAP.
Accès aux données
Dans des scénarios réels, les data Scientists utilisent généralement les données stockées dans FSX ONTAP pour créer leurs modèles de machine learning. Toutefois, à des fins de démonstration, puisque le système de fichiers FSX ONTAP est initialement vide après la création, il est nécessaire de télécharger manuellement les données d'entraînement. Ceci peut être réalisé en montant FSX ONTAP en tant que volume vers SageMaker. Une fois le système de fichiers correctement monté, vous pouvez télécharger votre dataset à l'emplacement monté, le rendant accessible pour l'entraînement de vos modèles dans l'environnement SageMaker. Cette approche vous permet d'exploiter la capacité et les fonctionnalités de stockage de FSX ONTAP tout en travaillant avec SageMaker pour le développement et la formation de modèles.
Le processus de lecture des données implique de configurer FSX ONTAP en tant que compartiment S3 privé. Pour connaître les instructions de configuration détaillées, reportez-vous à la section "1re partie - intégration d'Amazon FSX pour NetApp ONTAP (FSX ONTAP) en tant que compartiment S3 privé dans AWS SageMaker"
Présentation de l'intégration
Le workflow d'utilisation des données d'entraînement dans FSX ONTAP pour créer un modèle de deep learning dans SageMaker peut être résumé en trois étapes principales : la définition du data Loader, l'entraînement du modèle et le déploiement. À un niveau élevé, ces étapes constituent la base d'un pipeline MLOps. Cependant, chaque étape implique plusieurs sous-étapes détaillées pour une mise en œuvre complète. Ces sous-étapes englobent diverses tâches, telles que le prétraitement des données, la division des datasets, la configuration des modèles, le réglage des hyperparamètres, l'évaluation des modèles, et le déploiement des modèles. Ces étapes permettent d'assurer un processus complet et efficace pour créer et déployer des modèles de deep learning à l'aide des données d'entraînement de FSX ONTAP dans l'environnement SageMaker.
Intégration pas à pas
Chargeur de données
Afin d'entraîner un réseau de deep learning PyTorch avec des données, un chargeur de données est créé pour faciliter l'alimentation en données. Le chargeur de données définit non seulement la taille du lot, mais détermine également la procédure de lecture et de prétraitement de chaque enregistrement dans le lot. Grâce à la configuration du chargeur de données, nous pouvons traiter les données par lots, ce qui permet l'entraînement du réseau de deep learning.
Le chargeur de données se compose de 3 parties.
Fonction de prétraitement
from torchvision import transforms
preprocess = transforms.Compose([
transforms.ToTensor(),
transforms.Resize((224,224)),
transforms.Normalize(
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]
)
])
L'extrait de code ci-dessus illustre la définition des transformations de prétraitement d'image à l'aide du module torchvision.Transforms. Dans ce schéma, l'objet de prétraitement est créé pour appliquer une série de transformations. Tout d'abord, la transformation ToTensor() convertit l'image en représentation de tenseur. Par la suite, la transformation Resize224,224 redimensionne l'image à une taille fixe de 224x224 pixels. Enfin, la transformation Normalize() normalise les valeurs de tenseurs en soustrayant la moyenne et en divisant par l'écart-type le long de chaque canal. Les valeurs d'écart moyen et standard utilisées pour la normalisation sont généralement utilisées dans les modèles de réseaux neuronaux pré-entraînés. Dans l'ensemble, ce code prépare les données d'image pour un traitement ou une entrée ultérieurs dans un modèle pré-entraîné en les convertissant en tenseur, en les redimensionnant et en normalisant les valeurs de pixels.
Classe de jeu de données PyTorch
import torch
from io import BytesIO
from PIL import Image
class FSxNImageDataset(torch.utils.data.Dataset):
def __init__(self, bucket, prefix='', preprocess=None):
self.image_keys = [
s3_obj.key
for s3_obj in list(bucket.objects.filter(Prefix=prefix).all())
]
self.preprocess = preprocess
def __len__(self):
return len(self.image_keys)
def __getitem__(self, index):
key = self.image_keys[index]
response = bucket.Object(key)
label = 1 if key[13:].startswith('defective') else 0
image_bytes = response.get()['Body'].read()
image = Image.open(BytesIO(image_bytes))
if image.mode == 'L':
image = image.convert('RGB')
if self.preprocess is not None:
image = self.preprocess(image)
return image, label
Cette classe offre des fonctionnalités permettant d'obtenir le nombre total d'enregistrements dans le jeu de données et définit la méthode de lecture des données pour chaque enregistrement. Dans la fonction getitem, le code utilise l'objet de compartiment S3 boto3 pour extraire les données binaires de FSX ONTAP. Le style de code pour l'accès aux données à partir de FSX ONTAP est similaire à celui pour la lecture des données à partir d'Amazon S3. L'explication suivante est intégrée au processus de création de l'objet privé S3 bucket.
FSX ONTAP en tant que référentiel S3 privé
seed = 77 # Random seed
bucket_name = '<Your ONTAP bucket name>' # The bucket name in ONTAP
aws_access_key_id = '<Your ONTAP bucket key id>' # Please get this credential from ONTAP
aws_secret_access_key = '<Your ONTAP bucket access key>' # Please get this credential from ONTAP
fsx_endpoint_ip = '<Your FSx ONTAP IP address>' # Please get this IP address from FSXN
import boto3
# Get session info
region_name = boto3.session.Session().region_name
# Initialize Fsxn S3 bucket object
# --- Start integrating SageMaker with FSXN ---
# This is the only code change we need to incorporate SageMaker with FSXN
s3_client: boto3.client = boto3.resource(
's3',
region_name=region_name,
aws_access_key_id=aws_access_key_id,
aws_secret_access_key=aws_secret_access_key,
use_ssl=False,
endpoint_url=f'http://{fsx_endpoint_ip}',
config=boto3.session.Config(
signature_version='s3v4',
s3={'addressing_style': 'path'}
)
)
# s3_client = boto3.resource('s3')
bucket = s3_client.Bucket(bucket_name)
# --- End integrating SageMaker with FSXN ---
Pour lire les données de FSX ONTAP dans SageMaker, un gestionnaire est créé et pointe vers le stockage de FSX ONTAP à l'aide du protocole S3. Ainsi, FSX ONTAP peut être traité comme un compartiment S3 privé. La configuration de gestionnaire inclut la spécification de l'adresse IP du SVM FSX ONTAP, du nom de compartiment et des informations d'identification nécessaires. Pour obtenir une explication complète sur l'obtention de ces éléments de configuration, reportez-vous au document à l'adresse "1re partie : intégration d'Amazon FSX pour NetApp ONTAP (FSX ONTAP) en tant que compartiment S3 privé dans AWS SageMaker".
Dans l'exemple mentionné ci-dessus, l'objet de compartiment est utilisé pour instancier l'objet de jeu de données PyTorch. L'objet Dataset sera expliqué plus en détail dans la section suivante.
Le chargeur de données PyTorch
from torch.utils.data import DataLoader
torch.manual_seed(seed)
# 1. Hyperparameters
batch_size = 64
# 2. Preparing for the dataset
dataset = FSxNImageDataset(bucket, 'dataset/tyre', preprocess=preprocess)
train, test = torch.utils.data.random_split(dataset, [1500, 356])
data_loader = DataLoader(dataset, batch_size=batch_size, shuffle=True)
Dans l'exemple fourni, une taille de lot de 64 est spécifiée, indiquant que chaque lot contiendra 64 enregistrements. En combinant la classe PyTorch Dataset, la fonction de prétraitement et la taille du lot d'entraînement, nous obtenons le chargeur de données pour l'entraînement. Ce chargeur de données facilite le processus d'itération dans l'ensemble de données en lots pendant la phase d'entraînement.
Entraînement du modèle
from torch import nn
class TyreQualityClassifier(nn.Module):
def __init__(self):
super().__init__()
self.model = nn.Sequential(
nn.Conv2d(3,32,(3,3)),
nn.ReLU(),
nn.Conv2d(32,32,(3,3)),
nn.ReLU(),
nn.Conv2d(32,64,(3,3)),
nn.ReLU(),
nn.Flatten(),
nn.Linear(64*(224-6)*(224-6),2)
)
def forward(self, x):
return self.model(x)
import datetime
num_epochs = 2
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = TyreQualityClassifier()
fn_loss = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
model.to(device)
for epoch in range(num_epochs):
for idx, (X, y) in enumerate(data_loader):
X = X.to(device)
y = y.to(device)
y_hat = model(X)
loss = fn_loss(y_hat, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"Current Time: {current_time} - Epoch [{epoch+1}/{num_epochs}]- Batch [{idx + 1}] - Loss: {loss}", end='\r')
Ce code met en œuvre un processus de formation PyTorch standard. Il définit un modèle de réseau neuronal appelé TireQualityClassifier utilisant des couches convolutionnelles et une couche linéaire pour classer la qualité des pneus. La boucle d'entraînement effectue une itération sur les lots de données, calcule la perte et met à jour les paramètres du modèle à l'aide de la rétropropagation et de l'optimisation. En outre, il imprime l'heure, l'époque, le lot et la perte actuels à des fins de surveillance.
Déploiement du modèle
Déploiement
import io
import os
import tarfile
import sagemaker
# 1. Save the PyTorch model to memory
buffer_model = io.BytesIO()
traced_model = torch.jit.script(model)
torch.jit.save(traced_model, buffer_model)
# 2. Upload to AWS S3
sagemaker_session = sagemaker.Session()
bucket_name_default = sagemaker_session.default_bucket()
model_name = f'tyre_quality_classifier.pth'
# 2.1. Zip PyTorch model into tar.gz file
buffer_zip = io.BytesIO()
with tarfile.open(fileobj=buffer_zip, mode="w:gz") as tar:
# Add PyTorch pt file
file_name = os.path.basename(model_name)
file_name_with_extension = os.path.split(file_name)[-1]
tarinfo = tarfile.TarInfo(file_name_with_extension)
tarinfo.size = len(buffer_model.getbuffer())
buffer_model.seek(0)
tar.addfile(tarinfo, buffer_model)
# 2.2. Upload the tar.gz file to S3 bucket
buffer_zip.seek(0)
boto3.resource('s3') \
.Bucket(bucket_name_default) \
.Object(f'pytorch/{model_name}.tar.gz') \
.put(Body=buffer_zip.getvalue())
Le code enregistre le modèle PyTorch dans Amazon S3 car SageMaker requiert que le modèle soit stocké dans S3 pour le déploiement. En téléchargeant le modèle vers Amazon S3, il devient accessible à SageMaker, ce qui permet le déploiement et l'inférence sur le modèle déployé.
import time
from sagemaker.pytorch import PyTorchModel
from sagemaker.predictor import Predictor
from sagemaker.serializers import IdentitySerializer
from sagemaker.deserializers import JSONDeserializer
class TyreQualitySerializer(IdentitySerializer):
CONTENT_TYPE = 'application/x-torch'
def serialize(self, data):
transformed_image = preprocess(data)
tensor_image = torch.Tensor(transformed_image)
serialized_data = io.BytesIO()
torch.save(tensor_image, serialized_data)
serialized_data.seek(0)
serialized_data = serialized_data.read()
return serialized_data
class TyreQualityPredictor(Predictor):
def __init__(self, endpoint_name, sagemaker_session):
super().__init__(
endpoint_name,
sagemaker_session=sagemaker_session,
serializer=TyreQualitySerializer(),
deserializer=JSONDeserializer(),
)
sagemaker_model = PyTorchModel(
model_data=f's3://{bucket_name_default}/pytorch/{model_name}.tar.gz',
role=sagemaker.get_execution_role(),
framework_version='2.0.1',
py_version='py310',
predictor_cls=TyreQualityPredictor,
entry_point='inference.py',
source_dir='code',
)
timestamp = int(time.time())
pytorch_endpoint_name = '{}-{}-{}'.format('tyre-quality-classifier', 'pt', timestamp)
sagemaker_predictor = sagemaker_model.deploy(
initial_instance_count=1,
instance_type='ml.p3.2xlarge',
endpoint_name=pytorch_endpoint_name
)
Ce code facilite le déploiement d'un modèle PyTorch sur SageMaker. Il définit un sérialiseur personnalisé, TireQualitySerializer, qui prétraite et sérialise les données d'entrée en tant que tenseur PyTorch. La classe TireQualityPredictor est un prédicteur personnalisé qui utilise le sérialiseur défini et un JSONDeserializer. Le code crée également un objet PyTorchModel pour spécifier l'emplacement S3 du modèle, le rôle IAM, la version du framework et le point d'entrée pour l'inférence. Le code génère un horodatage et construit un nom de point final basé sur le modèle et l'horodatage. Enfin, le modèle est déployé à l'aide de la méthode deploy, en spécifiant le nombre d'instances, le type d'instance et le nom du noeud final généré. Cela permet de déployer le modèle PyTorch et d'y accéder pour l'inférence sur SageMaker.
Inférence
image_object = list(bucket.objects.filter('dataset/tyre'))[0].get()
image_bytes = image_object['Body'].read()
with Image.open(with Image.open(BytesIO(image_bytes)) as image:
predicted_classes = sagemaker_predictor.predict(image)
print(predicted_classes)
Voici un exemple d'utilisation du terminal déployé pour effectuer l'inférence.