aimodelshare 0.3.7__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 (171) hide show
  1. aimodelshare/README.md +26 -0
  2. aimodelshare/__init__.py +100 -0
  3. aimodelshare/aimsonnx.py +2381 -0
  4. aimodelshare/api.py +836 -0
  5. aimodelshare/auth.py +163 -0
  6. aimodelshare/aws.py +511 -0
  7. aimodelshare/aws_client.py +173 -0
  8. aimodelshare/base_image.py +154 -0
  9. aimodelshare/bucketpolicy.py +106 -0
  10. aimodelshare/color_mappings/color_mapping_keras.csv +121 -0
  11. aimodelshare/color_mappings/color_mapping_pytorch.csv +117 -0
  12. aimodelshare/containerisation.py +244 -0
  13. aimodelshare/containerization.py +712 -0
  14. aimodelshare/containerization_templates/Dockerfile.txt +8 -0
  15. aimodelshare/containerization_templates/Dockerfile_PySpark.txt +23 -0
  16. aimodelshare/containerization_templates/buildspec.txt +14 -0
  17. aimodelshare/containerization_templates/lambda_function.txt +40 -0
  18. aimodelshare/custom_approach/__init__.py +1 -0
  19. aimodelshare/custom_approach/lambda_function.py +17 -0
  20. aimodelshare/custom_eval_metrics.py +103 -0
  21. aimodelshare/data_sharing/__init__.py +0 -0
  22. aimodelshare/data_sharing/data_sharing_templates/Dockerfile.txt +3 -0
  23. aimodelshare/data_sharing/data_sharing_templates/__init__.py +1 -0
  24. aimodelshare/data_sharing/data_sharing_templates/buildspec.txt +15 -0
  25. aimodelshare/data_sharing/data_sharing_templates/codebuild_policies.txt +129 -0
  26. aimodelshare/data_sharing/data_sharing_templates/codebuild_trust_relationship.txt +12 -0
  27. aimodelshare/data_sharing/download_data.py +620 -0
  28. aimodelshare/data_sharing/share_data.py +373 -0
  29. aimodelshare/data_sharing/utils.py +8 -0
  30. aimodelshare/deploy_custom_lambda.py +246 -0
  31. aimodelshare/documentation/Makefile +20 -0
  32. aimodelshare/documentation/karma_sphinx_theme/__init__.py +28 -0
  33. aimodelshare/documentation/karma_sphinx_theme/_version.py +2 -0
  34. aimodelshare/documentation/karma_sphinx_theme/breadcrumbs.html +70 -0
  35. aimodelshare/documentation/karma_sphinx_theme/layout.html +172 -0
  36. aimodelshare/documentation/karma_sphinx_theme/search.html +50 -0
  37. aimodelshare/documentation/karma_sphinx_theme/searchbox.html +14 -0
  38. aimodelshare/documentation/karma_sphinx_theme/static/css/custom.css +2 -0
  39. aimodelshare/documentation/karma_sphinx_theme/static/css/custom.css.map +1 -0
  40. aimodelshare/documentation/karma_sphinx_theme/static/css/theme.css +2751 -0
  41. aimodelshare/documentation/karma_sphinx_theme/static/css/theme.css.map +1 -0
  42. aimodelshare/documentation/karma_sphinx_theme/static/css/theme.min.css +2 -0
  43. aimodelshare/documentation/karma_sphinx_theme/static/css/theme.min.css.map +1 -0
  44. aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.eot +0 -0
  45. aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.svg +32 -0
  46. aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.ttf +0 -0
  47. aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.woff +0 -0
  48. aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.woff2 +0 -0
  49. aimodelshare/documentation/karma_sphinx_theme/static/js/theme.js +68 -0
  50. aimodelshare/documentation/karma_sphinx_theme/theme.conf +9 -0
  51. aimodelshare/documentation/make.bat +35 -0
  52. aimodelshare/documentation/requirements.txt +2 -0
  53. aimodelshare/documentation/source/about.rst +18 -0
  54. aimodelshare/documentation/source/advanced_features.rst +137 -0
  55. aimodelshare/documentation/source/competition.rst +218 -0
  56. aimodelshare/documentation/source/conf.py +58 -0
  57. aimodelshare/documentation/source/create_credentials.rst +86 -0
  58. aimodelshare/documentation/source/example_notebooks.rst +132 -0
  59. aimodelshare/documentation/source/functions.rst +151 -0
  60. aimodelshare/documentation/source/gettingstarted.rst +390 -0
  61. aimodelshare/documentation/source/images/creds1.png +0 -0
  62. aimodelshare/documentation/source/images/creds2.png +0 -0
  63. aimodelshare/documentation/source/images/creds3.png +0 -0
  64. aimodelshare/documentation/source/images/creds4.png +0 -0
  65. aimodelshare/documentation/source/images/creds5.png +0 -0
  66. aimodelshare/documentation/source/images/creds_file_example.png +0 -0
  67. aimodelshare/documentation/source/images/predict_tab.png +0 -0
  68. aimodelshare/documentation/source/index.rst +110 -0
  69. aimodelshare/documentation/source/modelplayground.rst +132 -0
  70. aimodelshare/exceptions.py +11 -0
  71. aimodelshare/generatemodelapi.py +1270 -0
  72. aimodelshare/iam/codebuild_policy.txt +129 -0
  73. aimodelshare/iam/codebuild_trust_relationship.txt +12 -0
  74. aimodelshare/iam/lambda_policy.txt +15 -0
  75. aimodelshare/iam/lambda_trust_relationship.txt +12 -0
  76. aimodelshare/json_templates/__init__.py +1 -0
  77. aimodelshare/json_templates/api_json.txt +155 -0
  78. aimodelshare/json_templates/auth/policy.txt +1 -0
  79. aimodelshare/json_templates/auth/role.txt +1 -0
  80. aimodelshare/json_templates/eval/policy.txt +1 -0
  81. aimodelshare/json_templates/eval/role.txt +1 -0
  82. aimodelshare/json_templates/function/policy.txt +1 -0
  83. aimodelshare/json_templates/function/role.txt +1 -0
  84. aimodelshare/json_templates/integration_response.txt +5 -0
  85. aimodelshare/json_templates/lambda_policy_1.txt +15 -0
  86. aimodelshare/json_templates/lambda_policy_2.txt +8 -0
  87. aimodelshare/json_templates/lambda_role_1.txt +12 -0
  88. aimodelshare/json_templates/lambda_role_2.txt +16 -0
  89. aimodelshare/leaderboard.py +174 -0
  90. aimodelshare/main/1.txt +132 -0
  91. aimodelshare/main/1B.txt +112 -0
  92. aimodelshare/main/2.txt +153 -0
  93. aimodelshare/main/3.txt +134 -0
  94. aimodelshare/main/4.txt +128 -0
  95. aimodelshare/main/5.txt +109 -0
  96. aimodelshare/main/6.txt +105 -0
  97. aimodelshare/main/7.txt +144 -0
  98. aimodelshare/main/8.txt +142 -0
  99. aimodelshare/main/__init__.py +1 -0
  100. aimodelshare/main/authorization.txt +275 -0
  101. aimodelshare/main/eval_classification.txt +79 -0
  102. aimodelshare/main/eval_lambda.txt +1709 -0
  103. aimodelshare/main/eval_regression.txt +80 -0
  104. aimodelshare/main/lambda_function.txt +8 -0
  105. aimodelshare/main/nst.txt +149 -0
  106. aimodelshare/model.py +1543 -0
  107. aimodelshare/modeluser.py +215 -0
  108. aimodelshare/moral_compass/README.md +408 -0
  109. aimodelshare/moral_compass/__init__.py +65 -0
  110. aimodelshare/moral_compass/_version.py +3 -0
  111. aimodelshare/moral_compass/api_client.py +601 -0
  112. aimodelshare/moral_compass/apps/__init__.py +69 -0
  113. aimodelshare/moral_compass/apps/ai_consequences.py +540 -0
  114. aimodelshare/moral_compass/apps/bias_detective.py +714 -0
  115. aimodelshare/moral_compass/apps/ethical_revelation.py +898 -0
  116. aimodelshare/moral_compass/apps/fairness_fixer.py +889 -0
  117. aimodelshare/moral_compass/apps/judge.py +888 -0
  118. aimodelshare/moral_compass/apps/justice_equity_upgrade.py +853 -0
  119. aimodelshare/moral_compass/apps/mc_integration_helpers.py +820 -0
  120. aimodelshare/moral_compass/apps/model_building_game.py +1104 -0
  121. aimodelshare/moral_compass/apps/model_building_game_beginner.py +687 -0
  122. aimodelshare/moral_compass/apps/moral_compass_challenge.py +858 -0
  123. aimodelshare/moral_compass/apps/session_auth.py +254 -0
  124. aimodelshare/moral_compass/apps/shared_activity_styles.css +349 -0
  125. aimodelshare/moral_compass/apps/tutorial.py +481 -0
  126. aimodelshare/moral_compass/apps/what_is_ai.py +853 -0
  127. aimodelshare/moral_compass/challenge.py +365 -0
  128. aimodelshare/moral_compass/config.py +187 -0
  129. aimodelshare/placeholders/model.onnx +0 -0
  130. aimodelshare/placeholders/preprocessor.zip +0 -0
  131. aimodelshare/playground.py +1968 -0
  132. aimodelshare/postprocessormodules.py +157 -0
  133. aimodelshare/preprocessormodules.py +373 -0
  134. aimodelshare/pyspark/1.txt +195 -0
  135. aimodelshare/pyspark/1B.txt +181 -0
  136. aimodelshare/pyspark/2.txt +220 -0
  137. aimodelshare/pyspark/3.txt +204 -0
  138. aimodelshare/pyspark/4.txt +187 -0
  139. aimodelshare/pyspark/5.txt +178 -0
  140. aimodelshare/pyspark/6.txt +174 -0
  141. aimodelshare/pyspark/7.txt +211 -0
  142. aimodelshare/pyspark/8.txt +206 -0
  143. aimodelshare/pyspark/__init__.py +1 -0
  144. aimodelshare/pyspark/authorization.txt +258 -0
  145. aimodelshare/pyspark/eval_classification.txt +79 -0
  146. aimodelshare/pyspark/eval_lambda.txt +1441 -0
  147. aimodelshare/pyspark/eval_regression.txt +80 -0
  148. aimodelshare/pyspark/lambda_function.txt +8 -0
  149. aimodelshare/pyspark/nst.txt +213 -0
  150. aimodelshare/python/my_preprocessor.py +58 -0
  151. aimodelshare/readme.md +26 -0
  152. aimodelshare/reproducibility.py +181 -0
  153. aimodelshare/sam/Dockerfile.txt +8 -0
  154. aimodelshare/sam/Dockerfile_PySpark.txt +24 -0
  155. aimodelshare/sam/__init__.py +1 -0
  156. aimodelshare/sam/buildspec.txt +11 -0
  157. aimodelshare/sam/codebuild_policies.txt +129 -0
  158. aimodelshare/sam/codebuild_trust_relationship.txt +12 -0
  159. aimodelshare/sam/codepipeline_policies.txt +173 -0
  160. aimodelshare/sam/codepipeline_trust_relationship.txt +12 -0
  161. aimodelshare/sam/spark-class.txt +2 -0
  162. aimodelshare/sam/template.txt +54 -0
  163. aimodelshare/tools.py +103 -0
  164. aimodelshare/utils/__init__.py +78 -0
  165. aimodelshare/utils/optional_deps.py +38 -0
  166. aimodelshare/utils.py +57 -0
  167. aimodelshare-0.3.7.dist-info/METADATA +298 -0
  168. aimodelshare-0.3.7.dist-info/RECORD +171 -0
  169. aimodelshare-0.3.7.dist-info/WHEEL +5 -0
  170. aimodelshare-0.3.7.dist-info/licenses/LICENSE +5 -0
  171. aimodelshare-0.3.7.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1968 @@
