snowflake-ml-python 1.0.2__py3-none-any.whl → 1.0.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/ml/_internal/env_utils.py +2 -1
- snowflake/ml/_internal/file_utils.py +29 -7
- snowflake/ml/_internal/telemetry.py +5 -8
- snowflake/ml/_internal/utils/uri.py +7 -2
- snowflake/ml/model/_deploy_client/image_builds/base_image_builder.py +15 -0
- snowflake/ml/model/_deploy_client/image_builds/client_image_builder.py +259 -0
- snowflake/ml/model/_deploy_client/image_builds/docker_context.py +89 -0
- snowflake/ml/model/_deploy_client/image_builds/gunicorn_run.sh +24 -0
- snowflake/ml/model/_deploy_client/image_builds/inference_server/main.py +118 -0
- snowflake/ml/model/_deploy_client/image_builds/templates/dockerfile_template +40 -0
- snowflake/ml/model/_deploy_client/snowservice/deploy.py +199 -0
- snowflake/ml/model/_deploy_client/snowservice/deploy_options.py +88 -0
- snowflake/ml/model/_deploy_client/snowservice/templates/service_spec_template +24 -0
- snowflake/ml/model/_deploy_client/utils/constants.py +47 -0
- snowflake/ml/model/_deploy_client/utils/snowservice_client.py +178 -0
- snowflake/ml/model/_deploy_client/warehouse/deploy.py +24 -6
- snowflake/ml/model/_deploy_client/warehouse/infer_template.py +5 -2
- snowflake/ml/model/_deployer.py +14 -27
- snowflake/ml/model/_env.py +4 -4
- snowflake/ml/model/_handlers/custom.py +14 -2
- snowflake/ml/model/_handlers/pytorch.py +186 -0
- snowflake/ml/model/_handlers/sklearn.py +14 -9
- snowflake/ml/model/_handlers/snowmlmodel.py +14 -9
- snowflake/ml/model/_handlers/torchscript.py +180 -0
- snowflake/ml/model/_handlers/xgboost.py +19 -9
- snowflake/ml/model/_model.py +3 -2
- snowflake/ml/model/_model_meta.py +12 -7
- snowflake/ml/model/model_signature.py +446 -66
- snowflake/ml/model/type_hints.py +23 -4
- snowflake/ml/modeling/calibration/calibrated_classifier_cv.py +51 -26
- snowflake/ml/modeling/cluster/affinity_propagation.py +51 -26
- snowflake/ml/modeling/cluster/agglomerative_clustering.py +51 -26
- snowflake/ml/modeling/cluster/birch.py +51 -26
- snowflake/ml/modeling/cluster/bisecting_k_means.py +51 -26
- snowflake/ml/modeling/cluster/dbscan.py +51 -26
- snowflake/ml/modeling/cluster/feature_agglomeration.py +51 -26
- snowflake/ml/modeling/cluster/k_means.py +51 -26
- snowflake/ml/modeling/cluster/mean_shift.py +51 -26
- snowflake/ml/modeling/cluster/mini_batch_k_means.py +51 -26
- snowflake/ml/modeling/cluster/optics.py +51 -26
- snowflake/ml/modeling/cluster/spectral_biclustering.py +51 -26
- snowflake/ml/modeling/cluster/spectral_clustering.py +51 -26
- snowflake/ml/modeling/cluster/spectral_coclustering.py +51 -26
- snowflake/ml/modeling/compose/column_transformer.py +51 -26
- snowflake/ml/modeling/compose/transformed_target_regressor.py +51 -26
- snowflake/ml/modeling/covariance/elliptic_envelope.py +51 -26
- snowflake/ml/modeling/covariance/empirical_covariance.py +51 -26
- snowflake/ml/modeling/covariance/graphical_lasso.py +51 -26
- snowflake/ml/modeling/covariance/graphical_lasso_cv.py +51 -26
- snowflake/ml/modeling/covariance/ledoit_wolf.py +51 -26
- snowflake/ml/modeling/covariance/min_cov_det.py +51 -26
- snowflake/ml/modeling/covariance/oas.py +51 -26
- snowflake/ml/modeling/covariance/shrunk_covariance.py +51 -26
- snowflake/ml/modeling/decomposition/dictionary_learning.py +51 -26
- snowflake/ml/modeling/decomposition/factor_analysis.py +51 -26
- snowflake/ml/modeling/decomposition/fast_ica.py +51 -26
- snowflake/ml/modeling/decomposition/incremental_pca.py +51 -26
- snowflake/ml/modeling/decomposition/kernel_pca.py +51 -26
- snowflake/ml/modeling/decomposition/mini_batch_dictionary_learning.py +51 -26
- snowflake/ml/modeling/decomposition/mini_batch_sparse_pca.py +51 -26
- snowflake/ml/modeling/decomposition/pca.py +51 -26
- snowflake/ml/modeling/decomposition/sparse_pca.py +51 -26
- snowflake/ml/modeling/decomposition/truncated_svd.py +51 -26
- snowflake/ml/modeling/discriminant_analysis/linear_discriminant_analysis.py +51 -26
- snowflake/ml/modeling/discriminant_analysis/quadratic_discriminant_analysis.py +51 -26
- snowflake/ml/modeling/ensemble/ada_boost_classifier.py +51 -26
- snowflake/ml/modeling/ensemble/ada_boost_regressor.py +51 -26
- snowflake/ml/modeling/ensemble/bagging_classifier.py +51 -26
- snowflake/ml/modeling/ensemble/bagging_regressor.py +51 -26
- snowflake/ml/modeling/ensemble/extra_trees_classifier.py +51 -26
- snowflake/ml/modeling/ensemble/extra_trees_regressor.py +51 -26
- snowflake/ml/modeling/ensemble/gradient_boosting_classifier.py +51 -26
- snowflake/ml/modeling/ensemble/gradient_boosting_regressor.py +51 -26
- snowflake/ml/modeling/ensemble/hist_gradient_boosting_classifier.py +51 -26
- snowflake/ml/modeling/ensemble/hist_gradient_boosting_regressor.py +51 -26
- snowflake/ml/modeling/ensemble/isolation_forest.py +51 -26
- snowflake/ml/modeling/ensemble/random_forest_classifier.py +51 -26
- snowflake/ml/modeling/ensemble/random_forest_regressor.py +51 -26
- snowflake/ml/modeling/ensemble/stacking_regressor.py +51 -26
- snowflake/ml/modeling/ensemble/voting_classifier.py +51 -26
- snowflake/ml/modeling/ensemble/voting_regressor.py +51 -26
- snowflake/ml/modeling/feature_selection/generic_univariate_select.py +51 -26
- snowflake/ml/modeling/feature_selection/select_fdr.py +51 -26
- snowflake/ml/modeling/feature_selection/select_fpr.py +51 -26
- snowflake/ml/modeling/feature_selection/select_fwe.py +51 -26
- snowflake/ml/modeling/feature_selection/select_k_best.py +51 -26
- snowflake/ml/modeling/feature_selection/select_percentile.py +51 -26
- snowflake/ml/modeling/feature_selection/sequential_feature_selector.py +51 -26
- snowflake/ml/modeling/feature_selection/variance_threshold.py +51 -26
- snowflake/ml/modeling/gaussian_process/gaussian_process_classifier.py +51 -26
- snowflake/ml/modeling/gaussian_process/gaussian_process_regressor.py +51 -26
- snowflake/ml/modeling/impute/iterative_imputer.py +51 -26
- snowflake/ml/modeling/impute/knn_imputer.py +51 -26
- snowflake/ml/modeling/impute/missing_indicator.py +51 -26
- snowflake/ml/modeling/kernel_approximation/additive_chi2_sampler.py +51 -26
- snowflake/ml/modeling/kernel_approximation/nystroem.py +51 -26
- snowflake/ml/modeling/kernel_approximation/polynomial_count_sketch.py +51 -26
- snowflake/ml/modeling/kernel_approximation/rbf_sampler.py +51 -26
- snowflake/ml/modeling/kernel_approximation/skewed_chi2_sampler.py +51 -26
- snowflake/ml/modeling/kernel_ridge/kernel_ridge.py +51 -26
- snowflake/ml/modeling/lightgbm/lgbm_classifier.py +51 -26
- snowflake/ml/modeling/lightgbm/lgbm_regressor.py +51 -26
- snowflake/ml/modeling/linear_model/ard_regression.py +51 -26
- snowflake/ml/modeling/linear_model/bayesian_ridge.py +51 -26
- snowflake/ml/modeling/linear_model/elastic_net.py +51 -26
- snowflake/ml/modeling/linear_model/elastic_net_cv.py +51 -26
- snowflake/ml/modeling/linear_model/gamma_regressor.py +51 -26
- snowflake/ml/modeling/linear_model/huber_regressor.py +51 -26
- snowflake/ml/modeling/linear_model/lars.py +51 -26
- snowflake/ml/modeling/linear_model/lars_cv.py +51 -26
- snowflake/ml/modeling/linear_model/lasso.py +51 -26
- snowflake/ml/modeling/linear_model/lasso_cv.py +51 -26
- snowflake/ml/modeling/linear_model/lasso_lars.py +51 -26
- snowflake/ml/modeling/linear_model/lasso_lars_cv.py +51 -26
- snowflake/ml/modeling/linear_model/lasso_lars_ic.py +51 -26
- snowflake/ml/modeling/linear_model/linear_regression.py +51 -26
- snowflake/ml/modeling/linear_model/logistic_regression.py +51 -26
- snowflake/ml/modeling/linear_model/logistic_regression_cv.py +51 -26
- snowflake/ml/modeling/linear_model/multi_task_elastic_net.py +51 -26
- snowflake/ml/modeling/linear_model/multi_task_elastic_net_cv.py +51 -26
- snowflake/ml/modeling/linear_model/multi_task_lasso.py +51 -26
- snowflake/ml/modeling/linear_model/multi_task_lasso_cv.py +51 -26
- snowflake/ml/modeling/linear_model/orthogonal_matching_pursuit.py +51 -26
- snowflake/ml/modeling/linear_model/passive_aggressive_classifier.py +51 -26
- snowflake/ml/modeling/linear_model/passive_aggressive_regressor.py +51 -26
- snowflake/ml/modeling/linear_model/perceptron.py +51 -26
- snowflake/ml/modeling/linear_model/poisson_regressor.py +51 -26
- snowflake/ml/modeling/linear_model/ransac_regressor.py +51 -26
- snowflake/ml/modeling/linear_model/ridge.py +51 -26
- snowflake/ml/modeling/linear_model/ridge_classifier.py +51 -26
- snowflake/ml/modeling/linear_model/ridge_classifier_cv.py +51 -26
- snowflake/ml/modeling/linear_model/ridge_cv.py +51 -26
- snowflake/ml/modeling/linear_model/sgd_classifier.py +51 -26
- snowflake/ml/modeling/linear_model/sgd_one_class_svm.py +51 -26
- snowflake/ml/modeling/linear_model/sgd_regressor.py +51 -26
- snowflake/ml/modeling/linear_model/theil_sen_regressor.py +51 -26
- snowflake/ml/modeling/linear_model/tweedie_regressor.py +51 -26
- snowflake/ml/modeling/manifold/isomap.py +51 -26
- snowflake/ml/modeling/manifold/mds.py +51 -26
- snowflake/ml/modeling/manifold/spectral_embedding.py +51 -26
- snowflake/ml/modeling/manifold/tsne.py +51 -26
- snowflake/ml/modeling/mixture/bayesian_gaussian_mixture.py +51 -26
- snowflake/ml/modeling/mixture/gaussian_mixture.py +51 -26
- snowflake/ml/modeling/model_selection/grid_search_cv.py +51 -26
- snowflake/ml/modeling/model_selection/randomized_search_cv.py +51 -26
- snowflake/ml/modeling/multiclass/one_vs_one_classifier.py +51 -26
- snowflake/ml/modeling/multiclass/one_vs_rest_classifier.py +51 -26
- snowflake/ml/modeling/multiclass/output_code_classifier.py +51 -26
- snowflake/ml/modeling/naive_bayes/bernoulli_nb.py +51 -26
- snowflake/ml/modeling/naive_bayes/categorical_nb.py +51 -26
- snowflake/ml/modeling/naive_bayes/complement_nb.py +51 -26
- snowflake/ml/modeling/naive_bayes/gaussian_nb.py +51 -26
- snowflake/ml/modeling/naive_bayes/multinomial_nb.py +51 -26
- snowflake/ml/modeling/neighbors/k_neighbors_classifier.py +51 -26
- snowflake/ml/modeling/neighbors/k_neighbors_regressor.py +51 -26
- snowflake/ml/modeling/neighbors/kernel_density.py +51 -26
- snowflake/ml/modeling/neighbors/local_outlier_factor.py +51 -26
- snowflake/ml/modeling/neighbors/nearest_centroid.py +51 -26
- snowflake/ml/modeling/neighbors/nearest_neighbors.py +51 -26
- snowflake/ml/modeling/neighbors/neighborhood_components_analysis.py +51 -26
- snowflake/ml/modeling/neighbors/radius_neighbors_classifier.py +51 -26
- snowflake/ml/modeling/neighbors/radius_neighbors_regressor.py +51 -26
- snowflake/ml/modeling/neural_network/bernoulli_rbm.py +51 -26
- snowflake/ml/modeling/neural_network/mlp_classifier.py +51 -26
- snowflake/ml/modeling/neural_network/mlp_regressor.py +51 -26
- snowflake/ml/modeling/preprocessing/ordinal_encoder.py +2 -0
- snowflake/ml/modeling/preprocessing/polynomial_features.py +51 -26
- snowflake/ml/modeling/semi_supervised/label_propagation.py +51 -26
- snowflake/ml/modeling/semi_supervised/label_spreading.py +51 -26
- snowflake/ml/modeling/svm/linear_svc.py +51 -26
- snowflake/ml/modeling/svm/linear_svr.py +51 -26
- snowflake/ml/modeling/svm/nu_svc.py +51 -26
- snowflake/ml/modeling/svm/nu_svr.py +51 -26
- snowflake/ml/modeling/svm/svc.py +51 -26
- snowflake/ml/modeling/svm/svr.py +51 -26
- snowflake/ml/modeling/tree/decision_tree_classifier.py +51 -26
- snowflake/ml/modeling/tree/decision_tree_regressor.py +51 -26
- snowflake/ml/modeling/tree/extra_tree_classifier.py +51 -26
- snowflake/ml/modeling/tree/extra_tree_regressor.py +51 -26
- snowflake/ml/modeling/xgboost/xgb_classifier.py +51 -26
- snowflake/ml/modeling/xgboost/xgb_regressor.py +51 -26
- snowflake/ml/modeling/xgboost/xgbrf_classifier.py +51 -26
- snowflake/ml/modeling/xgboost/xgbrf_regressor.py +51 -26
- snowflake/ml/registry/model_registry.py +74 -56
- snowflake/ml/version.py +1 -1
- {snowflake_ml_python-1.0.2.dist-info → snowflake_ml_python-1.0.3.dist-info}/METADATA +27 -8
- snowflake_ml_python-1.0.3.dist-info/RECORD +259 -0
- snowflake_ml_python-1.0.2.dist-info/RECORD +0 -246
- {snowflake_ml_python-1.0.2.dist-info → snowflake_ml_python-1.0.3.dist-info}/WHEEL +0 -0
@@ -7,6 +7,7 @@
|
|
7
7
|
#
|
8
8
|
import inspect
|
9
9
|
import os
|
10
|
+
import posixpath
|
10
11
|
from typing import Iterable, Optional, Union, List, Any, Dict, Callable, Set
|
11
12
|
from uuid import uuid4
|
12
13
|
|
@@ -26,6 +27,7 @@ from snowflake.ml._internal.utils.temp_file_utils import cleanup_temp_files, get
|
|
26
27
|
from snowflake.snowpark import DataFrame, Session
|
27
28
|
from snowflake.snowpark.functions import pandas_udf, sproc
|
28
29
|
from snowflake.snowpark.types import PandasSeries
|
30
|
+
from snowflake.snowpark._internal.type_utils import convert_sp_to_sf_type
|
29
31
|
|
30
32
|
from snowflake.ml.model.model_signature import (
|
31
33
|
DataType,
|
@@ -392,7 +394,6 @@ class XGBRFRegressor(BaseTransformer):
|
|
392
394
|
**kwargs,
|
393
395
|
) -> None:
|
394
396
|
super().__init__()
|
395
|
-
self.id = str(uuid4()).replace("-", "_").upper()
|
396
397
|
deps: Set[str] = set([f'numpy=={np.__version__}', f'xgboost=={xgboost.__version__}', f'cloudpickle=={cp.__version__}'])
|
397
398
|
|
398
399
|
self._deps = list(deps)
|
@@ -416,6 +417,15 @@ class XGBRFRegressor(BaseTransformer):
|
|
416
417
|
self.set_drop_input_cols(drop_input_cols)
|
417
418
|
self.set_sample_weight_col(sample_weight_col)
|
418
419
|
|
420
|
+
def _get_rand_id(self) -> str:
|
421
|
+
"""
|
422
|
+
Generate random id to be used in sproc and stage names.
|
423
|
+
|
424
|
+
Returns:
|
425
|
+
Random id string usable in sproc, table, and stage names.
|
426
|
+
"""
|
427
|
+
return str(uuid4()).replace("-", "_").upper()
|
428
|
+
|
419
429
|
def _infer_input_output_cols(self, dataset: Union[DataFrame, pd.DataFrame]) -> None:
|
420
430
|
"""
|
421
431
|
Infer `self.input_cols` and `self.output_cols` if they are not explicitly set.
|
@@ -494,7 +504,7 @@ class XGBRFRegressor(BaseTransformer):
|
|
494
504
|
cp.dump(self._sklearn_object, local_transform_file)
|
495
505
|
|
496
506
|
# Create temp stage to run fit.
|
497
|
-
transform_stage_name = "SNOWML_TRANSFORM_{safe_id}".format(safe_id=self.
|
507
|
+
transform_stage_name = "SNOWML_TRANSFORM_{safe_id}".format(safe_id=self._get_rand_id())
|
498
508
|
stage_creation_query = f"CREATE OR REPLACE TEMPORARY STAGE {transform_stage_name};"
|
499
509
|
SqlResultValidator(
|
500
510
|
session=session,
|
@@ -507,11 +517,12 @@ class XGBRFRegressor(BaseTransformer):
|
|
507
517
|
expected_value=f"Stage area {transform_stage_name} successfully created."
|
508
518
|
).validate()
|
509
519
|
|
510
|
-
|
520
|
+
# Use posixpath to construct stage paths
|
521
|
+
stage_transform_file_name = posixpath.join(transform_stage_name, os.path.basename(local_transform_file_name))
|
522
|
+
stage_result_file_name = posixpath.join(transform_stage_name, os.path.basename(local_transform_file_name))
|
511
523
|
local_result_file_name = get_temp_file_path()
|
512
|
-
stage_result_file_name = os.path.join(transform_stage_name, os.path.basename(local_transform_file_name))
|
513
524
|
|
514
|
-
fit_sproc_name = "SNOWML_FIT_{safe_id}".format(safe_id=self.
|
525
|
+
fit_sproc_name = "SNOWML_FIT_{safe_id}".format(safe_id=self._get_rand_id())
|
515
526
|
statement_params = telemetry.get_function_usage_statement_params(
|
516
527
|
project=_PROJECT,
|
517
528
|
subproject=_SUBPROJECT,
|
@@ -537,6 +548,7 @@ class XGBRFRegressor(BaseTransformer):
|
|
537
548
|
replace=True,
|
538
549
|
session=session,
|
539
550
|
statement_params=statement_params,
|
551
|
+
anonymous=True
|
540
552
|
)
|
541
553
|
def fit_wrapper_sproc(
|
542
554
|
session: Session,
|
@@ -545,7 +557,8 @@ class XGBRFRegressor(BaseTransformer):
|
|
545
557
|
stage_result_file_name: str,
|
546
558
|
input_cols: List[str],
|
547
559
|
label_cols: List[str],
|
548
|
-
sample_weight_col: Optional[str]
|
560
|
+
sample_weight_col: Optional[str],
|
561
|
+
statement_params: Dict[str, str]
|
549
562
|
) -> str:
|
550
563
|
import cloudpickle as cp
|
551
564
|
import numpy as np
|
@@ -612,15 +625,15 @@ class XGBRFRegressor(BaseTransformer):
|
|
612
625
|
api_calls=[Session.call],
|
613
626
|
custom_tags=dict([("autogen", True)]),
|
614
627
|
)
|
615
|
-
sproc_export_file_name =
|
616
|
-
|
628
|
+
sproc_export_file_name = fit_wrapper_sproc(
|
629
|
+
session,
|
617
630
|
query,
|
618
631
|
stage_transform_file_name,
|
619
632
|
stage_result_file_name,
|
620
633
|
identifier.get_unescaped_names(self.input_cols),
|
621
634
|
identifier.get_unescaped_names(self.label_cols),
|
622
635
|
identifier.get_unescaped_names(self.sample_weight_col),
|
623
|
-
statement_params
|
636
|
+
statement_params,
|
624
637
|
)
|
625
638
|
|
626
639
|
if "|" in sproc_export_file_name:
|
@@ -630,7 +643,7 @@ class XGBRFRegressor(BaseTransformer):
|
|
630
643
|
print("\n".join(fields[1:]))
|
631
644
|
|
632
645
|
session.file.get(
|
633
|
-
|
646
|
+
posixpath.join(stage_result_file_name, sproc_export_file_name),
|
634
647
|
local_result_file_name,
|
635
648
|
statement_params=statement_params
|
636
649
|
)
|
@@ -676,7 +689,7 @@ class XGBRFRegressor(BaseTransformer):
|
|
676
689
|
|
677
690
|
# Register vectorized UDF for batch inference
|
678
691
|
batch_inference_udf_name = "SNOWML_BATCH_INFERENCE_{safe_id}_{method}".format(
|
679
|
-
safe_id=self.
|
692
|
+
safe_id=self._get_rand_id(), method=inference_method)
|
680
693
|
|
681
694
|
# Need to do this since if we use self._sklearn_object directly in the UDF, Snowpark
|
682
695
|
# will try to pickle all of self which fails.
|
@@ -768,7 +781,7 @@ class XGBRFRegressor(BaseTransformer):
|
|
768
781
|
return transformed_pandas_df.to_dict("records")
|
769
782
|
|
770
783
|
batch_inference_table_name = "SNOWML_BATCH_INFERENCE_INPUT_TABLE_{safe_id}".format(
|
771
|
-
safe_id=self.
|
784
|
+
safe_id=self._get_rand_id()
|
772
785
|
)
|
773
786
|
|
774
787
|
pass_through_columns = self._get_pass_through_columns(dataset)
|
@@ -935,11 +948,18 @@ class XGBRFRegressor(BaseTransformer):
|
|
935
948
|
Transformed dataset.
|
936
949
|
"""
|
937
950
|
if isinstance(dataset, DataFrame):
|
951
|
+
expected_type_inferred = "float"
|
952
|
+
# when it is classifier, infer the datatype from label columns
|
953
|
+
if expected_type_inferred == "" and 'predict' in self.model_signatures:
|
954
|
+
expected_type_inferred = convert_sp_to_sf_type(
|
955
|
+
self.model_signatures['predict'].outputs[0].as_snowpark_type()
|
956
|
+
)
|
957
|
+
|
938
958
|
output_df = self._batch_inference(
|
939
959
|
dataset=dataset,
|
940
960
|
inference_method="predict",
|
941
961
|
expected_output_cols_list=self.output_cols,
|
942
|
-
expected_output_cols_type=
|
962
|
+
expected_output_cols_type=expected_type_inferred,
|
943
963
|
)
|
944
964
|
elif isinstance(dataset, pd.DataFrame):
|
945
965
|
output_df = self._sklearn_inference(
|
@@ -1010,10 +1030,10 @@ class XGBRFRegressor(BaseTransformer):
|
|
1010
1030
|
|
1011
1031
|
def _get_output_column_names(self, output_cols_prefix: str) -> List[str]:
|
1012
1032
|
""" Returns the list of output columns for predict_proba(), decision_function(), etc.. functions.
|
1013
|
-
Returns
|
1033
|
+
Returns a list with output_cols_prefix as the only element if the estimator is not a classifier.
|
1014
1034
|
"""
|
1015
1035
|
if getattr(self._sklearn_object, "classes_", None) is None:
|
1016
|
-
return []
|
1036
|
+
return [output_cols_prefix]
|
1017
1037
|
|
1018
1038
|
classes = self._sklearn_object.classes_
|
1019
1039
|
if isinstance(classes, numpy.ndarray):
|
@@ -1238,7 +1258,7 @@ class XGBRFRegressor(BaseTransformer):
|
|
1238
1258
|
cp.dump(self._sklearn_object, local_score_file)
|
1239
1259
|
|
1240
1260
|
# Create temp stage to run score.
|
1241
|
-
score_stage_name = "SNOWML_SCORE_{safe_id}".format(safe_id=self.
|
1261
|
+
score_stage_name = "SNOWML_SCORE_{safe_id}".format(safe_id=self._get_rand_id())
|
1242
1262
|
session = dataset._session
|
1243
1263
|
stage_creation_query = f"CREATE OR REPLACE TEMPORARY STAGE {score_stage_name};"
|
1244
1264
|
SqlResultValidator(
|
@@ -1252,8 +1272,9 @@ class XGBRFRegressor(BaseTransformer):
|
|
1252
1272
|
expected_value=f"Stage area {score_stage_name} successfully created."
|
1253
1273
|
).validate()
|
1254
1274
|
|
1255
|
-
|
1256
|
-
|
1275
|
+
# Use posixpath to construct stage paths
|
1276
|
+
stage_score_file_name = posixpath.join(score_stage_name, os.path.basename(local_score_file_name))
|
1277
|
+
score_sproc_name = "SNOWML_SCORE_{safe_id}".format(safe_id=self._get_rand_id())
|
1257
1278
|
statement_params = telemetry.get_function_usage_statement_params(
|
1258
1279
|
project=_PROJECT,
|
1259
1280
|
subproject=_SUBPROJECT,
|
@@ -1279,6 +1300,7 @@ class XGBRFRegressor(BaseTransformer):
|
|
1279
1300
|
replace=True,
|
1280
1301
|
session=session,
|
1281
1302
|
statement_params=statement_params,
|
1303
|
+
anonymous=True
|
1282
1304
|
)
|
1283
1305
|
def score_wrapper_sproc(
|
1284
1306
|
session: Session,
|
@@ -1286,7 +1308,8 @@ class XGBRFRegressor(BaseTransformer):
|
|
1286
1308
|
stage_score_file_name: str,
|
1287
1309
|
input_cols: List[str],
|
1288
1310
|
label_cols: List[str],
|
1289
|
-
sample_weight_col: Optional[str]
|
1311
|
+
sample_weight_col: Optional[str],
|
1312
|
+
statement_params: Dict[str, str]
|
1290
1313
|
) -> float:
|
1291
1314
|
import cloudpickle as cp
|
1292
1315
|
import numpy as np
|
@@ -1336,14 +1359,14 @@ class XGBRFRegressor(BaseTransformer):
|
|
1336
1359
|
api_calls=[Session.call],
|
1337
1360
|
custom_tags=dict([("autogen", True)]),
|
1338
1361
|
)
|
1339
|
-
score =
|
1340
|
-
|
1362
|
+
score = score_wrapper_sproc(
|
1363
|
+
session,
|
1341
1364
|
query,
|
1342
1365
|
stage_score_file_name,
|
1343
1366
|
identifier.get_unescaped_names(self.input_cols),
|
1344
1367
|
identifier.get_unescaped_names(self.label_cols),
|
1345
1368
|
identifier.get_unescaped_names(self.sample_weight_col),
|
1346
|
-
statement_params
|
1369
|
+
statement_params,
|
1347
1370
|
)
|
1348
1371
|
|
1349
1372
|
cleanup_temp_files([local_score_file_name])
|
@@ -1361,18 +1384,20 @@ class XGBRFRegressor(BaseTransformer):
|
|
1361
1384
|
if self._sklearn_object._estimator_type == 'classifier':
|
1362
1385
|
outputs = _infer_signature(dataset[self.label_cols], "output") # label columns is the desired type for output
|
1363
1386
|
outputs = _rename_features(outputs, self.output_cols) # rename the output columns
|
1364
|
-
self._model_signature_dict["predict"] = ModelSignature(inputs,
|
1387
|
+
self._model_signature_dict["predict"] = ModelSignature(inputs,
|
1388
|
+
([] if self._drop_input_cols else inputs) + outputs)
|
1365
1389
|
# For regressor, the type of predict is float64
|
1366
1390
|
elif self._sklearn_object._estimator_type == 'regressor':
|
1367
1391
|
outputs = [FeatureSpec(dtype=DataType.DOUBLE, name=c) for c in self.output_cols]
|
1368
|
-
self._model_signature_dict["predict"] = ModelSignature(inputs,
|
1369
|
-
|
1392
|
+
self._model_signature_dict["predict"] = ModelSignature(inputs,
|
1393
|
+
([] if self._drop_input_cols else inputs) + outputs)
|
1370
1394
|
for prob_func in PROB_FUNCTIONS:
|
1371
1395
|
if hasattr(self, prob_func):
|
1372
1396
|
output_cols_prefix: str = f"{prob_func}_"
|
1373
1397
|
output_column_names = self._get_output_column_names(output_cols_prefix)
|
1374
1398
|
outputs = [FeatureSpec(dtype=DataType.DOUBLE, name=c) for c in output_column_names]
|
1375
|
-
self._model_signature_dict[prob_func] = ModelSignature(inputs,
|
1399
|
+
self._model_signature_dict[prob_func] = ModelSignature(inputs,
|
1400
|
+
([] if self._drop_input_cols else inputs) + outputs)
|
1376
1401
|
|
1377
1402
|
@property
|
1378
1403
|
def model_signatures(self) -> Dict[str, ModelSignature]:
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import inspect
|
2
2
|
import json
|
3
3
|
import os
|
4
|
+
import posixpath
|
4
5
|
import sys
|
5
6
|
import tempfile
|
6
7
|
import types
|
@@ -34,7 +35,7 @@ _DEFAULT_REGISTRY_NAME: str = "_SYSTEM_MODEL_REGISTRY"
|
|
34
35
|
_DEFAULT_SCHEMA_NAME: str = "_SYSTEM_MODEL_REGISTRY_SCHEMA"
|
35
36
|
_MODELS_TABLE_NAME: str = "_SYSTEM_REGISTRY_MODELS"
|
36
37
|
_METADATA_TABLE_NAME: str = "_SYSTEM_REGISTRY_METADATA"
|
37
|
-
_DEPLOYMENT_TABLE_NAME: str = "
|
38
|
+
_DEPLOYMENT_TABLE_NAME: str = "_SYSTEM_REGISTRY_DEPLOYMENTS"
|
38
39
|
|
39
40
|
# Metadata operation types.
|
40
41
|
_SET_METADATA_OPERATION: str = "SET"
|
@@ -83,9 +84,11 @@ def create_model_registry(
|
|
83
84
|
"""
|
84
85
|
|
85
86
|
# These might be exposed as parameters in the future.
|
86
|
-
|
87
|
-
|
88
|
-
|
87
|
+
database_name = identifier.get_inferred_name(database_name)
|
88
|
+
schema_name = identifier.get_inferred_name(schema_name)
|
89
|
+
registry_table_name = identifier.get_inferred_name(_MODELS_TABLE_NAME)
|
90
|
+
metadata_table_name = identifier.get_inferred_name(_METADATA_TABLE_NAME)
|
91
|
+
deployment_table_name = identifier.get_inferred_name(_DEPLOYMENT_TABLE_NAME)
|
89
92
|
statement_params = telemetry.get_function_usage_statement_params(
|
90
93
|
project=_TELEMETRY_PROJECT,
|
91
94
|
subproject=_TELEMETRY_SUBPROJECT,
|
@@ -129,14 +132,14 @@ def _create_registry_database(
|
|
129
132
|
database_name: Desired name of the model registry database.
|
130
133
|
statement_params: Function usage statement parameters used in sql query executions.
|
131
134
|
"""
|
132
|
-
registry_databases = session.sql(f"SHOW DATABASES LIKE '{database_name}'").collect(
|
135
|
+
registry_databases = session.sql(f"SHOW DATABASES LIKE '{identifier.get_unescaped_names(database_name)}'").collect(
|
133
136
|
statement_params=statement_params
|
134
137
|
)
|
135
138
|
if len(registry_databases) > 0:
|
136
139
|
logging.warning(f"The database {database_name} already exists. Skipping creation.")
|
137
140
|
return
|
138
141
|
|
139
|
-
session.sql(f
|
142
|
+
session.sql(f"CREATE DATABASE {database_name}").collect(statement_params=statement_params)
|
140
143
|
|
141
144
|
|
142
145
|
def _create_registry_schema(
|
@@ -153,31 +156,31 @@ def _create_registry_schema(
|
|
153
156
|
statement_params: Function usage statement parameters used in sql query executions.
|
154
157
|
"""
|
155
158
|
# The default PUBLIC schema is created by default so it might already exist even in a new database.
|
156
|
-
registry_schemas = session.sql(
|
157
|
-
|
158
|
-
)
|
159
|
+
registry_schemas = session.sql(
|
160
|
+
f"SHOW SCHEMAS LIKE '{identifier.get_unescaped_names(schema_name)}' IN DATABASE {database_name}"
|
161
|
+
).collect(statement_params=statement_params)
|
159
162
|
|
160
163
|
if len(registry_schemas) > 0:
|
161
|
-
logging.warning(
|
164
|
+
logging.warning(
|
165
|
+
f"The schema {_get_fully_qualified_schema_name(database_name, schema_name)}already exists. "
|
166
|
+
+ "Skipping creation."
|
167
|
+
)
|
162
168
|
return
|
163
169
|
|
164
|
-
session.sql(f
|
170
|
+
session.sql(f"CREATE SCHEMA {_get_fully_qualified_schema_name(database_name, schema_name)}").collect(
|
171
|
+
statement_params=statement_params
|
172
|
+
)
|
165
173
|
|
166
174
|
|
167
175
|
def _get_fully_qualified_schema_name(database_name: str, schema_name: str) -> str:
|
168
|
-
return ".".join(
|
169
|
-
[
|
170
|
-
f"{identifier.quote_name_without_upper_casing(database_name)}",
|
171
|
-
f"{identifier.quote_name_without_upper_casing(schema_name)}",
|
172
|
-
]
|
173
|
-
)
|
176
|
+
return ".".join([database_name, schema_name])
|
174
177
|
|
175
178
|
|
176
179
|
def _get_fully_qualified_table_name(database_name: str, schema_name: str, table_name: str) -> str:
|
177
180
|
return ".".join(
|
178
181
|
[
|
179
182
|
_get_fully_qualified_schema_name(database_name, schema_name),
|
180
|
-
|
183
|
+
table_name,
|
181
184
|
]
|
182
185
|
)
|
183
186
|
|
@@ -291,10 +294,10 @@ def _create_registry_views(
|
|
291
294
|
)
|
292
295
|
|
293
296
|
# Create views on most recent metadata items.
|
294
|
-
metadata_view_name_prefix = metadata_table_name
|
297
|
+
metadata_view_name_prefix = identifier.concat_names([metadata_table_name, "_LAST_"])
|
295
298
|
metadata_view_template = formatting.unwrap(
|
296
|
-
"""CREATE OR REPLACE VIEW
|
297
|
-
SELECT DISTINCT MODEL_ID, {select_expression} AS {final_attribute_name} FROM
|
299
|
+
"""CREATE OR REPLACE VIEW {database}.{schema}.{attribute_view} COPY GRANTS AS
|
300
|
+
SELECT DISTINCT MODEL_ID, {select_expression} AS {final_attribute_name} FROM {metadata_table}
|
298
301
|
WHERE ATTRIBUTE_NAME = '{attribute_name}'"""
|
299
302
|
)
|
300
303
|
|
@@ -302,7 +305,7 @@ def _create_registry_views(
|
|
302
305
|
metadata_view_names = []
|
303
306
|
metadata_select_fields = []
|
304
307
|
for attribute_name in _LIST_METADATA_ATTRIBUTE:
|
305
|
-
view_name =
|
308
|
+
view_name = identifier.concat_names([metadata_view_name_prefix, attribute_name])
|
306
309
|
select_expression = f"(LAST_VALUE(VALUE) OVER (PARTITION BY MODEL_ID ORDER BY SEQUENCE_ID))['{attribute_name}']"
|
307
310
|
sql = metadata_view_template.format(
|
308
311
|
database=database_name,
|
@@ -315,14 +318,12 @@ def _create_registry_views(
|
|
315
318
|
)
|
316
319
|
session.sql(sql).collect(statement_params=statement_params)
|
317
320
|
metadata_view_names.append(view_name)
|
318
|
-
metadata_select_fields.append(
|
319
|
-
f"{identifier.quote_name_without_upper_casing(view_name)}.{attribute_name} AS {attribute_name}"
|
320
|
-
)
|
321
|
+
metadata_select_fields.append(f"{view_name}.{attribute_name} AS {attribute_name}")
|
321
322
|
|
322
323
|
# Create a special view for the registration timestamp.
|
323
324
|
attribute_name = _METADATA_ATTRIBUTE_REGISTRATION
|
324
|
-
final_attribute_name = attribute_name
|
325
|
-
view_name =
|
325
|
+
final_attribute_name = identifier.concat_names([attribute_name, "_TIMESTAMP"])
|
326
|
+
view_name = identifier.concat_names([metadata_view_name_prefix, attribute_name])
|
326
327
|
create_registration_view_sql = metadata_view_template.format(
|
327
328
|
database=database_name,
|
328
329
|
schema=schema_name,
|
@@ -334,13 +335,11 @@ def _create_registry_views(
|
|
334
335
|
)
|
335
336
|
session.sql(create_registration_view_sql).collect(statement_params=statement_params)
|
336
337
|
metadata_view_names.append(view_name)
|
337
|
-
metadata_select_fields.append(
|
338
|
-
f"{identifier.quote_name_without_upper_casing(view_name)}.{final_attribute_name} AS {final_attribute_name}"
|
339
|
-
)
|
338
|
+
metadata_select_fields.append(f"{view_name}.{final_attribute_name} AS {final_attribute_name}")
|
340
339
|
|
341
340
|
metadata_views_join = " ".join(
|
342
341
|
[
|
343
|
-
|
342
|
+
"LEFT JOIN {view} ON ({view}.MODEL_ID = {registry_table}.ID)".format(
|
344
343
|
view=view, registry_table=registry_table_name
|
345
344
|
)
|
346
345
|
for view in metadata_view_names
|
@@ -348,12 +347,12 @@ def _create_registry_views(
|
|
348
347
|
)
|
349
348
|
|
350
349
|
# Create view to combine all attributes.
|
351
|
-
registry_view_name = registry_table_name
|
350
|
+
registry_view_name = identifier.concat_names([registry_table_name, "_VIEW"])
|
352
351
|
metadata_select_fields_formatted = ",".join(metadata_select_fields)
|
353
352
|
session.sql(
|
354
|
-
f"""CREATE OR REPLACE VIEW {fully_qualified_schema_name}.
|
355
|
-
SELECT
|
356
|
-
FROM
|
353
|
+
f"""CREATE OR REPLACE VIEW {fully_qualified_schema_name}.{registry_view_name} COPY GRANTS AS
|
354
|
+
SELECT {registry_table_name}.*, {metadata_select_fields_formatted}
|
355
|
+
FROM {registry_table_name} {metadata_views_join}"""
|
357
356
|
).collect(statement_params=statement_params)
|
358
357
|
|
359
358
|
|
@@ -376,8 +375,9 @@ def _create_active_permanent_deployment_view(
|
|
376
375
|
|
377
376
|
# Create a view on active permanent deployments
|
378
377
|
# Active deployments are those whose last operation is not DROP.
|
378
|
+
active_deployments_view_name = identifier.concat_names([deployment_table_name, "_VIEW"])
|
379
379
|
active_deployments_view_expr = f"""
|
380
|
-
CREATE OR REPLACE VIEW {fully_qualified_schema_name}.
|
380
|
+
CREATE OR REPLACE VIEW {fully_qualified_schema_name}.{active_deployments_view_name}
|
381
381
|
COPY GRANTS AS
|
382
382
|
SELECT
|
383
383
|
DEPLOYMENT_NAME,
|
@@ -416,14 +416,14 @@ class ModelRegistry:
|
|
416
416
|
database_name: Desired name of the model registry database.
|
417
417
|
schema_name: Desired name of the schema used by this model registry inside the database.
|
418
418
|
"""
|
419
|
-
self._name = database_name
|
420
|
-
self._schema = schema_name
|
421
|
-
self._registry_table = _MODELS_TABLE_NAME
|
422
|
-
self._registry_table_view = self._registry_table
|
423
|
-
self._metadata_table = _METADATA_TABLE_NAME
|
424
|
-
self._deployment_table = _DEPLOYMENT_TABLE_NAME
|
425
|
-
self._permanent_deployment_view = self._deployment_table
|
426
|
-
self._permanent_deployment_stage = self._deployment_table
|
419
|
+
self._name = identifier.get_inferred_name(database_name)
|
420
|
+
self._schema = identifier.get_inferred_name(schema_name)
|
421
|
+
self._registry_table = identifier.get_inferred_name(_MODELS_TABLE_NAME)
|
422
|
+
self._registry_table_view = identifier.concat_names([self._registry_table, "_VIEW"])
|
423
|
+
self._metadata_table = identifier.get_inferred_name(_METADATA_TABLE_NAME)
|
424
|
+
self._deployment_table = identifier.get_inferred_name(_DEPLOYMENT_TABLE_NAME)
|
425
|
+
self._permanent_deployment_view = identifier.concat_names([self._deployment_table, "_VIEW"])
|
426
|
+
self._permanent_deployment_stage = identifier.concat_names([self._deployment_table, "_STAGE"])
|
427
427
|
|
428
428
|
self._session = session
|
429
429
|
|
@@ -440,23 +440,39 @@ class ModelRegistry:
|
|
440
440
|
# Check that the required tables exist and are accessible by the current role.
|
441
441
|
|
442
442
|
query_result_checker.SqlResultValidator(
|
443
|
-
self._session, query=f"SHOW DATABASES LIKE '{self._name}'"
|
443
|
+
self._session, query=f"SHOW DATABASES LIKE '{identifier.get_unescaped_names(self._name)}'"
|
444
444
|
).has_dimensions(expected_rows=1).validate()
|
445
445
|
|
446
446
|
query_result_checker.SqlResultValidator(
|
447
|
-
self._session,
|
447
|
+
self._session,
|
448
|
+
query=f"SHOW SCHEMAS LIKE '{identifier.get_unescaped_names(self._schema)}' IN DATABASE {self._name}",
|
448
449
|
).has_dimensions(expected_rows=1).validate()
|
449
450
|
|
450
451
|
query_result_checker.SqlResultValidator(
|
451
|
-
self._session,
|
452
|
+
self._session,
|
453
|
+
query=formatting.unwrap(
|
454
|
+
f"""
|
455
|
+
SHOW TABLES LIKE '{identifier.get_unescaped_names(self._registry_table)}'
|
456
|
+
IN {self._fully_qualified_schema_name()}"""
|
457
|
+
),
|
452
458
|
).has_dimensions(expected_rows=1).validate()
|
453
459
|
|
454
460
|
query_result_checker.SqlResultValidator(
|
455
|
-
self._session,
|
461
|
+
self._session,
|
462
|
+
query=formatting.unwrap(
|
463
|
+
f"""
|
464
|
+
SHOW TABLES LIKE '{identifier.get_unescaped_names(self._metadata_table)}'
|
465
|
+
IN {self._fully_qualified_schema_name()}"""
|
466
|
+
),
|
456
467
|
).has_dimensions(expected_rows=1).validate()
|
457
468
|
|
458
469
|
query_result_checker.SqlResultValidator(
|
459
|
-
self._session,
|
470
|
+
self._session,
|
471
|
+
query=formatting.unwrap(
|
472
|
+
f"""
|
473
|
+
SHOW TABLES LIKE '{identifier.get_unescaped_names(self._deployment_table)}'
|
474
|
+
IN {self._fully_qualified_schema_name()}"""
|
475
|
+
),
|
460
476
|
).has_dimensions(expected_rows=1).validate()
|
461
477
|
|
462
478
|
# TODO(zzhu): Also check validity of views. Consider checking schema as well.
|
@@ -824,7 +840,7 @@ class ModelRegistry:
|
|
824
840
|
before setting the metadata attribute. False by default meaning that by default we will check.
|
825
841
|
|
826
842
|
Raises:
|
827
|
-
DataError: Failed to set the
|
843
|
+
DataError: Failed to set the metadata attribute.
|
828
844
|
KeyError: The target model doesn't exist
|
829
845
|
"""
|
830
846
|
selected_models = self._list_selected_models(id=id, model_name=model_name, model_version=model_version)
|
@@ -954,13 +970,13 @@ class ModelRegistry:
|
|
954
970
|
# Check if directory or file and adapt accordingly.
|
955
971
|
# TODO: Unify and explicit about compression for both file and directory.
|
956
972
|
if os.path.isfile(path):
|
957
|
-
self._session.file.put(path,
|
973
|
+
self._session.file.put(path, posixpath.join(fully_qualified_model_stage_name, "data"))
|
958
974
|
elif os.path.isdir(path):
|
959
975
|
with file_utils.zip_file_or_directory_to_stream(path, path) as input_stream:
|
960
976
|
self._session._conn.upload_stream(
|
961
977
|
input_stream=input_stream,
|
962
978
|
stage_location=fully_qualified_model_stage_name,
|
963
|
-
dest_filename=f"{
|
979
|
+
dest_filename=f"{posixpath.basename(path)}.zip",
|
964
980
|
dest_prefix="",
|
965
981
|
source_compression="DEFLATE",
|
966
982
|
compress_data=False,
|
@@ -1066,7 +1082,7 @@ class ModelRegistry:
|
|
1066
1082
|
"""
|
1067
1083
|
# Explicitly not calling collect.
|
1068
1084
|
return self._session.sql(
|
1069
|
-
|
1085
|
+
"SELECT * FROM {database}.{schema}.{view}".format(
|
1070
1086
|
database=self._name, schema=self._schema, view=self._registry_table_view
|
1071
1087
|
)
|
1072
1088
|
)
|
@@ -1123,7 +1139,9 @@ class ModelRegistry:
|
|
1123
1139
|
try:
|
1124
1140
|
del model_tags[tag_name]
|
1125
1141
|
except KeyError:
|
1126
|
-
raise connector.DataError(
|
1142
|
+
raise connector.DataError(
|
1143
|
+
f"Model {model_name}/{model_version} has no tag named {tag_name}. Full list of tags: {model_tags}"
|
1144
|
+
)
|
1127
1145
|
|
1128
1146
|
self._set_metadata_attribute(
|
1129
1147
|
_METADATA_ATTRIBUTE_TAGS, model_tags, model_name=model_name, model_version=model_version
|
@@ -1226,7 +1244,7 @@ class ModelRegistry:
|
|
1226
1244
|
result = self._get_metadata_attribute(
|
1227
1245
|
_METADATA_ATTRIBUTE_DESCRIPTION, model_name=model_name, model_version=model_version
|
1228
1246
|
)
|
1229
|
-
return None if result is None else
|
1247
|
+
return None if result is None else json.loads(result)
|
1230
1248
|
|
1231
1249
|
@telemetry.send_api_usage_telemetry(
|
1232
1250
|
project=_TELEMETRY_PROJECT,
|
@@ -1558,7 +1576,7 @@ class ModelRegistry:
|
|
1558
1576
|
restored_model = None
|
1559
1577
|
with tempfile.TemporaryDirectory() as local_model_directory:
|
1560
1578
|
self._session.file.get(remote_model_path, local_model_directory)
|
1561
|
-
local_path = os.path.join(local_model_directory,
|
1579
|
+
local_path = os.path.join(local_model_directory, posixpath.basename(remote_model_path))
|
1562
1580
|
if zipfile.is_zipfile(local_path):
|
1563
1581
|
extracted_dir = os.path.join(local_model_directory, "extracted")
|
1564
1582
|
with zipfile.ZipFile(local_path, "r") as myzip:
|
snowflake/ml/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
VERSION="1.0.
|
1
|
+
VERSION="1.0.3"
|
@@ -1,11 +1,15 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: snowflake-ml-python
|
3
|
-
Version: 1.0.2
|
4
|
-
Description-Content-Type: text/markdown
|
5
3
|
Author: Snowflake, Inc
|
6
4
|
Author-email: support@snowflake.com
|
7
5
|
Home-page: https://github.com/snowflakedb/snowflake-ml-python
|
8
6
|
License: Apache License, Version 2.0
|
7
|
+
Description-Content-Type: text/markdown
|
8
|
+
Summary: The machine learning client library that is used for interacting with Snowflake to build machine learning solutions.
|
9
|
+
Project-URL: Changelog, https://github.com/snowflakedb/snowflake-ml-python/blob/main/CHANGELOG.md
|
10
|
+
Project-URL: Documentation, https://docs.snowflake.com/developer-guide/snowpark-ml
|
11
|
+
Project-URL: Issues, https://github.com/snowflakedb/snowflake-ml-python/issues
|
12
|
+
Project-URL: Source, https://github.com/snowflakedb/snowflake-ml-python
|
9
13
|
Classifier: Development Status :: 3 - Alpha
|
10
14
|
Classifier: Environment :: Console
|
11
15
|
Classifier: Environment :: Other Environment
|
@@ -25,17 +29,15 @@ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
25
29
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
26
30
|
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
27
31
|
Requires-Python: >=3.8,<4
|
28
|
-
Summary: The machine learning client library that is used for interacting with Snowflake to build machine learning solutions.
|
29
32
|
Requires-Dist: absl-py>=0.15,<2
|
30
33
|
Requires-Dist: anyio>=3.5.0,<4
|
31
34
|
Requires-Dist: cloudpickle
|
32
|
-
Requires-Dist: cryptography>=3.1.0,<39.0.0
|
33
35
|
Requires-Dist: fsspec[http]>=2022.11,<=2023.1
|
34
36
|
Requires-Dist: numpy>=1.23,<2
|
35
37
|
Requires-Dist: packaging>=20.9,<24
|
36
38
|
Requires-Dist: pandas>=1.0.0,<2
|
37
39
|
Requires-Dist: pyyaml>=6.0,<7
|
38
|
-
Requires-Dist: scikit-learn>=1.2.1,<
|
40
|
+
Requires-Dist: scikit-learn>=1.2.1,<1.3
|
39
41
|
Requires-Dist: scipy>=1.9,<2
|
40
42
|
Requires-Dist: snowflake-connector-python[pandas]>=3.0.3,<4
|
41
43
|
Requires-Dist: snowflake-snowpark-python>=1.4.0,<2
|
@@ -52,6 +54,7 @@ Provides-Extra: tensorflow
|
|
52
54
|
Requires-Dist: tensorflow>=2.9,<3; extra == 'tensorflow'
|
53
55
|
Provides-Extra: torch
|
54
56
|
Requires-Dist: torchdata>=0.4,<1; extra == 'torch'
|
57
|
+
Version: 1.0.3
|
55
58
|
|
56
59
|
# Snowpark ML
|
57
60
|
|
@@ -77,9 +80,7 @@ Snowpark MLOps complements the Snowpark ML Development API, and provides model m
|
|
77
80
|
|
78
81
|
During PrPr, we are iterating on API without backward compatibility guarantees. It is better to recreate your registry everytime you update the package. This means, at this time, you cannot use the registry for production use.
|
79
82
|
|
80
|
-
- [Documentation](
|
81
|
-
- [Issues](https://github.com/snowflakedb/snowflake-ml-python/issues)
|
82
|
-
- [Source](https://github.com/snowflakedb/snowflake-ml-python/)
|
83
|
+
- [Documentation](https://docs.snowflake.com/developer-guide/snowpark-ml)
|
83
84
|
|
84
85
|
## Getting started
|
85
86
|
### Have your Snowflake account ready
|
@@ -96,6 +97,24 @@ pip install snowflake-ml-python
|
|
96
97
|
```
|
97
98
|
# Release History
|
98
99
|
|
100
|
+
## 1.0.3 (2023-07-14)
|
101
|
+
|
102
|
+
### Behavior Changes
|
103
|
+
- Model Registry: When predicting a model whose output is a list of NumPy ndarray, the output would not be flattened, instead, every ndarray will act as a feature(column) in the output.
|
104
|
+
|
105
|
+
### New Features
|
106
|
+
- Model Registry: Added support save/load/deploy PyTorch models (`torch.nn.Module` and `torch.jit.ScriptModule`).
|
107
|
+
|
108
|
+
### Bug Fixes
|
109
|
+
|
110
|
+
- Model Registry: Fix an issue that when database or schema name provided to `create_model_registry` contains special characters, the model registry cannot be created.
|
111
|
+
- Model Registry: Fix an issue that `get_model_description` returns with additional quotes.
|
112
|
+
- Model Registry: Fix incorrect error message when attempting to remove a unset tag of a model.
|
113
|
+
- Model Registry: Fix a typo in the default deployment table name.
|
114
|
+
- Model Registry: Snowpark dataframe for sample input or input for `predict` method that contains a column with Snowflake `NUMBER(precision, scale)` data type where `scale = 0` will not lead to error, and will now correctly recognized as `INT64` data type in model signature.
|
115
|
+
- Model Registry: Fix an issue that prevent model logged in the system whose default encoding is not UTF-8 compatible from deploying.
|
116
|
+
- Model Registry: Added earlier and better error message when any file name in the model or the file name of model itself contains characters that are unable to be encoded using ASCII. It is currently not supported to deploy such a model.
|
117
|
+
|
99
118
|
## 1.0.2 (2023-06-22)
|
100
119
|
|
101
120
|
### Behavior Changes
|