Model Serving dans Snowpark Container Services¶
Note
Cette fonction est disponible dans les régions commerciales AWS et Azure. Elle n’est pas disponible dans les régions gouvernementales.
Note
La possibilité d’exécuter des modèles dans Snowpark Container Services (SPCS) décrite dans cette rubrique est disponible dans snowflake-ml-python
version 1.8.0 et ultérieure.
Le Snowflake Model Registry vous permet d’exécuter des modèles soit dans un entrepôt (par défaut), soit dans un pool de calcul Snowpark Container Services (SPCS) via Model Serving. L’exécution de modèles dans un entrepôt impose quelques limitations sur la taille et les types de modèles que vous pouvez utiliser (en particulier, les modèles ayant des CPU de petite à moyenne taille dont les dépendances peuvent être satisfaites par les paquets disponibles dans le canal Snowflake conda).
L’exécution de modèles sur Snowpark Container Services (SPCS) assouplit ces restrictions, voire les élimine complètement. Vous pouvez utiliser tous les paquets de votre choix, y compris ceux du Python Package Index (PyPI) ou d’autres sources. Les grands modèles peuvent être exécutés sur des clusters distribués de GPUs. Et vous n’avez pas besoin de connaître quoi que ce soit sur les technologies de conteneurs, telles que Docker ou Kubernetes. Snowflake Model Serving s’occupe de tous les détails.
Concepts clés¶
Un aperçu simplifié de haut niveau de l’architecture d’inférence de Snowflake Model Serving est présenté ci-dessous.

Les principaux composants de l’architecture sont les suivants :
Serveur d’inférence : le serveur qui exécute le modèle et fournit des prédictions. Le serveur d’inférence peut utiliser plusieurs processus d’inférence pour exploiter pleinement les capacités du nœud. Les requêtes adressées au modèle sont expédiées par le contrôle d’admission, qui gère la file d’attente des requêtes entrantes pour éviter les conditions de manque de mémoire, rejetant les clients lorsque le serveur est surchargé. Aujourd’hui, Snowflake fournit un serveur d’inférence simple et flexible basé sur Python qui peut exécuter des inférences pour tous les types de modèles. Progressivement, Snowflake prévoit de proposer des serveurs d’inférence optimisés pour des types de modèles spécifiques.
Environnement Python spécifique au modèle : pour réduire la latence de démarrage d’un modèle, qui inclut le temps nécessaire au téléchargement des dépendances et au chargement du modèle, Snowflake crée un conteneur qui encapsule les dépendances du modèle spécifique.
Fonctions de service : pour communiquer avec le serveur d’inférence à partir du code exécuté dans un entrepôt, Snowflake Model Serving crée des fonctions qui ont la même signature que le modèle, mais qui appellent à la place le serveur d’inférence via le protocole de fonction externe.
Point de terminaison d’entrée : pour permettre aux applications extérieures à Snowflake d’appeler le modèle, Snowflake Model Serving peut provisionner un point de terminaison HTTP facultatif, accessible à l’Internet public.
Comment cela fonctionne-t-il ?¶
Le diagramme suivant montre comment Snowflake Model Serving déploie et sert des modèles dans un entrepôt ou sur SPCS.

