Skip to content

Commit 11716e8

Browse files
algattikdtzar
authored andcommitted
Simplified build with Azure CLI; various bugfixes (#121)
1 parent d360198 commit 11716e8

20 files changed

+348
-313
lines changed

.pipelines/azdo-ci-build-train.yml

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ trigger:
77
exclude:
88
- docs/
99
- environment_setup/
10-
- charts/
11-
- ml_service/util/create_scoring_image.py
10+
- ml_service/util/create_scoring_image.*
1211

1312
variables:
1413
- template: azdo-variables.yml
@@ -27,12 +26,15 @@ stages:
2726
timeoutInMinutes: 0
2827
steps:
2928
- template: azdo-base-pipeline.yml
30-
- script: |
31-
# Invoke the Python building and publishing a training pipeline
32-
python3 $(Build.SourcesDirectory)/ml_service/pipelines/${{ variables.BUILD_TRAIN_SCRIPT }}
33-
failOnStderr: 'false'
34-
env:
35-
SP_APP_SECRET: '$(SP_APP_SECRET)'
29+
- task: AzureCLI@1
30+
inputs:
31+
azureSubscription: '$(WORKSPACE_SVC_CONNECTION)'
32+
scriptLocation: inlineScript
33+
inlineScript: |
34+
set -e # fail on error
35+
export SUBSCRIPTION_ID=$(az account show --query id -o tsv)
36+
# Invoke the Python building and publishing a training pipeline
37+
python $(Build.SourcesDirectory)/ml_service/pipelines/${{ variables.BUILD_TRAIN_SCRIPT }}
3638
displayName: 'Publish Azure Machine Learning Pipeline'
3739
- stage: 'Trigger_AML_Pipeline'
3840
displayName: 'Train, evaluate, register model via previously published AML pipeline'
@@ -45,30 +47,43 @@ stages:
4547
container: mcr.microsoft.com/mlops/python:latest
4648
timeoutInMinutes: 0
4749
steps:
48-
- script: |
49-
python $(Build.SourcesDirectory)/ml_service/pipelines/run_train_pipeline.py
50-
# Set AMLPIPELINEID variable for next AML Pipeline task in next job
51-
source $(Build.SourcesDirectory)/tmp.sh
52-
echo "##vso[task.setvariable variable=AMLPIPELINEID;isOutput=true]$AMLPIPELINE_ID"
53-
rm $(Build.SourcesDirectory)/tmp.sh
50+
- task: AzureCLI@1
51+
inputs:
52+
azureSubscription: '$(WORKSPACE_SVC_CONNECTION)'
53+
scriptLocation: inlineScript
54+
inlineScript: |
55+
set -e # fail on error
56+
export SUBSCRIPTION_ID=$(az account show --query id -o tsv)
57+
python $(Build.SourcesDirectory)/ml_service/pipelines/run_train_pipeline.py --output_pipeline_id_file "pipeline_id.txt" --skip_train_execution
58+
# Set AMLPIPELINEID variable for next AML Pipeline task in next job
59+
AMLPIPELINEID="$(cat pipeline_id.txt)"
60+
echo "##vso[task.setvariable variable=AMLPIPELINEID;isOutput=true]$AMLPIPELINEID"
5461
name: 'getpipelineid'
5562
displayName: 'Get Pipeline ID'
56-
env:
57-
SP_APP_SECRET: '$(SP_APP_SECRET)'
63+
- bash: |
64+
# Generate a hyperparameter value as a random number between 0 and 1.
65+
# A random value is used here to make the Azure ML dashboards "interesting" when testing
66+
# the solution sample.
67+
alpha=$(printf "0.%03d\n" $((($RANDOM*1000)/32767)))
68+
echo "Alpha: $alpha"
69+
echo "##vso[task.setvariable variable=ALPHA;isOutput=true]$alpha"
70+
name: 'getalpha'
71+
displayName: 'Generate random value for hyperparameter alpha'
5872
- job: "Run_ML_Pipeline"
5973
dependsOn: "Get_Pipeline_ID"
6074
displayName: "Trigger ML Training Pipeline"
6175
pool: server
6276
variables:
6377
AMLPIPELINE_ID: $[ dependencies.Get_Pipeline_ID.outputs['getpipelineid.AMLPIPELINEID'] ]
78+
ALPHA: $[ dependencies.Get_Pipeline_ID.outputs['getalpha.ALPHA'] ]
6479
steps:
6580
- task: ms-air-aiagility.vss-services-azureml.azureml-restApi-task.MLPublishedPipelineRestAPITask@0
6681
displayName: 'Invoke ML pipeline'
6782
inputs:
6883
azureSubscription: '$(WORKSPACE_SVC_CONNECTION)'
6984
PipelineId: '$(AMLPIPELINE_ID)'
7085
ExperimentName: '$(EXPERIMENT_NAME)'
71-
PipelineParameters: '"model_name": "sklearn_regression_model.pkl"'
86+
PipelineParameters: '"ParameterAssignments": {"model_name": "$(MODEL_NAME)", "hyperparameter_alpha": "$(ALPHA)"}'
7287
- job: "Training_Run_Report"
7388
dependsOn: "Run_ML_Pipeline"
7489
displayName: "Determine if evaluation succeeded and new model is registered"
@@ -77,22 +92,27 @@ stages:
7792
container: mcr.microsoft.com/mlops/python:latest
7893
timeoutInMinutes: 0
7994
steps:
80-
- script: |
81-
python $(Build.SourcesDirectory)/code/register/register_model.py --build_id $(Build.BuildId) --validate True
82-
displayName: 'Check if new model registered'
83-
env:
84-
SP_APP_SECRET: '$(SP_APP_SECRET)'
95+
- task: AzureCLI@1
96+
inputs:
97+
azureSubscription: '$(WORKSPACE_SVC_CONNECTION)'
98+
scriptLocation: inlineScript
99+
inlineScript: |
100+
set -e # fail on error
101+
export SUBSCRIPTION_ID=$(az account show --query id -o tsv)
102+
python $(Build.SourcesDirectory)/ml_service/pipelines/verify_train_pipeline.py --build_id $(Build.BuildId)
103+
displayName: "Determine if evaluation succeeded and new model is registered"
85104
- task: CopyFiles@2
86105
displayName: 'Copy Files to: $(Build.ArtifactStagingDirectory)'
87106
inputs:
88107
SourceFolder: '$(Build.SourcesDirectory)'
89108
TargetFolder: '$(Build.ArtifactStagingDirectory)'
90109
Contents: |
91110
code/scoring/**
111+
ml_service/util/**
92112
- task: PublishBuildArtifacts@1
93113
displayName: 'Publish Artifact'
94114
inputs:
95115
ArtifactName: 'mlops-pipelines'
96116
publishLocation: 'container'
97117
pathtoPublish: '$(Build.ArtifactStagingDirectory)'
98-
TargetPath: '$(Build.ArtifactStagingDirectory)'
118+
TargetPath: '$(Build.ArtifactStagingDirectory)'

code/evaluate/evaluate_model.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import sys
2828
from azureml.core import Run, Workspace, Experiment
2929
import argparse
30-
from azureml.core.authentication import ServicePrincipalAuthentication
3130
import traceback
3231

3332
run = Run.get_context()
@@ -48,16 +47,11 @@
4847
build_id = os.environ.get('BUILD_BUILDID')
4948
# run_id useful to query previous runs
5049
run_id = "57fee47f-5ae8-441c-bc0c-d4c371f32d70"
51-
service_principal = ServicePrincipalAuthentication(
52-
tenant_id=tenant_id,
53-
service_principal_id=app_id,
54-
service_principal_password=app_secret)
5550

5651
aml_workspace = Workspace.get(
5752
name=workspace_name,
5853
subscription_id=subscription_id,
59-
resource_group=resource_group,
60-
auth=service_principal
54+
resource_group=resource_group
6155
)
6256
ws = aml_workspace
6357
exp = Experiment(ws, experiment_name)

code/register/register_model.py

Lines changed: 5 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -29,45 +29,30 @@
2929
import traceback
3030
from azureml.core import Run, Experiment, Workspace
3131
from azureml.core.model import Model as AMLModel
32-
from azureml.core.authentication import ServicePrincipalAuthentication
3332

3433

3534
def main():
3635

3736
run = Run.get_context()
3837
if (run.id.startswith('OfflineRun')):
3938
from dotenv import load_dotenv
40-
sys.path.append(os.path.abspath("./code/util")) # NOQA: E402
41-
from model_helper import get_model_by_tag
4239
# For local development, set values in this section
4340
load_dotenv()
4441
workspace_name = os.environ.get("WORKSPACE_NAME")
4542
experiment_name = os.environ.get("EXPERIMENT_NAME")
4643
resource_group = os.environ.get("RESOURCE_GROUP")
4744
subscription_id = os.environ.get("SUBSCRIPTION_ID")
48-
tenant_id = os.environ.get("TENANT_ID")
49-
model_name = os.environ.get("MODEL_NAME")
50-
app_id = os.environ.get('SP_APP_ID')
51-
app_secret = os.environ.get('SP_APP_SECRET')
5245
build_id = os.environ.get('BUILD_BUILDID')
5346
# run_id useful to query previous runs
5447
run_id = "bd184a18-2ac8-4951-8e78-e290bef3b012"
55-
service_principal = ServicePrincipalAuthentication(
56-
tenant_id=tenant_id,
57-
service_principal_id=app_id,
58-
service_principal_password=app_secret)
59-
6048
aml_workspace = Workspace.get(
6149
name=workspace_name,
6250
subscription_id=subscription_id,
63-
resource_group=resource_group,
64-
auth=service_principal
51+
resource_group=resource_group
6552
)
6653
ws = aml_workspace
6754
exp = Experiment(ws, experiment_name)
6855
else:
69-
sys.path.append(os.path.abspath("./util")) # NOQA: E402
70-
from model_helper import get_model_by_tag
7156
ws = run.experiment.workspace
7257
exp = run.experiment
7358
run_id = 'amlcompute'
@@ -89,12 +74,6 @@ def main():
8974
help="Name of the Model",
9075
default="sklearn_regression_model.pkl",
9176
)
92-
parser.add_argument(
93-
"--validate",
94-
type=str,
95-
help="Set to true to only validate if model is registered for run",
96-
default=False,
97-
)
9877

9978
args = parser.parse_args()
10079
if (args.build_id is not None):
@@ -103,30 +82,13 @@ def main():
10382
run_id = args.run_id
10483
if (run_id == 'amlcompute'):
10584
run_id = run.parent.id
106-
if (args.validate is not None):
107-
validate = args.validate
10885
model_name = args.model_name
10986

110-
if (validate):
111-
try:
112-
tag_name = 'BuildId'
113-
model = get_model_by_tag(
114-
model_name, tag_name, build_id, exp.workspace)
115-
if (model is not None):
116-
print("Model was registered for this build.")
117-
if (model is None):
118-
print("Model was not registered for this run.")
119-
sys.exit(1)
120-
except Exception as e:
121-
print(e)
122-
print("Model was not registered for this run.")
123-
sys.exit(1)
87+
if (build_id is None):
88+
register_aml_model(model_name, exp, run_id)
12489
else:
125-
if (build_id is None):
126-
register_aml_model(model_name, exp, run_id)
127-
else:
128-
run.tag("BuildId", value=build_id)
129-
register_aml_model(model_name, exp, run_id, build_id)
90+
run.tag("BuildId", value=build_id)
91+
register_aml_model(model_name, exp, run_id, build_id)
13092

13193

13294
def model_already_registered(model_name, exp, run_id):

code/scoring/score.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,10 @@ def init():
3939

4040

4141
def run(raw_data):
42-
try:
43-
data = json.loads(raw_data)["data"]
44-
data = numpy.array(data)
45-
result = model.predict(data)
46-
return json.dumps({"result": result.tolist()})
47-
except Exception as e:
48-
result = str(e)
49-
return json.dumps({"error": result})
42+
data = json.loads(raw_data)["data"]
43+
data = numpy.array(data)
44+
result = model.predict(data)
45+
return {"result": result.tolist()}
5046

5147

5248
if __name__ == "__main__":

0 commit comments

Comments
 (0)