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.
Files changed (189) hide show
  1. snowflake/ml/_internal/env_utils.py +2 -1
  2. snowflake/ml/_internal/file_utils.py +29 -7
  3. snowflake/ml/_internal/telemetry.py +5 -8
  4. snowflake/ml/_internal/utils/uri.py +7 -2
  5. snowflake/ml/model/_deploy_client/image_builds/base_image_builder.py +15 -0
  6. snowflake/ml/model/_deploy_client/image_builds/client_image_builder.py +259 -0
  7. snowflake/ml/model/_deploy_client/image_builds/docker_context.py +89 -0
  8. snowflake/ml/model/_deploy_client/image_builds/gunicorn_run.sh +24 -0
  9. snowflake/ml/model/_deploy_client/image_builds/inference_server/main.py +118 -0
  10. snowflake/ml/model/_deploy_client/image_builds/templates/dockerfile_template +40 -0
  11. snowflake/ml/model/_deploy_client/snowservice/deploy.py +199 -0
  12. snowflake/ml/model/_deploy_client/snowservice/deploy_options.py +88 -0
  13. snowflake/ml/model/_deploy_client/snowservice/templates/service_spec_template +24 -0
  14. snowflake/ml/model/_deploy_client/utils/constants.py +47 -0
  15. snowflake/ml/model/_deploy_client/utils/snowservice_client.py +178 -0
  16. snowflake/ml/model/_deploy_client/warehouse/deploy.py +24 -6
  17. snowflake/ml/model/_deploy_client/warehouse/infer_template.py +5 -2
  18. snowflake/ml/model/_deployer.py +14 -27
  19. snowflake/ml/model/_env.py +4 -4
  20. snowflake/ml/model/_handlers/custom.py +14 -2
  21. snowflake/ml/model/_handlers/pytorch.py +186 -0
  22. snowflake/ml/model/_handlers/sklearn.py +14 -9
  23. snowflake/ml/model/_handlers/snowmlmodel.py +14 -9
  24. snowflake/ml/model/_handlers/torchscript.py +180 -0
  25. snowflake/ml/model/_handlers/xgboost.py +19 -9
  26. snowflake/ml/model/_model.py +3 -2
  27. snowflake/ml/model/_model_meta.py +12 -7
  28. snowflake/ml/model/model_signature.py +446 -66
  29. snowflake/ml/model/type_hints.py +23 -4
  30. snowflake/ml/modeling/calibration/calibrated_classifier_cv.py +51 -26
  31. snowflake/ml/modeling/cluster/affinity_propagation.py +51 -26
  32. snowflake/ml/modeling/cluster/agglomerative_clustering.py +51 -26
  33. snowflake/ml/modeling/cluster/birch.py +51 -26
  34. snowflake/ml/modeling/cluster/bisecting_k_means.py +51 -26
  35. snowflake/ml/modeling/cluster/dbscan.py +51 -26
  36. snowflake/ml/modeling/cluster/feature_agglomeration.py +51 -26
  37. snowflake/ml/modeling/cluster/k_means.py +51 -26
  38. snowflake/ml/modeling/cluster/mean_shift.py +51 -26
  39. snowflake/ml/modeling/cluster/mini_batch_k_means.py +51 -26
  40. snowflake/ml/modeling/cluster/optics.py +51 -26
  41. snowflake/ml/modeling/cluster/spectral_biclustering.py +51 -26
  42. snowflake/ml/modeling/cluster/spectral_clustering.py +51 -26
  43. snowflake/ml/modeling/cluster/spectral_coclustering.py +51 -26
  44. snowflake/ml/modeling/compose/column_transformer.py +51 -26
  45. snowflake/ml/modeling/compose/transformed_target_regressor.py +51 -26
  46. snowflake/ml/modeling/covariance/elliptic_envelope.py +51 -26
  47. snowflake/ml/modeling/covariance/empirical_covariance.py +51 -26
  48. snowflake/ml/modeling/covariance/graphical_lasso.py +51 -26
  49. snowflake/ml/modeling/covariance/graphical_lasso_cv.py +51 -26
  50. snowflake/ml/modeling/covariance/ledoit_wolf.py +51 -26
  51. snowflake/ml/modeling/covariance/min_cov_det.py +51 -26
  52. snowflake/ml/modeling/covariance/oas.py +51 -26
  53. snowflake/ml/modeling/covariance/shrunk_covariance.py +51 -26
  54. snowflake/ml/modeling/decomposition/dictionary_learning.py +51 -26
  55. snowflake/ml/modeling/decomposition/factor_analysis.py +51 -26
  56. snowflake/ml/modeling/decomposition/fast_ica.py +51 -26
  57. snowflake/ml/modeling/decomposition/incremental_pca.py +51 -26
  58. snowflake/ml/modeling/decomposition/kernel_pca.py +51 -26
  59. snowflake/ml/modeling/decomposition/mini_batch_dictionary_learning.py +51 -26
  60. snowflake/ml/modeling/decomposition/mini_batch_sparse_pca.py +51 -26
  61. snowflake/ml/modeling/decomposition/pca.py +51 -26
  62. snowflake/ml/modeling/decomposition/sparse_pca.py +51 -26
  63. snowflake/ml/modeling/decomposition/truncated_svd.py +51 -26
  64. snowflake/ml/modeling/discriminant_analysis/linear_discriminant_analysis.py +51 -26
  65. snowflake/ml/modeling/discriminant_analysis/quadratic_discriminant_analysis.py +51 -26
  66. snowflake/ml/modeling/ensemble/ada_boost_classifier.py +51 -26
  67. snowflake/ml/modeling/ensemble/ada_boost_regressor.py +51 -26
  68. snowflake/ml/modeling/ensemble/bagging_classifier.py +51 -26
  69. snowflake/ml/modeling/ensemble/bagging_regressor.py +51 -26
  70. snowflake/ml/modeling/ensemble/extra_trees_classifier.py +51 -26
  71. snowflake/ml/modeling/ensemble/extra_trees_regressor.py +51 -26
  72. snowflake/ml/modeling/ensemble/gradient_boosting_classifier.py +51 -26
  73. snowflake/ml/modeling/ensemble/gradient_boosting_regressor.py +51 -26
  74. snowflake/ml/modeling/ensemble/hist_gradient_boosting_classifier.py +51 -26
  75. snowflake/ml/modeling/ensemble/hist_gradient_boosting_regressor.py +51 -26
  76. snowflake/ml/modeling/ensemble/isolation_forest.py +51 -26
  77. snowflake/ml/modeling/ensemble/random_forest_classifier.py +51 -26
  78. snowflake/ml/modeling/ensemble/random_forest_regressor.py +51 -26
  79. snowflake/ml/modeling/ensemble/stacking_regressor.py +51 -26
  80. snowflake/ml/modeling/ensemble/voting_classifier.py +51 -26
  81. snowflake/ml/modeling/ensemble/voting_regressor.py +51 -26
  82. snowflake/ml/modeling/feature_selection/generic_univariate_select.py +51 -26
  83. snowflake/ml/modeling/feature_selection/select_fdr.py +51 -26
  84. snowflake/ml/modeling/feature_selection/select_fpr.py +51 -26
  85. snowflake/ml/modeling/feature_selection/select_fwe.py +51 -26
  86. snowflake/ml/modeling/feature_selection/select_k_best.py +51 -26
  87. snowflake/ml/modeling/feature_selection/select_percentile.py +51 -26
  88. snowflake/ml/modeling/feature_selection/sequential_feature_selector.py +51 -26
  89. snowflake/ml/modeling/feature_selection/variance_threshold.py +51 -26
  90. snowflake/ml/modeling/gaussian_process/gaussian_process_classifier.py +51 -26
  91. snowflake/ml/modeling/gaussian_process/gaussian_process_regressor.py +51 -26
  92. snowflake/ml/modeling/impute/iterative_imputer.py +51 -26
  93. snowflake/ml/modeling/impute/knn_imputer.py +51 -26
  94. snowflake/ml/modeling/impute/missing_indicator.py +51 -26
  95. snowflake/ml/modeling/kernel_approximation/additive_chi2_sampler.py +51 -26
  96. snowflake/ml/modeling/kernel_approximation/nystroem.py +51 -26
  97. snowflake/ml/modeling/kernel_approximation/polynomial_count_sketch.py +51 -26
  98. snowflake/ml/modeling/kernel_approximation/rbf_sampler.py +51 -26
  99. snowflake/ml/modeling/kernel_approximation/skewed_chi2_sampler.py +51 -26
  100. snowflake/ml/modeling/kernel_ridge/kernel_ridge.py +51 -26
  101. snowflake/ml/modeling/lightgbm/lgbm_classifier.py +51 -26
  102. snowflake/ml/modeling/lightgbm/lgbm_regressor.py +51 -26
  103. snowflake/ml/modeling/linear_model/ard_regression.py +51 -26
  104. snowflake/ml/modeling/linear_model/bayesian_ridge.py +51 -26
  105. snowflake/ml/modeling/linear_model/elastic_net.py +51 -26
  106. snowflake/ml/modeling/linear_model/elastic_net_cv.py +51 -26
  107. snowflake/ml/modeling/linear_model/gamma_regressor.py +51 -26
  108. snowflake/ml/modeling/linear_model/huber_regressor.py +51 -26
  109. snowflake/ml/modeling/linear_model/lars.py +51 -26
  110. snowflake/ml/modeling/linear_model/lars_cv.py +51 -26
  111. snowflake/ml/modeling/linear_model/lasso.py +51 -26
  112. snowflake/ml/modeling/linear_model/lasso_cv.py +51 -26
  113. snowflake/ml/modeling/linear_model/lasso_lars.py +51 -26
  114. snowflake/ml/modeling/linear_model/lasso_lars_cv.py +51 -26
  115. snowflake/ml/modeling/linear_model/lasso_lars_ic.py +51 -26
  116. snowflake/ml/modeling/linear_model/linear_regression.py +51 -26
  117. snowflake/ml/modeling/linear_model/logistic_regression.py +51 -26
  118. snowflake/ml/modeling/linear_model/logistic_regression_cv.py +51 -26
  119. snowflake/ml/modeling/linear_model/multi_task_elastic_net.py +51 -26
  120. snowflake/ml/modeling/linear_model/multi_task_elastic_net_cv.py +51 -26
  121. snowflake/ml/modeling/linear_model/multi_task_lasso.py +51 -26
  122. snowflake/ml/modeling/linear_model/multi_task_lasso_cv.py +51 -26
  123. snowflake/ml/modeling/linear_model/orthogonal_matching_pursuit.py +51 -26
  124. snowflake/ml/modeling/linear_model/passive_aggressive_classifier.py +51 -26
  125. snowflake/ml/modeling/linear_model/passive_aggressive_regressor.py +51 -26
  126. snowflake/ml/modeling/linear_model/perceptron.py +51 -26
  127. snowflake/ml/modeling/linear_model/poisson_regressor.py +51 -26
  128. snowflake/ml/modeling/linear_model/ransac_regressor.py +51 -26
  129. snowflake/ml/modeling/linear_model/ridge.py +51 -26
  130. snowflake/ml/modeling/linear_model/ridge_classifier.py +51 -26
  131. snowflake/ml/modeling/linear_model/ridge_classifier_cv.py +51 -26
  132. snowflake/ml/modeling/linear_model/ridge_cv.py +51 -26
  133. snowflake/ml/modeling/linear_model/sgd_classifier.py +51 -26
  134. snowflake/ml/modeling/linear_model/sgd_one_class_svm.py +51 -26
  135. snowflake/ml/modeling/linear_model/sgd_regressor.py +51 -26
  136. snowflake/ml/modeling/linear_model/theil_sen_regressor.py +51 -26
  137. snowflake/ml/modeling/linear_model/tweedie_regressor.py +51 -26
  138. snowflake/ml/modeling/manifold/isomap.py +51 -26
  139. snowflake/ml/modeling/manifold/mds.py +51 -26
  140. snowflake/ml/modeling/manifold/spectral_embedding.py +51 -26
  141. snowflake/ml/modeling/manifold/tsne.py +51 -26
  142. snowflake/ml/modeling/mixture/bayesian_gaussian_mixture.py +51 -26
  143. snowflake/ml/modeling/mixture/gaussian_mixture.py +51 -26
  144. snowflake/ml/modeling/model_selection/grid_search_cv.py +51 -26
  145. snowflake/ml/modeling/model_selection/randomized_search_cv.py +51 -26
  146. snowflake/ml/modeling/multiclass/one_vs_one_classifier.py +51 -26
  147. snowflake/ml/modeling/multiclass/one_vs_rest_classifier.py +51 -26
  148. snowflake/ml/modeling/multiclass/output_code_classifier.py +51 -26
  149. snowflake/ml/modeling/naive_bayes/bernoulli_nb.py +51 -26
  150. snowflake/ml/modeling/naive_bayes/categorical_nb.py +51 -26
  151. snowflake/ml/modeling/naive_bayes/complement_nb.py +51 -26
  152. snowflake/ml/modeling/naive_bayes/gaussian_nb.py +51 -26
  153. snowflake/ml/modeling/naive_bayes/multinomial_nb.py +51 -26
  154. snowflake/ml/modeling/neighbors/k_neighbors_classifier.py +51 -26
  155. snowflake/ml/modeling/neighbors/k_neighbors_regressor.py +51 -26
  156. snowflake/ml/modeling/neighbors/kernel_density.py +51 -26
  157. snowflake/ml/modeling/neighbors/local_outlier_factor.py +51 -26
  158. snowflake/ml/modeling/neighbors/nearest_centroid.py +51 -26
  159. snowflake/ml/modeling/neighbors/nearest_neighbors.py +51 -26
  160. snowflake/ml/modeling/neighbors/neighborhood_components_analysis.py +51 -26
  161. snowflake/ml/modeling/neighbors/radius_neighbors_classifier.py +51 -26
  162. snowflake/ml/modeling/neighbors/radius_neighbors_regressor.py +51 -26
  163. snowflake/ml/modeling/neural_network/bernoulli_rbm.py +51 -26
  164. snowflake/ml/modeling/neural_network/mlp_classifier.py +51 -26
  165. snowflake/ml/modeling/neural_network/mlp_regressor.py +51 -26
  166. snowflake/ml/modeling/preprocessing/ordinal_encoder.py +2 -0
  167. snowflake/ml/modeling/preprocessing/polynomial_features.py +51 -26
  168. snowflake/ml/modeling/semi_supervised/label_propagation.py +51 -26
  169. snowflake/ml/modeling/semi_supervised/label_spreading.py +51 -26
  170. snowflake/ml/modeling/svm/linear_svc.py +51 -26
  171. snowflake/ml/modeling/svm/linear_svr.py +51 -26
  172. snowflake/ml/modeling/svm/nu_svc.py +51 -26
  173. snowflake/ml/modeling/svm/nu_svr.py +51 -26
  174. snowflake/ml/modeling/svm/svc.py +51 -26
  175. snowflake/ml/modeling/svm/svr.py +51 -26
  176. snowflake/ml/modeling/tree/decision_tree_classifier.py +51 -26
  177. snowflake/ml/modeling/tree/decision_tree_regressor.py +51 -26
  178. snowflake/ml/modeling/tree/extra_tree_classifier.py +51 -26
  179. snowflake/ml/modeling/tree/extra_tree_regressor.py +51 -26
  180. snowflake/ml/modeling/xgboost/xgb_classifier.py +51 -26
  181. snowflake/ml/modeling/xgboost/xgb_regressor.py +51 -26
  182. snowflake/ml/modeling/xgboost/xgbrf_classifier.py +51 -26
  183. snowflake/ml/modeling/xgboost/xgbrf_regressor.py +51 -26
  184. snowflake/ml/registry/model_registry.py +74 -56
  185. snowflake/ml/version.py +1 -1
  186. {snowflake_ml_python-1.0.2.dist-info → snowflake_ml_python-1.0.3.dist-info}/METADATA +27 -8
  187. snowflake_ml_python-1.0.3.dist-info/RECORD +259 -0
  188. snowflake_ml_python-1.0.2.dist-info/RECORD +0 -246
  189. {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.id)
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
- stage_transform_file_name = os.path.join(transform_stage_name, os.path.basename(local_transform_file_name))
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.id)
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 = session.call(
616
- fit_sproc_name,
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=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
- os.path.join(stage_result_file_name, sproc_export_file_name),
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.id, method=inference_method)
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.id
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="float",
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 an empty list if current object is not a classifier or not yet fitted.
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.id)
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
- stage_score_file_name = os.path.join(score_stage_name, os.path.basename(local_score_file_name))
1256
- score_sproc_name = "SNOWML_SCORE_{safe_id}".format(safe_id=self.id)
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 = session.call(
1340
- score_sproc_name,
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=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, outputs)
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, outputs)
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, outputs)
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 = "_SYSTEM_REGISRTRY_DEPLOYMENTS"
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
- registry_table_name = _MODELS_TABLE_NAME
87
- metadata_table_name = _METADATA_TABLE_NAME
88
- deployment_table_name = _DEPLOYMENT_TABLE_NAME
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'CREATE DATABASE "{database_name}"').collect(statement_params=statement_params)
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(f"SHOW SCHEMAS LIKE '{schema_name}' IN DATABASE \"{database_name}\"").collect(
157
- statement_params=statement_params
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(f'The schmea "{database_name}"."{schema_name}" already exists. Skipping creation.')
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'CREATE SCHEMA "{database_name}"."{schema_name}"').collect(statement_params=statement_params)
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
- f"{identifier.quote_name_without_upper_casing(table_name)}",
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 + "_LAST_"
297
+ metadata_view_name_prefix = identifier.concat_names([metadata_table_name, "_LAST_"])
295
298
  metadata_view_template = formatting.unwrap(
296
- """CREATE OR REPLACE VIEW "{database}"."{schema}"."{attribute_view}" COPY GRANTS AS
297
- SELECT DISTINCT MODEL_ID, {select_expression} AS {final_attribute_name} FROM "{metadata_table}"
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 = f"{metadata_view_name_prefix}{attribute_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 + "_TIMESTAMP"
325
- view_name = f"{metadata_view_name_prefix}{attribute_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
- 'LEFT JOIN "{view}" ON ("{view}".MODEL_ID = "{registry_table}".ID)'.format(
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 + "_VIEW"
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}."{registry_view_name}" COPY GRANTS AS
355
- SELECT "{registry_table_name}".*, {metadata_select_fields_formatted}
356
- FROM "{registry_table_name}" {metadata_views_join}"""
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}."{deployment_table_name}_VIEW"
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 + "_VIEW"
423
- self._metadata_table = _METADATA_TABLE_NAME
424
- self._deployment_table = _DEPLOYMENT_TABLE_NAME
425
- self._permanent_deployment_view = self._deployment_table + "_VIEW"
426
- self._permanent_deployment_stage = self._deployment_table + "_STAGE"
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, query=f"SHOW SCHEMAS LIKE '{self._schema}' IN DATABASE \"{self._name}\""
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, query=f"SHOW TABLES LIKE '{self._registry_table}' IN {self._fully_qualified_schema_name()}"
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, query=f"SHOW TABLES LIKE '{self._metadata_table}' IN {self._fully_qualified_schema_name()}"
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, query=f"SHOW TABLES LIKE '{self._deployment_table}' IN {self._fully_qualified_schema_name()}"
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 meatdata attribute.
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, f"{fully_qualified_model_stage_name}/data")
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"{os.path.basename(path)}.zip",
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
- 'SELECT * FROM "{database}"."{schema}"."{view}"'.format(
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(f"Model id {id} has not tag named {tag_name}. Full list of tags: {model_tags}")
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 str(result)
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, os.path.basename(remote_model_path))
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.2"
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,<2
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](http://docs.snowflake.com/developer-guide/snowpark/python/snowpark-ml-modeling)
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