1
+ # import packages
2
+ import os
3
+ import contextlib
4
+ import boto3
5
+ from aimodelshare.api import get_api_json
6
+ import tempfile
7
+
8
+ try:
9
+ import torch
10
+ except:
11
+ pass
12
+ import onnx
13
+ from aimodelshare.utils import HiddenPrints
14
+ import signal
15
+ from aimodelshare.aimsonnx import model_to_onnx, model_to_onnx_timed
16
+ from aimodelshare.tools import extract_varnames_fromtrainingdata, _get_extension_from_filepath
17
+ import time
18
+ import numpy as np
19
+ import json
20
+ import pandas
21
+ import requests
22
+ from aimodelshare.aws import get_aws_token
23
+
24
+
25
+ class ModelPlayground:
26
+ """
27
+ Parameters:
28
+ ----------
29
+ `model_type` : ``string``
30
+ values - [ 'text' , 'image' , 'tabular' , 'video', 'audio','timeseries' ]
31
+ type of model data
32
+ `classification`: ``bool, default=True``
33
+ True [DEFAULT] if model is of Classification type with categorical target variables
34
+ False if model is of Regression type with continuous target variables
35
+ `private` : ``bool, default = False``
36
+ True if model and its corresponding data is not public
37
+ False [DEFAULT] if model and its corresponding data is public
38
+ `email_list`: ``list of string values``
39
+ values - list including all emails of users who have access the private playground.
40
+ list should contain same emails that were used by users to sign up for modelshare.ai account.
41
+ [OPTIONAL] set by the playground owner for private playgrounds. Can also be updated by editing deployed
42
+ playground page at www.modelshare.ai.
43
+ """
44
+
45
+ def __init__(self, input_type=None, task_type=None, private=None, playground_url=None, email_list=None):
46
+ # confirm correct args are provided
47
+ if playground_url == None and any([input_type == None, task_type == None, private == None]):
48
+ raise ValueError(
49
+ "To instantiate a ModelPlayground instance, please provide either a playground_url or \n the input_type, task_type, and private arguments.")
50
+
51
+ self.model_type = input_type
52
+
53
+ if task_type == None:
54
+ post_dict = {"return_task_type": "TRUE"}
55
+ headers = { 'Content-Type':'application/json', 'authorizationToken': os.environ.get("AWS_TOKEN"),}
56
+ playground_url_eval=playground_url[:-1]+"eval"
57
+ response = requests.post(playground_url_eval,headers=headers,data=json.dumps(post_dict))
58
+ task_type = json.loads(response.text)['task_type']
59
+
60
+ if task_type == "classification":
61
+ self.categorical = True
62
+ elif task_type == "regression":
63
+ self.categorical = False
64
+ else:
65
+ raise ValueError('Please set task_type argument to "classification" or "regression".')
66
+
67
+ self.private = private
68
+ self.playground_url = playground_url
69
+ self.model_page = None
70
+
71
+ if email_list is None:
72
+ self.email_list = []
73
+ else:
74
+ self.email_list = email_list
75
+
76
+ def codestring(self):
77
+ if self.playground_url == None:
78
+ return "ModelPlayground(model_type=" + "'" + str(self.model_type) + "'" + ",classification=" + str(
79
+ self.categorical) + ",private=" + str(self.private) + ",playground_url=" + str(
80
+ self.playground_url) + ",email_list=" + str(self.email_list) + ")"
81
+ else:
82
+ return "ModelPlayground(model_type=" + "'" + str(self.model_type) + "'" + ",classification=" + str(
83
+ self.categorical) + ",private=" + str(self.private) + ",playground_url=" + "'" + str(
84
+ self.playground_url) + "'" + ",email_list=" + str(self.email_list) + ")"
85
+
86
+ self.class_string = codestring(self)
87
+
88
+ def __str__(self):
89
+ return f"ModelPlayground(self.model_type,self.categorical,self.private = private,self.playground_url,self.email_list)"
90
+
91
+ def activate(self, model_filepath=None, preprocessor_filepath=None, y_train=None, example_data=None,
92
+ custom_libraries="FALSE", image="", reproducibility_env_filepath=None, memory=None, timeout=None,
93
+ onnx_timeout=60, pyspark_support=False, model_input=None, input_dict=None, playground_id=False):
94
+
95
+ """
96
+ Launches a live model playground to the www.modelshare.ai website. The playground can optionally include a live prediction REST API for deploying ML models using model parameters and user credentials, provided by the user.
97
+ Inputs : 7
98
+ Output : model launched to an API
99
+ detailed API info printed out
100
+ Parameters:
101
+ ----------
102
+ `model_filepath` : ``string`` ends with '.onnx'
103
+ value - Absolute path to model file
104
+ .onnx is the only accepted model file extension
105
+ "example_model.onnx" filename for file in directory.
106
+ "/User/xyz/model/example_model.onnx" absolute path to model file from local directory
107
+ if no value is set the playground will be launched with only a placeholder prediction API.
108
+ `preprocessor_filepath`: ``string``
109
+ value - absolute path to preprocessor file
110
+ "./preprocessor.zip"
111
+ searches for an exported zip preprocessor file in the current directory
112
+ file is generated using export_preprocessor function from the AI Modelshare library
113
+ if no value is set the playground will be launched with only a placeholder prediction API.
114
+ `y_train` : training labels for classification models.
115
+ expects pandas dataframe of one hot encoded y train data
116
+ if no value is set ... #TODO
117
+ `example_data`: ``Example of X data that will be shown on the online Playground page.
118
+ if no example data is submitted, certain functionalities may be limited, including the deployment of live prediction APIs.
119
+ Example data can be updated at a later stage, using the update_example_data() method.``
120
+ `custom_libraries`: ``string``
121
+ "TRUE" if user wants to load custom Python libraries to their prediction runtime
122
+ "FALSE" if user wishes to use AI Model Share base libraries including latest versions of most common ML libs.
123
+ `reproducibility_env_filepath`: ``TODO``
124
+ `memory`: ``TODO``
125
+ `timeout`: ``TODO``
126
+ `onnx_timeout`: ``int``
127
+ Time in seconds after which ONNX conversion should be interrupted.
128
+ Set to False if you want to force ONNX conversion.
129
+ `pyspark_support`: ``TODO``
130
+ `model_input`: ``array_like``
131
+ Required only when framework="pytorch"
132
+ One example of X training data in correct format.
133
+
134
+ Returns:
135
+ --------
136
+ print_api_info : prints statements with generated model playground page and live prediction API details
137
+ also prints steps to update the model submissions by the user/team
138
+ """
139
+
140
+ # test whether playground is already active
141
+ if self.playground_url:
142
+ print(self.playground_url)
143
+
144
+ def ask_user():
145
+ print("Playground is already active. Would you like to overwrite?")
146
+ response = ''
147
+ while response not in {"yes", "no"}:
148
+ response = input("Please enter yes or no: ").lower()
149
+ return response != "yes"
150
+
151
+ r = ask_user()
152
+
153
+ if r:
154
+ return
155
+
156
+ # convert model to onnx
157
+ if onnx_timeout == False:
158
+ force_onnx = True
159
+ else:
160
+ force_onnx = False
161
+ model_filepath = model_to_onnx_timed(model_filepath, timeout=onnx_timeout,
162
+ force_onnx=force_onnx, model_input=model_input)
163
+
164
+ # keep track of submitted artifacts
165
+ if isinstance(y_train, pandas.Series):
166
+ y_train_bool = True
167
+ else:
168
+ y_train_bool = bool(y_train)
169
+
170
+ if isinstance(example_data, (pandas.Series, pandas.DataFrame, str)):
171
+ example_data_bool = True
172
+ else:
173
+ example_data_bool = False
174
+
175
+ track_artifacts = {"model_filepath": bool(model_filepath),
176
+ "preprocessor_filepath": bool(preprocessor_filepath),
177
+ "y_train": y_train_bool,
178
+ "example_data": example_data_bool,
179
+ "custom_libraries": bool(custom_libraries),
180
+ "image": bool(image),
181
+ "reproducibility_env_filepath": bool(reproducibility_env_filepath),
182
+ "memory": bool(memory),
183
+ "timeout": bool(timeout),
184
+ "pyspark_support": bool(pyspark_support)
185
+ }
186
+
187
+ import pkg_resources
188
+
189
+ # insert placeholders into empty arguments
190
+ if model_filepath == None:
191
+ model_filepath = pkg_resources.resource_filename(__name__, "placeholders/model.onnx")
192
+
193
+ if preprocessor_filepath == None:
194
+ preprocessor_filepath = pkg_resources.resource_filename(__name__, "placeholders/preprocessor.zip")
195
+
196
+ if y_train_bool == False:
197
+ y_train = []
198
+
199
+ if example_data_bool == False and self.model_type == "tabular":
200
+ example_data = pandas.DataFrame()
201
+
202
+ import json, tempfile
203
+ tfile = tempfile.NamedTemporaryFile(mode="w+")
204
+ json.dump(track_artifacts, tfile)
205
+ tfile.flush()
206
+
207
+ if input_dict == None:
208
+ input_dict = {"requirements": "",
209
+ "model_name": "Default Model Playground",
210
+ "model_description": "",
211
+ "tags": ""}
212
+ playground_id = True
213
+ else:
214
+ playground_id = False
215
+
216
+ from aimodelshare.generatemodelapi import model_to_api
217
+ self.playground_url = model_to_api(model_filepath=model_filepath,
218
+ model_type=self.model_type,
219
+ private=self.private,
220
+ categorical=self.categorical,
221
+ y_train=y_train,
222
+ preprocessor_filepath=preprocessor_filepath,
223
+ example_data=example_data,
224
+ custom_libraries=custom_libraries,
225
+ image=image,
226
+ reproducibility_env_filepath=reproducibility_env_filepath,
227
+ memory=memory,
228
+ timeout=timeout,
229
+ email_list=self.email_list,
230
+ pyspark_support=pyspark_support,
231
+ input_dict=input_dict,
232
+ print_output=False,
233
+ playground_id=playground_id
234
+ )
235
+ # remove extra quotes
236
+ self.playground_url = self.playground_url[1:-1]
237
+
238
+ # upload track artifacts
239
+ from aimodelshare.aws import get_s3_iam_client
240
+ s3, iam, region = get_s3_iam_client(os.environ.get("AWS_ACCESS_KEY_ID_AIMS"),
241
+ os.environ.get("AWS_SECRET_ACCESS_KEY_AIMS"),
242
+ os.environ.get("AWS_REGION_AIMS"))
243
+
244
+ unique_model_id = self.playground_url.split(".")[0].split("//")[-1]
245
+
246
+ try:
247
+ s3["client"].upload_file(tfile.name, os.environ.get("BUCKET_NAME"),
248
+ unique_model_id + "/track_artifacts.json")
249
+ except:
250
+ pass
251
+
252
+ def deploy(self, model_filepath, preprocessor_filepath, y_train, example_data=None, custom_libraries="FALSE",
253
+ image="", reproducibility_env_filepath=None, memory=None, timeout=None, onnx_timeout=60,
254
+ pyspark_support=False,
255
+ model_input=None, input_dict=None):
256
+
257
+ """
258
+ Launches a live prediction REST API for deploying ML models using model parameters and user credentials, provided by the user
259
+ Inputs : 7
260
+ Output : model launched to an API
261
+ detailed API info printed out
262
+ Parameters:
263
+ ----------
264
+ `model_filepath` : ``string`` ends with '.onnx'
265
+ value - Absolute path to model file
266
+ [REQUIRED] to be set by the user
267
+ .onnx is the only accepted model file extension
268
+ "example_model.onnx" filename for file in directory.
269
+ "/User/xyz/model/example_model.onnx" absolute path to model file from local directory
270
+ `preprocessor_filepath`: ``string``
271
+ value - absolute path to preprocessor file
272
+ [REQUIRED] to be set by the user
273
+ "./preprocessor.zip"
274
+ searches for an exported zip preprocessor file in the current directory
275
+ file is generated using export_preprocessor function from the AI Modelshare library
276
+ `y_train` : training labels for classification models.
277
+ [REQUIRED] for classification type models
278
+ expects pandas dataframe of one hot encoded y train data
279
+ `example_data`: ``Example of X data that will be shown on the online Playground page.
280
+ if no example data is submitted, certain functionalities may be limited, including the deployment of live prediction APIs.
281
+ Example data can be updated at a later stage, using the update_example_data() method.``
282
+ `custom_libraries`: ``string``
283
+ "TRUE" if user wants to load custom Python libraries to their prediction runtime
284
+ "FALSE" if user wishes to use AI Model Share base libraries including latest versions of most common ML libs.
285
+ `image`: ``TODO``
286
+ `reproducibility_env_filepath`: ``TODO``
287
+ `memory`: ``TODO``
288
+ `timeout`: ``TODO``
289
+ `onnx_timeout`: ``int``
290
+ Time in seconds after which ONNX conversion should be interrupted.
291
+ Set to False if you want to force ONNX conversion.
292
+ `pyspark_support`: ``TODO``
293
+ `model_input`: ``array_like``
294
+ Required only when framework="pytorch"
295
+ One example of X training data in correct format.
296
+ `input_dict`: ``dictionary``
297
+ Use to bypass text input boxes Example: {"model_name": "My Model Playground",
298
+ "model_description": "My Model Description",
299
+ "tags": "model, classification, awesome"}
300
+
301
+ Returns:
302
+ --------
303
+ print_api_info : prints statements with generated live prediction API details
304
+ also prints steps to update the model submissions by the user/team
305
+ """
306
+
307
+ # check whether playground url exists
308
+ if self.playground_url:
309
+ print(self.playground_url)
310
+ print("Trying to deploy to active playground. Would you like to overwrite prediction API?")
311
+ response = ''
312
+ while response not in {"yes", "no"}:
313
+ response = input("Please enter yes or no: ").lower()
314
+
315
+ if response == "no":
316
+ print("Please instantiate a new playground and try again.")
317
+ return
318
+ # model deployment files (plus ytrain object)
319
+
320
+ # convert model to onnx
321
+ if onnx_timeout == False:
322
+ force_onnx = True
323
+ else:
324
+ force_onnx = False
325
+ model_filepath = model_to_onnx_timed(model_filepath, timeout=onnx_timeout,
326
+ force_onnx=force_onnx, model_input=model_input)
327
+
328
+ import os
329
+ if os.environ.get("cloud_location") is not None:
330
+ cloudlocation = os.environ.get("cloud_location")
331
+ else:
332
+ cloudlocation = "not set"
333
+ if "model_share" == cloudlocation:
334
+ print("Creating your Model Playground...\nEst. completion: ~1 minute\n")
335
+
336
+ def deployment_output_information():
337
+ import os
338
+ import sys
339
+
340
+ sys.stdout.write(
341
+ "[=== ] Progress: 5% - Accessing cloud, uploading resources...")
342
+ sys.stdout.flush()
343
+ time.sleep(15)
344
+ sys.stdout.write('\r')
345
+ sys.stdout.write(
346
+ "[======== ] Progress: 30% - Building serverless functions and updating permissions...")
347
+ sys.stdout.flush()
348
+ time.sleep(15)
349
+ sys.stdout.write('\r')
350
+ sys.stdout.write(
351
+ "[============ ] Progress: 40% - Creating custom containers... ")
352
+ sys.stdout.flush()
353
+ time.sleep(15)
354
+ sys.stdout.write('\r')
355
+ sys.stdout.write(
356
+ "[========================== ] Progress: 75% - Deploying prediction API... ")
357
+ sys.stdout.flush()
358
+ time.sleep(10)
359
+ sys.stdout.write('\r')
360
+ sys.stdout.write(
361
+ "[================================ ] Progress: 90% - Configuring prediction API... ")
362
+ sys.stdout.flush()
363
+ time.sleep(10)
364
+
365
+ from threading import Thread
366
+ import time
367
+
368
+ thread_running = True
369
+ t1 = Thread(target=deployment_output_information)
370
+ t1.start()
371
+
372
+ def run_deployment_code(model_filepath=model_filepath,
373
+ model_type=self.model_type,
374
+ private=self.private,
375
+ categorical=self.categorical,
376
+ y_train=y_train,
377
+ preprocessor_filepath=preprocessor_filepath,
378
+ example_data=example_data,
379
+ custom_libraries=custom_libraries,
380
+ image=image,
381
+ reproducibility_env_filepath=reproducibility_env_filepath,
382
+ memory=memory,
383
+ timeout=timeout,
384
+ email_list=self.email_list,
385
+ pyspark_support=pyspark_support,
386
+ input_dict=input_dict,
387
+ print_output=False):
388
+
389
+ def upload_playground_zipfile(model_filepath=None, preprocessor_filepath=None, y_train=None,
390
+ example_data=None):
391
+ """
392
+ minimally requires model_filepath, preprocessor_filepath
393
+ """
394
+ import json
395
+ import os
396
+ import requests
397
+ import pandas as pd
398
+ wkingdir = os.getcwd()
399
+ if os.path.dirname(model_filepath) == '':
400
+ model_filepath = wkingdir + "/" + model_filepath
401
+ else:
402
+ pass
403
+
404
+ if os.path.dirname(preprocessor_filepath) == '':
405
+ preprocessor_filepath = wkingdir + "/" + preprocessor_filepath
406
+ else:
407
+ pass
408
+ zipfilelist = [model_filepath, preprocessor_filepath]
409
+
410
+ if any([isinstance(example_data, pd.DataFrame), isinstance(example_data, pd.Series),
411
+ example_data is None]):
412
+ pass
413
+ else:
414
+ if os.path.dirname(example_data) == '':
415
+ example_data = wkingdir + "/" + example_data
416
+ else:
417
+ pass
418
+ zipfilelist.append(example_data)
419
+
420
+ # need to save dict pkl file with arg name and filepaths to add to zipfile
421
+
422
+ apiurl = "https://djoehnv623.execute-api.us-east-2.amazonaws.com/prod/m"
423
+
424
+ apiurl_eval = apiurl[:-1] + "eval"
425
+
426
+ headers = {'Content-Type': 'application/json', 'authorizationToken': json.dumps(
427
+ {"token": os.environ.get("AWS_TOKEN"), "eval": "TEST"}), }
428
+ post_dict = {"return_zip": "True"}
429
+ zipfile = requests.post(apiurl_eval, headers=headers, data=json.dumps(post_dict))
430
+
431
+ zipfileputlistofdicts = json.loads(zipfile.text)['put']
432
+
433
+ zipfilename = list(zipfileputlistofdicts.keys())[0]
434
+
435
+ from zipfile import ZipFile
436
+ import os
437
+ from os.path import basename
438
+ import tempfile
439
+
440
+ wkingdir = os.getcwd()
441
+
442
+ tempdir = tempfile.gettempdir()
443
+
444
+ zipObj = ZipFile(tempdir + "/" + zipfilename, 'w')
445
+ # Add multiple files to the zip
446
+ for i in zipfilelist:
447
+ zipObj.write(i)
448
+
449
+ # add object to pkl file pathway here. (saving y label data)
450
+ import pickle
451
+
452
+ if y_train is None:
453
+ pass
454
+ else:
455
+ with open(tempdir + "/" + 'ytrain.pkl', 'wb') as f:
456
+ pickle.dump(y_train, f)
457
+
458
+ os.chdir(tempdir)
459
+ zipObj.write('ytrain.pkl')
460
+
461
+ if any([isinstance(example_data, pd.DataFrame), isinstance(example_data, pd.Series)]):
462
+ if isinstance(example_data, pd.Series):
463
+ example_data = example_data.to_frame()
464
+ else:
465
+ pass
466
+ with open(tempdir + "/" + 'exampledata.pkl', 'wb') as f:
467
+ pickle.dump(example_data, f)
468
+
469
+ os.chdir(tempdir)
470
+ zipObj.write('exampledata.pkl')
471
+ else:
472
+ pass
473
+
474
+ # close the Zip File
475
+ os.chdir(wkingdir)
476
+
477
+ zipObj.close()
478
+
479
+ import ast
480
+
481
+ finalzipdict = ast.literal_eval(zipfileputlistofdicts[zipfilename])
482
+
483
+ url = finalzipdict['url']
484
+ fields = finalzipdict['fields']
485
+
486
+ #### save files from model deploy to zipfile in tempdir before loading to s3
487
+
488
+ ### Load zipfile to s3
489
+ with open(tempdir + "/" + zipfilename, 'rb') as f:
490
+ files = {'file': (tempdir + "/" + zipfilename, f)}
491
+ http_response = requests.post(url, data=fields, files=files)
492
+ return zipfilename
493
+
494
+ deployzipfilename = upload_playground_zipfile(model_filepath, preprocessor_filepath, y_train,
495
+ example_data)
496
+
497
+ # if aws arg = false, do this, otherwise do aws code
498
+ # create deploy code_string
499
+ def nonecheck(objinput=""):
500
+ if isinstance(objinput, str):
501
+ if objinput is None:
502
+ objinput = "None"
503
+ else:
504
+ objinput = "'/tmp/" + objinput + "'"
505
+ else:
506
+ objinput = 'example_data'
507
+ return objinput
508
+
509
+ deploystring = self.class_string.replace(",aws=False",
510
+ "") + "." + "deploy('/tmp/" + model_filepath + "','/tmp/" + preprocessor_filepath + "'," + 'y_train' + "," + nonecheck(
511
+ example_data) + ",input_dict=" + str(input_dict) + ')'
512
+ import base64
513
+ import requests
514
+ import json
515
+
516
+ api_url = "https://z4kvag4sxdnv2mvs2b6c4thzj40bxnuw.lambda-url.us-east-2.on.aws/"
517
+
518
+ data = json.dumps({"code": """from aimodelshare import ModelPlayground;myplayground=""" + deploystring,
519
+ "zipfilename": deployzipfilename, "username": os.environ.get("username"),
520
+ "password": os.environ.get("password"),
521
+ "token": os.environ.get("JWT_AUTHORIZATION_TOKEN"), "s3keyid": "xrjpv1i7xe"})
522
+
523
+ headers = {"Content-Type": "application/json"}
524
+
525
+ response = requests.request("POST", api_url, headers=headers, data=data)
526
+ # Print response
527
+ global successful_deployment_info340893124738241023
528
+
529
+ result = json.loads(response.text)
530
+ successful_deployment_info340893124738241023 = result
531
+
532
+ modelplaygroundurlid = json.loads(result['body'])[-7].replace("Playground Url: ", "").strip()
533
+ try:
534
+ self.playground_url = modelplaygroundurlid[1:-1]
535
+ except:
536
+ import json
537
+ self.playground_url = json.loads(modelplaygroundurlid)
538
+ pass
539
+
540
+ t2 = Thread(target=run_deployment_code(model_filepath=model_filepath,
541
+ model_type=self.model_type,
542
+ private=self.private,
543
+ categorical=self.categorical,
544
+ y_train=y_train,
545
+ preprocessor_filepath=preprocessor_filepath,
546
+ example_data=example_data,
547
+ custom_libraries=custom_libraries,
548
+ image=image,
549
+ reproducibility_env_filepath=reproducibility_env_filepath,
550
+ memory=memory,
551
+ timeout=timeout,
552
+ email_list=self.email_list,
553
+ pyspark_support=pyspark_support,
554
+ input_dict=input_dict,
555
+ print_output=False))
556
+
557
+ t2.start()
558
+
559
+ t2.join() # interpreter will wait until your process get completed or terminated
560
+ # clear last output
561
+ import os
562
+ import sys
563
+
564
+ def cls():
565
+ os.system('cls' if os.name == 'nt' else 'clear')
566
+
567
+ # now, to clear the screen
568
+ cls()
569
+ from IPython.display import clear_output
570
+ clear_output()
571
+ sys.stdout.write('\r')
572
+ sys.stdout.write(
573
+ "[=====================================] Progress: 100% - Complete! ")
574
+ sys.stdout.flush()
575
+ import json
576
+ print("\n" + json.loads(successful_deployment_info340893124738241023['body'])[-8] + "\n")
577
+ print(
578
+ "View live playground now at:\n" + json.loads(successful_deployment_info340893124738241023['body'])[-1])
579
+
580
+ print("\nConnect to your playground in Python:\n")
581
+ print("myplayground=ModelPlayground(playground_url=" +
582
+ json.loads(successful_deployment_info340893124738241023['body'])[-7].replace("Playground Url: ",
583
+ "").strip() + ")")
584
+
585
+ thread_running = False
586
+
587
+ else:
588
+
589
+ # aws pathway begins here
590
+ from aimodelshare.generatemodelapi import model_to_api
591
+ self.playground_url = model_to_api(model_filepath=model_filepath,
592
+ model_type=self.model_type,
593
+ private=self.private,
594
+ categorical=self.categorical,
595
+ y_train=y_train,
596
+ preprocessor_filepath=preprocessor_filepath,
597
+ example_data=example_data,
598
+ custom_libraries=custom_libraries,
599
+ image=image,
600
+ reproducibility_env_filepath=reproducibility_env_filepath,
601
+ memory=memory,
602
+ timeout=timeout,
603
+ email_list=self.email_list,
604
+ pyspark_support=pyspark_support,
605
+ input_dict=input_dict,
606
+ print_output=False)
607
+ # remove extra quotes
608
+ self.playground_url = self.playground_url[1:-1]
609
+
610
+ def get_apikey(self):
611
+ import os
612
+ import requests
613
+ import json
614
+ if all(["username" in os.environ,
615
+ "password" in os.environ]):
616
+ pass
617
+ else:
618
+ return print("'get_apikey()' unsuccessful. Please provide credentials with set_credentials().")
619
+
620
+ post_dict = {"return_apikey": "True"}
621
+
622
+ headers = {'Content-Type': 'application/json', 'authorizationToken': os.environ.get("AWS_TOKEN"), }
623
+
624
+ apiurl_eval = self.playground_url[:-1] + "eval"
625
+
626
+ api_json = requests.post(apiurl_eval, headers=headers, data=json.dumps(post_dict))
627
+
628
+ return json.loads(api_json.text)['apikey']
629
+
630
+ def create(self, eval_data=None, y_train=None, data_directory=None, eval_metric_filepath=None, email_list=None,
631
+ public=True, public_private_split=0.5, model_input=None, timeout=None, example_data=None,
632
+ custom_libraries="FALSE", image="", reproducibility_env_filepath=None, memory=None,
633
+ pyspark_support=False,
634
+ user_input=False):
635
+
636
+ """
637
+ Submits model/preprocessor to machine learning experiment leaderboard and model architecture database using live prediction API url generated by AI Modelshare library
638
+ The submitted model gets evaluated and compared with all existing models and a leaderboard can be generated
639
+
640
+ Parameters:
641
+ -----------
642
+ `eval_data` : ``list`` of y values used to generate metrics from predicted values from predictions submitted via the submit_model() method
643
+ [REQUIRED] to generate eval metrics in experiment leaderboard
644
+ `y_train` : ``list`` of y values for training data used to extract the set of class labels
645
+ [REQUIRED] for image classification models
646
+ `eval_metric_filepath`: [OPTIONAL] file path of zip file with custon evaluation functions
647
+ `data_directory` : folder storing training data and test data (excluding Y test data)
648
+ `email_list`: [OPTIONAL] list of comma separated emails for users who are allowed to submit models to experiment leaderboard. Emails should be strings in a list.
649
+ `public`: [REQUIRED] True/false. Defaults to False. If True, experiment is public and ANY AIMODELSHARE USER CAN SUBMIT MODELS. USE WITH CAUTION b/c one model and
650
+ one preprocessor file will be be saved to your AWS S3 folder for each model submission.
651
+ `public_private_split`: [REQUIRED] Float between 0 and 1. Defaults to 0. Porportion of test data that is allocated to private hold-out set.
652
+ `model_input`: ``array_like``
653
+ Required only when framework="pytorch"
654
+ One example of X training data in correct format.
655
+ `timeout`: ``TODO``
656
+ `onnx_timeout`: ``int``
657
+ Time in seconds after which ONNX conversion should be interrupted.
658
+ Set to False if you want to force ONNX conversion.
659
+ `example_data`: ``Example of X data that will be shown on the online Playground page.
660
+ if no example data is submitted, certain functionalities may be limited, including the deployment of live prediction APIs.
661
+ Example data can be updated at a later stage, using the update_example_data() method.``
662
+
663
+ Returns:
664
+ -------
665
+ response: Model version if the model is submitted sucessfully
666
+ error if there is any error while submitting models
667
+ """
668
+
669
+ # use placeholder y_train labels if none are submitted
670
+ if y_train == None:
671
+ ytrain = []
672
+
673
+ # use placeholder y_train labels if none are submitted
674
+ if eval_data == None:
675
+ eval_data = []
676
+
677
+ if email_list == None:
678
+ email_list = []
679
+
680
+ # catch email list error
681
+ if public == False and email_list == []:
682
+ raise ValueError("Please submit valid email list for private competition/experiment.")
683
+
684
+ # test whether playground is active, activate if that is not the case
685
+ if not self.playground_url:
686
+
687
+ if user_input:
688
+
689
+ print("Submit Model Playground data.")
690
+ model_name = input("Playground name: ")
691
+ model_description = input("Playground description: ")
692
+ requirements = input("Requirements: ")
693
+ tags = input("Tags: ")
694
+ print()
695
+
696
+ input_dict = {"requirements": requirements,
697
+ "model_name": model_name,
698
+ "model_description": model_description,
699
+ "tags": tags}
700
+
701
+ playground_id = False
702
+
703
+ else:
704
+
705
+ input_dict = {"requirements": "",
706
+ "model_name": "Default Model Playground",
707
+ "model_description": "",
708
+ "tags": ""}
709
+
710
+ playground_id = True
711
+
712
+ self.activate(None, None, example_data=example_data,
713
+ onnx_timeout=None, y_train=y_train, custom_libraries=custom_libraries,
714
+ image=image, reproducibility_env_filepath=reproducibility_env_filepath,
715
+ memory=memory, pyspark_support=pyspark_support, timeout=timeout, input_dict=input_dict,
716
+ playground_id=playground_id)
717
+ print()
718
+
719
+ # if playground is active, ask whether user wants to overwrite
720
+ else:
721
+
722
+ print(
723
+ "The Model Playground is already active. Do you want to overwrite existing competitions and experiments?")
724
+ response = ''
725
+ while response not in {"yes", "no"}:
726
+ response = input("Please enter yes or no: ").lower()
727
+
728
+ if response == "no":
729
+ print("Please instantiate a new playground and try again.")
730
+ return
731
+
732
+ # get model id from playground url
733
+ unique_model_id = self.playground_url.split(".")[0].split("//")[-1]
734
+
735
+ if user_input == False:
736
+
737
+ competition_name = "Default Competition " + unique_model_id
738
+ competition_description = ""
739
+ data_description = ""
740
+ data_license = ""
741
+
742
+ else:
743
+
744
+ print("Submit Model Competition data.")
745
+ competition_name = input("Competition name: ")
746
+ competition_description = input("Competition description: ")
747
+ data_description = input("Competition data description: ")
748
+ data_license = input("Cometition data license: ")
749
+
750
+ comp_input_dict = {"competition_name": competition_name,
751
+ "competition_description": competition_description,
752
+ "data_description": data_description,
753
+ "data_license": data_license}
754
+
755
+ with HiddenPrints():
756
+
757
+ from aimodelshare.generatemodelapi import create_competition
758
+ create_competition(apiurl=self.playground_url,
759
+ data_directory=data_directory,
760
+ y_test=eval_data,
761
+ eval_metric_filepath=eval_metric_filepath,
762
+ email_list=email_list,
763
+ public=public,
764
+ public_private_split=public_private_split,
765
+ input_dict=comp_input_dict,
766
+ print_output=False)
767
+
768
+ if user_input == False:
769
+
770
+ experiment_name = "Default Experiment " + unique_model_id
771
+ experiment_description = ""
772
+ data_description = ""
773
+ data_license = ""
774
+
775
+ else:
776
+ print("Submit Model Experiment data.")
777
+ experiment_name = input("Experiment name: ")
778
+ experiment_description = input("Experiment description: ")
779
+ data_description = input("Experiment data description: ")
780
+ data_license = input("Experiment data license: ")
781
+
782
+ exp_input_dict = {"experiment_name": experiment_name,
783
+ "experiment_description": experiment_description,
784
+ "data_description": data_description,
785
+ "data_license": data_license}
786
+
787
+ with HiddenPrints():
788
+
789
+ from aimodelshare.generatemodelapi import create_experiment
790
+ create_experiment(apiurl=self.playground_url,
791
+ data_directory=data_directory,
792
+ y_test=eval_data,
793
+ eval_metric_filepath=eval_metric_filepath,
794
+ email_list=email_list,
795
+ public=public,
796
+ public_private_split=0, #set to 0 because its an experiment
797
+ input_dict=exp_input_dict,
798
+ print_output=False)
799
+
800
+ print("Check out your Model Playground page for more.")
801
+
802
+ try:
803
+ temp.close()
804
+ except:
805
+ pass
806
+
807
+ return
808
+
809
+ def create_competition(self, data_directory, y_test, eval_metric_filepath=None, email_list=None, public=True,
810
+ public_private_split=0.5, input_dict=None):
811
+ """
812
+ Creates a model competition for a deployed prediction REST API
813
+ Inputs : 4
814
+ Output : Create ML model competition and allow authorized users to submit models to resulting leaderboard/competition
815
+
816
+ Parameters:
817
+ -----------
818
+ `y_test` : ``list`` of y values for test data used to generate metrics from predicted values from X test data submitted via the submit_model() function
819
+ [REQUIRED] to generate eval metrics in competition leaderboard
820
+
821
+ `data_directory` : folder storing training data and test data (excluding Y test data)
822
+ `eval_metric_filepath`: [OPTIONAL] file path of zip file with custon evaluation functions
823
+ `email_list`: [OPTIONAL] list of comma separated emails for users who are allowed to submit models to competition. Emails should be strings in a list.
824
+ `public`: [REQUIRED] True/false. Defaults to False. If True, competition is public and ANY AIMODELSHARE USER CAN SUBMIT MODELS. USE WITH CAUTION b/c one model and
825
+ one preprocessor file will be be saved to your AWS S3 folder for each model submission.
826
+ `public_private_split`: [REQUIRED] Float between 0 and 1. Defaults to 0.5. Porportion of test data that is allocated to private hold-out set.
827
+
828
+ Returns:
829
+ -----------
830
+ finalmessage : Information such as how to submit models to competition
831
+
832
+ """
833
+
834
+ if email_list is None:
835
+ email_list = []
836
+
837
+ # catch email list error
838
+ if public == False and email_list == []:
839
+ raise ValueError("Please submit valid email list for private competition.")
840
+ import os
841
+ if os.environ.get("cloud_location") is not None:
842
+ cloudlocation = os.environ.get("cloud_location")
843
+ else:
844
+ cloudlocation = "not set"
845
+ if "model_share" == cloudlocation:
846
+ print("Creating your Model Playground Competition...\nEst. completion: ~1 minute\n")
847
+ if input_dict is None:
848
+ print("\n--INPUT COMPETITION DETAILS--\n")
849
+
850
+ aishare_competitionname = input("Enter competition name:")
851
+ aishare_competitiondescription = input("Enter competition description:")
852
+
853
+ print("\n--INPUT DATA DETAILS--\n")
854
+ print(
855
+ "Note: (optional) Save an optional LICENSE.txt file in your competition data directory to make users aware of any restrictions on data sharing/usage.\n")
856
+
857
+ aishare_datadescription = input(
858
+ "Enter data description (i.e.- filenames denoting training and test data, file types, and any subfolders where files are stored):")
859
+
860
+ aishare_datalicense = input(
861
+ "Enter optional data license descriptive name (e.g.- 'MIT, Apache 2.0, CC0, Other, etc.'):")
862
+
863
+ input_dict = {"competition_name": aishare_competitionname,
864
+ "competition_description": aishare_competitiondescription,
865
+ "data_description": aishare_datadescription, "data_license": aishare_datalicense}
866
+ else:
867
+ pass
868
+
869
+ # model competition files
870
+ def upload_comp_exp_zipfile(data_directory, y_test=None, eval_metric_filepath=None, email_list=[]):
871
+ """
872
+ minimally requires model_filepath, preprocessor_filepath
873
+ """
874
+ zipfilelist = [data_directory]
875
+
876
+ import json
877
+ import os
878
+ import requests
879
+ import pandas as pd
880
+ if eval_metric_filepath == None:
881
+ pass
882
+ else:
883
+ zipfilelist.append(eval_metric_filepath)
884
+
885
+ # need to save dict pkl file with arg name and filepaths to add to zipfile
886
+
887
+ apiurl = "https://djoehnv623.execute-api.us-east-2.amazonaws.com/prod/m"
888
+
889
+ apiurl_eval = apiurl[:-1] + "eval"
890
+
891
+ headers = {'Content-Type': 'application/json',
892
+ 'authorizationToken': json.dumps({"token": os.environ.get("AWS_TOKEN"), "eval": "TEST"}), }
893
+ post_dict = {"return_zip": "True"}
894
+ zipfile = requests.post(apiurl_eval, headers=headers, data=json.dumps(post_dict))
895
+
896
+ zipfileputlistofdicts = json.loads(zipfile.text)['put']
897
+
898
+ zipfilename = list(zipfileputlistofdicts.keys())[0]
899
+
900
+ from zipfile import ZipFile
901
+ import os
902
+ from os.path import basename
903
+ import tempfile
904
+
905
+ wkingdir = os.getcwd()
906
+
907
+ tempdir = tempfile.gettempdir()
908
+
909
+ zipObj = ZipFile(tempdir + "/" + zipfilename, 'w')
910
+ # Add multiple files to the zip
911
+
912
+ for i in zipfilelist:
913
+ for dirname, subdirs, files in os.walk(i):
914
+ zipObj.write(dirname)
915
+ for filename in files:
916
+ zipObj.write(os.path.join(dirname, filename))
917
+ # zipObj.write(i)
918
+
919
+ # add object to pkl file pathway here. (saving y label data)
920
+ import pickle
921
+
922
+ if y_test is None:
923
+ pass
924
+ else:
925
+ with open(tempdir + "/" + 'ytest.pkl', 'wb') as f:
926
+ pickle.dump(y_test, f)
927
+
928
+ os.chdir(tempdir)
929
+ zipObj.write('ytest.pkl')
930
+
931
+ if isinstance(email_list, list):
932
+ with open(tempdir + "/" + 'emaillist.pkl', 'wb') as f:
933
+ pickle.dump(email_list, f)
934
+
935
+ os.chdir(tempdir)
936
+ zipObj.write('emaillist.pkl')
937
+ else:
938
+ pass
939
+
940
+ # close the Zip File
941
+ os.chdir(wkingdir)
942
+
943
+ zipObj.close()
944
+
945
+ import ast
946
+
947
+ finalzipdict = ast.literal_eval(zipfileputlistofdicts[zipfilename])
948
+
949
+ url = finalzipdict['url']
950
+ fields = finalzipdict['fields']
951
+
952
+ #### save files from model deploy to zipfile in tempdir before loading to s3
953
+
954
+ ### Load zipfile to s3
955
+ with open(tempdir + "/" + zipfilename, 'rb') as f:
956
+ files = {'file': (tempdir + "/" + zipfilename, f)}
957
+ http_response = requests.post(url, data=fields, files=files)
958
+ return zipfilename
959
+
960
+ compzipfilename = upload_comp_exp_zipfile(data_directory, y_test, eval_metric_filepath, email_list)
961
+
962
+ # if aws arg = false, do this, otherwise do aws code
963
+ # create deploy code_string
964
+ def nonecheck(objinput=""):
965
+ if objinput is None:
966
+ objinput = "None"
967
+ else:
968
+ objinput = "'/tmp/" + objinput + "'"
969
+ return objinput
970
+
971
+ playgroundurlcode = "playground_url='" + self.playground_url + "'"
972
+ compstring = self.class_string.replace(",aws=False", "").replace("playground_url=None",
973
+ playgroundurlcode) + "." + "create_competition('/tmp/" + data_directory + "'," + 'y_test' + "," + nonecheck(
974
+ eval_metric_filepath) + "," + 'email_list' + ",input_dict=" + str(input_dict) + ')'
975
+
976
+ import base64
977
+ import requests
978
+ import json
979
+
980
+ api_url = "https://z4kvag4sxdnv2mvs2b6c4thzj40bxnuw.lambda-url.us-east-2.on.aws/"
981
+
982
+ data = json.dumps({"code": """from aimodelshare import ModelPlayground;myplayground=""" + compstring,
983
+ "zipfilename": compzipfilename, "username": os.environ.get("username"),
984
+ "password": os.environ.get("password"),
985
+ "token": os.environ.get("JWT_AUTHORIZATION_TOKEN"), "s3keyid": "xrjpv1i7xe"})
986
+
987
+ headers = {"Content-Type": "application/json"}
988
+
989
+ response = requests.request("POST", api_url, headers=headers, data=data)
990
+ result = json.loads(response.text)
991
+ printoutlist = json.loads(result['body'])
992
+ printoutlistfinal = printoutlist[2:len(printoutlist)]
993
+ print("\n")
994
+ for i in printoutlistfinal:
995
+ print(i)
996
+
997
+ else:
998
+
999
+ from aimodelshare.generatemodelapi import create_competition
1000
+
1001
+ competition = create_competition(self.playground_url,
1002
+ data_directory,
1003
+ y_test,
1004
+ eval_metric_filepath,
1005
+ email_list,
1006
+ public,
1007
+ public_private_split, input_dict=input_dict)
1008
+ return competition
1009
+
1010
+ def create_experiment(self, data_directory, y_test, eval_metric_filepath=None, email_list=[], public=False,
1011
+ public_private_split=0, input_dict=None):
1012
+ """
1013
+ Creates an experiment for a deployed prediction REST API
1014
+ Inputs : 4
1015
+ Output : Create ML model experiment and allows authorized users to submit models to resulting experiment tracking leaderboard
1016
+
1017
+ Parameters:
1018
+ -----------
1019
+ `y_test` : ``list`` of y values for test data used to generate metrics from predicted values from X test data submitted via the submit_model() function
1020
+ [REQUIRED] to generate eval metrics in experiment leaderboard
1021
+
1022
+ `data_directory` : folder storing training data and test data (excluding Y test data)
1023
+ `eval_metric_filepath`: [OPTIONAL] file path of zip file with custon evaluation functions
1024
+ `email_list`: [OPTIONAL] list of comma separated emails for users who are allowed to submit models to experiment leaderboard. Emails should be strings in a list.
1025
+ `public`: [REQUIRED] True/false. Defaults to False. If True, experiment is public and ANY AIMODELSHARE USER CAN SUBMIT MODELS. USE WITH CAUTION b/c one model and
1026
+ one preprocessor file will be be saved to your AWS S3 folder for each model submission.
1027
+ `public_private_split`: [REQUIRED] Float between 0 and 1. Defaults to 0. Porportion of test data that is allocated to private hold-out set.
1028
+
1029
+
1030
+ Returns:
1031
+ -----------
1032
+ finalmessage : Information such as how to submit models to experiment
1033
+
1034
+ """
1035
+
1036
+ # catch email list error
1037
+ if public == False and email_list == []:
1038
+ raise ValueError("Please submit valid email list for private experiment.")
1039
+ import os
1040
+ if os.environ.get("cloud_location") is not None:
1041
+ cloudlocation = os.environ.get("cloud_location")
1042
+ else:
1043
+ cloudlocation = "not set"
1044
+ if "model_share" == cloudlocation:
1045
+ print("Creating your Model Playground...\nEst. completion: ~1 minute\n")
1046
+ if input_dict is None:
1047
+ print("\n--INPUT Experiment DETAILS--\n")
1048
+
1049
+ aishare_competitionname = input("Enter experiment name:")
1050
+ aishare_competitiondescription = input("Enter experiment description:")
1051
+
1052
+ print("\n--INPUT DATA DETAILS--\n")
1053
+ print(
1054
+ "Note: (optional) Save an optional LICENSE.txt file in your experiment data directory to make users aware of any restrictions on data sharing/usage.\n")
1055
+
1056
+ aishare_datadescription = input(
1057
+ "Enter data description (i.e.- filenames denoting training and test data, file types, and any subfolders where files are stored):")
1058
+
1059
+ aishare_datalicense = input(
1060
+ "Enter optional data license descriptive name (e.g.- 'MIT, Apache 2.0, CC0, Other, etc.'):")
1061
+
1062
+ input_dict = {"competition_name": aishare_competitionname,
1063
+ "competition_description": aishare_competitiondescription,
1064
+ "data_description": aishare_datadescription, "data_license": aishare_datalicense}
1065
+ else:
1066
+ pass
1067
+
1068
+ # model competition files
1069
+ def upload_comp_exp_zipfile(data_directory, y_test=None, eval_metric_filepath=None, email_list=[]):
1070
+ """
1071
+ minimally requires model_filepath, preprocessor_filepath
1072
+ """
1073
+ zipfilelist = [data_directory]
1074
+
1075
+ import json
1076
+ import os
1077
+ import requests
1078
+ import pandas as pd
1079
+ if eval_metric_filepath == None:
1080
+ pass
1081
+ else:
1082
+ zipfilelist.append(eval_metric_filepath)
1083
+
1084
+ # need to save dict pkl file with arg name and filepaths to add to zipfile
1085
+
1086
+ apiurl = "https://djoehnv623.execute-api.us-east-2.amazonaws.com/prod/m"
1087
+
1088
+ apiurl_eval = apiurl[:-1] + "eval"
1089
+
1090
+ headers = {'Content-Type': 'application/json',
1091
+ 'authorizationToken': json.dumps({"token": os.environ.get("AWS_TOKEN"), "eval": "TEST"}), }
1092
+ post_dict = {"return_zip": "True"}
1093
+ zipfile = requests.post(apiurl_eval, headers=headers, data=json.dumps(post_dict))
1094
+
1095
+ zipfileputlistofdicts = json.loads(zipfile.text)['put']
1096
+
1097
+ zipfilename = list(zipfileputlistofdicts.keys())[0]
1098
+
1099
+ from zipfile import ZipFile
1100
+ import os
1101
+ from os.path import basename
1102
+ import tempfile
1103
+
1104
+ wkingdir = os.getcwd()
1105
+
1106
+ tempdir = tempfile.gettempdir()
1107
+
1108
+ zipObj = ZipFile(tempdir + "/" + zipfilename, 'w')
1109
+ # Add multiple files to the zip
1110
+
1111
+ for i in zipfilelist:
1112
+ for dirname, subdirs, files in os.walk(i):
1113
+ zipObj.write(dirname)
1114
+ for filename in files:
1115
+ zipObj.write(os.path.join(dirname, filename))
1116
+ # zipObj.write(i)
1117
+
1118
+ # add object to pkl file pathway here. (saving y label data)
1119
+ import pickle
1120
+
1121
+ if y_test is None:
1122
+ pass
1123
+ else:
1124
+ with open(tempdir + "/" + 'ytest.pkl', 'wb') as f:
1125
+ pickle.dump(y_test, f)
1126
+
1127
+ os.chdir(tempdir)
1128
+ zipObj.write('ytest.pkl')
1129
+
1130
+ if isinstance(email_list, list):
1131
+ with open(tempdir + "/" + 'emaillist.pkl', 'wb') as f:
1132
+ pickle.dump(email_list, f)
1133
+
1134
+ os.chdir(tempdir)
1135
+ zipObj.write('emaillist.pkl')
1136
+ else:
1137
+ pass
1138
+
1139
+ # close the Zip File
1140
+ os.chdir(wkingdir)
1141
+
1142
+ zipObj.close()
1143
+
1144
+ import ast
1145
+
1146
+ finalzipdict = ast.literal_eval(zipfileputlistofdicts[zipfilename])
1147
+
1148
+ url = finalzipdict['url']
1149
+ fields = finalzipdict['fields']
1150
+
1151
+ #### save files from model deploy to zipfile in tempdir before loading to s3
1152
+
1153
+ ### Load zipfile to s3
1154
+ with open(tempdir + "/" + zipfilename, 'rb') as f:
1155
+ files = {'file': (tempdir + "/" + zipfilename, f)}
1156
+ http_response = requests.post(url, data=fields, files=files)
1157
+ return zipfilename
1158
+
1159
+ compzipfilename = upload_comp_exp_zipfile(data_directory, y_test, eval_metric_filepath, email_list)
1160
+
1161
+ # if aws arg = false, do this, otherwise do aws code
1162
+ # create deploy code_string
1163
+ def nonecheck(objinput=""):
1164
+ if objinput == None:
1165
+ objinput = "None"
1166
+ else:
1167
+ objinput = "'/tmp/" + objinput + "'"
1168
+ return objinput
1169
+
1170
+ playgroundurlcode = "playground_url='" + self.playground_url + "'"
1171
+ compstring = self.class_string.replace(",aws=False", "").replace("playground_url=None",
1172
+ playgroundurlcode) + "." + "create_experiment('/tmp/" + data_directory + "'," + 'y_test' + "," + nonecheck(
1173
+ eval_metric_filepath) + "," + 'email_list' + ",input_dict=" + str(input_dict) + ')'
1174
+ print(compstring)
1175
+ import base64
1176
+ import requests
1177
+ import json
1178
+
1179
+ api_url = "https://z4kvag4sxdnv2mvs2b6c4thzj40bxnuw.lambda-url.us-east-2.on.aws/"
1180
+
1181
+ data = json.dumps({"code": """from aimodelshare import ModelPlayground;myplayground=""" + compstring,
1182
+ "zipfilename": compzipfilename, "username": os.environ.get("username"),
1183
+ "password": os.environ.get("password"),
1184
+ "token": os.environ.get("JWT_AUTHORIZATION_TOKEN"), "s3keyid": "xrjpv1i7xe"})
1185
+
1186
+ headers = {"Content-Type": "application/json"}
1187
+
1188
+ response = requests.request("POST", api_url, headers=headers, data=data)
1189
+ print(response.text)
1190
+
1191
+ return (response.text)
1192
+ else:
1193
+
1194
+ from aimodelshare.generatemodelapi import create_experiment
1195
+
1196
+ experiment = create_experiment(self.playground_url,
1197
+ data_directory,
1198
+ y_test,
1199
+ eval_metric_filepath,
1200
+ email_list,
1201
+ public,
1202
+ public_private_split, input_dict=None)
1203
+ return experiment
1204
+
1205
+ def submit_model(self, model, preprocessor, prediction_submission, submission_type="experiment",
1206
+ sample_data=None, reproducibility_env_filepath=None, custom_metadata=None, input_dict=None,
1207
+ onnx_timeout=60, model_input=None, token=None,return_metrics=None):
1208
+ """
1209
+ Submits model/preprocessor to machine learning competition using live prediction API url generated by AI Modelshare library
1210
+ The submitted model gets evaluated and compared with all existing models and a leaderboard can be generated
1211
+
1212
+ Parameters:
1213
+ -----------
1214
+ `model`: model object (sklearn, keras, pytorch, onnx) or onnx model file path
1215
+ `prediction_submission`: one hot encoded y_pred
1216
+ value - predictions for test data
1217
+ [REQUIRED] for evaluation metrics of the submitted model
1218
+ `preprocessor`: preprocessor function object
1219
+
1220
+ Returns:
1221
+ --------
1222
+ response: Model version if the model is submitted sucessfully
1223
+ """
1224
+
1225
+ if not self.playground_url:
1226
+ raise Exception(
1227
+ "Please instantiate ModelPlayground with playground_url or use create() method to setup Model Playground Page before submitting your model.")
1228
+
1229
+ from aimodelshare.model import submit_model
1230
+
1231
+ # convert model to onnx
1232
+ if onnx_timeout == False:
1233
+ force_onnx = True
1234
+ else:
1235
+ force_onnx = False
1236
+ model = model_to_onnx_timed(model, timeout=onnx_timeout,
1237
+ force_onnx=force_onnx, model_input=model_input)
1238
+
1239
+ # create input dict
1240
+ if not input_dict:
1241
+ input_dict = {}
1242
+ input_dict["tags"] = input("Insert search tags to help users find your model (optional): ")
1243
+ input_dict["description"] = input("Provide any useful notes about your model (optional): ")
1244
+
1245
+ if submission_type == "competition" or submission_type == "all":
1246
+ with HiddenPrints():
1247
+ competition = Competition(self.playground_url)
1248
+
1249
+ comp_result = competition.submit_model(model=model,
1250
+ prediction_submission=prediction_submission,
1251
+ preprocessor=preprocessor,
1252
+ reproducibility_env_filepath=reproducibility_env_filepath,
1253
+ custom_metadata=custom_metadata,
1254
+ input_dict=input_dict,
1255
+ print_output=False, token=token, return_metrics=return_metrics)
1256
+
1257
+ # Validate return structure before unpacking
1258
+ if not isinstance(comp_result, tuple) or len(comp_result) != 2:
1259
+ raise RuntimeError(f"Invalid return from competition.submit_model: expected (version, url) tuple, got {type(comp_result)}")
1260
+
1261
+ version_comp, model_page = comp_result
1262
+
1263
+ print(f"Your model has been submitted to competition as model version {version_comp}.")
1264
+
1265
+ if submission_type == "experiment" or submission_type == "all":
1266
+ with HiddenPrints():
1267
+ experiment = Experiment(self.playground_url)
1268
+
1269
+ exp_result = experiment.submit_model(model=model,
1270
+ prediction_submission=prediction_submission,
1271
+ preprocessor=preprocessor,
1272
+ reproducibility_env_filepath=reproducibility_env_filepath,
1273
+ custom_metadata=custom_metadata,
1274
+ input_dict=input_dict,
1275
+ print_output=False, token=token,return_metrics=return_metrics)
1276
+
1277
+ # Validate return structure before unpacking
1278
+ if not isinstance(exp_result, tuple) or len(exp_result) != 2:
1279
+ raise RuntimeError(f"Invalid return from experiment.submit_model: expected (version, url) tuple, got {type(exp_result)}")
1280
+
1281
+ version_exp, model_page = exp_result
1282
+
1283
+ print(f"Your model has been submitted to experiment as model version {version_exp}.")
1284
+
1285
+ self.model_page = model_page
1286
+
1287
+ print(f"\nVisit your Model Playground Page for more.")
1288
+ print(model_page)
1289
+ return
1290
+
1291
+ def deploy_model(self, model_version, example_data, y_train, submission_type="experiment"):
1292
+ """
1293
+ Updates the prediction API behind the Model Playground with a new model from the leaderboard and verifies Model Playground performance metrics.
1294
+ Parameters:
1295
+ -----------
1296
+ `model_version`: ``int`` model version number from competition leaderboard
1297
+ `example_data`: ``Example of X data that will be shown on the online Playground page``
1298
+ `y_train`: ``training labels for classification models. Expects pandas dataframe of one hot encoded y train data``
1299
+ """
1300
+
1301
+ with HiddenPrints():
1302
+ self.update_example_data(example_data)
1303
+
1304
+ self.update_labels(y_train)
1305
+
1306
+ self.update_runtime_model(model_version, submission_type)
1307
+
1308
+ return
1309
+
1310
+ def update_runtime_model(self, model_version, submission_type="experiment"):
1311
+ """
1312
+ Updates the prediction API behind the Model Playground with a new model from the leaderboard and verifies Model Playground performance metrics.
1313
+ Parameters:
1314
+ -----------
1315
+ `model_version`: ``int``
1316
+ model version number from competition leaderboard
1317
+ Returns:
1318
+ --------
1319
+ response: success message when the model and preprocessor are updated successfully
1320
+ """
1321
+ from aimodelshare.model import update_runtime_model as update
1322
+ update = update(apiurl=self.playground_url, model_version=model_version, submission_type=submission_type)
1323
+
1324
+ print(f"\nVisit your Model Playground Page for more.")
1325
+ if self.model_page:
1326
+ print(self.model_page)
1327
+
1328
+ return update
1329
+
1330
+ def instantiate_model(self, version=None, trained=False, reproduce=False, submission_type="experiment"):
1331
+ """
1332
+ Import a model previously submitted to a leaderboard to use in your session
1333
+ Parameters:
1334
+ -----------
1335
+ `version`: ``int``
1336
+ Model version number from competition or experiment leaderboard
1337
+ `trained`: ``bool, default=False``
1338
+ if True, a trained model is instantiated, if False, the untrained model is instantiated
1339
+ Returns:
1340
+ --------
1341
+ model: model chosen from leaderboard
1342
+ """
1343
+ raise AssertionError(
1344
+ "You are trying to Instantiate model with ModelPlayground Object, Please use the competition object to Instantiate model")
1345
+ from aimodelshare.aimsonnx import instantiate_model
1346
+ model = instantiate_model(apiurl=self.playground_url, trained=trained, version=version, reproduce=reproduce,
1347
+ submission_type=submission_type)
1348
+ return model
1349
+
1350
+ def replicate_model(self, version=None, submission_type="experiment"):
1351
+ """
1352
+ Instantiate an untrained model with reproducibility environment setup.
1353
+
1354
+ Parameters:
1355
+ -----------
1356
+ `version`: ``int``
1357
+ Model version number from competition or experiment leaderboard
1358
+
1359
+ Returns:
1360
+ --------
1361
+ model: model chosen from leaderboard
1362
+ """
1363
+
1364
+ model = self.instantiate_model(version=version, trained=False, reproduce=True, submission_type=submission_type)
1365
+
1366
+ return model
1367
+
1368
+ def delete_deployment(self, playground_url=None, confirmation=True):
1369
+ """
1370
+ Delete all components of a Model Playground, including: AWS s3 bucket & contents,
1371
+ attached competitions, prediction REST API, and interactive Model Playground web dashboard.
1372
+ Parameters:
1373
+ -----------
1374
+ `playground_url`: ``string`` of API URL the user wishes to delete
1375
+ WARNING: User must supply high-level credentials in order to delete an API.
1376
+ Returns:
1377
+ --------
1378
+ Success message when deployment is deleted.
1379
+ """
1380
+ from aimodelshare.api import delete_deployment
1381
+ if playground_url == None:
1382
+ playground_url = self.playground_url
1383
+ deletion = delete_deployment(apiurl=playground_url, confirmation=confirmation)
1384
+ return deletion
1385
+
1386
+ def import_reproducibility_env(self):
1387
+ from aimodelshare.reproducibility import import_reproducibility_env_from_model
1388
+ import_reproducibility_env_from_model(apiurl=self.playground_url)
1389
+
1390
+ def update_access_list(self, email_list=[], update_type="Replace_list"):
1391
+ """
1392
+ Updates list of authenticated participants who can submit new models to a competition.
1393
+ Parameters:
1394
+ -----------
1395
+ `apiurl`: string
1396
+ URL of deployed prediction API
1397
+
1398
+ `email_list`: [REQUIRED] list of comma separated emails for users who are allowed to submit models to competition. Emails should be strings in a list.
1399
+ `update_type`:[REQUIRED] options, ``string``: 'Add', 'Remove', 'Replace_list','Get. Add appends user emails to original list, Remove deletes users from list,
1400
+ 'Replace_list' overwrites the original list with the new list provided, and Get returns the current list.
1401
+ Returns:
1402
+ --------
1403
+ response: "Success" upon successful request
1404
+ """
1405
+ from aimodelshare.generatemodelapi import update_access_list as update_list
1406
+ update = update_list(apiurl=self.playground_url, email_list=email_list, update_type=update_type)
1407
+ return update
1408
+
1409
+ def update_example_data(self, example_data):
1410
+
1411
+ """
1412
+ Updates example data associated with a model playground prediction API.
1413
+
1414
+ Parameters:
1415
+ -----------
1416
+
1417
+ `example_data`: ``Example of X data that will be shown on the online Playground page``
1418
+ If no example data is submitted, certain functionalities may be limited, including the deployment of live prediction APIs.
1419
+
1420
+ Returns:
1421
+ --------
1422
+ response: "Success" upon successful request
1423
+ """
1424
+
1425
+ from aimodelshare.generatemodelapi import _create_exampledata_json
1426
+
1427
+ _create_exampledata_json(self.model_type, example_data)
1428
+
1429
+ temp_dir = tempfile.gettempdir()
1430
+ exampledata_json_filepath = temp_dir + "/exampledata.json"
1431
+
1432
+ from aimodelshare.aws import get_s3_iam_client
1433
+ s3, iam, region = get_s3_iam_client(os.environ.get("AWS_ACCESS_KEY_ID_AIMS"),
1434
+ os.environ.get("AWS_SECRET_ACCESS_KEY_AIMS"),
1435
+ os.environ.get("AWS_REGION_AIMS"))
1436
+
1437
+ unique_model_id = self.playground_url.split(".")[0].split("//")[-1]
1438
+
1439
+ s3["client"].upload_file(exampledata_json_filepath, os.environ.get("BUCKET_NAME"),
1440
+ unique_model_id + "/exampledata.json")
1441
+
1442
+ variablename_and_type_data = extract_varnames_fromtrainingdata(example_data)
1443
+
1444
+ bodydata = {"apiurl": self.playground_url,
1445
+ "apideveloper": os.environ.get("username"),
1446
+ "versionupdateput": "TRUE",
1447
+ "input_feature_dtypes": variablename_and_type_data[0],
1448
+ "input_feature_names": variablename_and_type_data[1],
1449
+ "exampledata": "TRUE"}
1450
+
1451
+ headers_with_authentication = {'Content-Type': 'application/json',
1452
+ 'authorizationToken': os.environ.get("JWT_AUTHORIZATION_TOKEN"),
1453
+ 'Access-Control-Allow-Headers':
1454
+ 'Content-Type,X-Amz-Date,authorizationToken,Access-Control-Allow-Origin,X-Api-Key,X-Amz-Security-Token,Authorization',
1455
+ 'Access-Control-Allow-Origin': '*'}
1456
+ response = requests.post("https://bhrdesksak.execute-api.us-east-1.amazonaws.com/dev/modeldata",
1457
+ json=bodydata, headers=headers_with_authentication)
1458
+
1459
+ print("Your evaluation data has been updated.")
1460
+
1461
+ print(f"\nVisit your Model Playground Page for more.")
1462
+ if self.model_page:
1463
+ print(self.model_page)
1464
+
1465
+ return
1466
+
1467
+ def update_labels(self, y_train):
1468
+
1469
+ """
1470
+ Updates class labels associated with a model playground prediction API.
1471
+ Class labels are automatically extracted from y_train data
1472
+
1473
+ Parameters:
1474
+ -----------
1475
+
1476
+ `y_train`: ``training labels for classification models. Expects pandas dataframe of one hot encoded y train data``
1477
+ If no example data is submitted, certain functionalities may be limited, including the deployment of live prediction APIs.
1478
+
1479
+ Returns:
1480
+ --------
1481
+ response: "Success" upon successful request
1482
+ """
1483
+
1484
+ # create labels json
1485
+
1486
+ try:
1487
+ labels = y_train.columns.tolist()
1488
+ except:
1489
+ # labels = list(set(y_train.to_frame()['tags'].tolist()))
1490
+ labels = list(set(y_train))
1491
+
1492
+ # labels_json = json.dumps(labels)
1493
+
1494
+ temp_dir = tempfile.gettempdir()
1495
+ labels_json_filepath = temp_dir + "/labels.json"
1496
+
1497
+ import json
1498
+ with open(labels_json_filepath, 'w', encoding='utf-8') as f:
1499
+ json.dump(labels, f)
1500
+
1501
+ from aimodelshare.aws import get_s3_iam_client
1502
+ s3, iam, region = get_s3_iam_client(os.environ.get("AWS_ACCESS_KEY_ID_AIMS"),
1503
+ os.environ.get("AWS_SECRET_ACCESS_KEY_AIMS"),
1504
+ os.environ.get("AWS_REGION_AIMS"))
1505
+
1506
+ unique_model_id = self.playground_url.split(".")[0].split("//")[-1]
1507
+
1508
+ s3["client"].upload_file(labels_json_filepath, os.environ.get("BUCKET_NAME"), unique_model_id + "/labels.json")
1509
+
1510
+ return
1511
+
1512
+ def update_eval_data(self, eval_data):
1513
+ """
1514
+ Updates evaluation data associated with a model playground prediction API.
1515
+
1516
+ Parameters:
1517
+ -----------
1518
+
1519
+ `eval_data` : ``list`` of y values used to generate metrics from predicted values from predictions submitted via the submit_model() method
1520
+ [REQUIRED] to generate eval metrics in experiment leaderboard
1521
+ """
1522
+
1523
+ # create temporary folder
1524
+ temp_dir = tempfile.gettempdir()
1525
+
1526
+ from aimodelshare.aws import get_s3_iam_client, run_function_on_lambda
1527
+ s3, iam, region = get_s3_iam_client(os.environ.get("AWS_ACCESS_KEY_ID_AIMS"),
1528
+ os.environ.get("AWS_SECRET_ACCESS_KEY_AIMS"),
1529
+ os.environ.get("AWS_REGION_AIMS"))
1530
+
1531
+ # Get bucket and model_id subfolder for user based on apiurl {{{
1532
+ response, error = run_function_on_lambda(
1533
+ self.playground_url, **{"delete": "FALSE", "versionupdateget": "TRUE"}
1534
+ )
1535
+ if error is not None:
1536
+ raise error
1537
+
1538
+ _, api_bucket, model_id = json.loads(response.content.decode("utf-8"))
1539
+ # }}}
1540
+
1541
+ # upload eval_data data:
1542
+ eval_data_path = os.path.join(temp_dir, "ytest.pkl")
1543
+ import pickle
1544
+ # ytest data to load to s3
1545
+
1546
+ if eval_data is not None:
1547
+ if type(eval_data) is not list:
1548
+ eval_data = eval_data.tolist()
1549
+
1550
+ if all(isinstance(x, (np.float64)) for x in eval_data):
1551
+ eval_data = [float(i) for i in eval_data]
1552
+
1553
+ pickle.dump(eval_data, open(eval_data_path, "wb"))
1554
+ s3["client"].upload_file(eval_data_path, os.environ.get("BUCKET_NAME"), model_id + "/experiment/ytest.pkl")
1555
+ s3["client"].upload_file(eval_data_path, os.environ.get("BUCKET_NAME"), model_id + "/competition/ytest.pkl")
1556
+
1557
+ print("Your evaluation data has been updated.")
1558
+
1559
+ print(f"\nVisit your Model Playground Page for more.")
1560
+ if self.model_page:
1561
+ print(self.model_page)
1562
+
1563
+ def get_leaderboard(self, verbose=3, columns=None, submission_type="experiment",token=None):
1564
+ """
1565
+ Get current competition leaderboard to rank all submitted models.
1566
+ Use in conjuction with stylize_leaderboard to visualize data.
1567
+
1568
+ Parameters:
1569
+ -----------
1570
+ `verbose` : optional, ``int``
1571
+ controls the verbosity: the higher, the more detail
1572
+ `columns` : optional, ``list of strings``
1573
+ list of specific column names to include in the leaderboard, all else will be excluded
1574
+ performance metrics will always be displayed
1575
+
1576
+ Returns:
1577
+ --------
1578
+ dictionary of leaderboard data
1579
+ """
1580
+ from aimodelshare.leaderboard import get_leaderboard
1581
+ data = get_leaderboard(verbose=verbose,
1582
+ columns=columns,
1583
+ apiurl=self.playground_url,
1584
+ submission_type=submission_type,token=token)
1585
+ return data
1586
+
1587
+ def stylize_leaderboard(self, leaderboard, naming_convention="keras"):
1588
+ """
1589
+ Stylizes data received from get_leaderbord.
1590
+ Parameters:
1591
+ -----------
1592
+ `leaderboard` : data dictionary object returned from get_leaderboard
1593
+ Returns:
1594
+ --------
1595
+ Formatted competition leaderboard
1596
+ """
1597
+ from aimodelshare.leaderboard import stylize_leaderboard as stylize_lead
1598
+ stylized_leaderboard = stylize_lead(leaderboard=leaderboard, naming_convention=naming_convention)
1599
+ return stylized_leaderboard
1600
+
1601
+ def compare_models(self, version_list="None", by_model_type=None, best_model=None, verbose=1,
1602
+ naming_convention=None, submission_type="experiment"):
1603
+ """
1604
+ Compare the structure of two or more models submitted to a competition leaderboard.
1605
+ Use in conjunction with stylize_compare to visualize data.
1606
+
1607
+ Parameters:
1608
+ -----------
1609
+ `version_list` = ``list of int``
1610
+ list of model version numbers to compare (previously submitted to competition leaderboard)
1611
+ `verbose` = ``int``
1612
+ controls the verbosity: the higher, the more detail
1613
+
1614
+ Returns:
1615
+ --------
1616
+ data : dictionary of model comparison information
1617
+ """
1618
+ from aimodelshare.aimsonnx import compare_models as compare
1619
+ data = compare(apiurl=self.playground_url,
1620
+ version_list=version_list,
1621
+ by_model_type=by_model_type,
1622
+ best_model=best_model,
1623
+ verbose=verbose,
1624
+ naming_convention=naming_convention,
1625
+ submission_type=submission_type)
1626
+ return data
1627
+
1628
+ def stylize_compare(self, compare_dict, naming_convention="keras"):
1629
+ """
1630
+ Stylizes data received from compare_models to highlight similarities & differences.
1631
+ Parameters:
1632
+ -----------
1633
+ `compare_dict` = dictionary of model data from compare_models
1634
+
1635
+ Returns:
1636
+ --------
1637
+ formatted table of model comparisons
1638
+ """
1639
+ from aimodelshare.aimsonnx import stylize_model_comparison
1640
+ stylized_compare = stylize_model_comparison(comp_dict_out=compare_dict, naming_convention=naming_convention)
1641
+ return (stylized_compare)
1642
+
1643
+ def instantiate_model(self, version=None, trained=False, reproduce=False, submission_type="experiment"):
1644
+ """
1645
+ Import a model previously submitted to the competition leaderboard to use in your session
1646
+ Parameters:
1647
+ -----------
1648
+ `version`: ``int``
1649
+ Model version number from competition leaderboard
1650
+ `trained`: ``bool, default=False``
1651
+ if True, a trained model is instantiated, if False, the untrained model is instantiated
1652
+
1653
+ Returns:
1654
+ --------
1655
+ model: model chosen from leaderboard
1656
+ """
1657
+ from aimodelshare.aimsonnx import instantiate_model
1658
+ model = instantiate_model(apiurl=self.playground_url, trained=trained, version=version,
1659
+ reproduce=reproduce, submission_type=submission_type)
1660
+ return model
1661
+
1662
+ def inspect_eval_data(self, submission_type="experiment"):
1663
+ """
1664
+ Examines structure of evaluation data to hep users understand how to submit models to the competition leaderboad.
1665
+ Parameters:
1666
+ ------------
1667
+ None
1668
+
1669
+ Returns:
1670
+ --------
1671
+ dictionary of a competition's y-test metadata
1672
+ """
1673
+ from aimodelshare.aimsonnx import inspect_y_test
1674
+ data = inspect_y_test(apiurl=self.playground_url, submission_type=submission_type)
1675
+ return data
1676
+
1677
+
1678
+ class Competition:
1679
+ """
1680
+ Parameters:
1681
+ ----------
1682
+ `playground_url`: playground_url attribute of ModelPlayground class or ``string``
1683
+ of existing ModelPlayground URL
1684
+ """
1685
+
1686
+ submission_type = "competition"
1687
+
1688
+ def __init__(self, playground_url):
1689
+ self.playground_url = playground_url
1690
+
1691
+ def __str__(self):
1692
+ return f"Competition class instance for playground: {self.playground_url}"
1693
+
1694
+ def submit_model(self, model, preprocessor, prediction_submission,
1695
+ sample_data=None, reproducibility_env_filepath=None, custom_metadata=None, input_dict=None,
1696
+ print_output=True, onnx_timeout=60, model_input=None, token=None,return_metrics=None):
1697
+ """
1698
+ Submits model/preprocessor to machine learning competition using live prediction API url generated by AI Modelshare library
1699
+ The submitted model gets evaluated and compared with all existing models and a leaderboard can be generated
1700
+
1701
+ Parameters:
1702
+ -----------
1703
+ `model_filepath`: ``string`` ends with '.onnx'
1704
+ value - Absolute path to model file [REQUIRED] to be set by the user
1705
+ .onnx is the only accepted model file extension
1706
+ "example_model.onnx" filename for file in directory.
1707
+ "/User/xyz/model/example_model.onnx" absolute path to model file from local directory
1708
+ `prediction_submission`: one hot encoded y_pred
1709
+ value - predictions for test data
1710
+ [REQUIRED] for evaluation metrics of the submitted model
1711
+ `preprocessor_filepath`: ``string``, default=None
1712
+ value - absolute path to preprocessor file
1713
+ [REQUIRED] to be set by the user
1714
+ "./preprocessor.zip"
1715
+ searches for an exported zip preprocessor file in the current directory
1716
+ file is generated from preprocessor module using export_preprocessor function from the AI Modelshare library
1717
+
1718
+ Returns:
1719
+ --------
1720
+ response: Model version if the model is submitted sucessfully
1721
+ """
1722
+
1723
+ # convert model to onnx
1724
+ if onnx_timeout == False:
1725
+ force_onnx = True
1726
+ else:
1727
+ force_onnx = False
1728
+
1729
+ with HiddenPrints():
1730
+ model = model_to_onnx_timed(model, timeout=onnx_timeout,
1731
+ force_onnx=force_onnx, model_input=model_input)
1732
+
1733
+ from aimodelshare.model import submit_model
1734
+ submission = submit_model(model_filepath=model,
1735
+ apiurl=self.playground_url,
1736
+ prediction_submission=prediction_submission,
1737
+ preprocessor=preprocessor,
1738
+ reproducibility_env_filepath=reproducibility_env_filepath,
1739
+ custom_metadata=custom_metadata,
1740
+ submission_type=self.submission_type,
1741
+ input_dict=input_dict,
1742
+ print_output=print_output, token=token,return_metrics=return_metrics)
1743
+
1744
+ return submission
1745
+
1746
+ def instantiate_model(self, version=None, trained=False, reproduce=False):
1747
+ """
1748
+ Import a model previously submitted to the competition leaderboard to use in your session
1749
+ Parameters:
1750
+ -----------
1751
+ `version`: ``int``
1752
+ Model version number from competition leaderboard
1753
+ `trained`: ``bool, default=False``
1754
+ if True, a trained model is instantiated, if False, the untrained model is instantiated
1755
+
1756
+ Returns:
1757
+ --------
1758
+ model: model chosen from leaderboard
1759
+ """
1760
+ from aimodelshare.aimsonnx import instantiate_model
1761
+ model = instantiate_model(apiurl=self.playground_url, trained=trained, version=version,
1762
+ reproduce=reproduce, submission_type=self.submission_type)
1763
+ return model
1764
+
1765
+ def replicate_model(self, version=None):
1766
+ """
1767
+ Instantiate an untrained model previously submitted to the competition leaderboard with its reproducibility environment setup.
1768
+
1769
+ Parameters:
1770
+ -----------
1771
+ `version`: ``int``
1772
+ Model version number from competition or experiment leaderboard
1773
+
1774
+ Returns:
1775
+ --------
1776
+ model: model chosen from leaderboard
1777
+ """
1778
+
1779
+ model = self.instantiate_model(version=version, trained=False, reproduce=True)
1780
+ return model
1781
+
1782
+ def set_model_reproducibility_env(self, version=None):
1783
+ """
1784
+ Set the reproducibility environment prior to instantiating an untrained model previously submitted to the competition leaderboard.
1785
+
1786
+ Parameters:
1787
+ -----------
1788
+ `version`: ``int``
1789
+ Model version number from competition or experiment leaderboard
1790
+
1791
+ Returns:
1792
+ --------
1793
+ Sets environment according to reproducibility.json from model if present.
1794
+ """
1795
+ from aimodelshare.reproducibility import import_reproducibility_env_from_competition_model
1796
+ import_reproducibility_env_from_competition_model(apiurl=self.playground_url, version=version,
1797
+ submission_type=self.submission_type)
1798
+
1799
+ def inspect_model(self, version=None, naming_convention=None):
1800
+ """
1801
+ Examine structure of model submitted to a competition leaderboard
1802
+ Parameters:
1803
+ ----------
1804
+ `version` : ``int``
1805
+ Model version number from competition leaderboard
1806
+
1807
+ Returns:
1808
+ --------
1809
+ inspect_pd : dictionary of model summary & metadata
1810
+ """
1811
+ from aimodelshare.aimsonnx import inspect_model
1812
+
1813
+ inspect_pd = inspect_model(apiurl=self.playground_url, version=version,
1814
+ naming_convention=naming_convention, submission_type=self.submission_type)
1815
+
1816
+ return inspect_pd
1817
+
1818
+ def compare_models(self, version_list="None", by_model_type=None, best_model=None, verbose=1,
1819
+ naming_convention=None):
1820
+ """
1821
+ Compare the structure of two or more models submitted to a competition leaderboard.
1822
+ Use in conjuction with stylize_compare to visualize data.
1823
+
1824
+ Parameters:
1825
+ -----------
1826
+ `version_list` = ``list of int``
1827
+ list of model version numbers to compare (previously submitted to competition leaderboard)
1828
+ `verbose` = ``int``
1829
+ controls the verbosity: the higher, the more detail
1830
+
1831
+ Returns:
1832
+ --------
1833
+ data : dictionary of model comparison information
1834
+ """
1835
+ from aimodelshare.aimsonnx import compare_models as compare
1836
+ data = compare(apiurl=self.playground_url,
1837
+ version_list=version_list,
1838
+ by_model_type=by_model_type,
1839
+ best_model=best_model,
1840
+ verbose=verbose,
1841
+ naming_convention=naming_convention,
1842
+ submission_type=self.submission_type)
1843
+ return data
1844
+
1845
+ def stylize_compare(self, compare_dict, naming_convention="keras"):
1846
+ """
1847
+ Stylizes data received from compare_models to highlight similarities & differences.
1848
+ Parameters:
1849
+ -----------
1850
+ `compare_dict` = dictionary of model data from compare_models
1851
+
1852
+ Returns:
1853
+ --------
1854
+ formatted table of model comparisons
1855
+ """
1856
+ from aimodelshare.aimsonnx import stylize_model_comparison
1857
+ stylized_compare = stylize_model_comparison(comp_dict_out=compare_dict, naming_convention=naming_convention)
1858
+ return (stylized_compare)
1859
+
1860
+ def inspect_y_test(self):
1861
+ """
1862
+ Examines structure of y-test data to hep users understand how to submit models to the competition leaderboad.
1863
+ Parameters:
1864
+ ------------
1865
+ None
1866
+
1867
+ Returns:
1868
+ --------
1869
+ dictionary of a competition's y-test metadata
1870
+ """
1871
+ from aimodelshare.aimsonnx import inspect_y_test
1872
+ data = inspect_y_test(apiurl=self.playground_url, submission_type=self.submission_type)
1873
+ return data
1874
+
1875
+ def get_leaderboard(self, verbose=3, columns=None,token=None):
1876
+ """
1877
+ Get current competition leaderboard to rank all submitted models.
1878
+ Use in conjuction with stylize_leaderboard to visualize data.
1879
+
1880
+ Parameters:
1881
+ -----------
1882
+ `verbose` : optional, ``int``
1883
+ controls the verbosity: the higher, the more detail
1884
+ `columns` : optional, ``list of strings``
1885
+ list of specific column names to include in the leaderboard, all else will be excluded
1886
+ performance metrics will always be displayed
1887
+
1888
+ Returns:
1889
+ --------
1890
+ dictionary of leaderboard data
1891
+ """
1892
+ from aimodelshare.leaderboard import get_leaderboard
1893
+ data = get_leaderboard(verbose=verbose,
1894
+ columns=columns,
1895
+ apiurl=self.playground_url,
1896
+ submission_type=self.submission_type, token=token)
1897
+ return data
1898
+
1899
+ def stylize_leaderboard(self, leaderboard, naming_convention="keras"):
1900
+ """
1901
+ Stylizes data received from get_leaderbord.
1902
+ Parameters:
1903
+ -----------
1904
+ `leaderboard` : data dictionary object returned from get_leaderboard
1905
+ Returns:
1906
+ --------
1907
+ Formatted competition leaderboard
1908
+ """
1909
+ from aimodelshare.leaderboard import stylize_leaderboard as stylize_lead
1910
+ stylized_leaderboard = stylize_lead(leaderboard=leaderboard, naming_convention=naming_convention)
1911
+ return stylized_leaderboard
1912
+
1913
+ def update_access_list(self, email_list=[], update_type="Replace_list"):
1914
+ """
1915
+ Updates list of authenticated participants who can submit new models to a competition.
1916
+ Parameters:
1917
+ -----------
1918
+ `apiurl`: string
1919
+ URL of deployed prediction API
1920
+
1921
+ `email_list`: [REQUIRED] list of comma separated emails for users who are allowed to submit models to competition. Emails should be strings in a list.
1922
+ `update_type`:[REQUIRED] options, ``string``: 'Add', 'Remove', 'Replace_list','Get. Add appends user emails to original list, Remove deletes users from list,
1923
+ 'Replace_list' overwrites the original list with the new list provided, and Get returns the current list.
1924
+ Returns:
1925
+ --------
1926
+ response: "Success" upon successful request
1927
+ """
1928
+ from aimodelshare.generatemodelapi import update_access_list as update_list
1929
+ update = update_list(apiurl=self.playground_url,
1930
+ email_list=email_list, update_type=update_type,
1931
+ submission_type=self.submission_type)
1932
+ return update
1933
+
1934
+
1935
+ class Experiment(Competition):
1936
+ """
1937
+ Parameters:
1938
+ ----------
1939
+ `playground_url`: playground_url attribute of ModelPlayground class or ``string``
1940
+ of existing ModelPlayground URL
1941
+ """
1942
+
1943
+ submission_type = "experiment"
1944
+
1945
+ def __init__(self, playground_url):
1946
+ self.playground_url = playground_url
1947
+
1948
+ def __str__(self):
1949
+ return f"Experiment class instance for playground: {self.playground_url}"
1950
+
1951
+
1952
+ class Data:
1953
+ def __init__(self, data_type, playground_url=None):
1954
+ self.data_type = data_type
1955
+ self.playground_url = playground_url
1956
+
1957
+ def __str__(self):
1958
+ return f"This is a description of the Data class."
1959
+
1960
+ def share_dataset(self, data_directory="folder_file_path", classification="default", private="FALSE"):
1961
+ from aimodelshare.data_sharing.share_data import share_dataset as share
1962
+ response = share(data_directory=data_directory, classification=classification, private=private)
1963
+ return response
1964
+
1965
+ def download_data(self, repository):
1966
+ from aimodelshare.data_sharing.download_data import download_data as download
1967
+ datadownload = download(repository)
1968
+ return datadownload