Comme vous pouvez le voir, le chemin vers le déploiement SPCS est plus complexe que le chemin vers le déploiement de l’entrepôt, mais Snowflake Model Serving fait tout le travail pour vous, y compris la création de l’image de conteneur qui contient le modèle et ses dépendances, et la création du serveur d’inférence qui exécute le modèle.
Conditions préalables¶
Avant de commencer, assurez-vous de disposer des éléments suivants :
Un compte Snowflake dans n’importe quelle région commerciale AWS ou Azure. Les régions gouvernementales ne sont pas prises en charge.
Version 1.6.4 ou ultérieure du paquet Python
snowflake-ml-python
.Un modèle que vous souhaitez exécuter sur Snowpark Container Services.
Connaissances de Snowflake Model Registry.
Connaissances de Snowpark Container Services. Plus précisément, vous devez comprendre ce que sont les pools de calcul, les référentiels d’images, et les privilèges associés.
Créer un pool de calcul¶
Snowpark Container Services (SPCS) exécute des images de conteneurs dans des pools de calcul. Si vous ne disposez pas encore d’un pool de calcul approprié, créez-en un comme suit :
CREATE COMPUTE POOL IF NOT EXISTS mypool
MIN_NODES = 2
MAX_NODES = 4
INSTANCE_FAMILY = 'CPU_X64_M'
AUTO_RESUME = TRUE;
Voir le tableau des noms de famille pour une liste de familles d’instances valides.
Assurez-vous que le rôle qui exécutera le modèle est le propriétaire du pool de calcul ou qu’il dispose des privilèges USAGE ou OPERATE sur le pool.
Créer un référentiel d’images¶
Snowflake Model Serving crée une image de conteneur qui contient le modèle et ses dépendances. Pour stocker cette image, vous avez besoin d’un référentiel d’images. Si vous n’en avez pas déjà un, créez-en un comme suit :
CREATE IMAGE REPOSITORY IF NOT EXISTS my_inference_images
Si vous utilisez un référentiel d’images dont vous n’êtes pas propriétaire, assurez-vous que le rôle qui créera l’image du conteneur dispose des privilèges READ WRITE, SERVICE READ, SERVICE et WRITE sur le référentiel. Accordez ces privilèges comme suit :
GRANT READ ON IMAGE REPOSITORY my_inference_images TO ROLE myrole;
GRANT WRITE ON IMAGE REPOSITORY my_inference_images TO ROLE myrole;
GRANT SERVICE READ ON IMAGE REPOSITORY my_inference_images TO ROLE myrole;
GRANT SERVICE WRITE ON IMAGE REPOSITORY my_inference_images TO ROLE myrole;
Privilèges requis¶
Modeling Serving s’exécute sur Snowpark Container Services. Pour utiliser Model Serving, un utilisateur doit disposer des privilèges suivants :
USAGE ou OWNERSHIP sur un pool de calcul où le service sera exécuté.
Un référentiel d’images avec les quatre privilèges : READ, WRITE, SERVICE READ et SERVICE WRITE. Si l’utilisateur est propriétaire du référentiel d’images, tous les privilèges lui sont automatiquement accordés.
Si un point de terminaison d’entrée est souhaité sur Model Serving, l’utilisateur doit avoir le privilège BIND SERVICE ENDPOINT sur le compte.
Seuls les propriétaires de modèles peuvent déployer le modèle sur Serving. Pour permettre aux non-propriétaires d’accéder à l’inférence, les propriétaires doivent déployer le service, puis accorder le rôle de service
INFERENCE_SERVICE_FUNCTION_USAGE
pour partager les fonctions du service etALL_ENDPOINTS_USAGE
pour partager les points terminaison d’entrée.
Limitations¶
Les limites suivantes s’appliquent à Model Serving dans Snowpark Container Services.
Seul le propriétaire d’un modèle peut le déployer sur Snowpark Container Services.
La taille du cluster de calcul ne s’adapte pas automatiquement. Vous pouvez modifier manuellement le nombre d’instances lors de l’exécution à l’aide de
ALTER SERVICE myservice MIN_INSTANCES = n
. Dans certains cas, cela entraîne la défaillance des nœuds existants.La mise à l’échelle des services et des pools de calcul est plus lente que prévu.
Les services d’inférence pour lesquels l’entrée est activée ne peuvent pas être suspendus.
La construction d’une image échoue si elle dure plus d’une heure.
Les fonctions de table ne sont pas prises en charge. Les modèles sans fonction régulière ne peuvent actuellement pas être déployés sur Snowpark Container Services.
Déploiement d’un modèle sur SPCS¶
Soit vous enregistrez une nouvelle version du modèle (en utilisant reg.log_model
) soit vous obtenez une référence à une version de modèle existante (reg.get_model(...).version(...)
). Dans les deux cas, vous vous retrouvez avec une référence à un objet ModelVersion
.
Dépendances et éligibilité du modèle¶
Les dépendances d’un modèle déterminent s’il peut s’exécuter dans un entrepôt, dans un service SPCS, ou les deux. Vous pouvez, si nécessaire, spécifier intentionnellement des dépendances pour rendre un modèle inéligible à l’exécution dans l’un de ces environnements.
Le canal Snowflake conda est disponible uniquement dans les entrepôts et constitue la seule source de dépendances d’entrepôt. Par défaut, les dépendances de conda pour les modèles SPCS obtiennent leurs dépendances de conda-forge.
Lorsque vous enregistrez une version de modèle, les dépendances conda du modèle sont validées par rapport au canal conda Snowflake. Si toutes les dépendances conda du modèle y sont disponibles, le modèle est considéré comme éligible pour être exécuté dans un entrepôt. Il peut également être éligible pour se présenter à un service SPCS si toutes ses dépendances sont disponibles depuis conda-forge, bien que cela ne soit pas vérifié tant que vous n’avez pas créé un service.
Les modèles connectés avec les dépendances PyPI doivent être exécutés sur SPCS. Spécifier au moins une dépendance PyPI est un moyen de rendre un modèle inéligible à l’exécution dans un entrepôt. Si votre modèle n’a que des dépendances conda, spécifiez-en au moins une avec un canal explicite (même conda-forge), comme indiqué dans l’exemple suivant.
# reg is a snowflake.ml.registry.Registry object
reg.log_model(
model_name="my_model",
version_name="v1",
model=model,
conda_dependencies=["conda-forge::scikit-learn"])
Pour les modèles déployés avec SPCS, les dépendances conda, le cas échéant, sont installées en premier, puis toutes les dépendances PyPI sont installées dans l’environnement conda à l’aide de pip
.
Créez un service¶
Pour créer un service SPCS et y déployer le modèle, appelez la méthode create_service
de la version du modèle, comme illustré dans l’exemple suivant.
# mv is a snowflake.ml.model.ModelVersion object
mv.create_service(service_name="myservice",
service_compute_pool="my_compute_pool",
image_repo="mydb.myschema.my_image_repo",
ingress_enabled=True,
gpu_requests=None)
Voici les arguments requis pour create_service
:
service_name
: le nom du service à créer. Ce nom doit être unique au sein du compte.service_compute_pool
: le nom du Compute Pool à utiliser pour exécuter le modèle. Le pool de calcul doit déjà exister.image_repo
: le nom du référentiel d’images à utiliser pour stocker l’image du conteneur. Le référentiel doit déjà exister et l’utilisateur doit avoir le privilège SERVICE WRITE sur celui-ci (ou OWNERSHIP).ingress_enabled
: si True, le service est rendu accessible via un point de terminaison HTTP. Pour créer le point de terminaison, l’utilisateur doit disposer du privilège BIND SERVICE ENDPOINT.gpu_requests
: une chaîne spécifiant le nombre de GPUs. Pour un modèle qui peut être exécuté sur l’un ou l’autre CPU ou GPU, cet argument détermine si le modèle sera exécuté sur le CPU ou sur les GPUs. Si le modèle est d’un type connu qui ne peut être exécuté que sur CPU (par exemple, les modèles scikit-learn), la création de l’image échoue si des GPUs sont demandés.
Si vous déployez un nouveau modèle, la création du service peut prendre 5 minutes pour les modèles alimentés par CPU et 10 minutes pour les modèles alimentés par GPU. Si le pool de calcul est inactif ou nécessite un redimensionnement, la création du service peut prendre plus de temps.
Cet exemple montre uniquement les arguments obligatoires et les plus couramment utilisés. Voir la référence d’API ModelVersion pour une liste complète des arguments.
Configuration de service par défaut¶
Dans sa version initiale, le serveur d’inférence utilise des paramètres par défaut faciles à utiliser qui conviennent à la plupart des cas d’utilisation. Ces paramètres sont les suivants :
Nombre de threads de travail : pour un modèle alimenté par CPU, le serveur utilise deux fois le nombre de CPUs plus un processus de travail. Les modèles alimentés par GPU utilisent un seul processus de travail. Vous pouvez passer outre en utilisant l’argument
num_workers
dans l’appelcreate_service
.Thread safety : certains modèles ne sont pas sécurisés au niveau du filetage. Par conséquent, le service charge une copie distincte du modèle pour chaque processus de travail. Cela peut entraîner un épuisement des ressources pour les grands modèles.
Utilisation du nœud : par défaut, une instance de serveur d’inférence sollicite l’ensemble du nœud en demandant la totalité du CPU et de la mémoire du nœud sur lequel elle s’exécute. Pour personnaliser l’allocation des ressources par instance, utilisez des arguments tels que
cpu_requests
,memory_requests
, etgpu_requests
.Point de terminaison : le point de terminaison de l’inférence est nommé
inference
et utilise le port 5000. Ceux-ci ne peuvent pas être personnalisés.Suspension automatique : Les services d’inférence sont automatiquement suspendus après trente minutes d’inactivité, sauf s’ils disposent d’un point de terminaison d’entrée. Un service suspendu reprend automatiquement lorsqu’il reçoit une requête.
Comportement de création d’image de conteneur¶
Par défaut, Snowflake Model Serving crée l’image du conteneur à l’aide du même pool de calcul qui sera utilisé pour exécuter le modèle. Ce pool de calcul d’inférence est probablement surpuissant pour cette tâche (par exemple, les GPUs ne sont pas utilisés dans la création d’images de conteneurs). Dans la plupart des cas, cela n’aura pas d’impact significatif sur les coûts de calcul, mais si cela constitue un problème, vous pouvez choisir un pool de calcul moins puissant pour créer des images en spécifiant l’argument image_build_compute_pool
.
create_service
est une fonction idempotente. L’appeler plusieurs fois ne déclenche pas la création d’image à chaque fois. Cependant, les images de conteneurs peuvent être reconstruites en fonction des mises à jour du service d’inférence, y compris des correctifs pour les vulnérabilités des paquets dépendants. Lorsque cela se produit, create_service
déclenche automatiquement une reconstruction de l’image.
Note
Les modèles développés à l’aide des classes de modélisation Snowpark ML ne peuvent pas être déployés dans des environnements dotés d’une GPU. Pour contourner le problème, vous pouvez extraire le modèle natif et le déployer. Par exemple :
# Train a model using Snowpark ML from snowflake.ml.modeling.xgboost import XGBRegressor regressor = XGBRegressor(...) regressor.fit(training_df) # Extract the native model xgb_model = regressor.to_xgboost() # Test the model with pandas dataframe pandas_test_df = test_df.select(['FEATURE1', 'FEATURE2', ...]).to_pandas() xgb_model.predict(pandas_test_df) # Log the model in Snowflake Model Registry mv = reg.log_model(xgb_model, model_name="my_native_xgb_model", sample_input_data=pandas_test_df, comment = 'A native XGB model trained from Snowflake Modeling API', ) # Now we should be able to deploy to a GPU compute pool on SPCS mv.create_service( service_name="my_service_gpu", service_compute_pool="my_gpu_pool", image_repo="my_repo", max_instances=1, gpu_requests="1", )
Interface utilisateur¶
Vous pouvez gérer les modèles déployés dans l’UI de Model Registry Snowsight. Pour plus d’informations, voir Services d’inférence de modèles.
Utilisation d’un modèle déployé dans SPCS¶
Vous pouvez appeler les méthodes d’un modèle en utilisant SQL, Python, ou un point de terminaison HTTP.
SQL¶
Snowflake Model Serving crée des fonctions de service lors du déploiement d’un modèle dans SPCS. Ces fonctions servent de passerelle entre SQL et le modèle exécuté dans le pool de calcul du SPCS. Une fonction de service est créée pour chaque méthode du modèle, et elles sont nommées comme service_name!method_name
. Par exemple, si le modèle a deux méthodes nommées PREDICT
et EXPLAIN
est qu’il est en cours de déploiement sur un service nommé MY_SERVICE
, les fonctions de service résultantes sont MY_SERVICE!PREDICT
et MY_SERVICE!EXPLAIN
.
Note
Les fonctions de service sont contenues dans le service. Pour cette raison, elles ne disposent que d’un seul point de contrôle d’accès, le service. Vous ne pouvez pas avoir différents privilèges de contrôle d’accès pour différentes fonctions dans un même service.
L’appel des fonctions de service d’un modèle en SQL se fait en utilisant un code comme celui-ci :
-- See signature of the inference function in SQL.
SHOW FUNCTIONS IN MODEL my_native_xgb_model VERSION ...;
-- Call the inference function in SQL following the same signature (from `arguments` column of the above query)
SELECT MY_SERVICE!PREDICT(feature1, feature2, ...) FROM input_data_table;
Python¶
Appeler les méthodes d’un service à l’aide de la méthode run
d’un objet de version de modèle, y compris l’argument service_name
pour spécifier le service où la méthode sera exécutée. Par exemple :
# Get signature of the inference function in Python
# mv is a snowflake.ml.model.ModelVersion object
mv.show_functions()
# Call the function in Python
service_prediction = mv.run(
test_df,
function_name="predict",
service_name="my_service")
Si vous n’incluez pas l’argument service_name
, le modèle s’exécute dans un entrepôt.
Point de terminaison HTTP¶
Le déploiement d’un service avec l’entrée activée crée un point de terminaison HTTP par lequel vous pouvez appeler le service. Vous pouvez trouver le point de terminaison en utilisant la commande SHOW ENDPOINTS IN SERVICE
.
SHOW ENDPOINTS IN SERVICE my_service;
Prenez note de la colonne ingress_url
, qui devrait ressembler à random_str-account-id.snowflakecomputing.app
. Les limites du nom DNS s’appliquent. Dans une URL, un trait de soulignement (_) dans le nom de la méthode est remplacé par un tiret (-) (par exemple, l’URL de predict_proba
est url/predict-proba
).
Les utilisateurs peuvent appeler le service en utilisant le point de terminaison public de manière programmatique. Les applications utilisent l’authentification par paire de clés pour authentifier les requêtes adressées au point de terminaison public. Générez un jeton Web JSON (JWT) à partir de la paire de clés, échangez le jeton JWT avec Snowflake contre un jeton OAuth et utilisez le jeton OAuth pour authentifier les requêtes adressées au point de terminaison public d’un service. Pour un exemple, voir Accéder au point de terminaison public de manière programmatique.
Pour plus d’informations sur le format de données requis, voir Formats des données d’entrée et de sortie des services à distance.
Voir Déployer un transformateur de phrases Hugging Face pour inférence alimentée par GPU pour un exemple d’utilisation d’un point de terminaison de service de modèle HTTP.
Gestion des services¶
Snowpark Container Services propose une interface SQL de gestion des services. Vous pouvez utiliser les commandes DESCRIBE SERVICE et ALTER SERVICE avec les services SPCS créés par Snowflake Model Serving comme vous le feriez pour gérer n’importe quel autre service SPCS. Par exemple, vous pouvez :
Changer MIN_INSTANCES et d’autres propriétés d’un service
Supprimer un service
Partager un service avec un autre compte
Changer la propriété d’un service (le nouveau propriétaire doit avoir accès au modèle)
Note
Si le propriétaire d’un service perd l’accès au modèle sous-jacent pour une raison quelconque, le service cesse de fonctionner après un redémarrage. Il continuera à fonctionner jusqu’à ce qu’il soit redémarré.
Pour garantir la reproductibilité et le débogage, vous ne pouvez pas modifier la spécification d’un service d’inférence existant. Vous pouvez cependant copier la spécification, la personnaliser et utiliser la spécification personnalisée pour créer votre propre service pour héberger le modèle. Cependant, cette méthode ne protège pas le modèle sous-jacent contre la suppression. En outre, il ne suit pas la lignée. Il est préférable de permettre à Snowflake Model Serving de créer des services.
Suspension de services¶
Si vous utilisez le service uniquement à partir de SQL via des fonctions de service, ne définissez pas le paramètre ingress_enabled
sur true. L’activation de l’entrée implique que le service doit rester en activité à tout moment afin de pouvoir répondre aux requêtes HTTP entrantes. Lorsque l’entrée n’est pas activée, le service d’inférence est suspendu automatiquement après trente minutes d’inactivité et reprend automatiquement lorsqu’il reçoit une requête.
Pour suspendre manuellement un service, utilisez la commande ALTER SERVICE.
ALTER SERVICE my_service SUSPEND;
La reprise automatique du service à la réception d’une nouvelle requête est soumise à des délais de planification et de démarrage. Le délai de planification dépend de la disponibilité du pool de calcul et le délai de démarrage dépend de la taille du modèle.
Suppression de modèles¶
Vous pouvez gérer les modèles et les versions de modèles comme d’habitude avec l’interface SQL ou l’API Python, à la condition qu’un modèle ou une version de modèle utilisé(e) par un service (qu’il soit en cours d’exécution ou suspendu) ne puisse pas être supprimé(e). Pour supprimer un modèle ou une version de modèle, supprimez d’abord le service.
Exemples¶
Ces exemples supposent que vous avez déjà créé un pool de calcul, un référentiel d’images et que vous avez accordé les privilèges nécessaires. Voir Conditions préalables pour plus de détails.
Déployer un modèle XGBoost pour une inférence alimentée par CPU¶
Le code suivant illustre les étapes clés du déploiement d’un modèle XGBoost pour l’inférence dans SPCS, puis en utilisant le modèle déployé pour l’inférence. Un notebook pour cet exemple est disponible.
from snowflake.ml.registry import registry
from snowflake.ml.utils.connection_params import SnowflakeLoginOptions
from snowflake.snowpark import Session
from xgboost import XGBRegressor
# your model training code here output of which is a trained xgb_model
# Open model registry
reg = registry.Registry(session=session, database_name='my_registry_db', schema_name='my_registry_schema')
# Log the model in Snowflake Model Registry
model_ref = reg.log_model(
model_name="my_xgb_forecasting_model",
version_name="v1",
model=xgb_model,
conda_dependencies=["scikit-learn","xgboost"],
sample_input_data=pandas_test_df,
comment="XGBoost model for forecasting customer demand"
)
# Deploy the model to SPCS
model_ref.create_service(
service_name="forecast_model_service",
service_compute_pool="my_cpu_pool",
image_repo="my_image_repo",
ingress_enabled=True)
# See all services running a model
model_ref.list_services()
# Run on SPCS
model_ref.run(pandas_test_df, function_name="predict", service_name="forecast_model_service")
# Delete the service
model_ref.delete_service("forecast_model_service")
Étant donné que l’entrée est activée sur ce modèle, vous pouvez appeler son point de terminaison HTTP comme suit.
import json
import numpy as np
from pprint import pprint
import requests
import snowflake.connector
# Generate headers including authorization.
# This example uses session token authorization. Ideally key-pair authentication is used for API access.
def initiate_snowflake_connection():
connection_parameters = SnowflakeLoginOptions("connection_name")
connection_parameters["session_parameters"] = {"PYTHON_CONNECTOR_QUERY_RESULT_FORMAT": "json"}
snowflake_conn = snowflake.connector.connect(**connection_parameters)
return snowflake_conn
def get_headers(snowflake_conn):
token = snowflake_conn._rest._token_request('ISSUE')
headers = {'Authorization': f'Snowflake Token=\"{token["data"]["sessionToken"]}\"'}
return headers
headers = get_headers(initiate_snowflake_connection())
# Put the endpoint url with method name `predict`
# The endpoint url can be found with `show endpoints in service <service_name>`.
URL = 'https://<random_str>-<organization>-<account>.snowflakecomputing.app/predict'
# Prepare data to be sent
data = {"data": np.column_stack([range(pandas_test_df.shape[0]), pandas_test_df.values]).tolist()}
# Send over HTTP
def send_request(data: dict):
output = requests.post(URL, json=data, headers=headers)
assert (output.status_code == 200), f"Failed to get response from the service. Status code: {output.status_code}"
return output.content
# Test
results = send_request(data=data)
pprint(json.loads(results))
Déployer un transformateur de phrases Hugging Face pour inférence alimentée par GPU¶
Le code suivant entraîne et déploie un transformateur de phrases Hugging Face, y compris un point de terminaison HTTP.
Cet exemple exige le paquet sentence-transformers
, un pool de calcul GPU et un référentiel d’images.
from snowflake.ml.registry import registry
from snowflake.ml.utils.connection_params import SnowflakeLoginOptions
from snowflake.snowpark import Session
from sentence_transformers import SentenceTransformer
session = Session.builder.configs(SnowflakeLoginOptions("connection_name")).create()
reg = registry.Registry(session=session, database_name='my_registry_db', schema_name='my_registry_schema')
# Take an example sentence transformer from HF
embed_model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
# Have some sample input data
input_data = [
"This is the first sentence.",
"Here's another sentence for testing.",
"The quick brown fox jumps over the lazy dog.",
"I love coding and programming.",
"Machine learning is an exciting field.",
"Python is a popular programming language.",
"I enjoy working with data.",
"Deep learning models are powerful.",
"Natural language processing is fascinating.",
"I want to improve my NLP skills.",
]
# Log the model with pip dependencies
pip_model = reg.log_model(
embed_model,
model_name="sentence_transformer_minilm",
version_name="pip",
sample_input_data=input_data, # Needed for determining signature of the model
pip_requirements=["sentence-transformers", "torch", "transformers"], # If you want to run this model in the Warehouse, you can use conda_dependencies instead
)
# Force Snowflake to not try to check warehouse
conda_forge_model = reg.log_model(
embed_model,
model_name="sentence_transformer_minilm",
version_name="conda_forge_force",
sample_input_data=input_data,
# setting any package from conda-forge is sufficient to know that it can't be run in warehouse
conda_dependencies=["sentence-transformers", "conda-forge::pytorch", "transformers"]
)
# Deploy the model to SPCS
pip_model.create_service(
service_name="my_minilm_service",
service_compute_pool="my_gpu_pool", # Using GPU_NV_S - smallest GPU node that can run the model
image_repo="my_image_repo",
ingress_enabled=True,
gpu_requests="1", # Model fits in GPU memory; only needed for GPU pool
max_instances=4, # 4 instances were able to run 10M inferences from an XS warehouse
)
# See all services running a model
pip_model.list_services()
# Run on SPCS
pip_model.run(input_data, function_name="encode", service_name="my_minilm_service")
# Delete the service
pip_model.delete_service("my_minilm_service")
Dans SQL, vous pouvez appeler la fonction de service comme suit :
SELECT my_minilm_service!encode('This is a test sentence.');
De même, vous pouvez appeler son point de terminaison HTTP comme suit.
import json
from pprint import pprint
import requests
# Put the endpoint url with method name `encode`
URL='https://<random_str>-<account>.snowflakecomputing.app/encode'
# Prepare data to be sent
data = {
'data': []
}
for idx, x in enumerate(input_data):
data['data'].append([idx, x])
# Send over HTTP
def send_request(data: dict):
output = requests.post(URL, json=data, headers=headers)
assert (output.status_code == 200), f"Failed to get response from the service. Status code: {output.status_code}"
return output.content
# Test
results = send_request(data=data)
pprint(json.loads(results))
Déployer un modèle PyTorch pour l’inférence alimentée par GPU¶
Voir ce démarrage rapide pour un exemple d’entraînement et de déploiement d’un modèle de recommandation d’apprentissage profond PyTorch (DLRM) dans SPCS pour une inférence par GPU.
Meilleures pratiques¶
- Partage d’un référentiel d’images
Il est courant que plusieurs utilisateurs ou rôles utilisent le même modèle. L’utilisation d’un référentiel d’images unique permet de créer l’image une seule fois et de la réutiliser par tous les utilisateurs, ce qui permet d’économiser du temps et de l’argent. Tous les rôles qui utiliseront le référentiel ont besoin de privilèges SERVICE READ, SERVICE WRITE, READ, et WRITE sur le référentiel. Étant donné que l’image peut avoir besoin d’être reconstruite pour mettre à jour les dépendances, vous devez conserver les privilèges d’écriture ; ne les révoquez pas une fois l’image initialement créée.
- Mise à l’échelle du service d’inférence
La mise à l’échelle automatique de Snowpark Container Services est très conservatrice et ne s’adapte pas assez rapidement à la plupart des charges de travail de ML. Pour cette raison, Snowflake vous recommande de définir les deux MIN_INSTANCES et MAX_INSTANCES sur la même valeur, en choisissant ces valeurs pour obtenir les performances dont vous avez besoin pour vos charges de travail typiques. Utilisez SQL comme ce qui suit :
ALTER SERVICE myservice SET MIN_INSTANCES = <new_num> MAX_INSTANCES = <new_num>;
Pour la même raison, lors de la création initiale du service à l’aide de l’API Python, la méthode
create_service
accepte uniquementmax_instances
et utilise cette même valeur pourmin_instances
.- Choix du type de nœud et du nombre d’instances
Utilisez le plus petit nœud de GPU où le modèle s’insère dans la mémoire. Dimensionnez en augmentant le nombre d’instances, plutôt qu’en augmentant
num_workers
dans un nœud de GPU plus grand. Par exemple, si le modèle correspond au type d’instance GPU_NV_S (GPU_NV_SM sur Azure), utilisezgpu_requests=1
et effectuez une évolution en augmentantmax_instances
plutôt que d’utiliser une combinaison degpu_requests
etnum_workers
sur une instance GPU plus grande.- Sélection d’une taille d’entrepôt
Plus l’entrepôt est grand, plus les requêtes parallèles sont envoyées aux serveurs d’inférence. L’inférence est une opération coûteuse, utilisez donc un entrepôt plus petit lorsque cela est possible. L’utilisation d’une taille d’entrepôt supérieure à la moyenne n’accélère pas les performances des requêtes et entraîne des coûts supplémentaires.
Résolution des problèmes¶
Surveiller les déploiements de SPCS¶
Vous pouvez surveiller le déploiement en inspectant les services lancés à l’aide de la requête SQL suivante.
SHOW SERVICES IN COMPUTE POOL my_compute_pool;
Deux tâches sont lancées :
MODEL_BUILD_xxxxx : les derniers caractères du nom sont choisis de façon aléatoire pour éviter les conflits de noms. Cette tâche construit l’image et se termine une fois l’image construite. Si une image existe déjà, la tâche est ignorée.
Les connexions sont utiles pour résoudre des problèmes tels que des conflits dans les dépendances des paquets. Pour voir les journaux de cette tâche, exécutez la commande SQL ci-dessous, en veillant à utiliser les mêmes caractères finaux :
CALL SYSTEM$GET_SERVICE_LOGS('MODEL_BUILD_xxxxx', 0, 'model-build');MYSERVICE : le nom du service tel que spécifié dans l’appel à
create_service
. Cette tâche est démarrée si la tâche MODEL_BUILD aboutit ou est ignorée. Pour voir les journaux de cette tâche, exécutez la commande SQL ci-dessous :CALL SYSTEM$GET_SERVICE_LOGS('MYSERVICE', 0, 'model-inference');Si les journaux ne sont pas disponibles via
SYSTEM$GET_SERVICE_LOG
car la tâche de construction ou le service a été supprimé, vous pouvez consulter la table des événements (si elle est activée) pour voir les journaux :SELECT RESOURCE_ATTRIBUTES, VALUE FROM <EVENT_TABLE_NAME> WHERE true AND timestamp > dateadd(day, -1, current_timestamp()) -- choose appropriate timestamp range AND RESOURCE_ATTRIBUTES:"snow.database.name" = '<db of the service>' AND RESOURCE_ATTRIBUTES:"snow.schema.name" = '<schema of the service>' AND RESOURCE_ATTRIBUTES:"snow.service.name" = '<Job or Service name>' AND RESOURCE_ATTRIBUTES:"snow.service.container.instance" = '0' -- choose all instances or one particular AND RESOURCE_ATTRIBUTES:"snow.service.container.name" != 'snowflake-ingress' --skip logs from internal sidecar ORDER BY timestamp ASC;
Conflits de paquets¶
Deux systèmes dictent les paquets installés dans le conteneur de services : le modèle lui-même et le serveur d’inférence. Pour réduire les conflits avec les dépendances de votre modèle, le serveur d’inférence ne nécessite que les paquets suivants :
gunicorn<24.0.0
starlette<1.0.0
uvicorn-standard<1.0.0
Assurez-vous que les dépendances de votre modèle, ainsi que celles ci-dessus, peuvent être résolues par pip
ou conda
, quel que soit votre choix.
Si un modèle possède à la fois conda_dependencies
et pip_requirements
, elles seront installées comme suit via conda :
Canaux :
conda-forge
nodefaults
Dépendances :
all_conda_packages
- pip :
all_pip_packages
Snowflake récupère les paquets Anaconda à partir de conda-forge
lors de la construction d’images de conteneurs car le canal conda de Snowflake n’est disponible que dans les entrepôts, et le canal defaults
exige que les utilisateurs acceptent les conditions d’utilisation d’Anaconda, ce qui n’est pas possible lors d’une construction automatisée. Pour obtenir des paquets provenant d’un canal différent, tel que defaults
, spécifiez chaque paquet avec le nom du canal, comme dans defaults::pkg_name
.
Note
Si vous spécifiez à la fois conda_dependencies
et pip_requirements
, l’image du conteneur se construit avec succès même si les deux ensembles de dépendances ne sont pas compatibles, ce qui peut faire que l’image du conteneur qui en résulte ne fonctionne pas comme prévu. Snowflake recommande d’utiliser uniquement conda_dependencies
ou uniquement pip_requirements
, et non les deux.
Service à court de mémoire¶
Certains modèles ne sont pas compatibles avec les threads, Snowflake charge donc une copie distincte du modèle en mémoire pour chaque processus de travail. Cela peut entraîner des conditions de pénurie de mémoire pour les grands modèles avec un nombre plus élevé de workers. Essayez de réduire num_workers
.
Performances de requête insatisfaisantes¶
En général, l’inférence est limitée par le nombre d’instances dans le service d’inférence. Essayez de transférer une valeur plus élevée pour max_instances
lorsque vous déployez le modèle.
Impossible de modifier les spécifications du service¶
Les spécifications des services de création de modèles et d’inférence ne peuvent pas être modifiées à l’aide de ALTER SERVICE. Vous ne pouvez modifier que des attributs tels que TAG, MIN_INSTANCES, et ainsi de suite. Cependant, étant donné que l’image est publiée dans le référentiel d’images, vous pouvez copier la spécification, la modifier et créer un nouveau service à partir de celle-ci, que vous pouvez démarrer manuellement.
Paquet non trouvé¶
Le déploiement du modèle a échoué pendant la phase de construction de l’image. Les journaux model-build
suggèrent qu’un paquet demandé n’a pas été trouvé. (Cette étape utilise conda-forge
par défaut si le paquet est mentionné dans conda_dependencies
.)
L’installation d’un paquet peut échouer pour l’une des raisons suivantes :
Le nom ou la version du paquet n’est pas valide. Vérifiez l’orthographe et la version du paquet.
La version demandée du paquet n’existe pas dans
conda-forge
. Vous pouvez essayer de supprimer la spécification de la version pour obtenir la dernière version disponible dansconda-forge
, ou utiliserpip_requirements
à la place. Vous pouvez consulter tous les paquets disponibles ici.Il peut arriver que vous ayez besoin d’un paquet provenant d’un canal spécial (par exemple
pytorch
). Ajoutez un préfixechannel_name::
à la dépendance, par exemplepytorch::torch
.
Inadéquation de la version de Hugging Face Hub¶
Un service d’inférence du modèle Hugging Face peut échouer avec le message d’erreur suivant :
ImportError: huggingface-hub>=0.30.0,<1.0 is required for a normal functioning of this module, but found huggingface-hub==0.25.2
Cela est dû au fait que le paquet transformers
ne spécifie pas les dépendances correctes dans huggingface-hub
, mais qu’il les vérifie dans le code. Pour résoudre ce problème, connectez à nouveau le modèle, en spécifiant cette fois explicitement la version requise de huggingface-hub
dans conda_dependencies
ou pip_requirements
.
Torch n’est pas compilé avec CUDA activé¶
La cause typique de cette erreur est que vous avez spécifié à la fois conda_dependencies
et pip_requirements
. Comme indiqué dans la section Conflits de paquets, conda
est le gestionnaire de paquets utilisé pour construire l’image du conteneur. Anaconda ne résout pas les paquets de conda_dependencies
et pip_requirements
ensemble et donne la priorité aux paquets conda. Cela peut conduire à une situation où les paquets conda ne sont pas compatibles avec les paquets pip. Vous avez peut-être spécifié torch
dans pip_requirements
, et non dans conda_dependencies
. Envisagez de consolider les dépendances dans conda_dependencies
ou pip_requirements
. Si cela n’est pas possible, préférez spécifier les paquets les plus importants dans conda_dependencies
.