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.
- aimodelshare/README.md +26 -0
- aimodelshare/__init__.py +100 -0
- aimodelshare/aimsonnx.py +2381 -0
- aimodelshare/api.py +836 -0
- aimodelshare/auth.py +163 -0
- aimodelshare/aws.py +511 -0
- aimodelshare/aws_client.py +173 -0
- aimodelshare/base_image.py +154 -0
- aimodelshare/bucketpolicy.py +106 -0
- aimodelshare/color_mappings/color_mapping_keras.csv +121 -0
- aimodelshare/color_mappings/color_mapping_pytorch.csv +117 -0
- aimodelshare/containerisation.py +244 -0
- aimodelshare/containerization.py +712 -0
- aimodelshare/containerization_templates/Dockerfile.txt +8 -0
- aimodelshare/containerization_templates/Dockerfile_PySpark.txt +23 -0
- aimodelshare/containerization_templates/buildspec.txt +14 -0
- aimodelshare/containerization_templates/lambda_function.txt +40 -0
- aimodelshare/custom_approach/__init__.py +1 -0
- aimodelshare/custom_approach/lambda_function.py +17 -0
- aimodelshare/custom_eval_metrics.py +103 -0
- aimodelshare/data_sharing/__init__.py +0 -0
- aimodelshare/data_sharing/data_sharing_templates/Dockerfile.txt +3 -0
- aimodelshare/data_sharing/data_sharing_templates/__init__.py +1 -0
- aimodelshare/data_sharing/data_sharing_templates/buildspec.txt +15 -0
- aimodelshare/data_sharing/data_sharing_templates/codebuild_policies.txt +129 -0
- aimodelshare/data_sharing/data_sharing_templates/codebuild_trust_relationship.txt +12 -0
- aimodelshare/data_sharing/download_data.py +620 -0
- aimodelshare/data_sharing/share_data.py +373 -0
- aimodelshare/data_sharing/utils.py +8 -0
- aimodelshare/deploy_custom_lambda.py +246 -0
- aimodelshare/documentation/Makefile +20 -0
- aimodelshare/documentation/karma_sphinx_theme/__init__.py +28 -0
- aimodelshare/documentation/karma_sphinx_theme/_version.py +2 -0
- aimodelshare/documentation/karma_sphinx_theme/breadcrumbs.html +70 -0
- aimodelshare/documentation/karma_sphinx_theme/layout.html +172 -0
- aimodelshare/documentation/karma_sphinx_theme/search.html +50 -0
- aimodelshare/documentation/karma_sphinx_theme/searchbox.html +14 -0
- aimodelshare/documentation/karma_sphinx_theme/static/css/custom.css +2 -0
- aimodelshare/documentation/karma_sphinx_theme/static/css/custom.css.map +1 -0
- aimodelshare/documentation/karma_sphinx_theme/static/css/theme.css +2751 -0
- aimodelshare/documentation/karma_sphinx_theme/static/css/theme.css.map +1 -0
- aimodelshare/documentation/karma_sphinx_theme/static/css/theme.min.css +2 -0
- aimodelshare/documentation/karma_sphinx_theme/static/css/theme.min.css.map +1 -0
- aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.eot +0 -0
- aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.svg +32 -0
- aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.ttf +0 -0
- aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.woff +0 -0
- aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.woff2 +0 -0
- aimodelshare/documentation/karma_sphinx_theme/static/js/theme.js +68 -0
- aimodelshare/documentation/karma_sphinx_theme/theme.conf +9 -0
- aimodelshare/documentation/make.bat +35 -0
- aimodelshare/documentation/requirements.txt +2 -0
- aimodelshare/documentation/source/about.rst +18 -0
- aimodelshare/documentation/source/advanced_features.rst +137 -0
- aimodelshare/documentation/source/competition.rst +218 -0
- aimodelshare/documentation/source/conf.py +58 -0
- aimodelshare/documentation/source/create_credentials.rst +86 -0
- aimodelshare/documentation/source/example_notebooks.rst +132 -0
- aimodelshare/documentation/source/functions.rst +151 -0
- aimodelshare/documentation/source/gettingstarted.rst +390 -0
- aimodelshare/documentation/source/images/creds1.png +0 -0
- aimodelshare/documentation/source/images/creds2.png +0 -0
- aimodelshare/documentation/source/images/creds3.png +0 -0
- aimodelshare/documentation/source/images/creds4.png +0 -0
- aimodelshare/documentation/source/images/creds5.png +0 -0
- aimodelshare/documentation/source/images/creds_file_example.png +0 -0
- aimodelshare/documentation/source/images/predict_tab.png +0 -0
- aimodelshare/documentation/source/index.rst +110 -0
- aimodelshare/documentation/source/modelplayground.rst +132 -0
- aimodelshare/exceptions.py +11 -0
- aimodelshare/generatemodelapi.py +1270 -0
- aimodelshare/iam/codebuild_policy.txt +129 -0
- aimodelshare/iam/codebuild_trust_relationship.txt +12 -0
- aimodelshare/iam/lambda_policy.txt +15 -0
- aimodelshare/iam/lambda_trust_relationship.txt +12 -0
- aimodelshare/json_templates/__init__.py +1 -0
- aimodelshare/json_templates/api_json.txt +155 -0
- aimodelshare/json_templates/auth/policy.txt +1 -0
- aimodelshare/json_templates/auth/role.txt +1 -0
- aimodelshare/json_templates/eval/policy.txt +1 -0
- aimodelshare/json_templates/eval/role.txt +1 -0
- aimodelshare/json_templates/function/policy.txt +1 -0
- aimodelshare/json_templates/function/role.txt +1 -0
- aimodelshare/json_templates/integration_response.txt +5 -0
- aimodelshare/json_templates/lambda_policy_1.txt +15 -0
- aimodelshare/json_templates/lambda_policy_2.txt +8 -0
- aimodelshare/json_templates/lambda_role_1.txt +12 -0
- aimodelshare/json_templates/lambda_role_2.txt +16 -0
- aimodelshare/leaderboard.py +174 -0
- aimodelshare/main/1.txt +132 -0
- aimodelshare/main/1B.txt +112 -0
- aimodelshare/main/2.txt +153 -0
- aimodelshare/main/3.txt +134 -0
- aimodelshare/main/4.txt +128 -0
- aimodelshare/main/5.txt +109 -0
- aimodelshare/main/6.txt +105 -0
- aimodelshare/main/7.txt +144 -0
- aimodelshare/main/8.txt +142 -0
- aimodelshare/main/__init__.py +1 -0
- aimodelshare/main/authorization.txt +275 -0
- aimodelshare/main/eval_classification.txt +79 -0
- aimodelshare/main/eval_lambda.txt +1709 -0
- aimodelshare/main/eval_regression.txt +80 -0
- aimodelshare/main/lambda_function.txt +8 -0
- aimodelshare/main/nst.txt +149 -0
- aimodelshare/model.py +1543 -0
- aimodelshare/modeluser.py +215 -0
- aimodelshare/moral_compass/README.md +408 -0
- aimodelshare/moral_compass/__init__.py +65 -0
- aimodelshare/moral_compass/_version.py +3 -0
- aimodelshare/moral_compass/api_client.py +601 -0
- aimodelshare/moral_compass/apps/__init__.py +69 -0
- aimodelshare/moral_compass/apps/ai_consequences.py +540 -0
- aimodelshare/moral_compass/apps/bias_detective.py +714 -0
- aimodelshare/moral_compass/apps/ethical_revelation.py +898 -0
- aimodelshare/moral_compass/apps/fairness_fixer.py +889 -0
- aimodelshare/moral_compass/apps/judge.py +888 -0
- aimodelshare/moral_compass/apps/justice_equity_upgrade.py +853 -0
- aimodelshare/moral_compass/apps/mc_integration_helpers.py +820 -0
- aimodelshare/moral_compass/apps/model_building_game.py +1104 -0
- aimodelshare/moral_compass/apps/model_building_game_beginner.py +687 -0
- aimodelshare/moral_compass/apps/moral_compass_challenge.py +858 -0
- aimodelshare/moral_compass/apps/session_auth.py +254 -0
- aimodelshare/moral_compass/apps/shared_activity_styles.css +349 -0
- aimodelshare/moral_compass/apps/tutorial.py +481 -0
- aimodelshare/moral_compass/apps/what_is_ai.py +853 -0
- aimodelshare/moral_compass/challenge.py +365 -0
- aimodelshare/moral_compass/config.py +187 -0
- aimodelshare/placeholders/model.onnx +0 -0
- aimodelshare/placeholders/preprocessor.zip +0 -0
- aimodelshare/playground.py +1968 -0
- aimodelshare/postprocessormodules.py +157 -0
- aimodelshare/preprocessormodules.py +373 -0
- aimodelshare/pyspark/1.txt +195 -0
- aimodelshare/pyspark/1B.txt +181 -0
- aimodelshare/pyspark/2.txt +220 -0
- aimodelshare/pyspark/3.txt +204 -0
- aimodelshare/pyspark/4.txt +187 -0
- aimodelshare/pyspark/5.txt +178 -0
- aimodelshare/pyspark/6.txt +174 -0
- aimodelshare/pyspark/7.txt +211 -0
- aimodelshare/pyspark/8.txt +206 -0
- aimodelshare/pyspark/__init__.py +1 -0
- aimodelshare/pyspark/authorization.txt +258 -0
- aimodelshare/pyspark/eval_classification.txt +79 -0
- aimodelshare/pyspark/eval_lambda.txt +1441 -0
- aimodelshare/pyspark/eval_regression.txt +80 -0
- aimodelshare/pyspark/lambda_function.txt +8 -0
- aimodelshare/pyspark/nst.txt +213 -0
- aimodelshare/python/my_preprocessor.py +58 -0
- aimodelshare/readme.md +26 -0
- aimodelshare/reproducibility.py +181 -0
- aimodelshare/sam/Dockerfile.txt +8 -0
- aimodelshare/sam/Dockerfile_PySpark.txt +24 -0
- aimodelshare/sam/__init__.py +1 -0
- aimodelshare/sam/buildspec.txt +11 -0
- aimodelshare/sam/codebuild_policies.txt +129 -0
- aimodelshare/sam/codebuild_trust_relationship.txt +12 -0
- aimodelshare/sam/codepipeline_policies.txt +173 -0
- aimodelshare/sam/codepipeline_trust_relationship.txt +12 -0
- aimodelshare/sam/spark-class.txt +2 -0
- aimodelshare/sam/template.txt +54 -0
- aimodelshare/tools.py +103 -0
- aimodelshare/utils/__init__.py +78 -0
- aimodelshare/utils/optional_deps.py +38 -0
- aimodelshare/utils.py +57 -0
- aimodelshare-0.3.7.dist-info/METADATA +298 -0
- aimodelshare-0.3.7.dist-info/RECORD +171 -0
- aimodelshare-0.3.7.dist-info/WHEEL +5 -0
- aimodelshare-0.3.7.dist-info/licenses/LICENSE +5 -0
- 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
|