Skip to content

Commit

Permalink
Merge pull request #54 from microsoft/sudivate/scoringimage
Browse files Browse the repository at this point in the history
Sudivate/scoringimage
  • Loading branch information
sudivate authored Aug 22, 2019
2 parents c540a2f + 984399b commit 9ec5009
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 43 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ AML_CLUSTER_MIN_NODES = ''
AML_CLUSTER_PRIORITY = 'lowpriority'
# Training Config
MODEL_NAME = ''
MODEL_VERSION = ''
# AML Pipeline Config
TRAINING_PIPELINE_NAME = ''
PIPELINE_CONDA_PATH = 'aml_config/conda_dependencies.yml'
Expand Down
111 changes: 68 additions & 43 deletions docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Please make note of the following values after creating a service principal, we
- Application Secret


**Note:** You must have sufficient permissions to register an application with your Azure AD tenant, and assign the application to a role in your Azure subscription. Contact your subscription adminstator if you don't have the permissions. Normally a subscription admin can create a Service principal and can provide you the details.
**Note:** You must have sufficient permissions to register an application with your Azure AD tenant, and assign the application to a role in your Azure subscription. Contact your subscription administrator if you don't have the permissions. Normally a subscription admin can create a Service principal and can provide you the details.


### 4. Create a Variable Group
Expand All @@ -29,26 +29,26 @@ We make use of variable group inside Azure DevOps to store variables and their v

Please name your variable group **``devopsforai-aml-vg``** as we are using this name within our build yaml file.

The varibale group should contain the following variables:

| Variable Name | Suggested Value |
| --- | --- |
| AML_COMPUTE_CLUSTER_CPU_SKU | STANDARD_DS2_V2 |
| AML_COMPUTE_CLUSTER_NAME | train-cluster |
| AML_WORKSPACE_NAME | mlops-AML-WS |
| BASE_NAME | mlops |
| EVALUATE_SCRIPT_PATH | evaluate/evaluate_model.py |
| EXPERIMENT_NAME | mlopspython |
| LOCATION | centralus |
| MODEL_NAME | sklearn_regression_model.pkl |
| REGISTER_SCRIPT_PATH | register/register_model.py |
| RESOURCE_GROUP | mlops-AML-RG |
| SOURCES_DIR_TRAIN | code |
| SP_APP_ID | |
| SP_APP_SECRET | |
| SUBSCRIPTION_ID | |
| TENANT_ID | |
| TRAIN_SCRIPT_PATH | training/train.py |
The variable group should contain the following variables:

| Variable Name | Suggested Value |
| --------------------------- | ---------------------------- |
| AML_COMPUTE_CLUSTER_CPU_SKU | STANDARD_DS2_V2 |
| AML_COMPUTE_CLUSTER_NAME | train-cluster |
| AML_WORKSPACE_NAME | mlops-AML-WS |
| BASE_NAME | mlops |
| EVALUATE_SCRIPT_PATH | evaluate/evaluate_model.py |
| EXPERIMENT_NAME | mlopspython |
| LOCATION | centralus |
| MODEL_NAME | sklearn_regression_model.pkl |
| REGISTER_SCRIPT_PATH | register/register_model.py |
| RESOURCE_GROUP | mlops-AML-RG |
| SOURCES_DIR_TRAIN | code |
| SP_APP_ID | |
| SP_APP_SECRET | |
| SUBSCRIPTION_ID | |
| TENANT_ID | |
| TRAIN_SCRIPT_PATH | training/train.py |

Mark **SP_APP_SECRET** variable as a secret one.

Expand Down Expand Up @@ -173,15 +173,15 @@ Create a stage **QA (ACI)** and add a single task to the job **Azure ML Model De
Specify task parameters as it is shown in the table below:


| Parameter | Value |
| --- | --- |
| Display Name | Azure ML Model Deploy |
| Azure ML Workspace | mlops-AML-WS |
| Inference config Path | `$(System.DefaultWorkingDirectory)/_ci-build/mlops-pipelines/code/scoring/inference_config.yml` |
| Model Deployment Target | Azure Container Instance |
| Deployment Name | mlopspython-aci |
| Parameter | Value |
| ----------------------------- | ---------------------------------------------------------------------------------------------------- |
| Display Name | Azure ML Model Deploy |
| Azure ML Workspace | mlops-AML-WS |
| Inference config Path | `$(System.DefaultWorkingDirectory)/_ci-build/mlops-pipelines/code/scoring/inference_config.yml` |
| Model Deployment Target | Azure Container Instance |
| Deployment Name | mlopspython-aci |
| Deployment Configuration file | `$(System.DefaultWorkingDirectory)/_ci-build/mlops-pipelines/code/scoring/deployment_config_aci.yml` |
| Overwrite existing deployment | X |
| Overwrite existing deployment | X |


