snowflake-ml-python 1.6.2__py3-none-any.whl → 1.6.3__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 +47 -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.3.dist-info}/METADATA +24 -9
- {snowflake_ml_python-1.6.2.dist-info → snowflake_ml_python-1.6.3.dist-info}/RECORD +225 -249
- {snowflake_ml_python-1.6.2.dist-info → snowflake_ml_python-1.6.3.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.3.dist-info}/LICENSE.txt +0 -0
- {snowflake_ml_python-1.6.2.dist-info → snowflake_ml_python-1.6.3.dist-info}/top_level.txt +0 -0
@@ -1,116 +0,0 @@
|
|
1
|
-
import inspect
|
2
|
-
import logging
|
3
|
-
from typing import Any, Dict, List, Optional
|
4
|
-
|
5
|
-
from snowflake.ml._internal.exceptions import (
|
6
|
-
error_codes,
|
7
|
-
exceptions as snowml_exceptions,
|
8
|
-
)
|
9
|
-
from snowflake.ml.model._deploy_client.utils import constants
|
10
|
-
|
11
|
-
logger = logging.getLogger(__name__)
|
12
|
-
|
13
|
-
|
14
|
-
class SnowServiceDeployOptions:
|
15
|
-
def __init__(
|
16
|
-
self,
|
17
|
-
compute_pool: str,
|
18
|
-
*,
|
19
|
-
external_access_integrations: List[str],
|
20
|
-
image_repo: Optional[str] = None,
|
21
|
-
min_instances: Optional[int] = 1,
|
22
|
-
max_instances: Optional[int] = 1,
|
23
|
-
prebuilt_snowflake_image: Optional[str] = None,
|
24
|
-
num_gpus: Optional[int] = 0,
|
25
|
-
num_workers: Optional[int] = None,
|
26
|
-
enable_remote_image_build: Optional[bool] = True,
|
27
|
-
force_image_build: Optional[bool] = False,
|
28
|
-
model_in_image: Optional[bool] = False,
|
29
|
-
debug_mode: Optional[bool] = False,
|
30
|
-
enable_ingress: Optional[bool] = False,
|
31
|
-
) -> None:
|
32
|
-
"""Initialization
|
33
|
-
|
34
|
-
When updated, please ensure the type hint is updated accordingly at: //snowflake/ml/model/type_hints
|
35
|
-
|
36
|
-
Args:
|
37
|
-
compute_pool: SnowService compute pool name. Please refer to official doc for how to create a
|
38
|
-
compute pool:
|
39
|
-
https://docs.snowflake.com/en/developer-guide/snowpark-container-services/working-with-compute-pool
|
40
|
-
external_access_integrations: External Access Integrations name used to build image and deploy the model.
|
41
|
-
Please refer to the doc for how to create an External Access Integrations: https://docs.snowflake.com/
|
42
|
-
developer-guide/snowpark-container-services/additional-considerations-services-jobs
|
43
|
-
#configuring-network-capabilities .
|
44
|
-
To make sure your image could be built, access to the following endpoint must be allowed.
|
45
|
-
docker.com:80, docker.com:443, anaconda.com:80, anaconda.com:443, anaconda.org:80, anaconda.org:443,
|
46
|
-
pypi.org:80, pypi.org:443
|
47
|
-
image_repo: SnowService image repo path. e.g. "<image_registry>/<db>/<schema>/<repo>". Default to auto
|
48
|
-
inferred based on session information.
|
49
|
-
min_instances: Minimum number of service replicas. Default to 1.
|
50
|
-
max_instances: Maximum number of service replicas. Default to 1.
|
51
|
-
prebuilt_snowflake_image: When provided, the image-building step is skipped, and the pre-built image from
|
52
|
-
Snowflake is used as is. This option is for users who consistently use the same image for multiple use
|
53
|
-
cases, allowing faster deployment. The snowflake image used for deployment is logged to the console for
|
54
|
-
future use. Default to None.
|
55
|
-
num_gpus: Number of GPUs to be used for the service. Default to 0.
|
56
|
-
num_workers: Number of workers used for model inference. Please ensure that the number of workers is set
|
57
|
-
lower than the total available memory divided by the size of model to prevent memory-related issues.
|
58
|
-
Default is number of CPU cores * 2 + 1.
|
59
|
-
enable_remote_image_build: When set to True, will enable image build on a remote SnowService job.
|
60
|
-
Default is True.
|
61
|
-
force_image_build: When set to True, an image rebuild will occur. The default is False, which means the
|
62
|
-
system will automatically check whether a previously built image can be reused
|
63
|
-
model_in_image: When set to True, image would container full model weights. The default if False, which
|
64
|
-
means image without model weights and we do stage mount to access weights.
|
65
|
-
debug_mode: When set to True, deployment artifacts will be persisted in a local temp directory.
|
66
|
-
enable_ingress: When set to True, will expose HTTP endpoint for access to the predict method of the created
|
67
|
-
service. Default to False.
|
68
|
-
"""
|
69
|
-
|
70
|
-
self.compute_pool = compute_pool
|
71
|
-
self.image_repo = image_repo
|
72
|
-
self.min_instances = min_instances
|
73
|
-
self.max_instances = max_instances
|
74
|
-
self.prebuilt_snowflake_image = prebuilt_snowflake_image
|
75
|
-
self.num_gpus = num_gpus
|
76
|
-
self.num_workers = num_workers
|
77
|
-
self.enable_remote_image_build = enable_remote_image_build
|
78
|
-
self.force_image_build = force_image_build
|
79
|
-
self.model_in_image = model_in_image
|
80
|
-
self.debug_mode = debug_mode
|
81
|
-
self.enable_ingress = enable_ingress
|
82
|
-
self.external_access_integrations = external_access_integrations
|
83
|
-
|
84
|
-
if self.num_workers is None and self.use_gpu:
|
85
|
-
logger.info("num_workers has been defaulted to 1 when using GPU.")
|
86
|
-
self.num_workers = 1
|
87
|
-
|
88
|
-
@property
|
89
|
-
def use_gpu(self) -> bool:
|
90
|
-
return self.num_gpus is not None and self.num_gpus > 0
|
91
|
-
|
92
|
-
@classmethod
|
93
|
-
def from_dict(cls, options_dict: Dict[str, Any]) -> "SnowServiceDeployOptions":
|
94
|
-
"""Construct SnowServiceDeployOptions instance based from an option dictionary.
|
95
|
-
|
96
|
-
Args:
|
97
|
-
options_dict: The dict containing various deployment options.
|
98
|
-
|
99
|
-
Raises:
|
100
|
-
SnowflakeMLException: When required option is missing.
|
101
|
-
|
102
|
-
Returns:
|
103
|
-
A SnowServiceDeployOptions object
|
104
|
-
"""
|
105
|
-
required_options = [constants.COMPUTE_POOL]
|
106
|
-
missing_keys = [key for key in required_options if options_dict.get(key) is None]
|
107
|
-
if missing_keys:
|
108
|
-
raise snowml_exceptions.SnowflakeMLException(
|
109
|
-
error_code=error_codes.INVALID_ARGUMENT,
|
110
|
-
original_exception=ValueError(
|
111
|
-
f"Must provide options when deploying to Snowpark Container Services: {', '.join(missing_keys)}"
|
112
|
-
),
|
113
|
-
)
|
114
|
-
supported_options_keys = inspect.signature(cls.__init__).parameters.keys()
|
115
|
-
filtered_options = {k: v for k, v in options_dict.items() if k in supported_options_keys}
|
116
|
-
return cls(**filtered_options)
|
@@ -1,28 +0,0 @@
|
|
1
|
-
spec:
|
2
|
-
container:
|
3
|
-
- name: ${inference_server_container_name}
|
4
|
-
image: ${image}
|
5
|
-
env:
|
6
|
-
MODEL_ZIP_STAGE_PATH: ${model_zip_stage_path}
|
7
|
-
TARGET_METHOD: ${target_method}
|
8
|
-
NUM_WORKERS: ${num_workers}
|
9
|
-
SNOWML_USE_GPU: ${use_gpu}
|
10
|
-
readinessProbe:
|
11
|
-
port: 5000
|
12
|
-
path: /health
|
13
|
-
volumeMounts:
|
14
|
-
- name: vol1
|
15
|
-
mountPath: /local/user/vol1
|
16
|
-
- name: stage
|
17
|
-
mountPath: ${model_stage}
|
18
|
-
endpoint:
|
19
|
-
- name: ${predict_endpoint_name}
|
20
|
-
port: 5000
|
21
|
-
public: ${enable_ingress}
|
22
|
-
volume:
|
23
|
-
- name: vol1
|
24
|
-
source: local # only local emptyDir volume is supported
|
25
|
-
- name: stage
|
26
|
-
source: "@${model_stage}"
|
27
|
-
uid: 1000
|
28
|
-
gid: 1000
|
@@ -1,21 +0,0 @@
|
|
1
|
-
spec:
|
2
|
-
container:
|
3
|
-
- name: ${inference_server_container_name}
|
4
|
-
image: ${image}
|
5
|
-
env:
|
6
|
-
TARGET_METHOD: ${target_method}
|
7
|
-
NUM_WORKERS: ${num_workers}
|
8
|
-
SNOWML_USE_GPU: ${use_gpu}
|
9
|
-
readinessProbe:
|
10
|
-
port: 5000
|
11
|
-
path: /health
|
12
|
-
volumeMounts:
|
13
|
-
- name: vol1
|
14
|
-
mountPath: /local/user/vol1
|
15
|
-
endpoint:
|
16
|
-
- name: ${predict_endpoint_name}
|
17
|
-
port: 5000
|
18
|
-
public: ${enable_ingress}
|
19
|
-
volume:
|
20
|
-
- name: vol1
|
21
|
-
source: local # only local emptyDir volume is supported
|
@@ -1,48 +0,0 @@
|
|
1
|
-
from enum import Enum
|
2
|
-
|
3
|
-
|
4
|
-
class ResourceType(Enum):
|
5
|
-
SERVICE = "service"
|
6
|
-
JOB = "job"
|
7
|
-
|
8
|
-
|
9
|
-
class ResourceStatus(Enum):
|
10
|
-
UNKNOWN = "UNKNOWN" # status is unknown because we have not received enough data from K8s yet.
|
11
|
-
PENDING = "PENDING" # resource set is being created, can't be used yet
|
12
|
-
READY = "READY" # resource set has been deployed.
|
13
|
-
DELETING = "DELETING" # resource set is being deleted
|
14
|
-
FAILED = "FAILED" # resource set has failed and cannot be used anymore
|
15
|
-
DONE = "DONE" # resource set has finished running
|
16
|
-
NOT_FOUND = "NOT_FOUND" # not found or deleted
|
17
|
-
INTERNAL_ERROR = "INTERNAL_ERROR" # there was an internal service error.
|
18
|
-
|
19
|
-
|
20
|
-
PREDICT = "predict"
|
21
|
-
STAGE = "stage"
|
22
|
-
COMPUTE_POOL = "compute_pool"
|
23
|
-
MIN_INSTANCES = "min_instances"
|
24
|
-
MAX_INSTANCES = "max_instances"
|
25
|
-
GPU_COUNT = "gpu"
|
26
|
-
OVERRIDDEN_BASE_IMAGE = "image"
|
27
|
-
ENDPOINT = "endpoint"
|
28
|
-
SERVICE_SPEC = "service_spec"
|
29
|
-
INFERENCE_SERVER_CONTAINER = "inference-server"
|
30
|
-
|
31
|
-
"""Image build related constants"""
|
32
|
-
SNOWML_IMAGE_REPO = "snowml_repo"
|
33
|
-
MODEL_DIR = "model_dir"
|
34
|
-
INFERENCE_SERVER_DIR = "inference_server"
|
35
|
-
ENTRYPOINT_SCRIPT = "gunicorn_run.sh"
|
36
|
-
PROD_IMAGE_REGISTRY_DOMAIN = "snowflakecomputing.com"
|
37
|
-
PROD_IMAGE_REGISTRY_SUBDOMAIN = "registry"
|
38
|
-
DEV_IMAGE_REGISTRY_SUBDOMAIN = "registry-dev"
|
39
|
-
MODEL_ENV_FOLDER = "env"
|
40
|
-
CONDA_FILE = "conda.yml"
|
41
|
-
IMAGE_BUILD_JOB_SPEC_TEMPLATE = "image_build_job_spec_template"
|
42
|
-
KANIKO_SHELL_SCRIPT_TEMPLATE = "kaniko_shell_script_template"
|
43
|
-
CONTEXT = "context"
|
44
|
-
KANIKO_SHELL_SCRIPT_NAME = "kaniko_shell_script_fixture.sh"
|
45
|
-
KANIKO_CONTAINER_NAME = "kaniko"
|
46
|
-
LATEST_IMAGE_TAG = "latest"
|
47
|
-
KANIKO_IMAGE = "kaniko-project/executor:v1.16.0-debug"
|
48
|
-
SPCS_MOUNTED_TOKEN_PATH = "/snowflake/session/token"
|
@@ -1,280 +0,0 @@
|
|
1
|
-
import json
|
2
|
-
import logging
|
3
|
-
import textwrap
|
4
|
-
import time
|
5
|
-
from typing import List, Optional
|
6
|
-
|
7
|
-
from snowflake.ml._internal.exceptions import (
|
8
|
-
error_codes,
|
9
|
-
exceptions as snowml_exceptions,
|
10
|
-
)
|
11
|
-
from snowflake.ml._internal.utils import log_stream_processor, uri
|
12
|
-
from snowflake.ml.model._deploy_client.utils import constants
|
13
|
-
from snowflake.snowpark import Session
|
14
|
-
|
15
|
-
logger = logging.getLogger(__name__)
|
16
|
-
|
17
|
-
|
18
|
-
class SnowServiceClient:
|
19
|
-
"""
|
20
|
-
SnowService client implementation: a Python wrapper for SnowService SQL queries.
|
21
|
-
"""
|
22
|
-
|
23
|
-
def __init__(self, session: Session) -> None:
|
24
|
-
"""Initialization
|
25
|
-
|
26
|
-
Args:
|
27
|
-
session: Snowpark session
|
28
|
-
"""
|
29
|
-
self.session = session
|
30
|
-
|
31
|
-
def create_image_repo(self, repo_name: str) -> None:
|
32
|
-
self.session.sql(f"CREATE IMAGE REPOSITORY IF NOT EXISTS {repo_name}").collect()
|
33
|
-
|
34
|
-
def create_or_replace_service(
|
35
|
-
self,
|
36
|
-
service_name: str,
|
37
|
-
compute_pool: str,
|
38
|
-
spec_stage_location: str,
|
39
|
-
external_access_integrations: List[str],
|
40
|
-
*,
|
41
|
-
min_instances: Optional[int] = 1,
|
42
|
-
max_instances: Optional[int] = 1,
|
43
|
-
) -> None:
|
44
|
-
"""Create or replace service. Since SnowService doesn't support the CREATE OR REPLACE service syntax, we will
|
45
|
-
first attempt to drop the service if it exists, and then create the service. Please note that this approach may
|
46
|
-
have side effects due to the lack of transaction support.
|
47
|
-
|
48
|
-
Args:
|
49
|
-
service_name: Name of the service.
|
50
|
-
min_instances: Minimum number of service replicas.
|
51
|
-
max_instances: Maximum number of service replicas.
|
52
|
-
external_access_integrations: EAIs for network connection.
|
53
|
-
compute_pool: Name of the compute pool.
|
54
|
-
spec_stage_location: Stage path for the service spec.
|
55
|
-
"""
|
56
|
-
stage, path = uri.get_stage_and_path(spec_stage_location)
|
57
|
-
self._drop_service_if_exists(service_name)
|
58
|
-
sql = textwrap.dedent(
|
59
|
-
f"""
|
60
|
-
CREATE SERVICE {service_name}
|
61
|
-
IN COMPUTE POOL {compute_pool}
|
62
|
-
FROM {stage}
|
63
|
-
SPEC = '{path}'
|
64
|
-
MIN_INSTANCES={min_instances}
|
65
|
-
MAX_INSTANCES={max_instances}
|
66
|
-
EXTERNAL_ACCESS_INTEGRATIONS = ({', '.join(external_access_integrations)})
|
67
|
-
"""
|
68
|
-
)
|
69
|
-
logger.info(f"Creating service {service_name}")
|
70
|
-
logger.debug(f"Create service with SQL: \n {sql}")
|
71
|
-
self.session.sql(sql).collect()
|
72
|
-
|
73
|
-
def create_job(
|
74
|
-
self, job_name: str, compute_pool: str, spec_stage_location: str, external_access_integrations: List[str]
|
75
|
-
) -> None:
|
76
|
-
"""Execute the job creation SQL command. Note that the job creation is synchronous, hence we execute it in a
|
77
|
-
async way so that we can query the log in the meantime.
|
78
|
-
|
79
|
-
Upon job failure, full job container log will be logged.
|
80
|
-
|
81
|
-
Args:
|
82
|
-
job_name: name of the job
|
83
|
-
compute_pool: name of the compute pool
|
84
|
-
spec_stage_location: path to the stage location where the spec is located at.
|
85
|
-
external_access_integrations: EAIs for network connection.
|
86
|
-
"""
|
87
|
-
stage, path = uri.get_stage_and_path(spec_stage_location)
|
88
|
-
sql = textwrap.dedent(
|
89
|
-
f"""
|
90
|
-
EXECUTE JOB SERVICE
|
91
|
-
IN COMPUTE POOL {compute_pool}
|
92
|
-
FROM {stage}
|
93
|
-
SPECIFICATION_FILE = '{path}'
|
94
|
-
NAME = {job_name}
|
95
|
-
EXTERNAL_ACCESS_INTEGRATIONS = ({', '.join(external_access_integrations)})
|
96
|
-
"""
|
97
|
-
)
|
98
|
-
logger.debug(f"Create job with SQL: \n {sql}")
|
99
|
-
self.session.sql(sql).collect_nowait()
|
100
|
-
self.block_until_resource_is_ready(
|
101
|
-
resource_name=job_name,
|
102
|
-
resource_type=constants.ResourceType.JOB,
|
103
|
-
container_name=constants.KANIKO_CONTAINER_NAME,
|
104
|
-
max_retries=240,
|
105
|
-
retry_interval_secs=15,
|
106
|
-
)
|
107
|
-
|
108
|
-
def _drop_service_if_exists(self, service_name: str) -> None:
|
109
|
-
"""Drop service if it already exists.
|
110
|
-
|
111
|
-
Args:
|
112
|
-
service_name: Name of the service.
|
113
|
-
"""
|
114
|
-
self.session.sql(f"DROP SERVICE IF EXISTS {service_name}").collect()
|
115
|
-
|
116
|
-
def create_or_replace_service_function(
|
117
|
-
self,
|
118
|
-
service_func_name: str,
|
119
|
-
service_name: str,
|
120
|
-
*,
|
121
|
-
endpoint_name: str = constants.PREDICT,
|
122
|
-
path_at_service_endpoint: str = constants.PREDICT,
|
123
|
-
max_batch_rows: Optional[int] = None,
|
124
|
-
) -> str:
|
125
|
-
"""Create or replace service function.
|
126
|
-
|
127
|
-
Args:
|
128
|
-
service_func_name: Name of the service function.
|
129
|
-
service_name: Name of the service.
|
130
|
-
endpoint_name: Name the service endpoint, declared in the service spec, indicating the listening port.
|
131
|
-
path_at_service_endpoint: Specify the path/route at the service endpoint. Multiple paths can exist for a
|
132
|
-
given endpoint. For example, an inference server listening on port 5000 may have paths like "/predict"
|
133
|
-
and "/monitoring
|
134
|
-
max_batch_rows: Specify the MAX_BATCH_ROWS property of the service function, if None, leave unset
|
135
|
-
|
136
|
-
Returns:
|
137
|
-
The actual SQL for service function creation.
|
138
|
-
"""
|
139
|
-
max_batch_rows_sql = ""
|
140
|
-
if max_batch_rows:
|
141
|
-
max_batch_rows_sql = f"MAX_BATCH_ROWS = {max_batch_rows}"
|
142
|
-
|
143
|
-
sql = textwrap.dedent(
|
144
|
-
f"""
|
145
|
-
CREATE OR REPLACE FUNCTION {service_func_name}(input OBJECT)
|
146
|
-
RETURNS OBJECT
|
147
|
-
SERVICE={service_name}
|
148
|
-
ENDPOINT={endpoint_name}
|
149
|
-
{max_batch_rows_sql}
|
150
|
-
AS '/{path_at_service_endpoint}'
|
151
|
-
"""
|
152
|
-
)
|
153
|
-
logger.debug(f"Create service function with SQL: \n {sql}")
|
154
|
-
self.session.sql(sql).collect()
|
155
|
-
logger.debug(f"Successfully created service function: {service_func_name}")
|
156
|
-
return sql
|
157
|
-
|
158
|
-
def block_until_resource_is_ready(
|
159
|
-
self,
|
160
|
-
resource_name: str,
|
161
|
-
resource_type: constants.ResourceType,
|
162
|
-
*,
|
163
|
-
max_retries: int = 180,
|
164
|
-
container_name: str = constants.INFERENCE_SERVER_CONTAINER,
|
165
|
-
retry_interval_secs: int = 10,
|
166
|
-
) -> None:
|
167
|
-
"""Blocks execution until the specified resource is ready.
|
168
|
-
Note that this is a best-effort approach because when launching a service, it's possible for it to initially
|
169
|
-
fail due to a system error. However, SnowService may automatically retry and recover the service, leading to
|
170
|
-
potential false-negative information.
|
171
|
-
|
172
|
-
Args:
|
173
|
-
resource_name: Name of the resource.
|
174
|
-
resource_type: Type of the resource.
|
175
|
-
container_name: The container to query the log from.
|
176
|
-
max_retries: The maximum number of retries to check the resource readiness (default: 60).
|
177
|
-
retry_interval_secs: The number of seconds to wait between each retry (default: 10).
|
178
|
-
|
179
|
-
Raises:
|
180
|
-
SnowflakeMLException: If the resource received the following status [failed, not_found, internal_error,
|
181
|
-
deleting]
|
182
|
-
SnowflakeMLException: If the resource does not reach the ready/done state within the specified number
|
183
|
-
of retries.
|
184
|
-
"""
|
185
|
-
assert resource_type == constants.ResourceType.SERVICE or resource_type == constants.ResourceType.JOB
|
186
|
-
query_command = ""
|
187
|
-
query_command = f"CALL SYSTEM$GET_SERVICE_LOGS('{resource_name}', '0', '{container_name}')"
|
188
|
-
logger.warning(
|
189
|
-
f"Best-effort log streaming from SPCS will be enabled when python logging level is set to INFO."
|
190
|
-
f"Alternatively, you can also query the logs by running the query '{query_command}'"
|
191
|
-
)
|
192
|
-
lsp = log_stream_processor.LogStreamProcessor()
|
193
|
-
|
194
|
-
for attempt_idx in range(max_retries):
|
195
|
-
if logger.level <= logging.INFO:
|
196
|
-
resource_log = self.get_resource_log(
|
197
|
-
resource_name=resource_name,
|
198
|
-
resource_type=resource_type,
|
199
|
-
container_name=container_name,
|
200
|
-
)
|
201
|
-
lsp.process_new_logs(resource_log, log_level=logging.INFO)
|
202
|
-
|
203
|
-
status = self.get_resource_status(resource_name=resource_name)
|
204
|
-
|
205
|
-
if resource_type == constants.ResourceType.JOB and status == constants.ResourceStatus.DONE:
|
206
|
-
return
|
207
|
-
elif resource_type == constants.ResourceType.SERVICE and status == constants.ResourceStatus.READY:
|
208
|
-
return
|
209
|
-
|
210
|
-
if (
|
211
|
-
status
|
212
|
-
in [
|
213
|
-
constants.ResourceStatus.FAILED,
|
214
|
-
constants.ResourceStatus.NOT_FOUND,
|
215
|
-
constants.ResourceStatus.INTERNAL_ERROR,
|
216
|
-
constants.ResourceStatus.DELETING,
|
217
|
-
]
|
218
|
-
or attempt_idx >= max_retries - 1
|
219
|
-
):
|
220
|
-
if logger.level > logging.INFO:
|
221
|
-
resource_log = self.get_resource_log(
|
222
|
-
resource_name=resource_name,
|
223
|
-
resource_type=resource_type,
|
224
|
-
container_name=container_name,
|
225
|
-
)
|
226
|
-
# Show full error log when logging level is above INFO level. For INFO level and below, we already
|
227
|
-
# show the log through logStreamProcessor above.
|
228
|
-
logger.error(resource_log)
|
229
|
-
|
230
|
-
error_message = "failed"
|
231
|
-
if attempt_idx >= max_retries - 1:
|
232
|
-
error_message = "does not reach ready/done status"
|
233
|
-
|
234
|
-
if resource_type == constants.ResourceType.SERVICE:
|
235
|
-
self._drop_service_if_exists(service_name=resource_name)
|
236
|
-
|
237
|
-
raise snowml_exceptions.SnowflakeMLException(
|
238
|
-
error_code=error_codes.INTERNAL_SNOWPARK_CONTAINER_SERVICE_ERROR,
|
239
|
-
original_exception=RuntimeError(
|
240
|
-
f"{resource_type} {resource_name} {error_message}." f"\nStatus: {status if status else ''} \n"
|
241
|
-
),
|
242
|
-
)
|
243
|
-
time.sleep(retry_interval_secs)
|
244
|
-
|
245
|
-
def get_resource_log(
|
246
|
-
self, resource_name: str, resource_type: constants.ResourceType, container_name: str
|
247
|
-
) -> Optional[str]:
|
248
|
-
try:
|
249
|
-
row = self.session.sql(
|
250
|
-
f"CALL SYSTEM$GET_SERVICE_LOGS('{resource_name}', '0', '{container_name}')"
|
251
|
-
).collect()
|
252
|
-
return str(row[0]["SYSTEM$GET_SERVICE_LOGS"])
|
253
|
-
except Exception:
|
254
|
-
return None
|
255
|
-
|
256
|
-
def get_resource_status(self, resource_name: str) -> Optional[constants.ResourceStatus]:
|
257
|
-
"""Get resource status.
|
258
|
-
|
259
|
-
Args:
|
260
|
-
resource_name: Name of the resource.
|
261
|
-
|
262
|
-
Returns:
|
263
|
-
Optional[constants.ResourceStatus]: The status of the resource, or None if the resource status is empty.
|
264
|
-
"""
|
265
|
-
status_func = "SYSTEM$GET_SERVICE_STATUS"
|
266
|
-
try:
|
267
|
-
row = self.session.sql(f"CALL {status_func}('{resource_name}');").collect()
|
268
|
-
except Exception:
|
269
|
-
# Silent fail as SPCS status call is not guaranteed to return in time. Will rely on caller to retry.
|
270
|
-
return None
|
271
|
-
|
272
|
-
resource_metadata = json.loads(row[0][status_func])[0]
|
273
|
-
logger.debug(f"Resource status metadata: {resource_metadata}")
|
274
|
-
if resource_metadata and resource_metadata["status"]:
|
275
|
-
try:
|
276
|
-
status = resource_metadata["status"]
|
277
|
-
return constants.ResourceStatus(status)
|
278
|
-
except ValueError:
|
279
|
-
logger.warning(f"Unknown status returned: {status}")
|
280
|
-
return None
|