snowflake-ml-python 1.3.0__py3-none-any.whl → 1.4.0__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/ml/_internal/file_utils.py +3 -3
- snowflake/ml/_internal/human_readable_id/adjectives.txt +128 -0
- snowflake/ml/_internal/human_readable_id/animals.txt +128 -0
- snowflake/ml/_internal/human_readable_id/hrid_generator.py +40 -0
- snowflake/ml/_internal/human_readable_id/hrid_generator_base.py +135 -0
- snowflake/ml/_internal/telemetry.py +11 -2
- snowflake/ml/_internal/utils/formatting.py +1 -1
- snowflake/ml/feature_store/feature_store.py +15 -106
- snowflake/ml/fileset/sfcfs.py +4 -3
- snowflake/ml/fileset/stage_fs.py +18 -0
- snowflake/ml/model/_api.py +9 -9
- snowflake/ml/model/_client/model/model_version_impl.py +20 -15
- snowflake/ml/model/_deploy_client/image_builds/docker_context.py +3 -9
- snowflake/ml/model/_deploy_client/image_builds/server_image_builder.py +3 -5
- snowflake/ml/model/_deploy_client/snowservice/deploy.py +7 -6
- snowflake/ml/model/_model_composer/model_composer.py +10 -8
- snowflake/ml/model/_model_composer/model_method/function_generator.py +1 -1
- snowflake/ml/model/_model_composer/model_method/infer_table_function.py_template +2 -1
- snowflake/ml/model/_model_composer/model_method/model_method.py +2 -2
- snowflake/ml/model/_model_composer/model_runtime/_runtime_requirements.py +1 -1
- snowflake/ml/model/_packager/model_handlers/_base.py +2 -2
- snowflake/ml/model/_packager/model_handlers/_utils.py +5 -5
- snowflake/ml/model/_packager/model_handlers/custom.py +7 -7
- snowflake/ml/model/_packager/model_handlers/huggingface_pipeline.py +2 -2
- snowflake/ml/model/_packager/model_handlers/llm.py +1 -1
- snowflake/ml/model/_packager/model_handlers/mlflow.py +1 -1
- snowflake/ml/model/_packager/model_handlers/pytorch.py +13 -10
- snowflake/ml/model/_packager/model_handlers/sentence_transformers.py +214 -0
- snowflake/ml/model/_packager/model_handlers/sklearn.py +6 -6
- snowflake/ml/model/_packager/model_handlers/snowmlmodel.py +15 -3
- snowflake/ml/model/_packager/model_handlers/tensorflow.py +8 -8
- snowflake/ml/model/_packager/model_handlers/torchscript.py +7 -7
- snowflake/ml/model/_packager/model_handlers/xgboost.py +8 -8
- snowflake/ml/model/_packager/model_meta/_core_requirements.py +1 -1
- snowflake/ml/model/_packager/model_packager.py +8 -6
- snowflake/ml/model/custom_model.py +3 -1
- snowflake/ml/model/type_hints.py +13 -0
- snowflake/ml/modeling/_internal/estimator_utils.py +61 -1
- snowflake/ml/modeling/_internal/local_implementations/pandas_handlers.py +4 -43
- snowflake/ml/modeling/_internal/local_implementations/pandas_trainer.py +4 -4
- snowflake/ml/modeling/_internal/ml_runtime_implementations/ml_runtime_handlers.py +21 -17
- snowflake/ml/modeling/_internal/model_specifications.py +3 -1
- snowflake/ml/modeling/_internal/model_trainer.py +2 -2
- snowflake/ml/modeling/_internal/snowpark_implementations/distributed_hpo_trainer.py +547 -1
- snowflake/ml/modeling/_internal/snowpark_implementations/snowpark_handlers.py +67 -114
- snowflake/ml/modeling/_internal/snowpark_implementations/snowpark_trainer.py +9 -9
- snowflake/ml/modeling/_internal/transformer_protocols.py +2 -3
- snowflake/ml/modeling/calibration/calibrated_classifier_cv.py +33 -61
- snowflake/ml/modeling/cluster/affinity_propagation.py +33 -61
- snowflake/ml/modeling/cluster/agglomerative_clustering.py +33 -61
- snowflake/ml/modeling/cluster/birch.py +33 -61
- snowflake/ml/modeling/cluster/bisecting_k_means.py +33 -61
- snowflake/ml/modeling/cluster/dbscan.py +33 -61
- snowflake/ml/modeling/cluster/feature_agglomeration.py +33 -61
- snowflake/ml/modeling/cluster/k_means.py +33 -61
- snowflake/ml/modeling/cluster/mean_shift.py +33 -61
- snowflake/ml/modeling/cluster/mini_batch_k_means.py +33 -61
- snowflake/ml/modeling/cluster/optics.py +33 -61
- snowflake/ml/modeling/cluster/spectral_biclustering.py +33 -61
- snowflake/ml/modeling/cluster/spectral_clustering.py +33 -61
- snowflake/ml/modeling/cluster/spectral_coclustering.py +33 -61
- snowflake/ml/modeling/compose/column_transformer.py +33 -61
- snowflake/ml/modeling/compose/transformed_target_regressor.py +33 -61
- snowflake/ml/modeling/covariance/elliptic_envelope.py +33 -61
- snowflake/ml/modeling/covariance/empirical_covariance.py +33 -61
- snowflake/ml/modeling/covariance/graphical_lasso.py +33 -61
- snowflake/ml/modeling/covariance/graphical_lasso_cv.py +33 -61
- snowflake/ml/modeling/covariance/ledoit_wolf.py +33 -61
- snowflake/ml/modeling/covariance/min_cov_det.py +33 -61
- snowflake/ml/modeling/covariance/oas.py +33 -61
- snowflake/ml/modeling/covariance/shrunk_covariance.py +33 -61
- snowflake/ml/modeling/decomposition/dictionary_learning.py +33 -61
- snowflake/ml/modeling/decomposition/factor_analysis.py +33 -61
- snowflake/ml/modeling/decomposition/fast_ica.py +33 -61
- snowflake/ml/modeling/decomposition/incremental_pca.py +33 -61
- snowflake/ml/modeling/decomposition/kernel_pca.py +33 -61
- snowflake/ml/modeling/decomposition/mini_batch_dictionary_learning.py +33 -61
- snowflake/ml/modeling/decomposition/mini_batch_sparse_pca.py +33 -61
- snowflake/ml/modeling/decomposition/pca.py +33 -61
- snowflake/ml/modeling/decomposition/sparse_pca.py +33 -61
- snowflake/ml/modeling/decomposition/truncated_svd.py +33 -61
- snowflake/ml/modeling/discriminant_analysis/linear_discriminant_analysis.py +33 -61
- snowflake/ml/modeling/discriminant_analysis/quadratic_discriminant_analysis.py +33 -61
- snowflake/ml/modeling/ensemble/ada_boost_classifier.py +33 -61
- snowflake/ml/modeling/ensemble/ada_boost_regressor.py +33 -61
- snowflake/ml/modeling/ensemble/bagging_classifier.py +33 -61
- snowflake/ml/modeling/ensemble/bagging_regressor.py +33 -61
- snowflake/ml/modeling/ensemble/extra_trees_classifier.py +33 -61
- snowflake/ml/modeling/ensemble/extra_trees_regressor.py +33 -61
- snowflake/ml/modeling/ensemble/gradient_boosting_classifier.py +33 -61
- snowflake/ml/modeling/ensemble/gradient_boosting_regressor.py +33 -61
- snowflake/ml/modeling/ensemble/hist_gradient_boosting_classifier.py +33 -61
- snowflake/ml/modeling/ensemble/hist_gradient_boosting_regressor.py +33 -61
- snowflake/ml/modeling/ensemble/isolation_forest.py +33 -61
- snowflake/ml/modeling/ensemble/random_forest_classifier.py +33 -61
- snowflake/ml/modeling/ensemble/random_forest_regressor.py +33 -61
- snowflake/ml/modeling/ensemble/stacking_regressor.py +33 -61
- snowflake/ml/modeling/ensemble/voting_classifier.py +33 -61
- snowflake/ml/modeling/ensemble/voting_regressor.py +33 -61
- snowflake/ml/modeling/feature_selection/generic_univariate_select.py +33 -61
- snowflake/ml/modeling/feature_selection/select_fdr.py +33 -61
- snowflake/ml/modeling/feature_selection/select_fpr.py +33 -61
- snowflake/ml/modeling/feature_selection/select_fwe.py +33 -61
- snowflake/ml/modeling/feature_selection/select_k_best.py +33 -61
- snowflake/ml/modeling/feature_selection/select_percentile.py +33 -61
- snowflake/ml/modeling/feature_selection/sequential_feature_selector.py +33 -61
- snowflake/ml/modeling/feature_selection/variance_threshold.py +33 -61
- snowflake/ml/modeling/framework/base.py +55 -5
- snowflake/ml/modeling/gaussian_process/gaussian_process_classifier.py +33 -61
- snowflake/ml/modeling/gaussian_process/gaussian_process_regressor.py +33 -61
- snowflake/ml/modeling/impute/iterative_imputer.py +33 -61
- snowflake/ml/modeling/impute/knn_imputer.py +33 -61
- snowflake/ml/modeling/impute/missing_indicator.py +33 -61
- snowflake/ml/modeling/impute/simple_imputer.py +4 -15
- snowflake/ml/modeling/kernel_approximation/additive_chi2_sampler.py +33 -61
- snowflake/ml/modeling/kernel_approximation/nystroem.py +33 -61
- snowflake/ml/modeling/kernel_approximation/polynomial_count_sketch.py +33 -61
- snowflake/ml/modeling/kernel_approximation/rbf_sampler.py +33 -61
- snowflake/ml/modeling/kernel_approximation/skewed_chi2_sampler.py +33 -61
- snowflake/ml/modeling/kernel_ridge/kernel_ridge.py +33 -61
- snowflake/ml/modeling/lightgbm/lgbm_classifier.py +36 -63
- snowflake/ml/modeling/lightgbm/lgbm_regressor.py +36 -63
- snowflake/ml/modeling/linear_model/ard_regression.py +33 -61
- snowflake/ml/modeling/linear_model/bayesian_ridge.py +33 -61
- snowflake/ml/modeling/linear_model/elastic_net.py +33 -61
- snowflake/ml/modeling/linear_model/elastic_net_cv.py +33 -61
- snowflake/ml/modeling/linear_model/gamma_regressor.py +33 -61
- snowflake/ml/modeling/linear_model/huber_regressor.py +33 -61
- snowflake/ml/modeling/linear_model/lars.py +33 -61
- snowflake/ml/modeling/linear_model/lars_cv.py +33 -61
- snowflake/ml/modeling/linear_model/lasso.py +33 -61
- snowflake/ml/modeling/linear_model/lasso_cv.py +33 -61
- snowflake/ml/modeling/linear_model/lasso_lars.py +33 -61
- snowflake/ml/modeling/linear_model/lasso_lars_cv.py +33 -61
- snowflake/ml/modeling/linear_model/lasso_lars_ic.py +33 -61
- snowflake/ml/modeling/linear_model/linear_regression.py +33 -61
- snowflake/ml/modeling/linear_model/logistic_regression.py +33 -61
- snowflake/ml/modeling/linear_model/logistic_regression_cv.py +33 -61
- snowflake/ml/modeling/linear_model/multi_task_elastic_net.py +33 -61
- snowflake/ml/modeling/linear_model/multi_task_elastic_net_cv.py +33 -61
- snowflake/ml/modeling/linear_model/multi_task_lasso.py +33 -61
- snowflake/ml/modeling/linear_model/multi_task_lasso_cv.py +33 -61
- snowflake/ml/modeling/linear_model/orthogonal_matching_pursuit.py +33 -61
- snowflake/ml/modeling/linear_model/passive_aggressive_classifier.py +33 -61
- snowflake/ml/modeling/linear_model/passive_aggressive_regressor.py +33 -61
- snowflake/ml/modeling/linear_model/perceptron.py +33 -61
- snowflake/ml/modeling/linear_model/poisson_regressor.py +33 -61
- snowflake/ml/modeling/linear_model/ransac_regressor.py +33 -61
- snowflake/ml/modeling/linear_model/ridge.py +33 -61
- snowflake/ml/modeling/linear_model/ridge_classifier.py +33 -61
- snowflake/ml/modeling/linear_model/ridge_classifier_cv.py +33 -61
- snowflake/ml/modeling/linear_model/ridge_cv.py +33 -61
- snowflake/ml/modeling/linear_model/sgd_classifier.py +33 -61
- snowflake/ml/modeling/linear_model/sgd_one_class_svm.py +33 -61
- snowflake/ml/modeling/linear_model/sgd_regressor.py +33 -61
- snowflake/ml/modeling/linear_model/theil_sen_regressor.py +33 -61
- snowflake/ml/modeling/linear_model/tweedie_regressor.py +33 -61
- snowflake/ml/modeling/manifold/isomap.py +33 -61
- snowflake/ml/modeling/manifold/mds.py +33 -61
- snowflake/ml/modeling/manifold/spectral_embedding.py +33 -61
- snowflake/ml/modeling/manifold/tsne.py +33 -61
- snowflake/ml/modeling/mixture/bayesian_gaussian_mixture.py +33 -61
- snowflake/ml/modeling/mixture/gaussian_mixture.py +33 -61
- snowflake/ml/modeling/model_selection/grid_search_cv.py +39 -57
- snowflake/ml/modeling/model_selection/randomized_search_cv.py +26 -57
- snowflake/ml/modeling/multiclass/one_vs_one_classifier.py +33 -61
- snowflake/ml/modeling/multiclass/one_vs_rest_classifier.py +33 -61
- snowflake/ml/modeling/multiclass/output_code_classifier.py +33 -61
- snowflake/ml/modeling/naive_bayes/bernoulli_nb.py +33 -61
- snowflake/ml/modeling/naive_bayes/categorical_nb.py +33 -61
- snowflake/ml/modeling/naive_bayes/complement_nb.py +33 -61
- snowflake/ml/modeling/naive_bayes/gaussian_nb.py +33 -61
- snowflake/ml/modeling/naive_bayes/multinomial_nb.py +33 -61
- snowflake/ml/modeling/neighbors/k_neighbors_classifier.py +33 -61
- snowflake/ml/modeling/neighbors/k_neighbors_regressor.py +33 -61
- snowflake/ml/modeling/neighbors/kernel_density.py +33 -61
- snowflake/ml/modeling/neighbors/local_outlier_factor.py +33 -61
- snowflake/ml/modeling/neighbors/nearest_centroid.py +33 -61
- snowflake/ml/modeling/neighbors/nearest_neighbors.py +33 -61
- snowflake/ml/modeling/neighbors/neighborhood_components_analysis.py +33 -61
- snowflake/ml/modeling/neighbors/radius_neighbors_classifier.py +33 -61
- snowflake/ml/modeling/neighbors/radius_neighbors_regressor.py +33 -61
- snowflake/ml/modeling/neural_network/bernoulli_rbm.py +33 -61
- snowflake/ml/modeling/neural_network/mlp_classifier.py +33 -61
- snowflake/ml/modeling/neural_network/mlp_regressor.py +33 -61
- snowflake/ml/modeling/preprocessing/polynomial_features.py +33 -61
- snowflake/ml/modeling/semi_supervised/label_propagation.py +33 -61
- snowflake/ml/modeling/semi_supervised/label_spreading.py +33 -61
- snowflake/ml/modeling/svm/linear_svc.py +33 -61
- snowflake/ml/modeling/svm/linear_svr.py +33 -61
- snowflake/ml/modeling/svm/nu_svc.py +33 -61
- snowflake/ml/modeling/svm/nu_svr.py +33 -61
- snowflake/ml/modeling/svm/svc.py +33 -61
- snowflake/ml/modeling/svm/svr.py +33 -61
- snowflake/ml/modeling/tree/decision_tree_classifier.py +33 -61
- snowflake/ml/modeling/tree/decision_tree_regressor.py +33 -61
- snowflake/ml/modeling/tree/extra_tree_classifier.py +33 -61
- snowflake/ml/modeling/tree/extra_tree_regressor.py +33 -61
- snowflake/ml/modeling/xgboost/xgb_classifier.py +33 -61
- snowflake/ml/modeling/xgboost/xgb_regressor.py +33 -61
- snowflake/ml/modeling/xgboost/xgbrf_classifier.py +33 -61
- snowflake/ml/modeling/xgboost/xgbrf_regressor.py +33 -61
- snowflake/ml/registry/_manager/model_manager.py +6 -2
- snowflake/ml/registry/model_registry.py +100 -27
- snowflake/ml/registry/registry.py +6 -2
- snowflake/ml/version.py +1 -1
- {snowflake_ml_python-1.3.0.dist-info → snowflake_ml_python-1.4.0.dist-info}/METADATA +43 -7
- {snowflake_ml_python-1.3.0.dist-info → snowflake_ml_python-1.4.0.dist-info}/RECORD +211 -206
- {snowflake_ml_python-1.3.0.dist-info → snowflake_ml_python-1.4.0.dist-info}/LICENSE.txt +0 -0
- {snowflake_ml_python-1.3.0.dist-info → snowflake_ml_python-1.4.0.dist-info}/WHEEL +0 -0
- {snowflake_ml_python-1.3.0.dist-info → snowflake_ml_python-1.4.0.dist-info}/top_level.txt +0 -0
snowflake/ml/fileset/stage_fs.py
CHANGED
@@ -75,6 +75,12 @@ class SFStageFileSystem(fsspec.AbstractFileSystem):
|
|
75
75
|
-74.00688,40.73049,-74.00563,40.70676,2\n'
|
76
76
|
"""
|
77
77
|
|
78
|
+
# Cached state marking whether we should use Snowpark file download instead of pre-signed URLs:
|
79
|
+
# None -> Try pre-signed URL access, fall back to file download
|
80
|
+
# True -> Use file download path without trying pre-signed URL access
|
81
|
+
# False -> Use pre-signed URL access, skip download fallback on failure
|
82
|
+
_USE_FALLBACK_FILE_ACCESS = None
|
83
|
+
|
78
84
|
def __init__(
|
79
85
|
self,
|
80
86
|
*,
|
@@ -227,6 +233,8 @@ class SFStageFileSystem(fsspec.AbstractFileSystem):
|
|
227
233
|
SnowflakeMLException: An error occurred when the given path points to a file that cannot be found.
|
228
234
|
"""
|
229
235
|
path = path.lstrip("/")
|
236
|
+
if self._USE_FALLBACK_FILE_ACCESS:
|
237
|
+
return self._session.file.get_stream(f"{self.stage_name}/{path}")
|
230
238
|
cached_presigned_url = self._url_cache.get(path, None)
|
231
239
|
if not cached_presigned_url:
|
232
240
|
res = self._fetch_presigned_urls([path])
|
@@ -242,6 +250,16 @@ class SFStageFileSystem(fsspec.AbstractFileSystem):
|
|
242
250
|
try:
|
243
251
|
return self._fs._open(url, mode=mode, **kwargs)
|
244
252
|
except FileNotFoundError:
|
253
|
+
# Enable fallback if _USE_FALLBACK_FILE_ACCESS is True or None; set to False to disable
|
254
|
+
if self._USE_FALLBACK_FILE_ACCESS != False: # noqa: E712
|
255
|
+
try:
|
256
|
+
# Try falling back to Snowpark file read if presigned URL access failed
|
257
|
+
# If fallback is successful, most likely in sproc without External Access Integration
|
258
|
+
content = self._session.file.get_stream(f"{self.stage_name}/{path}")
|
259
|
+
self._USE_FALLBACK_FILE_ACCESS = True
|
260
|
+
return content
|
261
|
+
except Exception:
|
262
|
+
pass
|
245
263
|
raise snowml_exceptions.SnowflakeMLException(
|
246
264
|
error_code=error_codes.SNOWML_NOT_FOUND,
|
247
265
|
original_exception=fileset_errors.StageFileNotFoundError(f"Stage file {path} doesn't exist."),
|
snowflake/ml/model/_api.py
CHANGED
@@ -108,7 +108,7 @@ def save_model(
|
|
108
108
|
model: model_types.SupportedRequireSignatureModelType,
|
109
109
|
session: Session,
|
110
110
|
stage_path: str,
|
111
|
-
|
111
|
+
sample_input_data: model_types.SupportedDataType,
|
112
112
|
metadata: Optional[Dict[str, str]] = None,
|
113
113
|
conda_dependencies: Optional[List[str]] = None,
|
114
114
|
pip_requirements: Optional[List[str]] = None,
|
@@ -125,7 +125,7 @@ def save_model(
|
|
125
125
|
model: Model object.
|
126
126
|
session: Snowpark connection session.
|
127
127
|
stage_path: Path to the stage where model will be saved.
|
128
|
-
|
128
|
+
sample_input_data: Sample input data to infer the model signatures from.
|
129
129
|
metadata: Model metadata.
|
130
130
|
conda_dependencies: List of Conda package specs. Use "[channel::]package [operator version]" syntax to specify
|
131
131
|
a dependency. It is a recommended way to specify your dependencies using conda. When channel is not
|
@@ -149,7 +149,7 @@ def save_model(
|
|
149
149
|
session: Session,
|
150
150
|
stage_path: str,
|
151
151
|
signatures: Optional[Dict[str, model_signature.ModelSignature]] = None,
|
152
|
-
|
152
|
+
sample_input_data: Optional[model_types.SupportedDataType] = None,
|
153
153
|
metadata: Optional[Dict[str, str]] = None,
|
154
154
|
conda_dependencies: Optional[List[str]] = None,
|
155
155
|
pip_requirements: Optional[List[str]] = None,
|
@@ -165,11 +165,11 @@ def save_model(
|
|
165
165
|
model: Model object.
|
166
166
|
session: Snowpark connection session.
|
167
167
|
stage_path: Path to the stage where model will be saved.
|
168
|
-
signatures: Model data signatures for inputs and output for every target methods. If it is None,
|
169
|
-
would be used to infer the signatures if it is a local (non-SnowML modeling model).
|
170
|
-
If not None,
|
171
|
-
|
172
|
-
if it is a local (non-SnowML modeling model). If not None, signatures should not be specified.
|
168
|
+
signatures: Model data signatures for inputs and output for every target methods. If it is None,
|
169
|
+
sample_input_data would be used to infer the signatures if it is a local (non-SnowML modeling model).
|
170
|
+
If not None, sample_input_data should not be specified. Defaults to None.
|
171
|
+
sample_input_data: Sample input data to infer the model signatures from. If it is None, signatures must be
|
172
|
+
specified if it is a local (non-SnowML modeling model). If not None, signatures should not be specified.
|
173
173
|
Defaults to None.
|
174
174
|
metadata: Model metadata.
|
175
175
|
conda_dependencies: List of Conda package specs. Use "[channel::]package [operator version]" syntax to specify
|
@@ -196,7 +196,7 @@ def save_model(
|
|
196
196
|
name=name,
|
197
197
|
model=model,
|
198
198
|
signatures=signatures,
|
199
|
-
|
199
|
+
sample_input_data=sample_input_data,
|
200
200
|
metadata=metadata,
|
201
201
|
conda_dependencies=conda_dependencies,
|
202
202
|
pip_requirements=pip_requirements,
|
@@ -21,6 +21,7 @@ class ModelVersion:
|
|
21
21
|
_model_ops: model_ops.ModelOperator
|
22
22
|
_model_name: sql_identifier.SqlIdentifier
|
23
23
|
_version_name: sql_identifier.SqlIdentifier
|
24
|
+
_functions: List[model_manifest_schema.ModelFunctionInfo]
|
24
25
|
|
25
26
|
def __init__(self) -> None:
|
26
27
|
raise RuntimeError("ModelVersion's initializer is not meant to be used. Use `version` from model instead.")
|
@@ -37,6 +38,7 @@ class ModelVersion:
|
|
37
38
|
self._model_ops = model_ops
|
38
39
|
self._model_name = model_name
|
39
40
|
self._version_name = version_name
|
41
|
+
self._functions = self._get_functions()
|
40
42
|
return self
|
41
43
|
|
42
44
|
def __eq__(self, __value: object) -> bool:
|
@@ -239,20 +241,7 @@ class ModelVersion:
|
|
239
241
|
return_functions_info.append(fi)
|
240
242
|
return return_functions_info
|
241
243
|
|
242
|
-
|
243
|
-
project=_TELEMETRY_PROJECT,
|
244
|
-
subproject=_TELEMETRY_SUBPROJECT,
|
245
|
-
)
|
246
|
-
def show_functions(self) -> List[model_manifest_schema.ModelFunctionInfo]:
|
247
|
-
"""Show all functions information in a model version that is callable.
|
248
|
-
|
249
|
-
Returns:
|
250
|
-
A list of ModelFunctionInfo objects containing the following information:
|
251
|
-
|
252
|
-
- name: The name of the function to be called (both in SQL and in Python SDK).
|
253
|
-
- target_method: The original method name in the logged Python object.
|
254
|
-
- signature: Python signature of the original method.
|
255
|
-
"""
|
244
|
+
def _get_functions(self) -> List[model_manifest_schema.ModelFunctionInfo]:
|
256
245
|
statement_params = telemetry.get_statement_params(
|
257
246
|
project=_TELEMETRY_PROJECT,
|
258
247
|
subproject=_TELEMETRY_SUBPROJECT,
|
@@ -274,6 +263,22 @@ class ModelVersion:
|
|
274
263
|
except (NotImplementedError, ValueError, connector.DataError):
|
275
264
|
return self._legacy_show_functions()
|
276
265
|
|
266
|
+
@telemetry.send_api_usage_telemetry(
|
267
|
+
project=_TELEMETRY_PROJECT,
|
268
|
+
subproject=_TELEMETRY_SUBPROJECT,
|
269
|
+
)
|
270
|
+
def show_functions(self) -> List[model_manifest_schema.ModelFunctionInfo]:
|
271
|
+
"""Show all functions information in a model version that is callable.
|
272
|
+
|
273
|
+
Returns:
|
274
|
+
A list of ModelFunctionInfo objects containing the following information:
|
275
|
+
|
276
|
+
- name: The name of the function to be called (both in SQL and in Python SDK).
|
277
|
+
- target_method: The original method name in the logged Python object.
|
278
|
+
- signature: Python signature of the original method.
|
279
|
+
"""
|
280
|
+
return self._functions
|
281
|
+
|
277
282
|
@telemetry.send_api_usage_telemetry(
|
278
283
|
project=_TELEMETRY_PROJECT,
|
279
284
|
subproject=_TELEMETRY_SUBPROJECT,
|
@@ -306,7 +311,7 @@ class ModelVersion:
|
|
306
311
|
subproject=_TELEMETRY_SUBPROJECT,
|
307
312
|
)
|
308
313
|
|
309
|
-
functions: List[model_manifest_schema.ModelFunctionInfo] = self.
|
314
|
+
functions: List[model_manifest_schema.ModelFunctionInfo] = self._functions
|
310
315
|
if function_name:
|
311
316
|
req_method_name = sql_identifier.SqlIdentifier(function_name).identifier()
|
312
317
|
find_method: Callable[[model_manifest_schema.ModelFunctionInfo], bool] = (
|
@@ -52,9 +52,7 @@ class DockerContext:
|
|
52
52
|
|
53
53
|
def _copy_entrypoint_script_to_docker_context(self) -> None:
|
54
54
|
"""Copy gunicorn_run.sh entrypoint to docker context directory."""
|
55
|
-
script_path = importlib_resources.files(image_builds).joinpath(
|
56
|
-
constants.ENTRYPOINT_SCRIPT
|
57
|
-
)
|
55
|
+
script_path = importlib_resources.files(image_builds).joinpath(constants.ENTRYPOINT_SCRIPT)
|
58
56
|
target_path = os.path.join(self.context_dir, constants.ENTRYPOINT_SCRIPT)
|
59
57
|
|
60
58
|
with open(script_path, encoding="utf-8") as source_file, file_utils.open_file(target_path, "w") as target_file:
|
@@ -72,9 +70,7 @@ class DockerContext:
|
|
72
70
|
"""
|
73
71
|
docker_file_path = os.path.join(self.context_dir, "Dockerfile")
|
74
72
|
docker_file_template = (
|
75
|
-
importlib_resources.files(image_builds)
|
76
|
-
.joinpath("templates/dockerfile_template") # type: ignore[no-untyped-call]
|
77
|
-
.read_text("utf-8")
|
73
|
+
importlib_resources.files(image_builds).joinpath("templates/dockerfile_template").read_text("utf-8")
|
78
74
|
)
|
79
75
|
|
80
76
|
if self.model_zip_stage_path is not None:
|
@@ -123,9 +119,7 @@ class DockerContext:
|
|
123
119
|
server code.
|
124
120
|
"""
|
125
121
|
with importlib_resources.as_file(
|
126
|
-
importlib_resources.files(image_builds).joinpath(
|
127
|
-
constants.INFERENCE_SERVER_DIR
|
128
|
-
)
|
122
|
+
importlib_resources.files(image_builds).joinpath(constants.INFERENCE_SERVER_DIR)
|
129
123
|
) as inference_server_folder_path:
|
130
124
|
destination_folder_path = os.path.join(self.context_dir, constants.INFERENCE_SERVER_DIR)
|
131
125
|
ignore_patterns = shutil.ignore_patterns("BUILD.bazel", "*test.py", "*.\\.*", "__pycache__")
|
@@ -114,7 +114,7 @@ class ServerImageBuilder(base_image_builder.ImageBuilder):
|
|
114
114
|
"""
|
115
115
|
kaniko_shell_script_template = (
|
116
116
|
importlib_resources.files(image_builds)
|
117
|
-
.joinpath(f"templates/{constants.KANIKO_SHELL_SCRIPT_TEMPLATE}")
|
117
|
+
.joinpath(f"templates/{constants.KANIKO_SHELL_SCRIPT_TEMPLATE}")
|
118
118
|
.read_text("utf-8")
|
119
119
|
)
|
120
120
|
|
@@ -170,13 +170,11 @@ class ServerImageBuilder(base_image_builder.ImageBuilder):
|
|
170
170
|
|
171
171
|
spec_template = (
|
172
172
|
importlib_resources.files(image_builds)
|
173
|
-
.joinpath(f"templates/{constants.IMAGE_BUILD_JOB_SPEC_TEMPLATE}")
|
173
|
+
.joinpath(f"templates/{constants.IMAGE_BUILD_JOB_SPEC_TEMPLATE}")
|
174
174
|
.read_text("utf-8")
|
175
175
|
)
|
176
176
|
|
177
|
-
spec_file_path = os.path.join(
|
178
|
-
os.path.dirname(self.context_dir), f"{constants.IMAGE_BUILD_JOB_SPEC_TEMPLATE}.yaml"
|
179
|
-
)
|
177
|
+
spec_file_path = os.path.join(self.context_dir, f"{constants.IMAGE_BUILD_JOB_SPEC_TEMPLATE}.yaml")
|
180
178
|
|
181
179
|
with file_utils.open_file(spec_file_path, "w+") as spec_file:
|
182
180
|
assert self.artifact_stage_location.startswith("@")
|
@@ -239,14 +239,17 @@ def _validate_compute_pool(session: Session, *, options: deploy_options.SnowServ
|
|
239
239
|
),
|
240
240
|
)
|
241
241
|
|
242
|
-
elif state not in ["ACTIVE", "IDLE"]:
|
242
|
+
elif state not in ["STARTING", "ACTIVE", "IDLE"]:
|
243
243
|
raise snowml_exceptions.SnowflakeMLException(
|
244
244
|
error_code=error_codes.INVALID_SNOWPARK_COMPUTE_POOL,
|
245
245
|
original_exception=RuntimeError(
|
246
|
-
"The compute pool you are requesting to use is not in the ACTIVE/IDLE status."
|
246
|
+
"The compute pool you are requesting to use is not in the ACTIVE/IDLE/STARTING status."
|
247
247
|
),
|
248
248
|
)
|
249
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
|
+
|
250
253
|
if options.use_gpu:
|
251
254
|
assert options.num_gpus is not None
|
252
255
|
request_gpus = options.num_gpus
|
@@ -482,14 +485,12 @@ class SnowServiceDeployment:
|
|
482
485
|
if self.options.model_in_image:
|
483
486
|
spec_template = (
|
484
487
|
importlib_resources.files(snowservice)
|
485
|
-
.joinpath("templates/service_spec_template_with_model")
|
488
|
+
.joinpath("templates/service_spec_template_with_model")
|
486
489
|
.read_text("utf-8")
|
487
490
|
)
|
488
491
|
else:
|
489
492
|
spec_template = (
|
490
|
-
importlib_resources.files(snowservice)
|
491
|
-
.joinpath("templates/service_spec_template") # type: ignore[no-untyped-call]
|
492
|
-
.read_text("utf-8")
|
493
|
+
importlib_resources.files(snowservice).joinpath("templates/service_spec_template").read_text("utf-8")
|
493
494
|
)
|
494
495
|
|
495
496
|
with _debug_aware_tmp_directory(self.debug_dir) as dir_path:
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import glob
|
2
2
|
import pathlib
|
3
3
|
import tempfile
|
4
|
+
import uuid
|
4
5
|
import zipfile
|
5
6
|
from types import ModuleType
|
6
7
|
from typing import Any, Dict, List, Optional
|
@@ -28,10 +29,9 @@ class ModelComposer:
|
|
28
29
|
packager: A ModelPackager object managing the (un)packaging of a Snowflake Native Model in the MODEL object.
|
29
30
|
|
30
31
|
_packager_workspace_path: A local path created from packager where it will dump all files there and ModelModel
|
31
|
-
will zip it. This would not required if we make directory import work.
|
32
|
+
will zip it. This would not be required if we make directory import work.
|
32
33
|
"""
|
33
34
|
|
34
|
-
MODEL_FILE_REL_PATH = "model.zip"
|
35
35
|
MODEL_DIR_REL_PATH = "model"
|
36
36
|
|
37
37
|
def __init__(
|
@@ -50,6 +50,8 @@ class ModelComposer:
|
|
50
50
|
self.packager = model_packager.ModelPackager(local_dir_path=str(self._packager_workspace_path))
|
51
51
|
self.manifest = model_manifest.ModelManifest(workspace_path=self.workspace_path)
|
52
52
|
|
53
|
+
self.model_file_rel_path = f"model-{uuid.uuid4().hex}.zip"
|
54
|
+
|
53
55
|
self._statement_params = statement_params
|
54
56
|
|
55
57
|
def __del__(self) -> None:
|
@@ -66,11 +68,11 @@ class ModelComposer:
|
|
66
68
|
|
67
69
|
@property
|
68
70
|
def model_stage_path(self) -> str:
|
69
|
-
return (self.stage_path /
|
71
|
+
return (self.stage_path / self.model_file_rel_path).as_posix()
|
70
72
|
|
71
73
|
@property
|
72
74
|
def model_local_path(self) -> str:
|
73
|
-
return str(self.workspace_path /
|
75
|
+
return str(self.workspace_path / self.model_file_rel_path)
|
74
76
|
|
75
77
|
def save(
|
76
78
|
self,
|
@@ -78,7 +80,7 @@ class ModelComposer:
|
|
78
80
|
name: str,
|
79
81
|
model: model_types.SupportedModelType,
|
80
82
|
signatures: Optional[Dict[str, model_signature.ModelSignature]] = None,
|
81
|
-
|
83
|
+
sample_input_data: Optional[model_types.SupportedDataType] = None,
|
82
84
|
metadata: Optional[Dict[str, str]] = None,
|
83
85
|
conda_dependencies: Optional[List[str]] = None,
|
84
86
|
pip_requirements: Optional[List[str]] = None,
|
@@ -106,7 +108,7 @@ class ModelComposer:
|
|
106
108
|
name=name,
|
107
109
|
model=model,
|
108
110
|
signatures=signatures,
|
109
|
-
|
111
|
+
sample_input_data=sample_input_data,
|
110
112
|
metadata=metadata,
|
111
113
|
conda_dependencies=conda_dependencies,
|
112
114
|
pip_requirements=pip_requirements,
|
@@ -130,7 +132,7 @@ class ModelComposer:
|
|
130
132
|
self.manifest.save(
|
131
133
|
session=self.session,
|
132
134
|
model_meta=self.packager.meta,
|
133
|
-
model_file_rel_path=pathlib.PurePosixPath(
|
135
|
+
model_file_rel_path=pathlib.PurePosixPath(self.model_file_rel_path),
|
134
136
|
options=options,
|
135
137
|
)
|
136
138
|
|
@@ -156,7 +158,7 @@ class ModelComposer:
|
|
156
158
|
|
157
159
|
# TODO (Server-side Model Rollout): Remove this section.
|
158
160
|
model_zip_path = pathlib.Path(glob.glob(str(self.workspace_path / "*.zip"))[0])
|
159
|
-
|
161
|
+
self.model_file_rel_path = str(model_zip_path.relative_to(self.workspace_path))
|
160
162
|
|
161
163
|
with zipfile.ZipFile(self.model_local_path, mode="r", compression=zipfile.ZIP_DEFLATED) as zf:
|
162
164
|
zf.extractall(path=self._packager_workspace_path)
|
@@ -72,5 +72,6 @@ dtype_map = {{feature.name: feature.as_dtype() for feature in features}}
|
|
72
72
|
|
73
73
|
# Actual table function
|
74
74
|
class {function_name}:
|
75
|
-
|
75
|
+
@vectorized(input=pd.DataFrame)
|
76
|
+
def end_partition(self, df: pd.DataFrame) -> pd.DataFrame:
|
76
77
|
return runner(df)
|
@@ -33,8 +33,8 @@ def get_model_method_options_from_options(
|
|
33
33
|
options: type_hints.ModelSaveOption, target_method: str
|
34
34
|
) -> ModelMethodOptions:
|
35
35
|
method_option = options.get("method_options", {}).get(target_method, {})
|
36
|
-
|
37
|
-
function_type = method_option.get("function_type",
|
36
|
+
global_function_type = options.get("function_type", ModelMethodFunctionTypes.FUNCTION.value)
|
37
|
+
function_type = method_option.get("function_type", global_function_type)
|
38
38
|
if function_type not in [function_type.value for function_type in ModelMethodFunctionTypes]:
|
39
39
|
raise NotImplementedError
|
40
40
|
|
@@ -48,7 +48,7 @@ class _BaseModelHandlerProtocol(Protocol[model_types._ModelType]):
|
|
48
48
|
model: model_types._ModelType,
|
49
49
|
model_meta: model_meta.ModelMetadata,
|
50
50
|
model_blobs_dir_path: str,
|
51
|
-
|
51
|
+
sample_input_data: Optional[model_types.SupportedDataType] = None,
|
52
52
|
is_sub_model: Optional[bool] = False,
|
53
53
|
**kwargs: Unpack[model_types.BaseModelSaveOption],
|
54
54
|
) -> None:
|
@@ -59,7 +59,7 @@ class _BaseModelHandlerProtocol(Protocol[model_types._ModelType]):
|
|
59
59
|
model: The model object.
|
60
60
|
model_meta: The model metadata.
|
61
61
|
model_blobs_dir_path: Directory path to the model.
|
62
|
-
|
62
|
+
sample_input_data: Sample input to infer the signatures from.
|
63
63
|
is_sub_model: Flag to show if it is a sub model, a sub model does not need signature.
|
64
64
|
kwargs: Additional saving options.
|
65
65
|
|
@@ -14,19 +14,19 @@ def validate_signature(
|
|
14
14
|
model: model_types.SupportedRequireSignatureModelType,
|
15
15
|
model_meta: model_meta.ModelMetadata,
|
16
16
|
target_methods: Iterable[str],
|
17
|
-
|
17
|
+
sample_input_data: Optional[model_types.SupportedDataType],
|
18
18
|
get_prediction_fn: Callable[[str, model_types.SupportedLocalDataType], model_types.SupportedLocalDataType],
|
19
19
|
) -> model_meta.ModelMetadata:
|
20
20
|
if model_meta.signatures:
|
21
21
|
validate_target_methods(model, list(model_meta.signatures.keys()))
|
22
22
|
return model_meta
|
23
23
|
|
24
|
-
# In this case
|
24
|
+
# In this case sample_input_data should be available, because of the check in save_model.
|
25
25
|
assert (
|
26
|
-
|
26
|
+
sample_input_data is not None
|
27
27
|
), "Model signature and sample input are None at the same time. This should not happen with local model."
|
28
|
-
trunc_sample_input = model_signature._truncate_data(
|
29
|
-
if isinstance(
|
28
|
+
trunc_sample_input = model_signature._truncate_data(sample_input_data)
|
29
|
+
if isinstance(sample_input_data, SnowparkDataFrame):
|
30
30
|
# Added because of Any from missing stubs.
|
31
31
|
trunc_sample_input = cast(SnowparkDataFrame, trunc_sample_input)
|
32
32
|
local_sample_input = snowpark_handler.SnowparkDataFrameHandler.convert_to_df(trunc_sample_input)
|
@@ -45,27 +45,27 @@ class CustomModelHandler(_base.BaseModelHandler["custom_model.CustomModel"]):
|
|
45
45
|
model: "custom_model.CustomModel",
|
46
46
|
model_meta: model_meta_api.ModelMetadata,
|
47
47
|
model_blobs_dir_path: str,
|
48
|
-
|
48
|
+
sample_input_data: Optional[model_types.SupportedDataType] = None,
|
49
49
|
is_sub_model: Optional[bool] = False,
|
50
50
|
**kwargs: Unpack[model_types.CustomModelSaveOption],
|
51
51
|
) -> None:
|
52
52
|
assert isinstance(model, custom_model.CustomModel)
|
53
53
|
|
54
54
|
def get_prediction(
|
55
|
-
target_method_name: str,
|
55
|
+
target_method_name: str, sample_input_data: model_types.SupportedLocalDataType
|
56
56
|
) -> model_types.SupportedLocalDataType:
|
57
57
|
target_method = getattr(model, target_method_name, None)
|
58
58
|
assert callable(target_method) and inspect.ismethod(target_method)
|
59
59
|
target_method = target_method.__func__
|
60
60
|
|
61
|
-
if not isinstance(
|
62
|
-
|
61
|
+
if not isinstance(sample_input_data, pd.DataFrame):
|
62
|
+
sample_input_data = model_signature._convert_local_data_to_df(sample_input_data)
|
63
63
|
|
64
64
|
if inspect.iscoroutinefunction(target_method):
|
65
65
|
with anyio.start_blocking_portal() as portal:
|
66
|
-
predictions_df = portal.call(target_method, model,
|
66
|
+
predictions_df = portal.call(target_method, model, sample_input_data)
|
67
67
|
else:
|
68
|
-
predictions_df = target_method(model,
|
68
|
+
predictions_df = target_method(model, sample_input_data)
|
69
69
|
return predictions_df
|
70
70
|
|
71
71
|
if not is_sub_model:
|
@@ -73,7 +73,7 @@ class CustomModelHandler(_base.BaseModelHandler["custom_model.CustomModel"]):
|
|
73
73
|
model=model,
|
74
74
|
model_meta=model_meta,
|
75
75
|
target_methods=[method.__name__ for method in model._get_infer_methods()],
|
76
|
-
|
76
|
+
sample_input_data=sample_input_data,
|
77
77
|
get_prediction_fn=get_prediction,
|
78
78
|
)
|
79
79
|
|
@@ -128,7 +128,7 @@ class HuggingFacePipelineHandler(
|
|
128
128
|
model: Union[huggingface_pipeline.HuggingFacePipelineModel, "transformers.Pipeline"],
|
129
129
|
model_meta: model_meta_api.ModelMetadata,
|
130
130
|
model_blobs_dir_path: str,
|
131
|
-
|
131
|
+
sample_input_data: Optional[model_types.SupportedDataType] = None,
|
132
132
|
is_sub_model: Optional[bool] = False,
|
133
133
|
**kwargs: Unpack[model_types.HuggingFaceSaveOptions],
|
134
134
|
) -> None:
|
@@ -174,7 +174,7 @@ class HuggingFacePipelineHandler(
|
|
174
174
|
)
|
175
175
|
else:
|
176
176
|
handlers_utils.validate_target_methods(model, target_methods)
|
177
|
-
if
|
177
|
+
if sample_input_data is not None:
|
178
178
|
warnings.warn(
|
179
179
|
"Inferring model signature from sample input for hugggingface pipeline is not supported. "
|
180
180
|
+ "Model signature will automatically be inferred from pipeline task. "
|
@@ -54,7 +54,7 @@ class LLMHandler(_base.BaseModelHandler[llm.LLM]):
|
|
54
54
|
model: llm.LLM,
|
55
55
|
model_meta: model_meta_api.ModelMetadata,
|
56
56
|
model_blobs_dir_path: str,
|
57
|
-
|
57
|
+
sample_input_data: Optional[model_types.SupportedDataType] = None,
|
58
58
|
is_sub_model: Optional[bool] = False,
|
59
59
|
**kwargs: Unpack[model_types.LLMSaveOptions],
|
60
60
|
) -> None:
|
@@ -92,7 +92,7 @@ class MLFlowHandler(_base.BaseModelHandler["mlflow.pyfunc.PyFuncModel"]):
|
|
92
92
|
model: "mlflow.pyfunc.PyFuncModel",
|
93
93
|
model_meta: model_meta_api.ModelMetadata,
|
94
94
|
model_blobs_dir_path: str,
|
95
|
-
|
95
|
+
sample_input_data: Optional[model_types.SupportedDataType] = None,
|
96
96
|
is_sub_model: Optional[bool] = False,
|
97
97
|
**kwargs: Unpack[model_types.MLFlowSaveOptions],
|
98
98
|
) -> None:
|
@@ -21,6 +21,7 @@ from snowflake.ml.model._signatures import (
|
|
21
21
|
)
|
22
22
|
|
23
23
|
if TYPE_CHECKING:
|
24
|
+
import sentence_transformers # noqa: F401
|
24
25
|
import torch
|
25
26
|
|
26
27
|
|
@@ -44,9 +45,11 @@ class PyTorchHandler(_base.BaseModelHandler["torch.nn.Module"]):
|
|
44
45
|
cls,
|
45
46
|
model: model_types.SupportedModelType,
|
46
47
|
) -> TypeGuard["torch.nn.Module"]:
|
47
|
-
return
|
48
|
-
"torch.
|
49
|
-
|
48
|
+
return (
|
49
|
+
type_utils.LazyType("torch.nn.Module").isinstance(model)
|
50
|
+
and not type_utils.LazyType("torch.jit.ScriptModule").isinstance(model)
|
51
|
+
and not type_utils.LazyType("sentence_transformers.SentenceTransformer").isinstance(model)
|
52
|
+
)
|
50
53
|
|
51
54
|
@classmethod
|
52
55
|
def cast_model(
|
@@ -66,7 +69,7 @@ class PyTorchHandler(_base.BaseModelHandler["torch.nn.Module"]):
|
|
66
69
|
model: "torch.nn.Module",
|
67
70
|
model_meta: model_meta_api.ModelMetadata,
|
68
71
|
model_blobs_dir_path: str,
|
69
|
-
|
72
|
+
sample_input_data: Optional[model_types.SupportedDataType] = None,
|
70
73
|
is_sub_model: Optional[bool] = False,
|
71
74
|
**kwargs: Unpack[model_types.PyTorchSaveOptions],
|
72
75
|
) -> None:
|
@@ -82,18 +85,18 @@ class PyTorchHandler(_base.BaseModelHandler["torch.nn.Module"]):
|
|
82
85
|
)
|
83
86
|
|
84
87
|
def get_prediction(
|
85
|
-
target_method_name: str,
|
88
|
+
target_method_name: str, sample_input_data: "model_types.SupportedLocalDataType"
|
86
89
|
) -> model_types.SupportedLocalDataType:
|
87
|
-
if not pytorch_handler.SeqOfPyTorchTensorHandler.can_handle(
|
88
|
-
|
89
|
-
model_signature._convert_local_data_to_df(
|
90
|
+
if not pytorch_handler.SeqOfPyTorchTensorHandler.can_handle(sample_input_data):
|
91
|
+
sample_input_data = pytorch_handler.SeqOfPyTorchTensorHandler.convert_from_df(
|
92
|
+
model_signature._convert_local_data_to_df(sample_input_data)
|
90
93
|
)
|
91
94
|
|
92
95
|
model.eval()
|
93
96
|
target_method = getattr(model, target_method_name, None)
|
94
97
|
assert callable(target_method)
|
95
98
|
with torch.no_grad():
|
96
|
-
predictions_df = target_method(*
|
99
|
+
predictions_df = target_method(*sample_input_data)
|
97
100
|
|
98
101
|
if isinstance(predictions_df, torch.Tensor):
|
99
102
|
predictions_df = [predictions_df]
|
@@ -103,7 +106,7 @@ class PyTorchHandler(_base.BaseModelHandler["torch.nn.Module"]):
|
|
103
106
|
model=model,
|
104
107
|
model_meta=model_meta,
|
105
108
|
target_methods=target_methods,
|
106
|
-
|
109
|
+
sample_input_data=sample_input_data,
|
107
110
|
get_prediction_fn=get_prediction,
|
108
111
|
)
|
109
112
|
|