mirror of
https://github.com/Azure/MachineLearningNotebooks.git
synced 2025-12-19 17:17:04 -05:00
update samples from Release-55 as a part of SDK release
This commit is contained in:
@@ -103,7 +103,7 @@
|
||||
"source": [
|
||||
"import azureml.core\n",
|
||||
"\n",
|
||||
"print(\"This notebook was created using version 1.6.0 of the Azure ML SDK\")\n",
|
||||
"print(\"This notebook was created using version 1.7.0 of the Azure ML SDK\")\n",
|
||||
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"This notebook was created using version 1.6.0 of the Azure ML SDK\")\n",
|
||||
"print(\"This notebook was created using version 1.7.0 of the Azure ML SDK\")\n",
|
||||
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"This notebook was created using version 1.6.0 of the Azure ML SDK\")\n",
|
||||
"print(\"This notebook was created using version 1.7.0 of the Azure ML SDK\")\n",
|
||||
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"This notebook was created using version 1.6.0 of the Azure ML SDK\")\n",
|
||||
"print(\"This notebook was created using version 1.7.0 of the Azure ML SDK\")\n",
|
||||
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
||||
]
|
||||
},
|
||||
@@ -491,8 +491,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"test_run = run_inference(test_experiment, compute_target, script_folder, best_dnn_run, test_dataset,\n",
|
||||
" target_column_name, model_name)"
|
||||
"test_run = run_inference(test_experiment, compute_target, script_folder, best_dnn_run,\n",
|
||||
" train_dataset, test_dataset, target_column_name, model_name)"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ from azureml.core.run import Run
|
||||
|
||||
|
||||
def run_inference(test_experiment, compute_target, script_folder, train_run,
|
||||
test_dataset, target_column_name, model_name):
|
||||
train_dataset, test_dataset, target_column_name, model_name):
|
||||
|
||||
train_run.download_file('outputs/conda_env_v_1_0_0.yml',
|
||||
'inference/condafile.yml')
|
||||
@@ -22,7 +22,10 @@ def run_inference(test_experiment, compute_target, script_folder, train_run,
|
||||
'--target_column_name': target_column_name,
|
||||
'--model_name': model_name
|
||||
},
|
||||
inputs=[test_dataset.as_named_input('test_data')],
|
||||
inputs=[
|
||||
train_dataset.as_named_input('train_data'),
|
||||
test_dataset.as_named_input('test_data')
|
||||
],
|
||||
compute_target=compute_target,
|
||||
environment_definition=inference_env)
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import numpy as np
|
||||
import argparse
|
||||
from azureml.core import Run
|
||||
|
||||
import numpy as np
|
||||
|
||||
from sklearn.externals import joblib
|
||||
from azureml.automl.core.shared import constants, metrics
|
||||
|
||||
from azureml.automl.runtime.shared.score import scoring, constants
|
||||
from azureml.core import Run
|
||||
from azureml.core.model import Model
|
||||
|
||||
|
||||
@@ -29,22 +32,26 @@ model = joblib.load(model_path)
|
||||
run = Run.get_context()
|
||||
# get input dataset by name
|
||||
test_dataset = run.input_datasets['test_data']
|
||||
train_dataset = run.input_datasets['train_data']
|
||||
|
||||
X_test_df = test_dataset.drop_columns(columns=[target_column_name]) \
|
||||
.to_pandas_dataframe()
|
||||
y_test_df = test_dataset.with_timestamp_columns(None) \
|
||||
.keep_columns(columns=[target_column_name]) \
|
||||
.to_pandas_dataframe()
|
||||
y_train_df = test_dataset.with_timestamp_columns(None) \
|
||||
.keep_columns(columns=[target_column_name]) \
|
||||
.to_pandas_dataframe()
|
||||
|
||||
predicted = model.predict_proba(X_test_df)
|
||||
|
||||
# use automl metrics module
|
||||
scores = metrics.compute_metrics_classification(
|
||||
np.array(predicted),
|
||||
np.array(y_test_df),
|
||||
class_labels=model.classes_,
|
||||
metrics=list(constants.Metric.SCALAR_CLASSIFICATION_SET)
|
||||
)
|
||||
# Use the AutoML scoring module
|
||||
class_labels = np.unique(np.concatenate((y_train_df.values, y_test_df.values)))
|
||||
train_labels = model.classes_
|
||||
classification_metrics = list(constants.CLASSIFICATION_SCALAR_SET)
|
||||
scores = scoring.score_classification(y_test_df.values, predicted,
|
||||
classification_metrics,
|
||||
class_labels, train_labels)
|
||||
|
||||
print("scores:")
|
||||
print(scores)
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"This notebook was created using version 1.6.0 of the Azure ML SDK\")\n",
|
||||
"print(\"This notebook was created using version 1.7.0 of the Azure ML SDK\")\n",
|
||||
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"This notebook was created using version 1.6.0 of the Azure ML SDK\")\n",
|
||||
"print(\"This notebook was created using version 1.7.0 of the Azure ML SDK\")\n",
|
||||
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import argparse
|
||||
from azureml.core import Run
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
from pandas.tseries.frequencies import to_offset
|
||||
from sklearn.externals import joblib
|
||||
from sklearn.metrics import mean_absolute_error, mean_squared_error
|
||||
from azureml.automl.core.shared import constants, metrics
|
||||
from pandas.tseries.frequencies import to_offset
|
||||
|
||||
from azureml.automl.runtime.shared.score import scoring, constants
|
||||
from azureml.core import Run
|
||||
|
||||
|
||||
def align_outputs(y_predicted, X_trans, X_test, y_test,
|
||||
@@ -299,12 +302,11 @@ print(df_all[target_column_name])
|
||||
print("predicted values:::")
|
||||
print(df_all['predicted'])
|
||||
|
||||
# use automl metrics module
|
||||
scores = metrics.compute_metrics_regression(
|
||||
df_all['predicted'],
|
||||
df_all[target_column_name],
|
||||
list(constants.Metric.SCALAR_REGRESSION_SET),
|
||||
None, None, None)
|
||||
# Use the AutoML scoring module
|
||||
regression_metrics = list(constants.REGRESSION_SCALAR_SET)
|
||||
y_test = np.array(df_all[target_column_name])
|
||||
y_pred = np.array(df_all['predicted'])
|
||||
scores = scoring.score_regression(y_test, y_pred, regression_metrics)
|
||||
|
||||
print("scores:")
|
||||
print(scores)
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"This notebook was created using version 1.6.0 of the Azure ML SDK\")\n",
|
||||
"print(\"This notebook was created using version 1.7.0 of the Azure ML SDK\")\n",
|
||||
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"This notebook was created using version 1.6.0 of the Azure ML SDK\")\n",
|
||||
"print(\"This notebook was created using version 1.7.0 of the Azure ML SDK\")\n",
|
||||
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"This notebook was created using version 1.6.0 of the Azure ML SDK\")\n",
|
||||
"print(\"This notebook was created using version 1.7.0 of the Azure ML SDK\")\n",
|
||||
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"This notebook was created using version 1.6.0 of the Azure ML SDK\")\n",
|
||||
"print(\"This notebook was created using version 1.7.0 of the Azure ML SDK\")\n",
|
||||
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
||||
]
|
||||
},
|
||||
@@ -336,7 +336,11 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"tags": [
|
||||
"sample-featurizationconfig-remarks"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"featurization_config = FeaturizationConfig()\n",
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
"1. [Setup](#Setup)\n",
|
||||
"1. [Train](#Train)\n",
|
||||
"1. [Results](#Results)\n",
|
||||
"1. [Test](#Test)\n",
|
||||
"1. [Test](#Tests)\n",
|
||||
"1. [Explanation](#Explanation)\n",
|
||||
"1. [Acknowledgements](#Acknowledgements)"
|
||||
]
|
||||
},
|
||||
@@ -49,9 +50,9 @@
|
||||
"2. Configure AutoML using `AutoMLConfig`.\n",
|
||||
"3. Train the model.\n",
|
||||
"4. Explore the results.\n",
|
||||
"5. Visualization model's feature importance in azure portal\n",
|
||||
"6. Explore any model's explanation and explore feature importance in azure portal\n",
|
||||
"7. Test the fitted model."
|
||||
"5. Test the fitted model.\n",
|
||||
"6. Explore any model's explanation and explore feature importance in azure portal.\n",
|
||||
"7. Create an AKS cluster, deploy the webservice of AutoML scoring model and the explainer model to the AKS and consume the web service."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -95,7 +96,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"This notebook was created using version 1.6.0 of the Azure ML SDK\")\n",
|
||||
"print(\"This notebook was created using version 1.7.0 of the Azure ML SDK\")\n",
|
||||
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
||||
]
|
||||
},
|
||||
@@ -255,9 +256,9 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Analyze results\n",
|
||||
"### Analyze results\n",
|
||||
"\n",
|
||||
"### Retrieve the Best Model\n",
|
||||
"#### Retrieve the Best Model\n",
|
||||
"\n",
|
||||
"Below we select the best pipeline from our iterations. The `get_output` method on `automl_classifier` returns the best run and the fitted model for the last invocation. Overloads on `get_output` allow you to retrieve the best run and fitted model for *any* logged metric or for a particular *iteration*."
|
||||
]
|
||||
@@ -284,9 +285,80 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Best Model 's explanation\n",
|
||||
"Retrieve the explanation from the best_run which includes explanations for engineered features and raw features.\n",
|
||||
"## Tests\n",
|
||||
"\n",
|
||||
"Now that the model is trained, split the data in the same way the data was split for training (The difference here is the data is being split locally) and then run the test data through the trained model to get the predicted values."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# convert the test data to dataframe\n",
|
||||
"X_test_df = validation_data.drop_columns(columns=[label_column_name]).to_pandas_dataframe()\n",
|
||||
"y_test_df = validation_data.keep_columns(columns=[label_column_name], validate=True).to_pandas_dataframe()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# call the predict functions on the model\n",
|
||||
"y_pred = fitted_model.predict(X_test_df)\n",
|
||||
"y_pred"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Calculate metrics for the prediction\n",
|
||||
"\n",
|
||||
"Now visualize the data on a scatter plot to show what our truth (actual) values are compared to the predicted values \n",
|
||||
"from the trained model that was returned."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from sklearn.metrics import confusion_matrix\n",
|
||||
"import numpy as np\n",
|
||||
"import itertools\n",
|
||||
"\n",
|
||||
"cf =confusion_matrix(y_test_df.values,y_pred)\n",
|
||||
"plt.imshow(cf,cmap=plt.cm.Blues,interpolation='nearest')\n",
|
||||
"plt.colorbar()\n",
|
||||
"plt.title('Confusion Matrix')\n",
|
||||
"plt.xlabel('Predicted')\n",
|
||||
"plt.ylabel('Actual')\n",
|
||||
"class_labels = ['False','True']\n",
|
||||
"tick_marks = np.arange(len(class_labels))\n",
|
||||
"plt.xticks(tick_marks,class_labels)\n",
|
||||
"plt.yticks([-0.5,0,1,1.5],['','False','True',''])\n",
|
||||
"# plotting text value inside cells\n",
|
||||
"thresh = cf.max() / 2.\n",
|
||||
"for i,j in itertools.product(range(cf.shape[0]),range(cf.shape[1])):\n",
|
||||
" plt.text(j,i,format(cf[i,j],'d'),horizontalalignment='center',color='white' if cf[i,j] >thresh else 'black')\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Explanation\n",
|
||||
"In this section, we will show how to compute model explanations and visualize the explanations using azureml-explain-model package. We will also show how to run the automl model and the explainer model through deploying an AKS web service.\n",
|
||||
"\n",
|
||||
"Besides retrieving an existing model explanation for an AutoML model, you can also explain your AutoML model with different test data. The following steps will allow you to compute and visualize engineered feature importance based on your test data.\n",
|
||||
"\n",
|
||||
"### Run the explanation\n",
|
||||
"#### Download engineered feature importance from artifact store\n",
|
||||
"You can use ExplanationClient to download the engineered feature explanations from the artifact store of the best_run. You can also use azure portal url to view the dash board visualization of the feature importance values of the engineered features."
|
||||
]
|
||||
@@ -303,14 +375,6 @@
|
||||
"print(\"You can visualize the engineered explanations under the 'Explanations (preview)' tab in the AutoML run at:-\\n\" + best_run.get_portal_url())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Explanations\n",
|
||||
"In this section, we will show how to compute model explanations and visualize the explanations using azureml-explain-model package. Besides retrieving an existing model explanation for an AutoML model, you can also explain your AutoML model with different test data. The following steps will allow you to compute and visualize engineered feature importance based on your test data."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
@@ -403,6 +467,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compute the engineered explanations\n",
|
||||
"engineered_explanations = explainer.explain(['local', 'global'], eval_dataset=automl_explainer_setup_obj.X_test_transform)\n",
|
||||
"print(engineered_explanations.get_feature_importance_dict())\n",
|
||||
"print(\"You can visualize the engineered explanations under the 'Explanations (preview)' tab in the AutoML run at:-\\n\" + automl_run.get_portal_url())"
|
||||
@@ -412,41 +477,37 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test the fitted model\n",
|
||||
"#### Initialize the scoring Explainer, save and upload it for later use in scoring explanation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from azureml.explain.model.scoring.scoring_explainer import TreeScoringExplainer\n",
|
||||
"import joblib\n",
|
||||
"\n",
|
||||
"Now that the model is trained, split the data in the same way the data was split for training (The difference here is the data is being split locally) and then run the test data through the trained model to get the predicted values."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# convert the test data to dataframe\n",
|
||||
"X_test_df = validation_data.drop_columns(columns=[label_column_name]).to_pandas_dataframe()\n",
|
||||
"y_test_df = validation_data.keep_columns(columns=[label_column_name], validate=True).to_pandas_dataframe()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# call the predict functions on the model\n",
|
||||
"y_pred = fitted_model.predict(X_test_df)\n",
|
||||
"y_pred"
|
||||
"# Initialize the ScoringExplainer\n",
|
||||
"scoring_explainer = TreeScoringExplainer(explainer.explainer, feature_maps=[automl_explainer_setup_obj.feature_map])\n",
|
||||
"\n",
|
||||
"# Pickle scoring explainer locally to './scoring_explainer.pkl'\n",
|
||||
"scoring_explainer_file_name = 'scoring_explainer.pkl'\n",
|
||||
"with open(scoring_explainer_file_name, 'wb') as stream:\n",
|
||||
" joblib.dump(scoring_explainer, stream)\n",
|
||||
"\n",
|
||||
"# Upload the scoring explainer to the automl run\n",
|
||||
"automl_run.upload_file('outputs/scoring_explainer.pkl', scoring_explainer_file_name)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Calculate metrics for the prediction\n",
|
||||
"### Deploying the scoring and explainer models to a web service to Azure Kubernetes Service (AKS)\n",
|
||||
"\n",
|
||||
"Now visualize the data on a scatter plot to show what our truth (actual) values are compared to the predicted values \n",
|
||||
"from the trained model that was returned."
|
||||
"We use the TreeScoringExplainer from azureml.explain.model package to create the scoring explainer which will be used to compute the raw and engineered feature importances at the inference time. In the cell below, we register the AutoML model and the scoring explainer with the Model Management Service."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -455,25 +516,238 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from sklearn.metrics import confusion_matrix\n",
|
||||
"import numpy as np\n",
|
||||
"import itertools\n",
|
||||
"# Register trained automl model present in the 'outputs' folder in the artifacts\n",
|
||||
"original_model = automl_run.register_model(model_name='automl_model', \n",
|
||||
" model_path='outputs/model.pkl')\n",
|
||||
"scoring_explainer_model = automl_run.register_model(model_name='scoring_explainer',\n",
|
||||
" model_path='outputs/scoring_explainer.pkl')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Create the conda dependencies for setting up the service\n",
|
||||
"\n",
|
||||
"cf =confusion_matrix(y_test_df.values,y_pred)\n",
|
||||
"plt.imshow(cf,cmap=plt.cm.Blues,interpolation='nearest')\n",
|
||||
"plt.colorbar()\n",
|
||||
"plt.title('Confusion Matrix')\n",
|
||||
"plt.xlabel('Predicted')\n",
|
||||
"plt.ylabel('Actual')\n",
|
||||
"class_labels = ['False','True']\n",
|
||||
"tick_marks = np.arange(len(class_labels))\n",
|
||||
"plt.xticks(tick_marks,class_labels)\n",
|
||||
"plt.yticks([-0.5,0,1,1.5],['','False','True',''])\n",
|
||||
"# plotting text value inside cells\n",
|
||||
"thresh = cf.max() / 2.\n",
|
||||
"for i,j in itertools.product(range(cf.shape[0]),range(cf.shape[1])):\n",
|
||||
" plt.text(j,i,format(cf[i,j],'d'),horizontalalignment='center',color='white' if cf[i,j] >thresh else 'black')\n",
|
||||
"plt.show()"
|
||||
"We need to create the conda dependencies comprising of the azureml-explain-model, azureml-train-automl and azureml-defaults packages."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from azureml.automl.core.shared import constants\n",
|
||||
"from azureml.core.environment import Environment\n",
|
||||
"\n",
|
||||
"automl_run.download_file(constants.CONDA_ENV_FILE_PATH, 'myenv.yml')\n",
|
||||
"myenv = Environment.from_conda_specification(name=\"myenv\", file_path=\"myenv.yml\")\n",
|
||||
"myenv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Write the Entry Script\n",
|
||||
"Write the script that will be used to predict on your model"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%writefile score.py\n",
|
||||
"import numpy as np\n",
|
||||
"import pandas as pd\n",
|
||||
"import os\n",
|
||||
"import pickle\n",
|
||||
"import azureml.train.automl\n",
|
||||
"import azureml.explain.model\n",
|
||||
"from azureml.train.automl.runtime.automl_explain_utilities import AutoMLExplainerSetupClass, \\\n",
|
||||
" automl_setup_model_explanations\n",
|
||||
"import joblib\n",
|
||||
"from azureml.core.model import Model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def init():\n",
|
||||
" global automl_model\n",
|
||||
" global scoring_explainer\n",
|
||||
"\n",
|
||||
" # Retrieve the path to the model file using the model name\n",
|
||||
" # Assume original model is named original_prediction_model\n",
|
||||
" automl_model_path = Model.get_model_path('automl_model')\n",
|
||||
" scoring_explainer_path = Model.get_model_path('scoring_explainer')\n",
|
||||
"\n",
|
||||
" automl_model = joblib.load(automl_model_path)\n",
|
||||
" scoring_explainer = joblib.load(scoring_explainer_path)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def run(raw_data):\n",
|
||||
" data = pd.read_json(raw_data, orient='records') \n",
|
||||
" # Make prediction\n",
|
||||
" predictions = automl_model.predict(data)\n",
|
||||
" # Setup for inferencing explanations\n",
|
||||
" automl_explainer_setup_obj = automl_setup_model_explanations(automl_model,\n",
|
||||
" X_test=data, task='classification')\n",
|
||||
" # Retrieve model explanations for engineered explanations\n",
|
||||
" engineered_local_importance_values = scoring_explainer.explain(automl_explainer_setup_obj.X_test_transform) \n",
|
||||
" # You can return any data type as long as it is JSON-serializable\n",
|
||||
" return {'predictions': predictions.tolist(),\n",
|
||||
" 'engineered_local_importance_values': engineered_local_importance_values}\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Create the InferenceConfig \n",
|
||||
"Create the inference config that will be used when deploying the model"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from azureml.core.model import InferenceConfig\n",
|
||||
"\n",
|
||||
"inf_config = InferenceConfig(entry_script='score.py', environment=myenv)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Provision the AKS Cluster\n",
|
||||
"This is a one time setup. You can reuse this cluster for multiple deployments after it has been created. If you delete the cluster or the resource group that contains it, then you would have to recreate it."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from azureml.core.compute import ComputeTarget, AksCompute\n",
|
||||
"from azureml.core.compute_target import ComputeTargetException\n",
|
||||
"\n",
|
||||
"# Choose a name for your cluster.\n",
|
||||
"aks_name = 'scoring-explain'\n",
|
||||
"\n",
|
||||
"# Verify that cluster does not exist already\n",
|
||||
"try:\n",
|
||||
" aks_target = ComputeTarget(workspace=ws, name=aks_name)\n",
|
||||
" print('Found existing cluster, use it.')\n",
|
||||
"except ComputeTargetException:\n",
|
||||
" prov_config = AksCompute.provisioning_configuration(vm_size='STANDARD_D3_V2')\n",
|
||||
" aks_target = ComputeTarget.create(workspace=ws, \n",
|
||||
" name=aks_name,\n",
|
||||
" provisioning_configuration=prov_config)\n",
|
||||
"aks_target.wait_for_completion(show_output=True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Deploy web service to AKS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Set the web service configuration (using default here)\n",
|
||||
"from azureml.core.webservice import AksWebservice\n",
|
||||
"from azureml.core.model import Model\n",
|
||||
"\n",
|
||||
"aks_config = AksWebservice.deploy_configuration()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"aks_service_name ='model-scoring-local-aks'\n",
|
||||
"\n",
|
||||
"aks_service = Model.deploy(workspace=ws,\n",
|
||||
" name=aks_service_name,\n",
|
||||
" models=[scoring_explainer_model, original_model],\n",
|
||||
" inference_config=inf_config,\n",
|
||||
" deployment_config=aks_config,\n",
|
||||
" deployment_target=aks_target)\n",
|
||||
"\n",
|
||||
"aks_service.wait_for_deployment(show_output = True)\n",
|
||||
"print(aks_service.state)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### View the service logs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"aks_service.get_logs()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Consume the web service using run method to do the scoring and explanation of scoring.\n",
|
||||
"We test the web sevice by passing data. Run() method retrieves API keys behind the scenes to make sure that call is authenticated."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Serialize the first row of the test data into json\n",
|
||||
"X_test_json = X_test_df[:1].to_json(orient='records')\n",
|
||||
"print(X_test_json)\n",
|
||||
"\n",
|
||||
"# Call the service to get the predictions and the engineered and raw explanations\n",
|
||||
"output = aks_service.run(X_test_json)\n",
|
||||
"\n",
|
||||
"# Print the predicted value\n",
|
||||
"print('predictions:\\n{}\\n'.format(output['predictions']))\n",
|
||||
"# Print the engineered feature importances for the predicted value\n",
|
||||
"print('engineered_local_importance_values:\\n{}\\n'.format(output['engineered_local_importance_values']))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Clean up\n",
|
||||
"Delete the service."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"aks_service.delete()"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"This notebook was created using version 1.6.0 of the Azure ML SDK\")\n",
|
||||
"print(\"This notebook was created using version 1.7.0 of the Azure ML SDK\")\n",
|
||||
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
||||
]
|
||||
},
|
||||
@@ -242,7 +242,11 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"tags": [
|
||||
"sample-featurizationconfig-remarks2"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"featurization_config = FeaturizationConfig()\n",
|
||||
@@ -260,7 +264,11 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"tags": [
|
||||
"sample-featurizationconfig-remarks3"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"automl_settings = {\n",
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"This notebook was created using version 1.6.0 of the Azure ML SDK\")\n",
|
||||
"print(\"This notebook was created using version 1.7.0 of the Azure ML SDK\")\n",
|
||||
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -108,9 +108,9 @@
|
||||
"environment.python.conda_dependencies = CondaDependencies.create(pip_packages=[\n",
|
||||
" 'azureml-defaults',\n",
|
||||
" 'inference-schema[numpy-support]',\n",
|
||||
" 'joblib',\n",
|
||||
" 'numpy',\n",
|
||||
" 'scikit-learn'\n",
|
||||
" 'scikit-learn==0.19.1',\n",
|
||||
" 'scipy'\n",
|
||||
"])"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -0,0 +1,354 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Copyright (c) Microsoft Corporation. All rights reserved.\n",
|
||||
"\n",
|
||||
"Licensed under the MIT License."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Deploying a web service to Azure Kubernetes Service (AKS)\n",
|
||||
"This notebook shows the steps for deploying a service: registering a model, provisioning a cluster with ssl (one time action), and deploying a service to it. \n",
|
||||
"We then test and delete the service, image and model."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from azureml.core import Workspace\n",
|
||||
"from azureml.core.compute import AksCompute, ComputeTarget\n",
|
||||
"from azureml.core.webservice import Webservice, AksWebservice\n",
|
||||
"from azureml.core.model import Model"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import azureml.core\n",
|
||||
"print(azureml.core.VERSION)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Get workspace\n",
|
||||
"Load existing workspace from the config file info."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from azureml.core.workspace import Workspace\n",
|
||||
"\n",
|
||||
"ws = Workspace.from_config()\n",
|
||||
"print(ws.name, ws.resource_group, ws.location, ws.subscription_id, sep = '\\n')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Register the model\n",
|
||||
"Register an existing trained model, add descirption and tags."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#Register the model\n",
|
||||
"from azureml.core.model import Model\n",
|
||||
"model = Model.register(model_path = \"sklearn_regression_model.pkl\", # this points to a local file\n",
|
||||
" model_name = \"sklearn_model\", # this is the name the model is registered as\n",
|
||||
" tags = {'area': \"diabetes\", 'type': \"regression\"},\n",
|
||||
" description = \"Ridge regression model to predict diabetes\",\n",
|
||||
" workspace = ws)\n",
|
||||
"\n",
|
||||
"print(model.name, model.description, model.version)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Create the Environment\n",
|
||||
"Create an environment that the model will be deployed with"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from azureml.core import Environment\n",
|
||||
"from azureml.core.conda_dependencies import CondaDependencies \n",
|
||||
"\n",
|
||||
"conda_deps = CondaDependencies.create(conda_packages=['numpy', 'scikit-learn==0.19.1', 'scipy'], pip_packages=['azureml-defaults', 'inference-schema'])\n",
|
||||
"myenv = Environment(name='myenv')\n",
|
||||
"myenv.python.conda_dependencies = conda_deps"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Use a custom Docker image\n",
|
||||
"\n",
|
||||
"You can also specify a custom Docker image to be used as base image if you don't want to use the default base image provided by Azure ML. Please make sure the custom Docker image has Ubuntu >= 16.04, Conda >= 4.5.\\* and Python(3.5.\\* or 3.6.\\*).\n",
|
||||
"\n",
|
||||
"Only supported with `python` runtime.\n",
|
||||
"```python\n",
|
||||
"# use an image available in public Container Registry without authentication\n",
|
||||
"myenv.docker.base_image = \"mcr.microsoft.com/azureml/o16n-sample-user-base/ubuntu-miniconda\"\n",
|
||||
"\n",
|
||||
"# or, use an image available in a private Container Registry\n",
|
||||
"myenv.docker.base_image = \"myregistry.azurecr.io/mycustomimage:1.0\"\n",
|
||||
"myenv.docker.base_image_registry.address = \"myregistry.azurecr.io\"\n",
|
||||
"myenv.docker.base_image_registry.username = \"username\"\n",
|
||||
"myenv.docker.base_image_registry.password = \"password\"\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Write the Entry Script\n",
|
||||
"Write the script that will be used to predict on your model"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%writefile score.py\n",
|
||||
"import os\n",
|
||||
"import pickle\n",
|
||||
"import json\n",
|
||||
"import numpy\n",
|
||||
"from sklearn.externals import joblib\n",
|
||||
"from sklearn.linear_model import Ridge\n",
|
||||
"from inference_schema.schema_decorators import input_schema, output_schema\n",
|
||||
"from inference_schema.parameter_types.standard_py_parameter_type import StandardPythonParameterType\n",
|
||||
"\n",
|
||||
"def init():\n",
|
||||
" global model\n",
|
||||
" # AZUREML_MODEL_DIR is an environment variable created during deployment.\n",
|
||||
" # It is the path to the model folder (./azureml-models/$MODEL_NAME/$VERSION)\n",
|
||||
" # For multiple models, it points to the folder containing all deployed models (./azureml-models)\n",
|
||||
" model_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'), 'sklearn_regression_model.pkl')\n",
|
||||
" # deserialize the model file back into a sklearn model\n",
|
||||
" model = joblib.load(model_path)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"standard_sample_input = {'a': 10, 'b': 9, 'c': 8, 'd': 7, 'e': 6, 'f': 5, 'g': 4, 'h': 3, 'i': 2, 'j': 1 }\n",
|
||||
"standard_sample_output = {'outcome': 1}\n",
|
||||
"\n",
|
||||
"@input_schema('param', StandardPythonParameterType(standard_sample_input))\n",
|
||||
"@output_schema(StandardPythonParameterType(standard_sample_output))\n",
|
||||
"def run(param):\n",
|
||||
" try:\n",
|
||||
" raw_data = [param['a'], param['b'], param['c'], param['d'], param['e'], param['f'], param['g'], param['h'], param['i'], param['j']]\n",
|
||||
" data = numpy.array([raw_data])\n",
|
||||
" result = model.predict(data)\n",
|
||||
" return { 'outcome' : result[0] }\n",
|
||||
" except Exception as e:\n",
|
||||
" error = str(e)\n",
|
||||
" return error"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Create the InferenceConfig\n",
|
||||
"Create the inference config that will be used when deploying the model"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from azureml.core.model import InferenceConfig\n",
|
||||
"\n",
|
||||
"inf_config = InferenceConfig(entry_script='score.py', environment=myenv)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Provision the AKS Cluster with SSL\n",
|
||||
"This is a one time setup. You can reuse this cluster for multiple deployments after it has been created. If you delete the cluster or the resource group that contains it, then you would have to recreate it.\n",
|
||||
"\n",
|
||||
"See code snippet below. Check the documentation [here](https://docs.microsoft.com/en-us/azure/machine-learning/service/how-to-secure-web-service) for more details"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Use the default configuration (can also provide parameters to customize)\n",
|
||||
"\n",
|
||||
"provisioning_config = AksCompute.provisioning_configuration()\n",
|
||||
"# Leaf domain label generates a name using the formula\n",
|
||||
"# \"<leaf-domain-label>######.<azure-region>.cloudapp.azure.net\"\n",
|
||||
"# where \"######\" is a random series of characters\n",
|
||||
"provisioning_config.enable_ssl(leaf_domain_label = \"contoso\")\n",
|
||||
"\n",
|
||||
"aks_name = 'my-aks-ssl-1' \n",
|
||||
"# Create the cluster\n",
|
||||
"aks_target = ComputeTarget.create(workspace = ws, \n",
|
||||
" name = aks_name, \n",
|
||||
" provisioning_configuration = provisioning_config)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"aks_target.wait_for_completion(show_output = True)\n",
|
||||
"print(aks_target.provisioning_state)\n",
|
||||
"print(aks_target.provisioning_errors)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Deploy web service to AKS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"tags": [
|
||||
"sample-deploy-to-aks"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"\n",
|
||||
"aks_config = AksWebservice.deploy_configuration()\n",
|
||||
"\n",
|
||||
"aks_service_name ='aks-service-ssl-1'\n",
|
||||
"\n",
|
||||
"aks_service = Model.deploy(workspace=ws,\n",
|
||||
" name=aks_service_name,\n",
|
||||
" models=[model],\n",
|
||||
" inference_config=inf_config,\n",
|
||||
" deployment_config=aks_config,\n",
|
||||
" deployment_target=aks_target,\n",
|
||||
" overwrite=True)\n",
|
||||
"\n",
|
||||
"aks_service.wait_for_deployment(show_output = True)\n",
|
||||
"print(aks_service.state)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Test the web service using run method\n",
|
||||
"We test the web sevice by passing data.\n",
|
||||
"Run() method retrieves API keys behind the scenes to make sure that call is authenticated."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"import json\n",
|
||||
"\n",
|
||||
"standard_sample_input = json.dumps({'param': {'a': 10, 'b': 9, 'c': 8, 'd': 7, 'e': 6, 'f': 5, 'g': 4, 'h': 3, 'i': 2, 'j': 1 }})\n",
|
||||
"\n",
|
||||
"aks_service.run(input_data=standard_sample_input)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Clean up\n",
|
||||
"Delete the service, image and model."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"aks_service.delete()\n",
|
||||
"model.delete()"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"authors": [
|
||||
{
|
||||
"name": "vaidyas"
|
||||
}
|
||||
],
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3.6",
|
||||
"language": "python",
|
||||
"name": "python36"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.6.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
name: production-deploy-to-aks-ssl
|
||||
dependencies:
|
||||
- pip:
|
||||
- azureml-sdk
|
||||
- matplotlib
|
||||
- tqdm
|
||||
- scipy
|
||||
- sklearn
|
||||
@@ -109,7 +109,7 @@
|
||||
"from azureml.core import Environment\n",
|
||||
"from azureml.core.conda_dependencies import CondaDependencies \n",
|
||||
"\n",
|
||||
"conda_deps = CondaDependencies.create(conda_packages=['numpy','scikit-learn'], pip_packages=['azureml-defaults'])\n",
|
||||
"conda_deps = CondaDependencies.create(conda_packages=['numpy','scikit-learn==0.19.1','scipy'], pip_packages=['azureml-defaults'])\n",
|
||||
"myenv = Environment(name='myenv')\n",
|
||||
"myenv.python.conda_dependencies = conda_deps"
|
||||
]
|
||||
@@ -300,7 +300,8 @@
|
||||
" 'inference-schema[numpy-support]',\n",
|
||||
" 'joblib',\n",
|
||||
" 'numpy',\n",
|
||||
" 'scikit-learn'\n",
|
||||
" 'scikit-learn==0.19.1',\n",
|
||||
" 'scipy'\n",
|
||||
"])\n",
|
||||
"inference_config = InferenceConfig(entry_script='score.py', environment=environment)\n",
|
||||
"# if cpu and memory_in_gb parameters are not provided\n",
|
||||
|
||||
@@ -261,6 +261,10 @@
|
||||
"if pandas_ver:\n",
|
||||
" pandas_dep = 'pandas=={}'.format(pandas_ver)\n",
|
||||
"# specify CondaDependencies obj\n",
|
||||
"# The CondaDependencies specifies the conda and pip packages that are installed in the environment\n",
|
||||
"# the submitted job is run in. Note the remote environment(s) needs to be similar to the local\n",
|
||||
"# environment, otherwise if a model is trained or deployed in a different environment this can\n",
|
||||
"# cause errors. Please take extra care when specifying your dependencies in a production environment.\n",
|
||||
"run_config.environment.python.conda_dependencies = CondaDependencies.create(conda_packages=[sklearn_dep, pandas_dep],\n",
|
||||
" pip_packages=azureml_pip_packages)\n",
|
||||
"\n",
|
||||
@@ -379,6 +383,10 @@
|
||||
"if pandas_ver:\n",
|
||||
" pandas_dep = 'pandas=={}'.format(pandas_ver)\n",
|
||||
"# specify CondaDependencies obj\n",
|
||||
"# The CondaDependencies specifies the conda and pip packages that are installed in the environment\n",
|
||||
"# the submitted job is run in. Note the remote environment(s) needs to be similar to the local\n",
|
||||
"# environment, otherwise if a model is trained or deployed in a different environment this can\n",
|
||||
"# cause errors. Please take extra care when specifying your dependencies in a production environment.\n",
|
||||
"run_config.environment.python.conda_dependencies = CondaDependencies.create(conda_packages=[sklearn_dep, pandas_dep],\n",
|
||||
" pip_packages=azureml_pip_packages)\n",
|
||||
"\n",
|
||||
@@ -509,6 +517,10 @@
|
||||
"if pandas_ver:\n",
|
||||
" pandas_dep = 'pandas=={}'.format(pandas_ver)\n",
|
||||
"# specify CondaDependencies obj\n",
|
||||
"# The CondaDependencies specifies the conda and pip packages that are installed in the environment\n",
|
||||
"# the submitted job is run in. Note the remote environment(s) needs to be similar to the local\n",
|
||||
"# environment, otherwise if a model is trained or deployed in a different environment this can\n",
|
||||
"# cause errors. Please take extra care when specifying your dependencies in a production environment.\n",
|
||||
"run_config.environment.python.conda_dependencies = CondaDependencies.create(conda_packages=[sklearn_dep, pandas_dep],\n",
|
||||
" pip_packages=azureml_pip_packages)\n",
|
||||
"\n",
|
||||
|
||||
@@ -346,6 +346,10 @@
|
||||
"if pandas_ver:\n",
|
||||
" pandas_dep = 'pandas=={}'.format(pandas_ver)\n",
|
||||
"# specify CondaDependencies obj\n",
|
||||
"# The CondaDependencies specifies the conda and pip packages that are installed in the environment\n",
|
||||
"# the submitted job is run in. Note the remote environment(s) needs to be similar to the local\n",
|
||||
"# environment, otherwise if a model is trained or deployed in a different environment this can\n",
|
||||
"# cause errors. Please take extra care when specifying your dependencies in a production environment.\n",
|
||||
"myenv = CondaDependencies.create(conda_packages=[sklearn_dep, pandas_dep],\n",
|
||||
" pip_packages=['sklearn-pandas', 'pyyaml'] + azureml_pip_packages,\n",
|
||||
" pin_sdk_version=False)\n",
|
||||
@@ -413,9 +417,9 @@
|
||||
"headers = {'Content-Type':'application/json'}\n",
|
||||
"\n",
|
||||
"# send request to service\n",
|
||||
"print(\"POST to url\", service.scoring_uri)\n",
|
||||
"resp = requests.post(service.scoring_uri, sample_data, headers=headers)\n",
|
||||
"\n",
|
||||
"print(\"POST to url\", service.scoring_uri)\n",
|
||||
"# can covert back to Python objects from json string if desired\n",
|
||||
"print(\"prediction:\", resp.text)\n",
|
||||
"result = json.loads(resp.text)"
|
||||
|
||||
@@ -264,6 +264,10 @@
|
||||
"if pandas_ver:\n",
|
||||
" pandas_dep = 'pandas=={}'.format(pandas_ver)\n",
|
||||
"# specify CondaDependencies obj\n",
|
||||
"# The CondaDependencies specifies the conda and pip packages that are installed in the environment\n",
|
||||
"# the submitted job is run in. Note the remote environment(s) needs to be similar to the local\n",
|
||||
"# environment, otherwise if a model is trained or deployed in a different environment this can\n",
|
||||
"# cause errors. Please take extra care when specifying your dependencies in a production environment.\n",
|
||||
"run_config.environment.python.conda_dependencies = CondaDependencies.create(conda_packages=[sklearn_dep, pandas_dep],\n",
|
||||
" pip_packages=['sklearn_pandas', 'pyyaml'] + azureml_pip_packages,\n",
|
||||
" pin_sdk_version=False)\n",
|
||||
@@ -432,6 +436,10 @@
|
||||
"if pandas_ver:\n",
|
||||
" pandas_dep = 'pandas=={}'.format(pandas_ver)\n",
|
||||
"# specify CondaDependencies obj\n",
|
||||
"# The CondaDependencies specifies the conda and pip packages that are installed in the environment\n",
|
||||
"# the submitted job is run in. Note the remote environment(s) needs to be similar to the local\n",
|
||||
"# environment, otherwise if a model is trained or deployed in a different environment this can\n",
|
||||
"# cause errors. Please take extra care when specifying your dependencies in a production environment.\n",
|
||||
"myenv = CondaDependencies.create(conda_packages=[sklearn_dep, pandas_dep],\n",
|
||||
" pip_packages=['sklearn-pandas', 'pyyaml'] + azureml_pip_packages,\n",
|
||||
" pin_sdk_version=False)\n",
|
||||
@@ -495,9 +503,9 @@
|
||||
"headers = {'Content-Type':'application/json'}\n",
|
||||
"\n",
|
||||
"# send request to service\n",
|
||||
"print(\"POST to url\", service.scoring_uri)\n",
|
||||
"resp = requests.post(service.scoring_uri, input_data, headers=headers)\n",
|
||||
"\n",
|
||||
"print(\"POST to url\", service.scoring_uri)\n",
|
||||
"# can covert back to Python objects from json string if desired\n",
|
||||
"print(\"prediction:\", resp.text)"
|
||||
]
|
||||
|
||||
@@ -381,7 +381,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"run.cancel()"
|
||||
"run.wait_for_completion(show_output=True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -7,4 +7,5 @@ dependencies:
|
||||
- azureml-monitoring
|
||||
- scikit-learn
|
||||
- numpy
|
||||
- packaging
|
||||
- inference-schema[numpy-support]
|
||||
|
||||
@@ -4,7 +4,13 @@ import numpy as np
|
||||
from azureml.monitoring import ModelDataCollector
|
||||
from inference_schema.parameter_types.numpy_parameter_type import NumpyParameterType
|
||||
from inference_schema.schema_decorators import input_schema, output_schema
|
||||
from sklearn.externals import joblib
|
||||
# sklearn.externals.joblib is removed in 0.23
|
||||
from sklearn import __version__ as sklearnver
|
||||
from packaging.version import Version
|
||||
if Version(sklearnver) < Version("0.23.0"):
|
||||
from sklearn.externals import joblib
|
||||
else:
|
||||
import joblib
|
||||
|
||||
|
||||
def init():
|
||||
|
||||
@@ -11,19 +11,29 @@ Taxonomies for products and languages: https://review.docs.microsoft.com/new-hop
|
||||
|
||||
This is an introduction to the [Azure Machine Learning](https://docs.microsoft.com/en-us/azure/machine-learning/service/) Reinforcement Learning (Public Preview) using the [Ray](https://github.com/ray-project/ray/) framework.
|
||||
|
||||
Using these samples, you will be able to do the following.
|
||||
## What is reinforcement learning?
|
||||
|
||||
1. Use an Azure Machine Learning workspace, set up virtual network and create compute clusters for running Ray.
|
||||
2. Run some experiments to train a reinforcement learning agent using Ray and RLlib.
|
||||
Reinforcement learning is an approach to machine learning to train agents to make a sequence of decisions. This technique has gained popularity over the last few years as breakthroughs have been made to teach reinforcement learning agents to excel at complex tasks like playing video games. There are many practical real-world use cases as well, including robotics, chemistry, online recommendations, advertising and more.
|
||||
|
||||
In reinforcement learning, the goal is to train an agent *policy* that outputs actions based on the agent’s observations of its environment. Actions result in further observations and *rewards* for taking the actions. In reinforcement learning, the full reward for policy actions may take many steps to obtain. Learning a policy involves many trial-and-error runs of the agent interacting with the environment and improving its policy.
|
||||
|
||||
## Reinforcement learning on Azure Machine Learning
|
||||
|
||||
Reinforcement learning support in Azure Machine Learning service enables data scientists to scale training to many powerful CPU or GPU enabled VMs using [Azure Machine Learning compute clusters](https://docs.microsoft.com/en-us/azure/machine-learning/how-to-set-up-training-targets#amlcompute) which automatically provision, manage, and scale down these VMs to help manage your costs.
|
||||
|
||||
Using these samples, you will learn how to do the following.
|
||||
|
||||
1. Use an Azure Machine Learning workspace, set up virtual network and create compute clusters for distributed training.
|
||||
2. Train reinforcement learning agents using Ray RLlib.
|
||||
|
||||
## Contents
|
||||
|
||||
| File/folder | Description |
|
||||
|-------------------|--------------------------------------------|
|
||||
| [devenv_setup.ipynb](setup/devenv_setup.ipynb) | Notebook to setup development environment for Azure ML RL |
|
||||
| [cartpole_ci.ipynb](cartpole-on-compute-instance/cartpole_ci.ipynb) | Notebook to train a Cartpole playing agent on an Azure ML Compute Instance |
|
||||
| [cartpole_sc.ipynb](cartpole-on-single-compute/cartpole_sc.ipynb) | Notebook to train a Cartpole playing agent on an Azure ML Compute Cluster (single node) |
|
||||
| [pong_rllib.ipynb](atari-on-distributed-compute/pong_rllib.ipynb) | Notebook to train Pong agent using RLlib on multiple compute targets |
|
||||
| [devenv_setup.ipynb](setup/devenv_setup.ipynb) | Notebook to setup virtual network for using Azure Machine Learning. Needed for the Pong and Minecraft examples. |
|
||||
| [cartpole_ci.ipynb](cartpole-on-compute-instance/cartpole_ci.ipynb) | Notebook to train a Cartpole playing agent on an Azure Machine Learning Compute Instance |
|
||||
| [cartpole_sc.ipynb](cartpole-on-single-compute/cartpole_sc.ipynb) | Notebook to train a Cartpole playing agent on an Azure Machine Learning Compute Cluster (single node) |
|
||||
| [pong_rllib.ipynb](atari-on-distributed-compute/pong_rllib.ipynb) | Notebook for distributed training of Pong agent using RLlib on multiple compute targets |
|
||||
| [minecraft.ipynb](minecraft-on-distributed-compute/minecraft.ipynb) | Notebook to train an agent to navigate through a lava maze in the Minecraft game |
|
||||
|
||||
## Prerequisites
|
||||
@@ -32,9 +42,10 @@ To make use of these samples, you need the following.
|
||||
|
||||
* A Microsoft Azure subscription.
|
||||
* A Microsoft Azure resource group.
|
||||
* An Azure Machine Learning Workspace in the resource group. Please make sure that the VM sizes `STANDARD_NC6` and `STANDARD_D2_V2` are supported in the workspace's region.
|
||||
* A virtual network set up in the resource group.
|
||||
* A virtual network is needed for the examples training on multiple compute targets.
|
||||
* An Azure Machine Learning Workspace in the resource group.
|
||||
* Azure Machine Learning training compute. These samples use the VM sizes `STANDARD_NC6` and `STANDARD_D2_V2`. If these are not available in your region,
|
||||
you can replace them with other sizes.
|
||||
* A virtual network set up in the resource group for samples that use multiple compute targets. The Cartpole examples do not need a virtual network.
|
||||
* The [devenv_setup.ipynb](setup/devenv_setup.ipynb) notebook shows you how to create a virtual network. You can alternatively use an existing virtual network, make sure it's in the same region as workspace is.
|
||||
* Any network security group defined on the virtual network must allow network traffic on ports used by Azure infrastructure services. This is described in more detail in the [devenv_setup.ipynb](setup/devenv_setup.ipynb) notebook.
|
||||
|
||||
@@ -43,10 +54,10 @@ To make use of these samples, you need the following.
|
||||
|
||||
You can run these samples in the following ways.
|
||||
|
||||
* On an Azure ML Compute Instance or Notebook VM.
|
||||
* On an Azure Machine Learning Compute Instance or Azure Data Science Virtual Machine (DSVM).
|
||||
* On a workstation with Python and the Azure ML Python SDK installed.
|
||||
|
||||
### Azure ML Compute Instance or Notebook VM
|
||||
### Compute Instance or DSVM
|
||||
#### Update packages
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
import sys
|
||||
import csv
|
||||
from azure.mgmt.network import NetworkManagementClient
|
||||
|
||||
|
||||
def check_port_in_port_range(expected_port: str,
|
||||
dest_port_range: str):
|
||||
"""
|
||||
Check if a port is within a port range
|
||||
Port range maybe like *, 8080 or 8888-8889
|
||||
"""
|
||||
|
||||
if dest_port_range == '*':
|
||||
return True
|
||||
|
||||
dest_ports = dest_port_range.split('-')
|
||||
|
||||
if len(dest_ports) == 1 and \
|
||||
int(dest_ports[0]) == int(expected_port):
|
||||
return True
|
||||
|
||||
if len(dest_ports) == 2 and \
|
||||
int(dest_ports[0]) <= int(expected_port) and \
|
||||
int(dest_ports[1]) >= int(expected_port):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def check_port_in_destination_port_ranges(expected_port: str,
|
||||
dest_port_ranges: list):
|
||||
"""
|
||||
Check if a port is within a given list of port ranges
|
||||
i.e. check if port 8080 is in port ranges of 22,80,8080-8090,443
|
||||
"""
|
||||
|
||||
for dest_port_range in dest_port_ranges:
|
||||
if check_port_in_port_range(expected_port, dest_port_range) is True:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def check_ports_in_destination_port_ranges(expected_ports: list,
|
||||
dest_port_ranges: list):
|
||||
"""
|
||||
Check if all ports in a given port list are within a given list
|
||||
of port ranges
|
||||
i.e. check if port 8080,8081 are in port ranges of 22,80,8080-8090,443
|
||||
"""
|
||||
|
||||
for expected_port in expected_ports:
|
||||
if check_port_in_destination_port_ranges(
|
||||
expected_port, dest_port_ranges) is False:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def check_source_address_prefix(source_address_prefix: str):
|
||||
"""Check if source address prefix is BatchNodeManagement or default"""
|
||||
|
||||
required_prefix = 'BatchNodeManagement'
|
||||
default_prefix = 'default'
|
||||
|
||||
if source_address_prefix.lower() == required_prefix.lower() or \
|
||||
source_address_prefix.lower() == default_prefix.lower():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def check_protocol(protocol: str):
|
||||
"""Check if protocol is supported - Tcp/Any"""
|
||||
|
||||
required_protocol = 'Tcp'
|
||||
any_protocol = 'Any'
|
||||
|
||||
if required_protocol.lower() == protocol.lower() or \
|
||||
any_protocol.lower() == protocol.lower():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def check_direction(direction: str):
|
||||
"""Check if port direction is inbound"""
|
||||
|
||||
required_direction = 'Inbound'
|
||||
|
||||
if required_direction.lower() == direction.lower():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def check_provisioning_state(provisioning_state: str):
|
||||
"""Check if the provisioning state is succeeded"""
|
||||
|
||||
required_provisioning_state = 'Succeeded'
|
||||
|
||||
if required_provisioning_state.lower() == provisioning_state.lower():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def check_rule_for_Azure_ML(rule):
|
||||
"""Check if the ports required for Azure Machine Learning are open"""
|
||||
|
||||
required_ports = ['29876', '29877']
|
||||
|
||||
if check_source_address_prefix(rule.source_address_prefix) is False:
|
||||
return False
|
||||
|
||||
if check_protocol(rule.protocol) is False:
|
||||
return False
|
||||
|
||||
if check_direction(rule.direction) is False:
|
||||
return False
|
||||
|
||||
if check_provisioning_state(rule.provisioning_state) is False:
|
||||
return False
|
||||
|
||||
if rule.destination_port_range is not None:
|
||||
if check_ports_in_destination_port_ranges(
|
||||
required_ports,
|
||||
[rule.destination_port_range]) is False:
|
||||
return False
|
||||
else:
|
||||
if check_ports_in_destination_port_ranges(
|
||||
required_ports,
|
||||
rule.destination_port_ranges) is False:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def check_vnet_security_rules(auth_object,
|
||||
vnet_subscription_id,
|
||||
vnet_resource_group,
|
||||
vnet_name,
|
||||
save_to_file=False):
|
||||
"""
|
||||
Check all the rules of virtual network if required ports for Azure Machine
|
||||
Learning are open
|
||||
"""
|
||||
|
||||
network_client = NetworkManagementClient(
|
||||
auth_object,
|
||||
vnet_subscription_id)
|
||||
|
||||
# get the vnet
|
||||
vnet = network_client.virtual_networks.get(
|
||||
resource_group_name=vnet_resource_group,
|
||||
virtual_network_name=vnet_name)
|
||||
|
||||
vnet_location = vnet.location
|
||||
vnet_info = []
|
||||
|
||||
if vnet.subnets is None or len(vnet.subnets) == 0:
|
||||
print('WARNING: No subnet found for VNet:', vnet_name)
|
||||
|
||||
# for each subnet of the vnet
|
||||
for subnet in vnet.subnets:
|
||||
if subnet.network_security_group is None:
|
||||
print('WARNING: No network security group found for subnet.',
|
||||
'Subnet',
|
||||
subnet.id.split("/")[-1])
|
||||
else:
|
||||
# get all the rules
|
||||
network_security_group_name = \
|
||||
subnet.network_security_group.id.split("/")[-1]
|
||||
network_security_group_resource_group_name = \
|
||||
subnet.network_security_group.id.split("/")[4]
|
||||
network_security_group_subscription_id = \
|
||||
subnet.network_security_group.id.split("/")[2]
|
||||
|
||||
security_rules = list(network_client.security_rules.list(
|
||||
network_security_group_resource_group_name,
|
||||
network_security_group_name))
|
||||
|
||||
rule_matched = None
|
||||
for rule in security_rules:
|
||||
rule_info = []
|
||||
# add vnet details
|
||||
rule_info.append(vnet_name)
|
||||
rule_info.append(vnet_subscription_id)
|
||||
rule_info.append(vnet_resource_group)
|
||||
rule_info.append(vnet_location)
|
||||
# add subnet details
|
||||
rule_info.append(subnet.id.split("/")[-1])
|
||||
rule_info.append(network_security_group_name)
|
||||
rule_info.append(network_security_group_subscription_id)
|
||||
rule_info.append(network_security_group_resource_group_name)
|
||||
# add rule details
|
||||
rule_info.append(rule.priority)
|
||||
rule_info.append(rule.name)
|
||||
rule_info.append(rule.source_address_prefix)
|
||||
if rule.destination_port_range is not None:
|
||||
rule_info.append(rule.destination_port_range)
|
||||
else:
|
||||
rule_info.append(rule.destination_port_ranges)
|
||||
rule_info.append(rule.direction)
|
||||
rule_info.append(rule.provisioning_state)
|
||||
vnet_info.append(rule_info)
|
||||
|
||||
if check_rule_for_Azure_ML(rule) is True:
|
||||
rule_matched = rule
|
||||
|
||||
if rule_matched is not None:
|
||||
print("INFORMATION: Rule matched with required ports. Subnet:",
|
||||
subnet.id.split("/")[-1], "Rule:", rule.name)
|
||||
else:
|
||||
print("WARNING: No rule matched with required ports. Subnet:",
|
||||
subnet.id.split("/")[-1])
|
||||
|
||||
if save_to_file is True:
|
||||
file_name = vnet_name + ".csv"
|
||||
with open(file_name, mode='w') as vnet_rule_file:
|
||||
vnet_rule_file_writer = csv.writer(
|
||||
vnet_rule_file,
|
||||
delimiter=',',
|
||||
quotechar='"',
|
||||
quoting=csv.QUOTE_MINIMAL)
|
||||
header = ['VNet_Name', 'VNet_Subscription_ID',
|
||||
'VNet_Resource_Group', 'VNet_Location',
|
||||
'Subnet_Name', 'NSG_Name',
|
||||
'NSG_Subscription_ID', 'NSG_Resource_Group',
|
||||
'Rule_Priority', 'Rule_Name', 'Rule_Source',
|
||||
'Rule_Destination_Ports', 'Rule_Direction',
|
||||
'Rule_Provisioning_State']
|
||||
vnet_rule_file_writer.writerow(header)
|
||||
vnet_rule_file_writer.writerows(vnet_info)
|
||||
|
||||
print("INFORMATION: Network security group rules for your virtual \
|
||||
network are saved in file", file_name)
|
||||
@@ -13,7 +13,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
""
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -155,6 +155,24 @@
|
||||
"vnet_name = 'your_vnet'"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Ensure that the virtual network is configured correctly with required ports open. It is possible that you have configured rules with broader range of ports that allows ports 29876-29877 to be opened. Kindly review your network security group rules. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from files.networkutils import *\n",
|
||||
"\n",
|
||||
"check_vnet_security_rules(ws._auth_object, ws.subscription_id, ws.resource_group, vnet_name, True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
""
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -161,6 +161,9 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from azureml.core.compute import ComputeTarget, ComputeInstance\n",
|
||||
"from azureml.core.compute_target import ComputeTargetException\n",
|
||||
"\n",
|
||||
"# Load current compute instance info\n",
|
||||
"current_compute_instance = load_nbvm()\n",
|
||||
"\n",
|
||||
@@ -169,17 +172,23 @@
|
||||
" print(\"Current compute instance:\", current_compute_instance)\n",
|
||||
" instance_name = current_compute_instance['instance']\n",
|
||||
"else:\n",
|
||||
" instance_name = next(iter(ws.compute_targets))\n",
|
||||
" instance_name = \"cartpole-ci-stdd2v2\"\n",
|
||||
" try:\n",
|
||||
" instance = ComputeInstance(workspace=ws, name=instance_name)\n",
|
||||
" print('Found existing instance, use it.')\n",
|
||||
" except ComputeTargetException:\n",
|
||||
" print(\"Creating new compute instance...\")\n",
|
||||
" compute_config = ComputeInstance.provisioning_configuration(\n",
|
||||
" vm_size='STANDARD_D2_V2'\n",
|
||||
" )\n",
|
||||
" instance = ComputeInstance.create(ws, instance_name, compute_config)\n",
|
||||
" instance.wait_for_completion(show_output=True)\n",
|
||||
" print(\"Instance name:\", instance_name)\n",
|
||||
"\n",
|
||||
"compute_target = ws.compute_targets[instance_name]\n",
|
||||
"\n",
|
||||
"print(\"Compute target status:\")\n",
|
||||
"try:\n",
|
||||
" print(compute_target.get_status().serialize())\n",
|
||||
"except:\n",
|
||||
" print(compute_target.get_status())\n",
|
||||
"\n",
|
||||
"print(compute_target.get_status().serialize())\n",
|
||||
"print(\"Compute target size:\")\n",
|
||||
"print(compute_target.size(ws))"
|
||||
]
|
||||
@@ -658,7 +667,11 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# To archive the created experiment:\n",
|
||||
"#exp.archive()"
|
||||
"#exp.archive()\n",
|
||||
"\n",
|
||||
"# To delete created compute instance\n",
|
||||
"if not current_compute_instance:\n",
|
||||
" compute_target.delete()"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -4,3 +4,4 @@ dependencies:
|
||||
- azureml-sdk
|
||||
- azureml-contrib-reinforcementlearning
|
||||
- azureml-widgets
|
||||
- azureml-dataprep
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
""
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -170,7 +170,7 @@
|
||||
"source": [
|
||||
"from azureml.core.experiment import Experiment\n",
|
||||
"\n",
|
||||
"experiment_name = 'CartPole-v0-CC'\n",
|
||||
"experiment_name = 'CartPole-v0-SC'\n",
|
||||
"exp = Experiment(workspace=ws, name=experiment_name)"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -4,3 +4,4 @@ dependencies:
|
||||
- azureml-sdk
|
||||
- azureml-contrib-reinforcementlearning
|
||||
- azureml-widgets
|
||||
- azureml-dataprep
|
||||
|
||||
@@ -209,7 +209,7 @@
|
||||
"# name of the Virtual Network subnet ('default' the default name)\n",
|
||||
"subnet_name = 'default'\n",
|
||||
"\n",
|
||||
"gpu_cluster_name = 'gpu-cluster-nc6'\n",
|
||||
"gpu_cluster_name = 'gpu-cl-nc6-vnet'\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" gpu_cluster = ComputeTarget(workspace=ws, name=gpu_cluster_name)\n",
|
||||
@@ -250,7 +250,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"cpu_cluster_name = 'cpu-cluster-d2'\n",
|
||||
"cpu_cluster_name = 'cpu-cl-d2-vnet'\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" cpu_cluster = ComputeTarget(workspace=ws, name=cpu_cluster_name)\n",
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
""
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -186,7 +186,7 @@
|
||||
")\n",
|
||||
"\n",
|
||||
"async_nsg_creation.wait() \n",
|
||||
"print(\"Network security group created successfully: \", async_nsg_creation.result())\n",
|
||||
"print(\"Network security group created successfully:\", async_nsg_creation.result())\n",
|
||||
"\n",
|
||||
"network_security_group = network_client.network_security_groups.get(\n",
|
||||
" resource_group,\n",
|
||||
@@ -211,6 +211,25 @@
|
||||
"async_subnet_creation.wait()\n",
|
||||
"print(\"Subnet created successfully:\", async_subnet_creation.result())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Review the virtual network security rules\n",
|
||||
"Ensure that the virtual network is configured correctly with required ports open. It is possible that you have configured rules with broader range of ports that allows ports 29876-29877 to be opened. Kindly review your network security group rules. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from files.networkutils import *\n",
|
||||
"\n",
|
||||
"check_vnet_security_rules(ws._auth_object, ws.subscription_id, ws.resource_group, vnet_name, True)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
import sys
|
||||
import csv
|
||||
from azure.mgmt.network import NetworkManagementClient
|
||||
|
||||
|
||||
def check_port_in_port_range(expected_port: str,
|
||||
dest_port_range: str):
|
||||
"""
|
||||
Check if a port is within a port range
|
||||
Port range maybe like *, 8080 or 8888-8889
|
||||
"""
|
||||
|
||||
if dest_port_range == '*':
|
||||
return True
|
||||
|
||||
dest_ports = dest_port_range.split('-')
|
||||
|
||||
if len(dest_ports) == 1 and \
|
||||
int(dest_ports[0]) == int(expected_port):
|
||||
return True
|
||||
|
||||
if len(dest_ports) == 2 and \
|
||||
int(dest_ports[0]) <= int(expected_port) and \
|
||||
int(dest_ports[1]) >= int(expected_port):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def check_port_in_destination_port_ranges(expected_port: str,
|
||||
dest_port_ranges: list):
|
||||
"""
|
||||
Check if a port is within a given list of port ranges
|
||||
i.e. check if port 8080 is in port ranges of 22,80,8080-8090,443
|
||||
"""
|
||||
|
||||
for dest_port_range in dest_port_ranges:
|
||||
if check_port_in_port_range(expected_port, dest_port_range) is True:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def check_ports_in_destination_port_ranges(expected_ports: list,
|
||||
dest_port_ranges: list):
|
||||
"""
|
||||
Check if all ports in a given port list are within a given list
|
||||
of port ranges
|
||||
i.e. check if port 8080,8081 are in port ranges of 22,80,8080-8090,443
|
||||
"""
|
||||
|
||||
for expected_port in expected_ports:
|
||||
if check_port_in_destination_port_ranges(
|
||||
expected_port, dest_port_ranges) is False:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def check_source_address_prefix(source_address_prefix: str):
|
||||
"""Check if source address prefix is BatchNodeManagement or default"""
|
||||
|
||||
required_prefix = 'BatchNodeManagement'
|
||||
default_prefix = 'default'
|
||||
|
||||
if source_address_prefix.lower() == required_prefix.lower() or \
|
||||
source_address_prefix.lower() == default_prefix.lower():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def check_protocol(protocol: str):
|
||||
"""Check if protocol is supported - Tcp/Any"""
|
||||
|
||||
required_protocol = 'Tcp'
|
||||
any_protocol = 'Any'
|
||||
|
||||
if required_protocol.lower() == protocol.lower() or \
|
||||
any_protocol.lower() == protocol.lower():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def check_direction(direction: str):
|
||||
"""Check if port direction is inbound"""
|
||||
|
||||
required_direction = 'Inbound'
|
||||
|
||||
if required_direction.lower() == direction.lower():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def check_provisioning_state(provisioning_state: str):
|
||||
"""Check if the provisioning state is succeeded"""
|
||||
|
||||
required_provisioning_state = 'Succeeded'
|
||||
|
||||
if required_provisioning_state.lower() == provisioning_state.lower():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def check_rule_for_Azure_ML(rule):
|
||||
"""Check if the ports required for Azure Machine Learning are open"""
|
||||
|
||||
required_ports = ['29876', '29877']
|
||||
|
||||
if check_source_address_prefix(rule.source_address_prefix) is False:
|
||||
return False
|
||||
|
||||
if check_protocol(rule.protocol) is False:
|
||||
return False
|
||||
|
||||
if check_direction(rule.direction) is False:
|
||||
return False
|
||||
|
||||
if check_provisioning_state(rule.provisioning_state) is False:
|
||||
return False
|
||||
|
||||
if rule.destination_port_range is not None:
|
||||
if check_ports_in_destination_port_ranges(
|
||||
required_ports,
|
||||
[rule.destination_port_range]) is False:
|
||||
return False
|
||||
else:
|
||||
if check_ports_in_destination_port_ranges(
|
||||
required_ports,
|
||||
rule.destination_port_ranges) is False:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def check_vnet_security_rules(auth_object,
|
||||
vnet_subscription_id,
|
||||
vnet_resource_group,
|
||||
vnet_name,
|
||||
save_to_file=False):
|
||||
"""
|
||||
Check all the rules of virtual network if required ports for Azure Machine
|
||||
Learning are open
|
||||
"""
|
||||
|
||||
network_client = NetworkManagementClient(
|
||||
auth_object,
|
||||
vnet_subscription_id)
|
||||
|
||||
# get the vnet
|
||||
vnet = network_client.virtual_networks.get(
|
||||
resource_group_name=vnet_resource_group,
|
||||
virtual_network_name=vnet_name)
|
||||
|
||||
vnet_location = vnet.location
|
||||
vnet_info = []
|
||||
|
||||
if vnet.subnets is None or len(vnet.subnets) == 0:
|
||||
print('WARNING: No subnet found for VNet:', vnet_name)
|
||||
|
||||
# for each subnet of the vnet
|
||||
for subnet in vnet.subnets:
|
||||
if subnet.network_security_group is None:
|
||||
print('WARNING: No network security group found for subnet.',
|
||||
'Subnet',
|
||||
subnet.id.split("/")[-1])
|
||||
else:
|
||||
# get all the rules
|
||||
network_security_group_name = \
|
||||
subnet.network_security_group.id.split("/")[-1]
|
||||
network_security_group_resource_group_name = \
|
||||
subnet.network_security_group.id.split("/")[4]
|
||||
network_security_group_subscription_id = \
|
||||
subnet.network_security_group.id.split("/")[2]
|
||||
|
||||
security_rules = list(network_client.security_rules.list(
|
||||
network_security_group_resource_group_name,
|
||||
network_security_group_name))
|
||||
|
||||
rule_matched = None
|
||||
for rule in security_rules:
|
||||
rule_info = []
|
||||
# add vnet details
|
||||
rule_info.append(vnet_name)
|
||||
rule_info.append(vnet_subscription_id)
|
||||
rule_info.append(vnet_resource_group)
|
||||
rule_info.append(vnet_location)
|
||||
# add subnet details
|
||||
rule_info.append(subnet.id.split("/")[-1])
|
||||
rule_info.append(network_security_group_name)
|
||||
rule_info.append(network_security_group_subscription_id)
|
||||
rule_info.append(network_security_group_resource_group_name)
|
||||
# add rule details
|
||||
rule_info.append(rule.priority)
|
||||
rule_info.append(rule.name)
|
||||
rule_info.append(rule.source_address_prefix)
|
||||
if rule.destination_port_range is not None:
|
||||
rule_info.append(rule.destination_port_range)
|
||||
else:
|
||||
rule_info.append(rule.destination_port_ranges)
|
||||
rule_info.append(rule.direction)
|
||||
rule_info.append(rule.provisioning_state)
|
||||
vnet_info.append(rule_info)
|
||||
|
||||
if check_rule_for_Azure_ML(rule) is True:
|
||||
rule_matched = rule
|
||||
|
||||
if rule_matched is not None:
|
||||
print("INFORMATION: Rule matched with required ports. Subnet:",
|
||||
subnet.id.split("/")[-1], "Rule:", rule.name)
|
||||
else:
|
||||
print("WARNING: No rule matched with required ports. Subnet:",
|
||||
subnet.id.split("/")[-1])
|
||||
|
||||
if save_to_file is True:
|
||||
file_name = vnet_name + ".csv"
|
||||
with open(file_name, mode='w') as vnet_rule_file:
|
||||
vnet_rule_file_writer = csv.writer(
|
||||
vnet_rule_file,
|
||||
delimiter=',',
|
||||
quotechar='"',
|
||||
quoting=csv.QUOTE_MINIMAL)
|
||||
header = ['VNet_Name', 'VNet_Subscription_ID',
|
||||
'VNet_Resource_Group', 'VNet_Location',
|
||||
'Subnet_Name', 'NSG_Name',
|
||||
'NSG_Subscription_ID', 'NSG_Resource_Group',
|
||||
'Rule_Priority', 'Rule_Name', 'Rule_Source',
|
||||
'Rule_Destination_Ports', 'Rule_Direction',
|
||||
'Rule_Provisioning_State']
|
||||
vnet_rule_file_writer.writerow(header)
|
||||
vnet_rule_file_writer.writerows(vnet_info)
|
||||
|
||||
print("INFORMATION: Network security group rules for your virtual \
|
||||
network are saved in file", file_name)
|
||||
@@ -100,7 +100,7 @@
|
||||
"\n",
|
||||
"# Check core SDK version number\n",
|
||||
"\n",
|
||||
"print(\"This notebook was created using SDK version 1.6.0, you are currently running version\", azureml.core.VERSION)"
|
||||
"print(\"This notebook was created using SDK version 1.7.0, you are currently running version\", azureml.core.VERSION)"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -227,7 +227,13 @@
|
||||
"from azureml.core import Dataset, Run\n",
|
||||
"from sklearn.model_selection import train_test_split\n",
|
||||
"from sklearn.tree import DecisionTreeClassifier\n",
|
||||
"from sklearn.externals import joblib\n",
|
||||
"# sklearn.externals.joblib is removed in 0.23\n",
|
||||
"from sklearn import __version__ as sklearnver\n",
|
||||
"from packaging.version import Version\n",
|
||||
"if Version(sklearnver) < Version(\"0.23.0\"):\n",
|
||||
" from sklearn.externals import joblib\n",
|
||||
"else:\n",
|
||||
" import joblib\n",
|
||||
"\n",
|
||||
"run = Run.get_context()\n",
|
||||
"# get input dataset by name\n",
|
||||
@@ -291,7 +297,7 @@
|
||||
" entry_script='train_iris.py', \n",
|
||||
" # pass dataset object as an input with name 'titanic'\n",
|
||||
" inputs=[dataset.as_named_input('iris')],\n",
|
||||
" pip_packages=['azureml-dataprep[fuse]'],\n",
|
||||
" pip_packages=['azureml-dataprep[fuse]', 'packaging'],\n",
|
||||
" compute_target=compute_target) "
|
||||
]
|
||||
},
|
||||
@@ -415,11 +421,17 @@
|
||||
"import os\n",
|
||||
"import glob\n",
|
||||
"\n",
|
||||
"from azureml.core.run import Run\n",
|
||||
"from sklearn.linear_model import Ridge\n",
|
||||
"from sklearn.metrics import mean_squared_error\n",
|
||||
"from sklearn.model_selection import train_test_split\n",
|
||||
"from azureml.core.run import Run\n",
|
||||
"from sklearn.externals import joblib\n",
|
||||
"# sklearn.externals.joblib is removed in 0.23\n",
|
||||
"from sklearn import __version__ as sklearnver\n",
|
||||
"from packaging.version import Version\n",
|
||||
"if Version(sklearnver) < Version(\"0.23.0\"):\n",
|
||||
" from sklearn.externals import joblib\n",
|
||||
"else:\n",
|
||||
" import joblib\n",
|
||||
"\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
@@ -480,9 +492,10 @@
|
||||
"from azureml.core.conda_dependencies import CondaDependencies\n",
|
||||
"\n",
|
||||
"conda_env = Environment('conda-env')\n",
|
||||
"conda_env.python.conda_dependencies = CondaDependencies.create(pip_packages=['azureml-sdk',\n",
|
||||
"conda_env.python.conda_dependencies = CondaDependencies.create(pip_packages=['azureml-core',\n",
|
||||
" 'azureml-dataprep[pandas,fuse]',\n",
|
||||
" 'scikit-learn'])"
|
||||
" 'scikit-learn',\n",
|
||||
" 'packaging'])"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
1
index.md
1
index.md
@@ -112,6 +112,7 @@ Machine Learning notebook samples and encourage efficient retrieval of topics an
|
||||
| [register-model-deploy-local-advanced](https://github.com/Azure/MachineLearningNotebooks/blob/master//how-to-use-azureml/deployment/deploy-to-local/register-model-deploy-local-advanced.ipynb) | | | | | | |
|
||||
| [enable-app-insights-in-production-service](https://github.com/Azure/MachineLearningNotebooks/blob/master//how-to-use-azureml/deployment/enable-app-insights-in-production-service/enable-app-insights-in-production-service.ipynb) | | | | | | |
|
||||
| [onnx-model-register-and-deploy](https://github.com/Azure/MachineLearningNotebooks/blob/master//how-to-use-azureml/deployment/onnx/onnx-model-register-and-deploy.ipynb) | | | | | | |
|
||||
| [production-deploy-to-aks-ssl](https://github.com/Azure/MachineLearningNotebooks/blob/master//how-to-use-azureml/deployment/production-deploy-to-aks/production-deploy-to-aks-ssl.ipynb) | | | | | | |
|
||||
| [production-deploy-to-aks](https://github.com/Azure/MachineLearningNotebooks/blob/master//how-to-use-azureml/deployment/production-deploy-to-aks/production-deploy-to-aks.ipynb) | | | | | | |
|
||||
| [production-deploy-to-aks-gpu](https://github.com/Azure/MachineLearningNotebooks/blob/master//how-to-use-azureml/deployment/production-deploy-to-aks-gpu/production-deploy-to-aks-gpu.ipynb) | | | | | | |
|
||||
| [explain-model-on-amlcompute](https://github.com/Azure/MachineLearningNotebooks/blob/master//how-to-use-azureml/explain-model/azure-integration/remote-explanation/explain-model-on-amlcompute.ipynb) | | | | | | |
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
"source": [
|
||||
"import azureml.core\n",
|
||||
"\n",
|
||||
"print(\"This notebook was created using version 1.6.0 of the Azure ML SDK\")\n",
|
||||
"print(\"This notebook was created using version 1.7.0 of the Azure ML SDK\")\n",
|
||||
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
||||
]
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user