In a similar way create a stage **Prod (AKS** and add a single task to the job **Azure ML Model Deploy**:
Expand All @@ -190,25 +190,50 @@ In a similar way create a stage **Prod (AKS** and add a single task to the job *

Specify task parameters as it is shown in the table below:

| Parameter | Value |
| --- | --- |
| Display Name | Azure ML Model Deploy |
| Azure ML Workspace | mlops-AML-WS |
| Inference config Path | `$(System.DefaultWorkingDirectory)/_ci-build/mlops-pipelines/code/scoring/inference_config.yml` |
| Model Deployment Target | Azure Kubernetes Service |
| Select AKS Cluster for Deployment | YOUR_DEPLOYMENT_K8S_CLUSTER |
| Deployment Name | mlopspython-aks |
| Deployment Configuration file | `$(System.DefaultWorkingDirectory)/_ci-build/mlops-pipelines/code/scoring/deployment_config_aks.yml` |
| Overwrite existing deployment | X |
| Parameter | Value |
| --------------------------------- | ---------------------------------------------------------------------------------------------------- |
| Display Name | Azure ML Model Deploy |
| Azure ML Workspace | mlops-AML-WS |
| Inference config Path | `$(System.DefaultWorkingDirectory)/_ci-build/mlops-pipelines/code/scoring/inference_config.yml` |
| Model Deployment Target | Azure Kubernetes Service |
| Select AKS Cluster for Deployment | YOUR_DEPLOYMENT_K8S_CLUSTER |
| Deployment Name | mlopspython-aks |
| Deployment Configuration file | `$(System.DefaultWorkingDirectory)/_ci-build/mlops-pipelines/code/scoring/deployment_config_aks.yml` |
| Overwrite existing deployment | X |

**Note:** Creating of a Kubernetes cluster on AKS is out of scope of this tutorial, so you should take care of it on your own.

Save the pipeline and craete a release to trigger it manually. Once the pipeline exection is finished, check out deployments in the **mlops-AML-WS** workspace.
**Deploy trained model to Azure Web App for containers**

Note: This is an optional step and can be used only if you are deploying your scoring service on Azure Web Apps.

[Create Image Script](../ml_service/util/create_scoring_image.py)
can be used to create a scoring image from the release pipeline. Image created by this script will be registered under Azure Container Registry(ACR) instance that belongs to Azure Machine Learning Service. Any dependencies that scoring file depends on can also be packaged with the container with Image config. To learn more on how to create a container with AML SDK click [here](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.image.image.image?view=azure-ml-py#create-workspace--name--models--image-config-).

Below is release pipeline with two tasks one to create an image using the above script and second is the deploy the image to Web App for containers
![release_webapp](./images/release-webapp-pipeline.PNG)

Using bash script task to invoke [Create Image Script](../ml_service/util/create_scoring_image.py)
![release_createimage](./images/release-task-createimage.PNG)

Specify task parameters as it is shown in the table below:


| Parameter | Value |
| ------------------ | --------------------------------------------------------------------------------------------------- |
| Azure subscription | Subscription used to deploy Web App |
| App name | Web App for Containers name |
| Image name | Specify the fully qualified container image name. For example, 'myregistry.azurecr.io/nginx:latest' |

![release_webapp](./images/release-task-webappdeploy.PNG)


Save the pipeline and create a release to trigger it manually. Once the pipeline execution is finished, check out deployments in the **mlops-AML-WS** workspace.



Congratulations! You have three pipelines set up end to end:
- Build pipeline: triggered on code change to master branch on GitHub, performs linting, unit testing and publishing a trainig pipeline
- Release Trigger pipeline: runs a published training pipeline to trian, evaluate and register a model
- Release Deployment pipeline: deploys a model to QA (ACI) and Prod (AKS) environemts
- Build pipeline: triggered on code change to master branch on GitHub, performs linting, unit testing and publishing a training pipeline
- Release Trigger pipeline: runs a published training pipeline to train, evaluate and register a model
- Release Deployment pipeline: deploys a model to QA (ACI) and Prod (AKS) environments

Binary file added docs/images/release-task-createimage.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/release-task-webappdeploy.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/release-webapp-pipeline.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions ml_service/util/create_scoring_image.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import os
from azureml.core import Workspace
from azureml.core.image import ContainerImage, Image
from azureml.core.model import Model
from dotenv import load_dotenv
from azureml.core.authentication import ServicePrincipalAuthentication

load_dotenv()

TENANT_ID = os.environ.get('TENANT_ID')
APP_ID = os.environ.get('APP_ID')
APP_SECRET = os.environ.get('APP_SECRET')
WORKSPACE_NAME = os.environ.get('WORKSPACE_NAME')
SUBSCRIPTION_ID = os.environ.get('SUBSCRIPTION_ID')
RESOURCE_GROUP = os.environ.get('RESOURCE_GROUP')
MODEL_NAME = os.environ.get('MODEL_NAME')
MODEL_VERSION = os.environ.get('MODEL_VERSION')
IMAGE_NAME = os.environ.get('IMAGE_NAME')


SP_AUTH = ServicePrincipalAuthentication(
tenant_id=TENANT_ID,
service_principal_id=APP_ID,
service_principal_password=APP_SECRET)

ws = Workspace.get(
WORKSPACE_NAME,
SP_AUTH,
SUBSCRIPTION_ID,
RESOURCE_GROUP
)


model = Model(ws, name=MODEL_NAME, version=MODEL_VERSION)
os.chdir("./code/scoring")

image_config = ContainerImage.image_configuration(
execution_script="score.py",
runtime="python",
conda_file="conda_dependencies.yml",
description="Image with ridge regression model",
tags={"area": "diabetes", "type": "regression"},
)

image = Image.create(
name=IMAGE_NAME, models=[model], image_config=image_config, workspace=ws
)

image.wait_for_creation(show_output=True)

if image.creation_state != "Succeeded":
raise Exception("Image creation status: {image.creation_state}")

print("{}(v.{} [{}]) stored at {} with build log {}".format(
image.name,
image.version,
image.creation_state,
image.image_location,
image.image_build_log_uri,
)
)

0 comments on commit 9ec5009

Please sign in to comment.