snowflake-ml-python 1.6.2__py3-none-any.whl → 1.6.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- snowflake/cortex/__init__.py +4 -0
- snowflake/cortex/_classify_text.py +2 -2
- snowflake/cortex/_embed_text_1024.py +37 -0
- snowflake/cortex/_embed_text_768.py +37 -0
- snowflake/cortex/_extract_answer.py +2 -2
- snowflake/cortex/_sentiment.py +2 -2
- snowflake/cortex/_summarize.py +2 -2
- snowflake/cortex/_translate.py +2 -2
- snowflake/cortex/_util.py +4 -4
- snowflake/ml/_internal/env_utils.py +5 -5
- snowflake/ml/_internal/exceptions/error_codes.py +2 -0
- snowflake/ml/_internal/utils/db_utils.py +50 -0
- snowflake/ml/_internal/utils/service_logger.py +63 -0
- snowflake/ml/_internal/utils/sql_identifier.py +25 -1
- snowflake/ml/data/_internal/arrow_ingestor.py +1 -11
- snowflake/ml/data/ingestor_utils.py +20 -10
- snowflake/ml/feature_store/access_manager.py +3 -3
- snowflake/ml/feature_store/feature_store.py +19 -2
- snowflake/ml/feature_store/feature_view.py +82 -28
- snowflake/ml/fileset/stage_fs.py +2 -1
- snowflake/ml/lineage/lineage_node.py +7 -2
- snowflake/ml/model/__init__.py +1 -2
- snowflake/ml/model/_client/model/model_version_impl.py +78 -9
- snowflake/ml/model/_client/ops/model_ops.py +89 -7
- snowflake/ml/model/_client/ops/service_ops.py +200 -91
- snowflake/ml/model/_client/service/model_deployment_spec.py +4 -0
- snowflake/ml/model/_client/service/model_deployment_spec_schema.py +1 -0
- snowflake/ml/model/_client/sql/_base.py +5 -0
- snowflake/ml/model/_client/sql/model.py +1 -0
- snowflake/ml/model/_client/sql/model_version.py +9 -5
- snowflake/ml/model/_client/sql/service.py +35 -13
- snowflake/ml/model/_model_composer/model_composer.py +11 -41
- snowflake/ml/model/_model_composer/model_manifest/model_manifest.py +29 -4
- snowflake/ml/model/_packager/model_env/model_env.py +4 -38
- snowflake/ml/model/_packager/model_handlers/_utils.py +106 -32
- snowflake/ml/model/_packager/model_handlers/catboost.py +26 -27
- snowflake/ml/model/_packager/model_handlers/huggingface_pipeline.py +3 -3
- snowflake/ml/model/_packager/model_handlers/lightgbm.py +21 -6
- snowflake/ml/model/_packager/model_handlers/mlflow.py +3 -5
- snowflake/ml/model/_packager/model_handlers/model_objective_utils.py +111 -58
- snowflake/ml/model/_packager/model_handlers/sentence_transformers.py +15 -8
- snowflake/ml/model/_packager/model_handlers/sklearn.py +50 -66
- snowflake/ml/model/_packager/model_handlers/snowmlmodel.py +36 -17
- snowflake/ml/model/_packager/model_handlers/xgboost.py +22 -7
- snowflake/ml/model/_packager/model_meta/model_meta.py +16 -45
- snowflake/ml/model/_packager/model_meta/model_meta_schema.py +1 -6
- snowflake/ml/model/_packager/model_packager.py +14 -10
- snowflake/ml/model/_packager/model_runtime/model_runtime.py +11 -0
- snowflake/ml/model/_signatures/snowpark_handler.py +3 -2
- snowflake/ml/model/type_hints.py +11 -152
- snowflake/ml/modeling/_internal/snowpark_implementations/distributed_hpo_trainer.py +0 -2
- snowflake/ml/modeling/_internal/snowpark_implementations/snowpark_trainer.py +17 -6
- snowflake/ml/modeling/_internal/snowpark_implementations/xgboost_external_memory_trainer.py +0 -1
- snowflake/ml/modeling/calibration/calibrated_classifier_cv.py +1 -0
- snowflake/ml/modeling/cluster/affinity_propagation.py +1 -0
- snowflake/ml/modeling/cluster/agglomerative_clustering.py +1 -0
- snowflake/ml/modeling/cluster/birch.py +1 -0
- snowflake/ml/modeling/cluster/bisecting_k_means.py +1 -0
- snowflake/ml/modeling/cluster/dbscan.py +1 -0
- snowflake/ml/modeling/cluster/feature_agglomeration.py +1 -0
- snowflake/ml/modeling/cluster/k_means.py +1 -0
- snowflake/ml/modeling/cluster/mean_shift.py +1 -0
- snowflake/ml/modeling/cluster/mini_batch_k_means.py +1 -0
- snowflake/ml/modeling/cluster/optics.py +1 -0
- snowflake/ml/modeling/cluster/spectral_biclustering.py +1 -0
- snowflake/ml/modeling/cluster/spectral_clustering.py +1 -0
- snowflake/ml/modeling/cluster/spectral_coclustering.py +1 -0
- snowflake/ml/modeling/compose/column_transformer.py +1 -0
- snowflake/ml/modeling/compose/transformed_target_regressor.py +1 -0
- snowflake/ml/modeling/covariance/elliptic_envelope.py +1 -0
- snowflake/ml/modeling/covariance/empirical_covariance.py +1 -0
- snowflake/ml/modeling/covariance/graphical_lasso.py +1 -0
- snowflake/ml/modeling/covariance/graphical_lasso_cv.py +1 -0
- snowflake/ml/modeling/covariance/ledoit_wolf.py +1 -0
- snowflake/ml/modeling/covariance/min_cov_det.py +1 -0
- snowflake/ml/modeling/covariance/oas.py +1 -0
- snowflake/ml/modeling/covariance/shrunk_covariance.py +1 -0
- snowflake/ml/modeling/decomposition/dictionary_learning.py +1 -0
- snowflake/ml/modeling/decomposition/factor_analysis.py +1 -0
- snowflake/ml/modeling/decomposition/fast_ica.py +1 -0
- snowflake/ml/modeling/decomposition/incremental_pca.py +1 -0
- snowflake/ml/modeling/decomposition/kernel_pca.py +1 -0
- snowflake/ml/modeling/decomposition/mini_batch_dictionary_learning.py +1 -0
- snowflake/ml/modeling/decomposition/mini_batch_sparse_pca.py +1 -0
- snowflake/ml/modeling/decomposition/pca.py +1 -0
- snowflake/ml/modeling/decomposition/sparse_pca.py +1 -0
- snowflake/ml/modeling/decomposition/truncated_svd.py +1 -0
- snowflake/ml/modeling/discriminant_analysis/linear_discriminant_analysis.py +1 -0
- snowflake/ml/modeling/discriminant_analysis/quadratic_discriminant_analysis.py +1 -0
- snowflake/ml/modeling/ensemble/ada_boost_classifier.py +1 -0
- snowflake/ml/modeling/ensemble/ada_boost_regressor.py +1 -0
- snowflake/ml/modeling/ensemble/bagging_classifier.py +1 -0
- snowflake/ml/modeling/ensemble/bagging_regressor.py +1 -0
- snowflake/ml/modeling/ensemble/extra_trees_classifier.py +1 -0
- snowflake/ml/modeling/ensemble/extra_trees_regressor.py +1 -0
- snowflake/ml/modeling/ensemble/gradient_boosting_classifier.py +1 -0
- snowflake/ml/modeling/ensemble/gradient_boosting_regressor.py +1 -0
- snowflake/ml/modeling/ensemble/hist_gradient_boosting_classifier.py +1 -0
- snowflake/ml/modeling/ensemble/hist_gradient_boosting_regressor.py +1 -0
- snowflake/ml/modeling/ensemble/isolation_forest.py +1 -0
- snowflake/ml/modeling/ensemble/random_forest_classifier.py +1 -0
- snowflake/ml/modeling/ensemble/random_forest_regressor.py +1 -0
- snowflake/ml/modeling/ensemble/stacking_regressor.py +1 -0
- snowflake/ml/modeling/ensemble/voting_classifier.py +1 -0
- snowflake/ml/modeling/ensemble/voting_regressor.py +1 -0
- snowflake/ml/modeling/feature_selection/generic_univariate_select.py +1 -0
- snowflake/ml/modeling/feature_selection/select_fdr.py +1 -0
- snowflake/ml/modeling/feature_selection/select_fpr.py +1 -0
- snowflake/ml/modeling/feature_selection/select_fwe.py +1 -0
- snowflake/ml/modeling/feature_selection/select_k_best.py +1 -0
- snowflake/ml/modeling/feature_selection/select_percentile.py +1 -0
- snowflake/ml/modeling/feature_selection/sequential_feature_selector.py +1 -0
- snowflake/ml/modeling/feature_selection/variance_threshold.py +1 -0
- snowflake/ml/modeling/gaussian_process/gaussian_process_classifier.py +1 -0
- snowflake/ml/modeling/gaussian_process/gaussian_process_regressor.py +1 -0
- snowflake/ml/modeling/impute/iterative_imputer.py +1 -0
- snowflake/ml/modeling/impute/knn_imputer.py +1 -0
- snowflake/ml/modeling/impute/missing_indicator.py +1 -0
- snowflake/ml/modeling/kernel_approximation/additive_chi2_sampler.py +1 -0
- snowflake/ml/modeling/kernel_approximation/nystroem.py +1 -0
- snowflake/ml/modeling/kernel_approximation/polynomial_count_sketch.py +1 -0
- snowflake/ml/modeling/kernel_approximation/rbf_sampler.py +1 -0
- snowflake/ml/modeling/kernel_approximation/skewed_chi2_sampler.py +1 -0
- snowflake/ml/modeling/kernel_ridge/kernel_ridge.py +1 -0
- snowflake/ml/modeling/lightgbm/lgbm_classifier.py +1 -0
- snowflake/ml/modeling/lightgbm/lgbm_regressor.py +1 -0
- snowflake/ml/modeling/linear_model/ard_regression.py +1 -0
- snowflake/ml/modeling/linear_model/bayesian_ridge.py +1 -0
- snowflake/ml/modeling/linear_model/elastic_net.py +1 -0
- snowflake/ml/modeling/linear_model/elastic_net_cv.py +1 -0
- snowflake/ml/modeling/linear_model/gamma_regressor.py +1 -0
- snowflake/ml/modeling/linear_model/huber_regressor.py +1 -0
- snowflake/ml/modeling/linear_model/lars.py +1 -0
- snowflake/ml/modeling/linear_model/lars_cv.py +1 -0
- snowflake/ml/modeling/linear_model/lasso.py +1 -0
- snowflake/ml/modeling/linear_model/lasso_cv.py +1 -0
- snowflake/ml/modeling/linear_model/lasso_lars.py +1 -0
- snowflake/ml/modeling/linear_model/lasso_lars_cv.py +1 -0
- snowflake/ml/modeling/linear_model/lasso_lars_ic.py +1 -0
- snowflake/ml/modeling/linear_model/linear_regression.py +1 -0
- snowflake/ml/modeling/linear_model/logistic_regression.py +1 -0
- snowflake/ml/modeling/linear_model/logistic_regression_cv.py +1 -0
- snowflake/ml/modeling/linear_model/multi_task_elastic_net.py +1 -0
- snowflake/ml/modeling/linear_model/multi_task_elastic_net_cv.py +1 -0
- snowflake/ml/modeling/linear_model/multi_task_lasso.py +1 -0
- snowflake/ml/modeling/linear_model/multi_task_lasso_cv.py +1 -0
- snowflake/ml/modeling/linear_model/orthogonal_matching_pursuit.py +1 -0
- snowflake/ml/modeling/linear_model/passive_aggressive_classifier.py +1 -0
- snowflake/ml/modeling/linear_model/passive_aggressive_regressor.py +1 -0
- snowflake/ml/modeling/linear_model/perceptron.py +1 -0
- snowflake/ml/modeling/linear_model/poisson_regressor.py +1 -0
- snowflake/ml/modeling/linear_model/ransac_regressor.py +1 -0
- snowflake/ml/modeling/linear_model/ridge.py +1 -0
- snowflake/ml/modeling/linear_model/ridge_classifier.py +1 -0
- snowflake/ml/modeling/linear_model/ridge_classifier_cv.py +1 -0
- snowflake/ml/modeling/linear_model/ridge_cv.py +1 -0
- snowflake/ml/modeling/linear_model/sgd_classifier.py +1 -0
- snowflake/ml/modeling/linear_model/sgd_one_class_svm.py +1 -0
- snowflake/ml/modeling/linear_model/sgd_regressor.py +1 -0
- snowflake/ml/modeling/linear_model/theil_sen_regressor.py +1 -0
- snowflake/ml/modeling/linear_model/tweedie_regressor.py +1 -0
- snowflake/ml/modeling/manifold/isomap.py +1 -0
- snowflake/ml/modeling/manifold/mds.py +1 -0
- snowflake/ml/modeling/manifold/spectral_embedding.py +1 -0
- snowflake/ml/modeling/manifold/tsne.py +1 -0
- snowflake/ml/modeling/metrics/metrics_utils.py +2 -2
- snowflake/ml/modeling/metrics/ranking.py +0 -3
- snowflake/ml/modeling/metrics/regression.py +0 -3
- snowflake/ml/modeling/mixture/bayesian_gaussian_mixture.py +1 -0
- snowflake/ml/modeling/mixture/gaussian_mixture.py +1 -0
- snowflake/ml/modeling/multiclass/one_vs_one_classifier.py +1 -0
- snowflake/ml/modeling/multiclass/one_vs_rest_classifier.py +1 -0
- snowflake/ml/modeling/multiclass/output_code_classifier.py +1 -0
- snowflake/ml/modeling/naive_bayes/bernoulli_nb.py +1 -0
- snowflake/ml/modeling/naive_bayes/categorical_nb.py +1 -0
- snowflake/ml/modeling/naive_bayes/complement_nb.py +1 -0
- snowflake/ml/modeling/naive_bayes/gaussian_nb.py +1 -0
- snowflake/ml/modeling/naive_bayes/multinomial_nb.py +1 -0
- snowflake/ml/modeling/neighbors/k_neighbors_classifier.py +1 -0
- snowflake/ml/modeling/neighbors/k_neighbors_regressor.py +1 -0
- snowflake/ml/modeling/neighbors/kernel_density.py +1 -0
- snowflake/ml/modeling/neighbors/local_outlier_factor.py +1 -0
- snowflake/ml/modeling/neighbors/nearest_centroid.py +1 -0
- snowflake/ml/modeling/neighbors/nearest_neighbors.py +1 -0
- snowflake/ml/modeling/neighbors/neighborhood_components_analysis.py +1 -0
- snowflake/ml/modeling/neighbors/radius_neighbors_classifier.py +1 -0
- snowflake/ml/modeling/neighbors/radius_neighbors_regressor.py +1 -0
- snowflake/ml/modeling/neural_network/bernoulli_rbm.py +1 -0
- snowflake/ml/modeling/neural_network/mlp_classifier.py +1 -0
- snowflake/ml/modeling/neural_network/mlp_regressor.py +1 -0
- snowflake/ml/modeling/pipeline/pipeline.py +0 -1
- snowflake/ml/modeling/preprocessing/polynomial_features.py +1 -0
- snowflake/ml/modeling/semi_supervised/label_propagation.py +1 -0
- snowflake/ml/modeling/semi_supervised/label_spreading.py +1 -0
- snowflake/ml/modeling/svm/linear_svc.py +1 -0
- snowflake/ml/modeling/svm/linear_svr.py +1 -0
- snowflake/ml/modeling/svm/nu_svc.py +1 -0
- snowflake/ml/modeling/svm/nu_svr.py +1 -0
- snowflake/ml/modeling/svm/svc.py +1 -0
- snowflake/ml/modeling/svm/svr.py +1 -0
- snowflake/ml/modeling/tree/decision_tree_classifier.py +1 -0
- snowflake/ml/modeling/tree/decision_tree_regressor.py +1 -0
- snowflake/ml/modeling/tree/extra_tree_classifier.py +1 -0
- snowflake/ml/modeling/tree/extra_tree_regressor.py +1 -0
- snowflake/ml/modeling/xgboost/xgb_classifier.py +1 -0
- snowflake/ml/modeling/xgboost/xgb_regressor.py +1 -0
- snowflake/ml/modeling/xgboost/xgbrf_classifier.py +1 -0
- snowflake/ml/modeling/xgboost/xgbrf_regressor.py +1 -0
- snowflake/ml/monitoring/_client/model_monitor.py +126 -0
- snowflake/ml/monitoring/_client/model_monitor_manager.py +361 -0
- snowflake/ml/monitoring/_client/model_monitor_version.py +1 -0
- snowflake/ml/monitoring/_client/monitor_sql_client.py +1335 -0
- snowflake/ml/monitoring/_client/queries/record_count.ssql +14 -0
- snowflake/ml/monitoring/_client/queries/rmse.ssql +28 -0
- snowflake/ml/monitoring/entities/model_monitor_config.py +28 -0
- snowflake/ml/monitoring/entities/model_monitor_interval.py +46 -0
- snowflake/ml/monitoring/entities/output_score_type.py +90 -0
- snowflake/ml/registry/_manager/model_manager.py +4 -4
- snowflake/ml/registry/registry.py +165 -6
- snowflake/ml/version.py +1 -1
- {snowflake_ml_python-1.6.2.dist-info → snowflake_ml_python-1.6.4.dist-info}/METADATA +30 -9
- {snowflake_ml_python-1.6.2.dist-info → snowflake_ml_python-1.6.4.dist-info}/RECORD +225 -249
- {snowflake_ml_python-1.6.2.dist-info → snowflake_ml_python-1.6.4.dist-info}/WHEEL +1 -1
- snowflake/ml/_internal/container_services/image_registry/credential.py +0 -84
- snowflake/ml/_internal/container_services/image_registry/http_client.py +0 -127
- snowflake/ml/_internal/container_services/image_registry/imagelib.py +0 -400
- snowflake/ml/_internal/container_services/image_registry/registry_client.py +0 -212
- snowflake/ml/_internal/utils/log_stream_processor.py +0 -30
- snowflake/ml/_internal/utils/session_token_manager.py +0 -46
- snowflake/ml/_internal/utils/spcs_attribution_utils.py +0 -122
- snowflake/ml/_internal/utils/uri.py +0 -77
- snowflake/ml/model/_api.py +0 -568
- snowflake/ml/model/_deploy_client/image_builds/base_image_builder.py +0 -12
- snowflake/ml/model/_deploy_client/image_builds/client_image_builder.py +0 -249
- snowflake/ml/model/_deploy_client/image_builds/docker_context.py +0 -130
- snowflake/ml/model/_deploy_client/image_builds/gunicorn_run.sh +0 -36
- snowflake/ml/model/_deploy_client/image_builds/inference_server/main.py +0 -268
- snowflake/ml/model/_deploy_client/image_builds/server_image_builder.py +0 -215
- snowflake/ml/model/_deploy_client/image_builds/templates/dockerfile_template +0 -53
- snowflake/ml/model/_deploy_client/image_builds/templates/image_build_job_spec_template +0 -38
- snowflake/ml/model/_deploy_client/image_builds/templates/kaniko_shell_script_template +0 -105
- snowflake/ml/model/_deploy_client/snowservice/deploy.py +0 -611
- snowflake/ml/model/_deploy_client/snowservice/deploy_options.py +0 -116
- snowflake/ml/model/_deploy_client/snowservice/instance_types.py +0 -10
- snowflake/ml/model/_deploy_client/snowservice/templates/service_spec_template +0 -28
- snowflake/ml/model/_deploy_client/snowservice/templates/service_spec_template_with_model +0 -21
- snowflake/ml/model/_deploy_client/utils/constants.py +0 -48
- snowflake/ml/model/_deploy_client/utils/snowservice_client.py +0 -280
- snowflake/ml/model/_deploy_client/warehouse/deploy.py +0 -202
- snowflake/ml/model/_deploy_client/warehouse/infer_template.py +0 -99
- snowflake/ml/model/_packager/model_handlers/llm.py +0 -269
- snowflake/ml/model/_packager/model_meta/_core_requirements.py +0 -11
- snowflake/ml/model/deploy_platforms.py +0 -6
- snowflake/ml/model/models/llm.py +0 -106
- snowflake/ml/monitoring/monitor.py +0 -203
- snowflake/ml/registry/_initial_schema.py +0 -142
- snowflake/ml/registry/_schema.py +0 -82
- snowflake/ml/registry/_schema_upgrade_plans.py +0 -116
- snowflake/ml/registry/_schema_version_manager.py +0 -163
- snowflake/ml/registry/model_registry.py +0 -2048
- {snowflake_ml_python-1.6.2.dist-info → snowflake_ml_python-1.6.4.dist-info}/LICENSE.txt +0 -0
- {snowflake_ml_python-1.6.2.dist-info → snowflake_ml_python-1.6.4.dist-info}/top_level.txt +0 -0
@@ -1,611 +0,0 @@
|
|
1
|
-
import copy
|
2
|
-
import logging
|
3
|
-
import os
|
4
|
-
import posixpath
|
5
|
-
import string
|
6
|
-
import tempfile
|
7
|
-
import time
|
8
|
-
from contextlib import contextmanager
|
9
|
-
from typing import Any, Dict, Generator, Optional, cast
|
10
|
-
|
11
|
-
import importlib_resources
|
12
|
-
import yaml
|
13
|
-
from packaging import requirements
|
14
|
-
from typing_extensions import Unpack
|
15
|
-
|
16
|
-
from snowflake.ml._internal import env_utils, file_utils
|
17
|
-
from snowflake.ml._internal.container_services.image_registry import (
|
18
|
-
registry_client as image_registry_client,
|
19
|
-
)
|
20
|
-
from snowflake.ml._internal.exceptions import (
|
21
|
-
error_codes,
|
22
|
-
exceptions as snowml_exceptions,
|
23
|
-
)
|
24
|
-
from snowflake.ml._internal.utils import (
|
25
|
-
identifier,
|
26
|
-
query_result_checker,
|
27
|
-
spcs_attribution_utils,
|
28
|
-
)
|
29
|
-
from snowflake.ml.model import type_hints
|
30
|
-
from snowflake.ml.model._deploy_client import snowservice
|
31
|
-
from snowflake.ml.model._deploy_client.image_builds import (
|
32
|
-
base_image_builder,
|
33
|
-
client_image_builder,
|
34
|
-
docker_context,
|
35
|
-
server_image_builder,
|
36
|
-
)
|
37
|
-
from snowflake.ml.model._deploy_client.snowservice import deploy_options, instance_types
|
38
|
-
from snowflake.ml.model._deploy_client.utils import constants, snowservice_client
|
39
|
-
from snowflake.ml.model._packager.model_meta import model_meta, model_meta_schema
|
40
|
-
from snowflake.snowpark import Session
|
41
|
-
|
42
|
-
logger = logging.getLogger(__name__)
|
43
|
-
|
44
|
-
|
45
|
-
@contextmanager
|
46
|
-
def _debug_aware_tmp_directory(debug_dir: Optional[str] = None) -> Generator[str, None, None]:
|
47
|
-
"""Debug-aware directory provider.
|
48
|
-
|
49
|
-
Args:
|
50
|
-
debug_dir: A folder for deploymement context.
|
51
|
-
|
52
|
-
Yields:
|
53
|
-
A directory path to write deployment artifacts
|
54
|
-
"""
|
55
|
-
create_temp = False
|
56
|
-
if debug_dir:
|
57
|
-
directory_path = debug_dir
|
58
|
-
else:
|
59
|
-
temp_dir_context = tempfile.TemporaryDirectory()
|
60
|
-
directory_path = temp_dir_context.name
|
61
|
-
create_temp = True
|
62
|
-
try:
|
63
|
-
yield directory_path
|
64
|
-
finally:
|
65
|
-
if create_temp:
|
66
|
-
temp_dir_context.cleanup()
|
67
|
-
|
68
|
-
|
69
|
-
def _deploy(
|
70
|
-
session: Session,
|
71
|
-
*,
|
72
|
-
model_id: str,
|
73
|
-
model_meta: model_meta.ModelMetadata,
|
74
|
-
service_func_name: str,
|
75
|
-
model_zip_stage_path: str,
|
76
|
-
deployment_stage_path: str,
|
77
|
-
target_method: str,
|
78
|
-
**kwargs: Unpack[type_hints.SnowparkContainerServiceDeployOptions],
|
79
|
-
) -> type_hints.SnowparkContainerServiceDeployDetails:
|
80
|
-
"""Entrypoint for model deployment to SnowService. This function will trigger a docker image build followed by
|
81
|
-
workflow deployment to SnowService.
|
82
|
-
|
83
|
-
Args:
|
84
|
-
session: Snowpark session
|
85
|
-
model_id: Unique hex string of length 32, provided by model registry.
|
86
|
-
model_meta: Model Metadata.
|
87
|
-
service_func_name: The service function name in SnowService associated with the created service.
|
88
|
-
model_zip_stage_path: Path to model zip file in stage. Note that this path has a "@" prefix.
|
89
|
-
deployment_stage_path: Path to stage containing deployment artifacts.
|
90
|
-
target_method: The name of the target method to be deployed.
|
91
|
-
**kwargs: various SnowService deployment options.
|
92
|
-
|
93
|
-
Returns:
|
94
|
-
Deployment details for SPCS.
|
95
|
-
|
96
|
-
Raises:
|
97
|
-
SnowflakeMLException: Raised when model_id is empty.
|
98
|
-
SnowflakeMLException: Raised when service_func_name is empty.
|
99
|
-
SnowflakeMLException: Raised when model_stage_file_path is empty.
|
100
|
-
"""
|
101
|
-
snowpark_logger = logging.getLogger("snowflake.snowpark")
|
102
|
-
snowflake_connector_logger = logging.getLogger("snowflake.connector")
|
103
|
-
snowpark_log_level = snowpark_logger.level
|
104
|
-
snowflake_connector_log_level = snowflake_connector_logger.level
|
105
|
-
|
106
|
-
query_result = (
|
107
|
-
query_result_checker.SqlResultValidator(
|
108
|
-
session,
|
109
|
-
query="SHOW PARAMETERS LIKE 'PYTHON_CONNECTOR_QUERY_RESULT_FORMAT' IN SESSION",
|
110
|
-
)
|
111
|
-
.has_dimensions(expected_rows=1)
|
112
|
-
.validate()
|
113
|
-
)
|
114
|
-
prev_format = query_result[0].value
|
115
|
-
|
116
|
-
try:
|
117
|
-
# Setting appropriate log level to prevent console from being polluted by vast amount of snowpark and snowflake
|
118
|
-
# connector logging.
|
119
|
-
snowpark_logger.setLevel(logging.WARNING)
|
120
|
-
snowflake_connector_logger.setLevel(logging.WARNING)
|
121
|
-
|
122
|
-
# Query format change is needed to ensure session token obtained from the session object is valid.
|
123
|
-
session.sql("ALTER SESSION SET PYTHON_CONNECTOR_QUERY_RESULT_FORMAT = 'json'").collect()
|
124
|
-
if not model_id:
|
125
|
-
raise snowml_exceptions.SnowflakeMLException(
|
126
|
-
error_code=error_codes.INVALID_ARGUMENT,
|
127
|
-
original_exception=ValueError(
|
128
|
-
'Must provide a non-empty string for "model_id" when deploying to Snowpark Container Services'
|
129
|
-
),
|
130
|
-
)
|
131
|
-
if not service_func_name:
|
132
|
-
raise snowml_exceptions.SnowflakeMLException(
|
133
|
-
error_code=error_codes.INVALID_ARGUMENT,
|
134
|
-
original_exception=ValueError(
|
135
|
-
'Must provide a non-empty string for "service_func_name"'
|
136
|
-
" when deploying to Snowpark Container Services"
|
137
|
-
),
|
138
|
-
)
|
139
|
-
if not model_zip_stage_path:
|
140
|
-
raise snowml_exceptions.SnowflakeMLException(
|
141
|
-
error_code=error_codes.INVALID_ARGUMENT,
|
142
|
-
original_exception=ValueError(
|
143
|
-
'Must provide a non-empty string for "model_stage_file_path"'
|
144
|
-
" when deploying to Snowpark Container Services"
|
145
|
-
),
|
146
|
-
)
|
147
|
-
if not deployment_stage_path:
|
148
|
-
raise snowml_exceptions.SnowflakeMLException(
|
149
|
-
error_code=error_codes.INVALID_ARGUMENT,
|
150
|
-
original_exception=ValueError(
|
151
|
-
'Must provide a non-empty string for "deployment_stage_path"'
|
152
|
-
" when deploying to Snowpark Container Services"
|
153
|
-
),
|
154
|
-
)
|
155
|
-
|
156
|
-
# Remove full qualified name to avoid double quotes corrupting the service spec
|
157
|
-
model_zip_stage_path = model_zip_stage_path.replace('"', "")
|
158
|
-
deployment_stage_path = deployment_stage_path.replace('"', "")
|
159
|
-
|
160
|
-
assert model_zip_stage_path.startswith("@"), f"stage path should start with @, actual: {model_zip_stage_path}"
|
161
|
-
assert deployment_stage_path.startswith("@"), f"stage path should start with @, actual: {deployment_stage_path}"
|
162
|
-
options = deploy_options.SnowServiceDeployOptions.from_dict(cast(Dict[str, Any], kwargs))
|
163
|
-
|
164
|
-
model_meta_deploy = copy.deepcopy(model_meta)
|
165
|
-
# Set conda-forge as backup channel for SPCS deployment
|
166
|
-
if "conda-forge" not in model_meta_deploy.env._conda_dependencies:
|
167
|
-
model_meta_deploy.env._conda_dependencies["conda-forge"] = []
|
168
|
-
# Snowflake connector needs pyarrow to work correctly.
|
169
|
-
env_utils.append_conda_dependency(
|
170
|
-
model_meta_deploy.env._conda_dependencies,
|
171
|
-
(env_utils.DEFAULT_CHANNEL_NAME, requirements.Requirement("pyarrow")),
|
172
|
-
)
|
173
|
-
if options.use_gpu:
|
174
|
-
# Make mypy happy
|
175
|
-
assert options.num_gpus is not None
|
176
|
-
if model_meta_deploy.env.cuda_version is None:
|
177
|
-
raise snowml_exceptions.SnowflakeMLException(
|
178
|
-
error_code=error_codes.INVALID_ARGUMENT,
|
179
|
-
original_exception=ValueError(
|
180
|
-
"You are requesting GPUs for models that do not use a GPU or does not have CUDA version set."
|
181
|
-
),
|
182
|
-
)
|
183
|
-
if model_meta.env.cuda_version:
|
184
|
-
model_meta_deploy.env.generate_env_for_cuda()
|
185
|
-
else:
|
186
|
-
# If user does not need GPU, we set this copies cuda_version to None, thus when Image builder gets a
|
187
|
-
# not-None cuda_version, it gets to know that GPU is required.
|
188
|
-
model_meta_deploy.env._cuda_version = None
|
189
|
-
|
190
|
-
_validate_compute_pool(session, options=options)
|
191
|
-
|
192
|
-
# TODO[shchen]: SNOW-863701, Explore ways to prevent entire model zip being downloaded during deploy step
|
193
|
-
# (for both warehouse and snowservice deployment)
|
194
|
-
# One alternative is for model registry to duplicate the model metadata and env dependency storage from model
|
195
|
-
# zip so that we don't have to pull down the entire model zip.
|
196
|
-
ss_deployment = SnowServiceDeployment(
|
197
|
-
session=session,
|
198
|
-
model_id=model_id,
|
199
|
-
model_meta=model_meta_deploy,
|
200
|
-
service_func_name=service_func_name,
|
201
|
-
model_zip_stage_path=model_zip_stage_path, # Pass down model_zip_stage_path for service spec file
|
202
|
-
deployment_stage_path=deployment_stage_path,
|
203
|
-
target_method=target_method,
|
204
|
-
options=options,
|
205
|
-
)
|
206
|
-
return ss_deployment.deploy()
|
207
|
-
finally:
|
208
|
-
session.sql(f"ALTER SESSION SET PYTHON_CONNECTOR_QUERY_RESULT_FORMAT = '{prev_format}'").collect()
|
209
|
-
# Preserve the original logging level.
|
210
|
-
snowpark_logger.setLevel(snowpark_log_level)
|
211
|
-
snowflake_connector_logger.setLevel(snowflake_connector_log_level)
|
212
|
-
|
213
|
-
|
214
|
-
def _validate_compute_pool(session: Session, *, options: deploy_options.SnowServiceDeployOptions) -> None:
|
215
|
-
# Remove full qualified name to avoid double quotes, which does not work well in desc compute pool syntax.
|
216
|
-
compute_pool = options.compute_pool.replace('"', "")
|
217
|
-
sql = f"DESC COMPUTE POOL {compute_pool}"
|
218
|
-
result = (
|
219
|
-
query_result_checker.SqlResultValidator(
|
220
|
-
session=session,
|
221
|
-
query=sql,
|
222
|
-
)
|
223
|
-
.has_column("instance_family")
|
224
|
-
.has_column("state")
|
225
|
-
.has_column("auto_resume")
|
226
|
-
.has_dimensions(expected_rows=1)
|
227
|
-
.validate()
|
228
|
-
)
|
229
|
-
|
230
|
-
state = result[0]["state"]
|
231
|
-
auto_resume = bool(result[0]["auto_resume"])
|
232
|
-
|
233
|
-
if state == "SUSPENDED":
|
234
|
-
if not auto_resume:
|
235
|
-
raise snowml_exceptions.SnowflakeMLException(
|
236
|
-
error_code=error_codes.INVALID_SNOWPARK_COMPUTE_POOL,
|
237
|
-
original_exception=RuntimeError(
|
238
|
-
"The compute pool you are requesting to use is suspended without auto-resume enabled"
|
239
|
-
),
|
240
|
-
)
|
241
|
-
|
242
|
-
elif state not in ["STARTING", "ACTIVE", "IDLE"]:
|
243
|
-
raise snowml_exceptions.SnowflakeMLException(
|
244
|
-
error_code=error_codes.INVALID_SNOWPARK_COMPUTE_POOL,
|
245
|
-
original_exception=RuntimeError(
|
246
|
-
"The compute pool you are requesting to use is not in the ACTIVE/IDLE/STARTING status."
|
247
|
-
),
|
248
|
-
)
|
249
|
-
|
250
|
-
if state in ["SUSPENDED", "STARTING"]:
|
251
|
-
logger.warning(f"The compute pool you are requesting is in {state} state. We are waiting it to be ready.")
|
252
|
-
|
253
|
-
if options.use_gpu:
|
254
|
-
assert options.num_gpus is not None
|
255
|
-
request_gpus = options.num_gpus
|
256
|
-
instance_family = result[0]["instance_family"]
|
257
|
-
if instance_family in instance_types.INSTANCE_TYPE_TO_GPU_COUNT:
|
258
|
-
gpu_capacity = instance_types.INSTANCE_TYPE_TO_GPU_COUNT[instance_family]
|
259
|
-
if request_gpus > gpu_capacity:
|
260
|
-
raise snowml_exceptions.SnowflakeMLException(
|
261
|
-
error_code=error_codes.INVALID_SNOWPARK_COMPUTE_POOL,
|
262
|
-
original_exception=RuntimeError(
|
263
|
-
f"GPU request exceeds instance capability; {instance_family} instance type has total "
|
264
|
-
f"capacity of {gpu_capacity} GPU, yet a request was made for {request_gpus} GPUs."
|
265
|
-
),
|
266
|
-
)
|
267
|
-
else:
|
268
|
-
logger.warning(f"Unknown instance type: {instance_family}, skipping GPU validation")
|
269
|
-
|
270
|
-
|
271
|
-
def _get_or_create_image_repo(session: Session, *, service_func_name: str, image_repo: Optional[str] = None) -> str:
|
272
|
-
def _sanitize_dns_url(url: str) -> str:
|
273
|
-
# Align with existing SnowService image registry url standard.
|
274
|
-
return url.lower()
|
275
|
-
|
276
|
-
if image_repo:
|
277
|
-
return _sanitize_dns_url(image_repo)
|
278
|
-
|
279
|
-
try:
|
280
|
-
conn = session._conn._conn
|
281
|
-
# We try to use the same db and schema as the service function locates, as we could retrieve those information
|
282
|
-
# if that is a fully qualified one. If not we use the current session one.
|
283
|
-
(_db, _schema, _) = identifier.parse_schema_level_object_identifier(service_func_name)
|
284
|
-
db = _db if _db is not None else conn._database
|
285
|
-
schema = _schema if _schema is not None else conn._schema
|
286
|
-
assert isinstance(db, str) and isinstance(schema, str)
|
287
|
-
|
288
|
-
client = snowservice_client.SnowServiceClient(session)
|
289
|
-
client.create_image_repo(identifier.get_schema_level_object_identifier(db, schema, constants.SNOWML_IMAGE_REPO))
|
290
|
-
sql = f"SHOW IMAGE REPOSITORIES LIKE '{constants.SNOWML_IMAGE_REPO}' IN SCHEMA {'.'.join([db, schema])}"
|
291
|
-
result = (
|
292
|
-
query_result_checker.SqlResultValidator(
|
293
|
-
session=session,
|
294
|
-
query=sql,
|
295
|
-
)
|
296
|
-
.has_column("repository_url")
|
297
|
-
.has_dimensions(expected_rows=1)
|
298
|
-
.validate()
|
299
|
-
)
|
300
|
-
repository_url = result[0]["repository_url"]
|
301
|
-
return str(repository_url)
|
302
|
-
except Exception as e:
|
303
|
-
raise snowml_exceptions.SnowflakeMLException(
|
304
|
-
error_code=error_codes.INTERNAL_SNOWPARK_CONTAINER_SERVICE_ERROR,
|
305
|
-
original_exception=RuntimeError("Failed to retrieve image repo URL"),
|
306
|
-
) from e
|
307
|
-
|
308
|
-
|
309
|
-
class SnowServiceDeployment:
|
310
|
-
"""
|
311
|
-
Class implementation that encapsulates image build and workflow deployment to SnowService
|
312
|
-
"""
|
313
|
-
|
314
|
-
def __init__(
|
315
|
-
self,
|
316
|
-
session: Session,
|
317
|
-
model_id: str,
|
318
|
-
model_meta: model_meta.ModelMetadata,
|
319
|
-
service_func_name: str,
|
320
|
-
model_zip_stage_path: str,
|
321
|
-
deployment_stage_path: str,
|
322
|
-
target_method: str,
|
323
|
-
options: deploy_options.SnowServiceDeployOptions,
|
324
|
-
) -> None:
|
325
|
-
"""Initialization
|
326
|
-
|
327
|
-
Args:
|
328
|
-
session: Snowpark session
|
329
|
-
model_id: Unique hex string of length 32, provided by model registry; if not provided, auto-generate one for
|
330
|
-
resource naming.The model_id serves as an idempotent key throughout the deployment workflow.
|
331
|
-
model_meta: Model Metadata.
|
332
|
-
service_func_name: The service function name in SnowService associated with the created service.
|
333
|
-
model_zip_stage_path: Path to model zip file in stage.
|
334
|
-
deployment_stage_path: Path to stage containing deployment artifacts.
|
335
|
-
target_method: The name of the target method to be deployed.
|
336
|
-
options: A SnowServiceDeployOptions object containing deployment options.
|
337
|
-
"""
|
338
|
-
|
339
|
-
self.session = session
|
340
|
-
self.id = model_id
|
341
|
-
self.model_meta = model_meta
|
342
|
-
self.service_func_name = service_func_name
|
343
|
-
self.model_zip_stage_path = model_zip_stage_path
|
344
|
-
self.options = options
|
345
|
-
self.target_method = target_method
|
346
|
-
(db, schema, _) = identifier.parse_schema_level_object_identifier(service_func_name)
|
347
|
-
|
348
|
-
self._service_name = identifier.get_schema_level_object_identifier(db, schema, f"service_{model_id}")
|
349
|
-
self._job_name = identifier.get_schema_level_object_identifier(db, schema, f"build_{model_id}")
|
350
|
-
# Spec file and future deployment related artifacts will be stored under {stage}/models/{model_id}
|
351
|
-
self._model_artifact_stage_location = posixpath.join(deployment_stage_path, "models", self.id)
|
352
|
-
self.debug_dir: Optional[str] = None
|
353
|
-
if self.options.debug_mode:
|
354
|
-
self.debug_dir = tempfile.mkdtemp()
|
355
|
-
logger.warning(f"Debug model is enabled, deployment artifacts will be available in {self.debug_dir}")
|
356
|
-
|
357
|
-
def deploy(self) -> type_hints.SnowparkContainerServiceDeployDetails:
|
358
|
-
"""
|
359
|
-
This function triggers image build followed by workflow deployment to SnowService.
|
360
|
-
|
361
|
-
Returns:
|
362
|
-
Deployment details.
|
363
|
-
"""
|
364
|
-
if self.options.prebuilt_snowflake_image:
|
365
|
-
logger.warning(f"Skipped image build. Use prebuilt image: {self.options.prebuilt_snowflake_image}")
|
366
|
-
service_function_sql = self._deploy_workflow(self.options.prebuilt_snowflake_image)
|
367
|
-
else:
|
368
|
-
with _debug_aware_tmp_directory(debug_dir=self.debug_dir) as context_dir:
|
369
|
-
extra_kwargs = {}
|
370
|
-
if self.options.model_in_image:
|
371
|
-
extra_kwargs = {
|
372
|
-
"session": self.session,
|
373
|
-
"model_zip_stage_path": self.model_zip_stage_path,
|
374
|
-
}
|
375
|
-
dc = docker_context.DockerContext(
|
376
|
-
context_dir=context_dir,
|
377
|
-
model_meta=self.model_meta,
|
378
|
-
**extra_kwargs, # type: ignore[arg-type]
|
379
|
-
)
|
380
|
-
dc.build()
|
381
|
-
image_repo = _get_or_create_image_repo(
|
382
|
-
self.session, service_func_name=self.service_func_name, image_repo=self.options.image_repo
|
383
|
-
)
|
384
|
-
full_image_name = self._get_full_image_name(image_repo=image_repo, context_dir=context_dir)
|
385
|
-
registry_client = image_registry_client.ImageRegistryClient(self.session, full_image_name)
|
386
|
-
|
387
|
-
if not self.options.force_image_build and registry_client.image_exists(full_image_name=full_image_name):
|
388
|
-
logger.warning(
|
389
|
-
f"Similar environment detected. Using existing image {full_image_name} to skip image "
|
390
|
-
f"build. To disable this feature, set 'force_image_build=True' in deployment options"
|
391
|
-
)
|
392
|
-
else:
|
393
|
-
logger.warning(
|
394
|
-
"Building the Docker image and deploying to Snowpark Container Service. "
|
395
|
-
"This process may take anywhere from a few minutes to a longer period for GPU-based models."
|
396
|
-
)
|
397
|
-
start = time.time()
|
398
|
-
self._build_and_upload_image(
|
399
|
-
context_dir=context_dir, image_repo=image_repo, full_image_name=full_image_name
|
400
|
-
)
|
401
|
-
end = time.time()
|
402
|
-
logger.info(f"Time taken to build and upload image to registry: {end - start:.2f} seconds")
|
403
|
-
logger.warning(
|
404
|
-
f"Image successfully built! For future model deployments, the image will be reused if "
|
405
|
-
f"possible, saving model deployment time. To enforce using the same image, include "
|
406
|
-
f"'prebuilt_snowflake_image': '{full_image_name}' in the deploy() function's options."
|
407
|
-
)
|
408
|
-
|
409
|
-
# Adding the model name as an additional tag to the existing image, excluding the version to prevent
|
410
|
-
# excessive tags and also due to version not available in current model metadata. This will allow
|
411
|
-
# users to associate images with specific models and perform relevant image registry actions. In the
|
412
|
-
# event that model dependencies change across versions, a new image hash will be computed, resulting in
|
413
|
-
# a new image.
|
414
|
-
try:
|
415
|
-
registry_client.add_tag_to_remote_image(
|
416
|
-
original_full_image_name=full_image_name, new_tag=self.model_meta.name
|
417
|
-
)
|
418
|
-
except Exception as e:
|
419
|
-
# Proceed to the deployment with a warning message.
|
420
|
-
logger.warning(f"Failed to add tag {self.model_meta.name} to image {full_image_name}: {str(e)}")
|
421
|
-
service_function_sql = self._deploy_workflow(full_image_name)
|
422
|
-
|
423
|
-
rows = self.session.sql(f"DESCRIBE SERVICE {self._service_name}").collect()
|
424
|
-
service_info = rows[0].as_dict() if rows and rows[0] else None
|
425
|
-
return type_hints.SnowparkContainerServiceDeployDetails(
|
426
|
-
service_info=service_info,
|
427
|
-
service_function_sql=service_function_sql,
|
428
|
-
)
|
429
|
-
|
430
|
-
def _get_full_image_name(self, image_repo: str, context_dir: str) -> str:
|
431
|
-
"""Return a valid full image name that consists of image name and tag. e.g
|
432
|
-
org-account.registry.snowflakecomputing.com/db/schema/repo/image:latest
|
433
|
-
|
434
|
-
Args:
|
435
|
-
image_repo: image repo path, e.g. org-account.registry.snowflakecomputing.com/db/schema/repo
|
436
|
-
context_dir: the local docker context directory, which consists everything needed to build the docker image.
|
437
|
-
|
438
|
-
Returns:
|
439
|
-
Full image name.
|
440
|
-
"""
|
441
|
-
image_repo = _get_or_create_image_repo(
|
442
|
-
self.session, service_func_name=self.service_func_name, image_repo=self.options.image_repo
|
443
|
-
)
|
444
|
-
|
445
|
-
# We skip "MODEL_METADATA_FILE" as it contains information that will always lead to cache misses. This isn't an
|
446
|
-
# issue because model dependency is also captured in the model env/ folder, which will be hashed. The aim is to
|
447
|
-
# reuse the same Docker image even if the user logs a similar model without new dependencies.
|
448
|
-
docker_context_dir_hash = file_utils.hash_directory(
|
449
|
-
context_dir, ignore_hidden=True, excluded_files=[model_meta.MODEL_METADATA_FILE]
|
450
|
-
)
|
451
|
-
# By default, we associate a 'latest' tag with each of our created images for easy existence checking.
|
452
|
-
# Additional tags are added for readability.
|
453
|
-
return f"{image_repo}/{docker_context_dir_hash}:{constants.LATEST_IMAGE_TAG}"
|
454
|
-
|
455
|
-
def _build_and_upload_image(self, context_dir: str, image_repo: str, full_image_name: str) -> None:
|
456
|
-
"""Handles image build and upload to image registry.
|
457
|
-
|
458
|
-
Args:
|
459
|
-
context_dir: the local docker context directory, which consists everything needed to build the docker image.
|
460
|
-
image_repo: image repo path, e.g. org-account.registry.snowflakecomputing.com/db/schema/repo
|
461
|
-
full_image_name: Full image name consists of image name and image tag.
|
462
|
-
"""
|
463
|
-
image_builder: base_image_builder.ImageBuilder
|
464
|
-
if self.options.enable_remote_image_build:
|
465
|
-
image_builder = server_image_builder.ServerImageBuilder(
|
466
|
-
context_dir=context_dir,
|
467
|
-
full_image_name=full_image_name,
|
468
|
-
image_repo=image_repo,
|
469
|
-
session=self.session,
|
470
|
-
artifact_stage_location=self._model_artifact_stage_location,
|
471
|
-
compute_pool=self.options.compute_pool,
|
472
|
-
job_name=self._job_name,
|
473
|
-
external_access_integrations=self.options.external_access_integrations,
|
474
|
-
)
|
475
|
-
else:
|
476
|
-
image_builder = client_image_builder.ClientImageBuilder(
|
477
|
-
context_dir=context_dir, full_image_name=full_image_name, image_repo=image_repo, session=self.session
|
478
|
-
)
|
479
|
-
image_builder.build_and_upload_image()
|
480
|
-
|
481
|
-
def _prepare_and_upload_artifacts_to_stage(self, image: str) -> None:
|
482
|
-
"""Constructs and upload service spec to stage.
|
483
|
-
|
484
|
-
Args:
|
485
|
-
image: Name of the image to create SnowService container from.
|
486
|
-
"""
|
487
|
-
if self.options.model_in_image:
|
488
|
-
spec_template = (
|
489
|
-
importlib_resources.files(snowservice)
|
490
|
-
.joinpath("templates/service_spec_template_with_model")
|
491
|
-
.read_text("utf-8")
|
492
|
-
)
|
493
|
-
else:
|
494
|
-
spec_template = (
|
495
|
-
importlib_resources.files(snowservice).joinpath("templates/service_spec_template").read_text("utf-8")
|
496
|
-
)
|
497
|
-
|
498
|
-
with _debug_aware_tmp_directory(self.debug_dir) as dir_path:
|
499
|
-
spec_file_path = os.path.join(dir_path, f"{constants.SERVICE_SPEC}.yaml")
|
500
|
-
|
501
|
-
with open(spec_file_path, "w+", encoding="utf-8") as spec_file:
|
502
|
-
assert self.model_zip_stage_path.startswith("@")
|
503
|
-
norm_stage_path = posixpath.normpath(identifier.remove_prefix(self.model_zip_stage_path, "@"))
|
504
|
-
# Ensure model stage path has root prefix as stage mount will it mount it to root.
|
505
|
-
absolute_model_stage_path = os.path.join("/", norm_stage_path)
|
506
|
-
(db, schema, stage, path) = identifier.parse_snowflake_stage_path(norm_stage_path)
|
507
|
-
substitutes = {
|
508
|
-
"image": image,
|
509
|
-
"predict_endpoint_name": constants.PREDICT,
|
510
|
-
"model_stage": identifier.get_schema_level_object_identifier(db, schema, stage),
|
511
|
-
"model_zip_stage_path": absolute_model_stage_path,
|
512
|
-
"inference_server_container_name": constants.INFERENCE_SERVER_CONTAINER,
|
513
|
-
"target_method": self.target_method,
|
514
|
-
"num_workers": self.options.num_workers,
|
515
|
-
"use_gpu": self.options.use_gpu,
|
516
|
-
"enable_ingress": self.options.enable_ingress,
|
517
|
-
}
|
518
|
-
if self.options.model_in_image:
|
519
|
-
del substitutes["model_stage"]
|
520
|
-
del substitutes["model_zip_stage_path"]
|
521
|
-
content = string.Template(spec_template).substitute(substitutes)
|
522
|
-
content_dict = yaml.safe_load(content)
|
523
|
-
if self.options.use_gpu:
|
524
|
-
container = content_dict["spec"]["container"][0]
|
525
|
-
# TODO[shchen]: SNOW-871538, external dependency that only single GPU is supported on SnowService.
|
526
|
-
# GPU limit has to be specified in order to trigger the workload to be run on GPU in SnowService.
|
527
|
-
container["resources"] = {
|
528
|
-
"limits": {"nvidia.com/gpu": self.options.num_gpus},
|
529
|
-
"requests": {"nvidia.com/gpu": self.options.num_gpus},
|
530
|
-
}
|
531
|
-
|
532
|
-
# Make LLM use case sequential
|
533
|
-
if any(
|
534
|
-
model_blob_meta.model_type == "huggingface_pipeline" or model_blob_meta.model_type == "llm"
|
535
|
-
for model_blob_meta in self.model_meta.models.values()
|
536
|
-
):
|
537
|
-
container["env"]["_CONCURRENT_REQUESTS_MAX"] = 1
|
538
|
-
|
539
|
-
yaml.dump(content_dict, spec_file)
|
540
|
-
logger.debug("Create service spec: \n, %s", content_dict)
|
541
|
-
|
542
|
-
self.session.file.put(
|
543
|
-
local_file_name=spec_file_path,
|
544
|
-
stage_location=self._model_artifact_stage_location,
|
545
|
-
auto_compress=False,
|
546
|
-
overwrite=True,
|
547
|
-
)
|
548
|
-
logger.debug(
|
549
|
-
f"Uploaded spec file {os.path.basename(spec_file_path)} " f"to {self._model_artifact_stage_location}"
|
550
|
-
)
|
551
|
-
|
552
|
-
def _get_max_batch_rows(self) -> Optional[int]:
|
553
|
-
# To avoid too large batch in HF LLM case
|
554
|
-
max_batch_rows = None
|
555
|
-
if self.options.use_gpu:
|
556
|
-
for model_blob_meta in self.model_meta.models.values():
|
557
|
-
batch_size = None
|
558
|
-
if model_blob_meta.model_type == "huggingface_pipeline":
|
559
|
-
model_blob_options_hf = cast(
|
560
|
-
model_meta_schema.HuggingFacePipelineModelBlobOptions, model_blob_meta.options
|
561
|
-
)
|
562
|
-
batch_size = model_blob_options_hf["batch_size"]
|
563
|
-
if model_blob_meta.model_type == "llm":
|
564
|
-
model_blob_options_llm = cast(model_meta_schema.LLMModelBlobOptions, model_blob_meta.options)
|
565
|
-
batch_size = model_blob_options_llm["batch_size"]
|
566
|
-
if batch_size:
|
567
|
-
if max_batch_rows is None:
|
568
|
-
max_batch_rows = batch_size
|
569
|
-
else:
|
570
|
-
max_batch_rows = min(batch_size, max_batch_rows)
|
571
|
-
return max_batch_rows
|
572
|
-
|
573
|
-
def _deploy_workflow(self, image: str) -> str:
|
574
|
-
"""This function handles workflow deployment to SnowService with the given image.
|
575
|
-
|
576
|
-
Args:
|
577
|
-
image: Name of the image to create SnowService container from.
|
578
|
-
|
579
|
-
Returns:
|
580
|
-
service function sql
|
581
|
-
"""
|
582
|
-
|
583
|
-
self._prepare_and_upload_artifacts_to_stage(image)
|
584
|
-
client = snowservice_client.SnowServiceClient(self.session)
|
585
|
-
spec_stage_location = posixpath.join(
|
586
|
-
self._model_artifact_stage_location.rstrip("/"), f"{constants.SERVICE_SPEC}.yaml"
|
587
|
-
)
|
588
|
-
client.create_or_replace_service(
|
589
|
-
service_name=self._service_name,
|
590
|
-
compute_pool=self.options.compute_pool,
|
591
|
-
spec_stage_location=spec_stage_location,
|
592
|
-
min_instances=self.options.min_instances,
|
593
|
-
max_instances=self.options.max_instances,
|
594
|
-
external_access_integrations=self.options.external_access_integrations,
|
595
|
-
)
|
596
|
-
logger.info(f"Wait for service {self._service_name} to become ready...")
|
597
|
-
client.block_until_resource_is_ready(
|
598
|
-
resource_name=self._service_name, resource_type=constants.ResourceType.SERVICE
|
599
|
-
)
|
600
|
-
logger.info(f"Service {self._service_name} is ready. Creating service function...")
|
601
|
-
|
602
|
-
spcs_attribution_utils.record_service_start(self.session, self._service_name)
|
603
|
-
|
604
|
-
service_function_sql = client.create_or_replace_service_function(
|
605
|
-
service_func_name=self.service_func_name,
|
606
|
-
service_name=self._service_name,
|
607
|
-
endpoint_name=constants.PREDICT,
|
608
|
-
max_batch_rows=self._get_max_batch_rows(),
|
609
|
-
)
|
610
|
-
logger.info(f"Service function {self.service_func_name} is created. Deployment completed successfully!")
|
611
|
-
return service_function_sql
|