{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Azure ML & Azure Databricks notebooks by Parashar Shah.\n", "\n", "Copyright (c) Microsoft Corporation. All rights reserved.\n", "\n", "Licensed under the MIT License." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![Impressions](https://PixelServer20190423114238.azurewebsites.net/api/impressions/MachineLearningNotebooks/how-to-use-azureml/automated-machine-learning/azure-databricks/amlsdk/deploy-to-aci-04.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Please ensure you have run all previous notebooks in sequence before running this.\n", "\n", "Please Register Azure Container Instance(ACI) using Azure Portal: https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-manager-supported-services#portal in your subscription before using the SDK to deploy your ML model to ACI." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import azureml.core\n", "\n", "# Check core SDK version number\n", "print(\"SDK version:\", azureml.core.VERSION)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Set auth to be used by workspace related APIs.\n", "# For automation or CI/CD ServicePrincipalAuthentication can be used.\n", "# https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.authentication.serviceprincipalauthentication?view=azure-ml-py\n", "auth = None" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from azureml.core import Workspace\n", "\n", "ws = Workspace.from_config(auth = auth)\n", "print('Workspace name: ' + ws.name, \n", " 'Azure region: ' + ws.location, \n", " 'Subscription id: ' + ws.subscription_id, \n", " 'Resource group: ' + ws.resource_group, sep = '\\n')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "##NOTE: service deployment always gets the model from the current working dir.\n", "import os\n", "\n", "model_name = \"AdultCensus_runHistory.mml\" # \n", "model_name_dbfs = os.path.join(\"/dbfs\", model_name)\n", "\n", "print(\"copy model from dbfs to local\")\n", "model_local = \"file:\" + os.getcwd() + \"/\" + model_name\n", "dbutils.fs.cp(model_name, model_local, True)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Register the model\n", "from azureml.core.model import Model\n", "mymodel = Model.register(model_path = model_name, # this points to a local file\n", " model_name = model_name, # this is the name the model is registered as, am using same name for both path and name. \n", " description = \"ADB trained model by Parashar\",\n", " workspace = ws)\n", "\n", "print(mymodel.name, mymodel.description, mymodel.version)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#%%writefile score_sparkml.py\n", "score_sparkml = \"\"\"\n", " \n", "import json\n", " \n", "def init():\n", " # One-time initialization of PySpark and predictive model\n", " import pyspark\n", " from azureml.core.model import Model\n", " from pyspark.ml import PipelineModel\n", " \n", " global trainedModel\n", " global spark\n", " \n", " spark = pyspark.sql.SparkSession.builder.appName(\"ADB and AML notebook by Parashar\").getOrCreate()\n", " model_name = \"{model_name}\" #interpolated\n", " model_path = Model.get_model_path(model_name)\n", " trainedModel = PipelineModel.load(model_path)\n", " \n", "def run(input_json):\n", " if isinstance(trainedModel, Exception):\n", " return json.dumps({{\"trainedModel\":str(trainedModel)}})\n", " \n", " try:\n", " sc = spark.sparkContext\n", " input_list = json.loads(input_json)\n", " input_rdd = sc.parallelize(input_list)\n", " input_df = spark.read.json(input_rdd)\n", " \n", " # Compute prediction\n", " prediction = trainedModel.transform(input_df)\n", " #result = prediction.first().prediction\n", " predictions = prediction.collect()\n", " \n", " #Get each scored result\n", " preds = [str(x['prediction']) for x in predictions]\n", " result = \",\".join(preds)\n", " # you can return any data type as long as it is JSON-serializable\n", " return result.tolist()\n", " except Exception as e:\n", " result = str(e)\n", " return result\n", " \n", "\"\"\".format(model_name=model_name)\n", " \n", "exec(score_sparkml)\n", " \n", "with open(\"score_sparkml.py\", \"w\") as file:\n", " file.write(score_sparkml)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from azureml.core.conda_dependencies import CondaDependencies \n", "\n", "myacienv = CondaDependencies.create(conda_packages=['scikit-learn','numpy','pandas']) #showing how to add libs as an eg. - not needed for this model.\n", "\n", "with open(\"mydeployenv.yml\",\"w\") as f:\n", " f.write(myacienv.serialize_to_string())" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#deploy to ACI\n", "from azureml.core.webservice import AciWebservice, Webservice\n", "\n", "myaci_config = AciWebservice.deploy_configuration(\n", " cpu_cores = 2, \n", " memory_gb = 2, \n", " tags = {'name':'Databricks Azure ML ACI'}, \n", " description = 'This is for ADB and AML example. Azure Databricks & Azure ML SDK demo with ACI by Parashar.')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# this will take 10-15 minutes to finish\n", "\n", "service_name = \"aciws\"\n", "runtime = \"spark-py\" \n", "driver_file = \"score_sparkml.py\"\n", "my_conda_file = \"mydeployenv.yml\"\n", "\n", "# image creation\n", "from azureml.core.image import ContainerImage\n", "myimage_config = ContainerImage.image_configuration(execution_script = driver_file, \n", " runtime = runtime, \n", " conda_file = my_conda_file)\n", "\n", "# Webservice creation\n", "myservice = Webservice.deploy_from_model(\n", " workspace=ws, \n", " name=service_name,\n", " deployment_config = myaci_config,\n", " models = [mymodel],\n", " image_config = myimage_config\n", " )\n", "\n", "myservice.wait_for_deployment(show_output=True)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "help(Webservice)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# List images by ws\n", "\n", "for i in ContainerImage.list(workspace = ws):\n", " print('{}(v.{} [{}]) stored at {} with build log {}'.format(i.name, i.version, i.creation_state, i.image_location, i.image_build_log_uri))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#for using the Web HTTP API \n", "print(myservice.scoring_uri)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import json\n", "\n", "#get the some sample data\n", "test_data_path = \"AdultCensusIncomeTest\"\n", "test = spark.read.parquet(test_data_path).limit(5)\n", "\n", "test_json = json.dumps(test.toJSON().collect())\n", "\n", "print(test_json)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#using data defined above predict if income is >50K (1) or <=50K (0)\n", "myservice.run(input_data=test_json)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#comment to not delete the web service\n", "myservice.delete()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![Impressions](https://PixelServer20190423114238.azurewebsites.net/api/impressions/MachineLearningNotebooks/how-to-use-azureml/azure-databricks/amlsdk/deploy-to-aci-04.png)" ] } ], "metadata": { "authors": [ { "name": "pasha" } ], "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" }, "name": "deploy-to-aci-04", "notebookId": 3836944406456376 }, "nbformat": 4, "nbformat_minor": 1 }