<jupyter_start><jupyter_text>Taking ML (Scikit Learn) to highly scalable production using RedisAIScikit learn is probably the most used machine learning package in the industry. Even though, there are few options readily available for taking deep learning to production (with tfserving etc), there were no widely accepted attempts to build a framework that could help us to take ML to production. Microsoft had build [ONNXRuntime](https://github.com/microsoft/onnxruntime) and the scikit learn exporter for this very purpose. Very recently RedisAI had announced the support for ONNXRuntime as the third backend (Tensorflow and PyTorch was already supported). This makes us capable of pushing a scikit-learn model through ONNX to a super scalable production. This demo is focusing on showing how this can be accomplished. We'll train a linear regression model for predicting boston house price first. The trained model is then converted to ONNX IR using [sk2onnx](https://github.com/onnx/sklearn-onnx). Third part of the demo shows how to load the onnx binary into RedisAI runtime and how to communicate.<jupyter_code># Installing dependencies
!pip install skl2onnx
!pip install skl2onnx
# !pip install redisai
# hack since the redisai version is not updated in pypi yet
!pip install git+https://github.com/RedisAI/redisai-py/@onnxruntime
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
import sklearn
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType<jupyter_output><empty_output><jupyter_text>RedisAI Python clientRedisAI has client utilites available in [different langauges](https://github.com/RedisAI/redisai-examples). We will be using the python client of RedisAI.<jupyter_code>import redisai as rai
from redisai.model import Model as raimodel
try:
    if rai.__version__ < '0.3.0':
        raise
except:
    raise RuntimeError('ONNX is introduced in redisai-py version 0.3.0. Upgrade!!')<jupyter_output><empty_output><jupyter_text>Loading training and testing data<jupyter_code>boston = load_boston()
X, y = boston.data, boston.target
X_train, X_test, y_train, y_test = train_test_split(X, y)
X_train.shape<jupyter_output><empty_output><jupyter_text>Building & Training the model<jupyter_code>model = LinearRegression()
model.fit(X_train, y_train)
pred = model.predict(X_test)

mse = sklearn.metrics.mean_squared_error(y_test, pred)
print("Mean Squared Error: ", mse)<jupyter_output>Mean Squared Error:  22.90649510340278<jupyter_text>Converting scikit learn model to ONNX<jupyter_code># 1 is batch size and 13 is num features
#   reference: https://github.com/onnx/sklearn-onnx/blob/master/skl2onnx/convert.py
initial_type = [('float_input', FloatTensorType([1, 13]))]

onnx_model = convert_sklearn(model, initial_types=initial_type)
raimodel.save(onnx_model, 'boston.onnx')<jupyter_output>The maximum opset needed by this model is only 1.<jupyter_text>Loading the ONNX model to RedisAIWe'll be using the same python client for rest of the example as well. Before we start the next you need to setup the RedisAI server (TODO: link to setting up tutorial). Once the server is up and running on an IP address (and a port), we have the required setup to complete this example. Let's jump right into it.<jupyter_code>con = rai.Client(host='localhost', port=6379, db=0)<jupyter_output><empty_output><jupyter_text>Loading the model<jupyter_code>model = raimodel.load("boston.onnx")
con.modelset("onnx_model", rai.Backend.onnx, rai.Device.cpu, model)<jupyter_output><empty_output><jupyter_text>Loading the input tensor<jupyter_code># dummydata taken from sklearn.datasets.load_boston().data[0]
dummydata = [
    0.00632, 18.0, 2.31, 0.0, 0.538, 6.575, 65.2, 4.09, 1.0, 296.0, 15.3, 396.9, 4.98]
tensor = rai.Tensor.scalar(rai.DType.float, *dummydata)
# If the tensor is too complex to pass it as python list, you can use BlobTensor that takes numpy array
# tensor = rai.BlobTensor.from_numpy(np.array(dummydata, dtype='float32'))
con.tensorset("input", tensor)<jupyter_output><empty_output><jupyter_text>Running the modelAs you know already, Redis is a key value store. You just saved the model to a key **"onnx_model"** and the tensor to another key **"input"**. Now we can invoke ONNX backend from RedisAI and ask it to take the model saved on the **"onnx_model"** key and tensor saved on the **"input"** key and run it against the model (first run will take the model from the given key and load it into the provided backend and keep it hot since then). While running the model we should let RedisAI know what should be the key to which we want to save the output (If all of these process seems efficientless to you because we need make multiple calls to run the model and network call is expensive, you should wait for the DAGRUN feature which will be coming out soon). In our example, we save the model output to the key **"output"** as given below.<jupyter_code>con.modelrun("onnx_model", ["input"], ["output"])<jupyter_output><empty_output><jupyter_text>We can fetch the output by calling **tensorget**<jupyter_code>outtensor = con.tensorget("output", as_type=rai.BlobTensor)
print(f"House cost predicted by model is ${outtensor.to_numpy().item() * 1000}")<jupyter_output>House cost predicted by model is $29969.89631652832
{'fraction_non_alphanumeric': 0.08344198174706649, 'fraction_numerical': 0.019929223319053828, 'mean_word_length': 5.814720812182741, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 38, 'https://': 5, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '98568', 'license': 'MIT', 'n_tokens_mistral': 1733, 'n_tokens_neox': 1645, 'n_words': 621, 'path': 'notebooks/ScikitLearn2Production.ipynb', 'repo_name': 'filipecosta90/redisai-examples', 'size': '5369'}