Skip to content

Model Serving Platform - Use Case: Predicting Wine Quality

This tutorial presents a use case of Model Serving Platform: Predicting Wine Quality.

Wine Quality is one of the most used datasets in Machine Learning to understand a wide range of regression models. The goal is to model wine quality based on physicochemical tests.


  • Databricks (it is a core service in Sidra)
  • Python notebook in Databricks

Where to run the notebook?

The intake clusters are generic and inmutable, with predictable loads. Therefore, it is not recommended to run model project notebooks and experiments on the data intake cluster. We recommend having separate cluster just for ML, or use the DataLabs environment, sync the data and use that cluster for the model activities.

Register Model

This first step is just to register a new model using the Model Serving API.

First, we need to authenticate against Sidra API:

import SidraCoreApiPythonClient
from SidraCoreApiPythonClient.api.model_serving_model_model_api import ModelServingModelModelApi
from SidraCoreApiPythonClient.models.model_serving_model_model_dto import ModelServingModelModelDTO

def get_SidraCoreApiPythonClient(): 

  # Configure OAuth2 access token for authorization: oauth2 
  configuration = SidraCoreApiPythonClient.Configuration( 
    host = dbutils.secrets.get(scope='api', key='api_url'),   
    auth_url = dbutils.secrets.get(scope='api', key='auth_url'), 
    scope = dbutils.secrets.get(scope='api', key='scope'), 
    client_id = dbutils.secrets.get(scope='api', key='client_id'), 
    client_secret = dbutils.secrets.get(scope='api', key='client_secret') 
  return SidraCoreApiPythonClient.ApiClient(configuration)   

sidra_core_api_client = get_SidraCoreApiPythonClient()

Then, we can create a new Model, which is just a way to group experiments into the same problem to solve:

modelName = "wineClassifier"      
sidra_core_api_client = get_SidraCoreApiPythonClient()
model_api = ModelServingModelModelApi(sidra_core_api_client)
model_DTO = ModelServingModelModelDTO(name=model_name, description="Anomaly detection model registered in Sidra ML platform")
registered_model = model_api.api_model_serving_model_post(body=model_DTO)

Track a new experiment

In the notebook, import the required packages. In this example, ElasticNet approach is used to train the model:

import pandas as pd
import numpy as np
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
from sklearn.model_selection import train_test_split
from sklearn.linear_model import ElasticNet

import mlflow
import mlflow.sklearn
from mlflow.tracking import MlflowClient

Next step consists of preparing data to train and evaluate the model. It is important to separate features from target column. To perform that, train_test_split method from Scikit-learn package is used:

csv_url = ''
data = pd.read_csv(csv_url, sep=';')

# Split the data into training and test sets. (0.75, 0.25) split.
train, test = train_test_split(data)

# The predicted column is "quality" which is a scalar from [3, 9]
train_x = train.drop(["quality"], axis=1)
test_x = test.drop(["quality"], axis=1)
train_y = train[["quality"]]
test_y = test[["quality"]]

Before training the model, it is necessary to configure the experiment in which MLflow will track all the information. In our case, below ML_Demo folder with the name of experiment:


Finally, it is necessary to create a new MLflow run to track parameters, metrics and the model. Model parameters, alpha and l1_ratio, are both set to 0.5 value.

def eval_metrics(actual, pred):
    rmse = np.sqrt(mean_squared_error(actual, pred))
    mae = mean_absolute_error(actual, pred)
    r2 = r2_score(actual, pred)
    return rmse, mae, r2  


with mlflow.start_run():
    # Execute ElasticNet
    lr = ElasticNet(alpha=alpha, l1_ratio=l1_ratio, random_state=42), train_y)

    # Evaluate Metrics
    predicted_qualities = lr.predict(test_x)
    (rmse, mae, r2) = eval_metrics(test_y, predicted_qualities)

    # Print out metrics
    print("Elasticnet model (alpha=%f, l1_ratio=%f):" % (alpha, l1_ratio))
    print("  RMSE: %s" % rmse)
    print("  MAE: %s" % mae)
    print("  R2: %s" % r2)

    # Log parameter, metrics, and model to MLflow
    mlflow.log_param("alpha", alpha)
    mlflow.log_param("l1_ratio", l1_ratio)
    mlflow.log_metric("rmse", rmse)
    mlflow.log_metric("r2", r2)
    mlflow.log_metric("mae", mae)

    mlflow.sklearn.log_model(lr, "model")

MLflow log capacities are used, which will help a lot on tracking the variables during training.

After executing the previous piece of code, a new experiment and run appears in MLflow UI:


Then, it is necessary to access to that run to copy the run id, which appears both in url and upper section of the run's details.


The created Model and related metadata is stored in Model and ModelVersion Management tables in Sidra Core metadata.

Create a ModelVersion and Docker image from MLflow experiment

Now it is time to create a ModelVersion to track the experiment into our platform.

