|
24 | 24 | POSSIBILITY OF SUCH DAMAGE.
|
25 | 25 | """
|
26 | 26 | import os
|
27 |
| -from azureml.core import Model, Run |
| 27 | +from azureml.core import Model, Run, Workspace, Experiment |
28 | 28 | import argparse
|
| 29 | +from azureml.core.authentication import ServicePrincipalAuthentication |
| 30 | +import traceback |
29 | 31 |
|
30 |
| - |
31 |
| -# Get workspace |
32 | 32 | run = Run.get_context()
|
33 |
| -exp = run.experiment |
34 |
| -ws = run.experiment.workspace |
| 33 | +if (run.id.startswith('OfflineRun')): |
| 34 | + from dotenv import load_dotenv |
| 35 | + # For local development, set values in this section |
| 36 | + load_dotenv() |
| 37 | + workspace_name = os.environ.get("WORKSPACE_NAME") |
| 38 | + experiment_name = os.environ.get("EXPERIMENT_NAME") |
| 39 | + resource_group = os.environ.get("RESOURCE_GROUP") |
| 40 | + subscription_id = os.environ.get("SUBSCRIPTION_ID") |
| 41 | + tenant_id = os.environ.get("TENANT_ID") |
| 42 | + model_name = os.environ.get("MODEL_NAME") |
| 43 | + app_id = os.environ.get('SP_APP_ID') |
| 44 | + app_secret = os.environ.get('SP_APP_SECRET') |
| 45 | + build_id = os.environ.get('BUILD_BUILDID') |
| 46 | + service_principal = ServicePrincipalAuthentication( |
| 47 | + tenant_id=tenant_id, |
| 48 | + service_principal_id=app_id, |
| 49 | + service_principal_password=app_secret) |
35 | 50 |
|
| 51 | + aml_workspace = Workspace.get( |
| 52 | + name=workspace_name, |
| 53 | + subscription_id=subscription_id, |
| 54 | + resource_group=resource_group, |
| 55 | + auth=service_principal |
| 56 | + ) |
| 57 | + ws = aml_workspace |
| 58 | + exp = Experiment(ws, experiment_name) |
| 59 | + run_id = "e78b2c27-5ceb-49d9-8e84-abe7aecf37d5" |
| 60 | +else: |
| 61 | + exp = run.experiment |
| 62 | + ws = run.experiment.workspace |
| 63 | + run_id = 'amlcompute' |
36 | 64 |
|
37 | 65 | parser = argparse.ArgumentParser("evaluate")
|
38 | 66 | parser.add_argument(
|
39 |
| - "--release_id", |
| 67 | + "--build_id", |
| 68 | + type=str, |
| 69 | + help="The Build ID of the build triggering this pipeline run", |
| 70 | +) |
| 71 | +parser.add_argument( |
| 72 | + "--run_id", |
40 | 73 | type=str,
|
41 |
| - help="The ID of the release triggering this pipeline run", |
| 74 | + help="Training run ID", |
42 | 75 | )
|
43 | 76 | parser.add_argument(
|
44 | 77 | "--model_name",
|
45 | 78 | type=str,
|
46 | 79 | help="Name of the Model",
|
47 | 80 | default="sklearn_regression_model.pkl",
|
48 | 81 | )
|
49 |
| -args = parser.parse_args() |
50 | 82 |
|
51 |
| -print("Argument 1: %s" % args.release_id) |
52 |
| -print("Argument 2: %s" % args.model_name) |
| 83 | +args = parser.parse_args() |
| 84 | +if (args.build_id is not None): |
| 85 | + build_id = args.build_id |
| 86 | +if (args.run_id is not None): |
| 87 | + run_id = args.run_id |
| 88 | +if (run_id == 'amlcompute'): |
| 89 | + run_id = run.parent.id |
53 | 90 | model_name = args.model_name
|
54 |
| -release_id = args.release_id |
| 91 | +metric_eval = "mse" |
| 92 | +run.tag("BuildId", value=build_id) |
55 | 93 |
|
56 |
| -# Paramaterize the matrics on which the models should be compared |
| 94 | +# Paramaterize the matrices on which the models should be compared |
57 | 95 | # Add golden data set on which all the model performance can be evaluated
|
58 |
| - |
59 |
| -all_runs = exp.get_runs( |
60 |
| - properties={"release_id": release_id, "run_type": "train"}, |
61 |
| - include_children=True |
62 |
| - ) |
63 |
| -new_model_run = next(all_runs) |
64 |
| -new_model_run_id = new_model_run.id |
65 |
| -print(f'New Run found with Run ID of: {new_model_run_id}') |
66 |
| - |
67 | 96 | try:
|
68 |
| - # Get most recently registered model, we assume that |
69 |
| - # is the model in production. |
70 |
| - # Download this model and compare it with the recently |
71 |
| - # trained model by running test with same data set. |
72 | 97 | model_list = Model.list(ws)
|
73 |
| - production_model = next( |
74 |
| - filter( |
75 |
| - lambda x: x.created_time == max( |
76 |
| - model.created_time for model in model_list), |
77 |
| - model_list, |
| 98 | + if (len(model_list) > 0): |
| 99 | + production_model = next( |
| 100 | + filter( |
| 101 | + lambda x: x.created_time == max( |
| 102 | + model.created_time for model in model_list), |
| 103 | + model_list, |
| 104 | + ) |
78 | 105 | )
|
79 |
| - ) |
80 |
| - production_model_run_id = production_model.tags.get("run_id") |
81 |
| - run_list = exp.get_runs() |
| 106 | + production_model_run_id = production_model.run_id |
82 | 107 |
|
83 |
| - # Get the run history for both production model and |
84 |
| - # newly trained model and compare mse |
85 |
| - production_model_run = Run(exp, run_id=production_model_run_id) |
86 |
| - new_model_run = Run(exp, run_id=new_model_run_id) |
| 108 | + # Get the run history for both production model and |
| 109 | + # newly trained model and compare mse |
| 110 | + production_model_run = Run(exp, run_id=production_model_run_id) |
| 111 | + new_model_run = run.parent |
| 112 | + print("Production model run is", production_model_run) |
87 | 113 |
|
88 |
| - production_model_mse = production_model_run.get_metrics().get("mse") |
89 |
| - new_model_mse = new_model_run.get_metrics().get("mse") |
90 |
| - print( |
91 |
| - "Current Production model mse: {}, New trained model mse: {}".format( |
92 |
| - production_model_mse, new_model_mse |
93 |
| - ) |
94 |
| - ) |
| 114 | + production_model_mse = \ |
| 115 | + production_model_run.get_metrics().get(metric_eval) |
| 116 | + new_model_mse = new_model_run.get_metrics().get(metric_eval) |
| 117 | + if (production_model_mse is None or new_model_mse is None): |
| 118 | + print("Unable to find", metric_eval, "metrics, " |
| 119 | + "exiting evaluation") |
| 120 | + run.parent.cancel() |
| 121 | + else: |
| 122 | + print( |
| 123 | + "Current Production model mse: {}, " |
| 124 | + "New trained model mse: {}".format( |
| 125 | + production_model_mse, new_model_mse |
| 126 | + ) |
| 127 | + ) |
95 | 128 |
|
96 |
| - promote_new_model = False |
97 |
| - if new_model_mse < production_model_mse: |
98 |
| - promote_new_model = True |
99 |
| - print("New trained model performs better, thus it will be registered") |
| 129 | + if (new_model_mse < production_model_mse): |
| 130 | + print("New trained model performs better, " |
| 131 | + "thus it should be registered") |
| 132 | + else: |
| 133 | + print("New trained model metric is less than or equal to " |
| 134 | + "production model so skipping model registration.") |
| 135 | + run.parent.cancel() |
| 136 | + else: |
| 137 | + print("This is the first model, " |
| 138 | + "thus it should be registered") |
100 | 139 | except Exception:
|
101 |
| - promote_new_model = True |
102 |
| - print("This is the first model to be trained, \ |
103 |
| - thus nothing to evaluate for now") |
104 |
| - |
105 |
| - |
106 |
| -# Writing the run id to /aml_config/run_id.json |
107 |
| -if promote_new_model: |
108 |
| - model_path = os.path.join('outputs', model_name) |
109 |
| - new_model_run.register_model( |
110 |
| - model_name=model_name, |
111 |
| - model_path=model_path, |
112 |
| - properties={"release_id": release_id}) |
113 |
| - print("Registered new model!") |
| 140 | + traceback.print_exc(limit=None, file=None, chain=True) |
| 141 | + print("Something went wrong trying to evaluate. Exiting.") |
| 142 | + raise |
0 commit comments