It can be performed in two ways:

  1. Create a ModelVersion with POST request and create a Docker image from that ModelVersion.
  2. Create Docker image from MLflow run.

First we set the required information about the experiment:

client = MlflowClient()

run_id = 'a198de769b314371b48138efce96d44e'
run = client.get_run(run_id)

experiment = client.get_experiment_by_name("/ML_Demo/{name}/experiment".format(name=modelName))

Finally, we can create the Docker image:

from SidraCoreApiPythonClient.api.model_serving_model_version_model_version_api import ModelServingModelVersionModelVersionApi
from SidraCoreApiPythonClient.api.data_storage_unit_data_storage_units_data_storage_units_api import DataStorageUnitDataStorageUnitsDataStorageUnitsApi
from SidraCoreApiPythonClient.models.api_model_serving_models_image_creation import APIModelServingModelsImageCreation

model_version_api = ModelServingModelVersionModelVersionApi(sidra_core_api_client)
dsu_api = DataStorageUnitDataStorageUnitsDataStorageUnitsApi(sidra_core_api_client) #data_api
dsu = dsu_api.api_datastorageunit_data_storage_units_get(skip=0,take=1)
dsu_id = dsu.items[0].id
image_request = APIModelServingModelsImageCreation(run_id=run_id,,
image_response = model_version_api.api_model_serving_model_version_data_storage_unit_data_storage_unit_id_image_post(dsu_id,body=image_request)

Deploy model

At this point, it is time to deploy our model. There are two choices: Azure Container Instances (ACI) and Azure Kubernetes Services (AKS). For the sake of simplicity, we go ahead with ACI deployment.

from SidraCoreApiPythonClient.models.api_model_serving_models_model_version_deployment import APIModelServingModelsModelVersionDeployment

model_version_id = ""
    while True:
      job_status = model_version_api.api_model_serving_model_version_id_data_storage_unit_data_storage_unit_id_job_job_run_id_status_get(data_storage_unit_id=dsu_id, job_run_id=image_response.run_id,
      if( == "TERMINATED"):
        if ( == "SUCCESS"):
          model_version_id =['modelVersionId']

deploy_request = APIModelServingModelsModelVersionDeployment(model_version_id=model_version_id)
model_serving_api = ModelServingModelVersionModelVersionApi(sidra_core_api_client)
model_version = model_serving_api.api_model_serving_model_version_data_storage_unit_data_storage_unit_id_deploy_post(data_storage_unit_id=dsu_id, body=deploy_request)

Now, it is possible to query our model by means of the recently created web service.

Let's define a method to query the endpoint:

import requests
import json

def query_endpoint_example(scoring_uri, inputs, service_key=None):
  headers = {
    "Content-Type": "application/json",
  if service_key is not None:
    headers["Authorization"] = "Bearer {service_key}".format(service_key=service_key)

  print("Sending batch prediction request with inputs: {}".format(inputs))
  response =, data=json.dumps(inputs), headers=headers)
  preds = json.loads(response.text)
  print("Received response: {}".format(preds))
  return preds

And let's prepare data to request the model:

# Import various libraries including sklearn, mlflow, numpy, pandas
from sklearn import datasets
import numpy as np
import pandas as pd

csv_url = ''
  data = pd.read_csv(csv_url, sep=';')
except Exception as e:
  logger.exception("Unable to download training & test CSV, check your internet connection. Error: %s", e)

sample = data.drop(["quality"],axis=1).iloc[[0]]

query_input = sample.to_json(orient='split')
query_input = eval(query_input)
query_input.pop('index', None)

Finally, execute the request:

prod_prediction1 = query_endpoint_example(scoring_uri=modelversion.endPoint, inputs=query_input)

Undeploy model

In a normal scenario, a model can be undeployed if it is not used anymore, or a new and improved version is deployed.

To undeploy a model, it is as simple as:

model_serving_api.api_model_serving_model_version_id_data_storage_unit_data_storage_unit_id_undeploy_post(, data_storage_unit_id=dsu_id)

Delete ModelVersion

In addition to the previous step, it is also possible to delete a Model or a ModelVersion. If a Model is deleted, all the related ModelVersions are also deleted. If a ModelVersion is deleted, all the Docker images and deployments are deleted as well. Besides, it is possible to remove MLflow experiments and runs, but this is an optional behaviour of this platform.

For example, to remove our ModelVersion without removing MLflow experiment or run:

RUN = 1
ALL = 2

from SidraCoreApiPythonClient.models.api_model_serving_models_delete_mode_enum import APIModelServingModelsDeleteModeEnum

APIModelServingModelsDeleteModeEnum(, data_storage_unit_id=dsu_id, deleteMode=NOTHING)

And finally, remove the Model:

# We can ignore deleteMode parameter since its default value is 0
model_serving_api.api_model_serving_model_version_id_data_storage_unit_data_storage_unit_id_delete(, data_storage_unit_id=dsu_id)

Sidra Ideas Portal

Last update: 2022-11-11
Back to top