<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ed Shee</title>
    <description>The latest articles on DEV Community by Ed Shee (@ukcloudman).</description>
    <link>https://dev.to/ukcloudman</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F670870%2Fe33dc8fa-d51b-4b8c-a2b4-6b0b2e05158c.png</url>
      <title>DEV Community: Ed Shee</title>
      <link>https://dev.to/ukcloudman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ukcloudman"/>
    <language>en</language>
    <item>
      <title>Serving Python Machine Learning Models With Ease</title>
      <dc:creator>Ed Shee</dc:creator>
      <pubDate>Tue, 12 Apr 2022 10:48:35 +0000</pubDate>
      <link>https://dev.to/ukcloudman/serving-python-machine-learning-models-with-ease-37kh</link>
      <guid>https://dev.to/ukcloudman/serving-python-machine-learning-models-with-ease-37kh</guid>
      <description>&lt;p&gt;Ever trained a new model and just wanted to use it through an API straight away? Sometimes you don't want to bother writing Flask code or containerizing your model and running it in Docker. If that sounds like you, you definitely want to check out &lt;a href="https://github.com/seldonio/mlserver"&gt;MLServer&lt;/a&gt;. It's a python based inference server that &lt;a href="https://www.seldon.io/introducing-mlserver"&gt;recently went GA&lt;/a&gt; and what's really neat about it is that it's a highly-performant server designed for production environments too. That means that, by serving models locally, you are running in the exact same environment as they will be in when they get to production. &lt;/p&gt;

&lt;p&gt;This blog walks you through how to use MLServer by using a couple of image models as examples...&lt;/p&gt;

&lt;h2&gt;
  
  
  Dataset
&lt;/h2&gt;

&lt;p&gt;The dataset we're going to work with is the &lt;a href="https://www.kaggle.com/zalando-research/fashionmnist"&gt;Fashion MNIST dataset&lt;/a&gt;. It contains 70,000 images of clothing in greyscale 28x28 pixels across 10 different classes (top, dress, coat, trouser etc...). &lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you want to reproduce the code from this blog, make sure you download the files and extract them in to a folder named &lt;code&gt;data&lt;/code&gt;. They have been omitted from the github repo because they are quite large.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Training the Scikit-learn Model
&lt;/h2&gt;

&lt;p&gt;First up, we're going to train a support vector machine (SVM) model using the &lt;a&gt;scikit-learn&lt;/a&gt; framework. We'll then save the model to a file named &lt;code&gt;Fashion-MNIST.joblib&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;sklearn&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;svm&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;joblib&lt;/span&gt;

&lt;span class="c1"&gt;#Load Training Data
&lt;/span&gt;&lt;span class="n"&gt;train&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'../../data/fashion-mnist_train.csv'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;y_train&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'label'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;X_train&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s"&gt;'label'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;classifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;svm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SVC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"poly"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;degree&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gamma&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;#Train Model
&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;exec_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'Execution time: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;exec_time&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; seconds'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;#Save Model
&lt;/span&gt;&lt;span class="n"&gt;joblib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Fashion-MNIST.joblib"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: The SVM algorithm is not particularly well suited to large datasets because of it's quadratic nature. The model in this example will, depending on your hardware, take a couple of minutes to train.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serving the Scikit-learn Model
&lt;/h2&gt;

&lt;p&gt;Ok, so we've now got a saved model file &lt;code&gt;Fashion-MNIST.joblib&lt;/code&gt;. Let's take a look at how we can serve that using MLServer...&lt;/p&gt;

&lt;p&gt;First up, we need to install MLServer.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pip install mlserver&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The additional runtimes are optional but make life really easy when serving models, we'll install the Scikit-Learn and XGBoost ones too&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pip install mlserver-sklearn mlserver-xgboost&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You can find details on all of the inference runtimes &lt;a href="https://mlserver.readthedocs.io/en/latest/runtimes/index.html#included-inference-runtimes"&gt;here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once we've done that, all we need to do is add two configuration files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;settings.json&lt;/code&gt; - This contains the configuration for the server itself.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;model-settings.json&lt;/code&gt; - As the name suggests, this file contains configuration for the model we want to run. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For our &lt;code&gt;settings.json&lt;/code&gt; file it's enough to just define single parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"debug"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"true"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;model-settings.json&lt;/code&gt; file requires a few more bits of info as it needs to know about the model we're trying to serve:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fashion-sklearn"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"implementation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mlserver_sklearn.SKLearnModel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"uri"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./Fashion_MNIST.joblib"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"v1"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;name&lt;/code&gt; parameter should be self-explanatory. It gives MLServer a unique identifier which is particularly useful when serving multiple models (we'll come to that in a bit). The &lt;code&gt;implementation&lt;/code&gt; defines which pre-built server, if any, to use. It is heavily coupled to the machine learning framework used to train your model. In our case we trained the model using scikit-learn so we're going to use the scikit-learn implementation for MLServer. For model &lt;code&gt;parameters&lt;/code&gt; we just need to provide the location of our model file as well as a version number.&lt;/p&gt;

&lt;p&gt;That's it, two small config files and we're ready to serve our model using the command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mlserver start .&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Boom, we've now got our model running on a production-ready server locally. It's now ready to accept requests over HTTP and gRPC (default ports &lt;code&gt;8080&lt;/code&gt; and &lt;code&gt;8081&lt;/code&gt; respectively).&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the Model
&lt;/h2&gt;

&lt;p&gt;Now that our model is up and running. Let's send some requests to see it in action.&lt;/p&gt;

&lt;p&gt;To make predictions on our model, we need to send a POST request to the following URL:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;http://localhost:8080/v2/models/&amp;lt;MODEL_NAME&amp;gt;/versions/&amp;lt;VERSION&amp;gt;/infer&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That means to access our scikit-learn model that we trained earlier, we need to replace the &lt;code&gt;MODEL_NAME&lt;/code&gt; with &lt;code&gt;fashion-sklearn&lt;/code&gt; and &lt;code&gt;VERSION&lt;/code&gt; with &lt;code&gt;v1&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The code below shows how to import the test data, make a request to the model server and then compare the result with the actual label:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;requests&lt;/span&gt;

&lt;span class="c1"&gt;#Import test data, grab the first row and corresponding label
&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'../../data/fashion-mnist_test.csv'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;y_test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'label'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;X_test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s"&gt;'label'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;#Prediction request parameters
&lt;/span&gt;&lt;span class="n"&gt;inference_request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"inputs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"predict"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s"&gt;"shape"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s"&gt;"datatype"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"FP64"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;endpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"http://localhost:8080/v2/models/fashion-sklearn/versions/v1/infer"&lt;/span&gt;

&lt;span class="c1"&gt;#Make request and print response
&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;inference_request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When running the &lt;code&gt;test.py&lt;/code&gt; code above we get the following response from MLServer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fashion-sklearn"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"31c3fa70-2e56-49b1-bcec-294452dbe73c"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"outputs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"predict"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"shape"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"datatype"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"INT64"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll notice that MLServer has generated a request id and automatically added metadata about the model and version that was used to serve our request. Capturing this kind of metadata is super important once our model gets to production; it allows us to log every request for audit and troubleshooting purposes. &lt;/p&gt;

&lt;p&gt;You might also notice that MLServer has returned an array for &lt;code&gt;outputs&lt;/code&gt;. In our request we only sent one row of data but MLServer also handles batch requests and returns them together. You can even use a technique called &lt;a href="https://mlserver.readthedocs.io/en/latest/user-guide/adaptive-batching.html"&gt;adaptive batching&lt;/a&gt; to optimise the way multiple requests are handled in production environments. &lt;/p&gt;

&lt;p&gt;In our example above, the model's prediction can be found in &lt;code&gt;outputs[0].data&lt;/code&gt; which shows that the model has labeled this sample with the category &lt;code&gt;0&lt;/code&gt; (The value 0 corresponds to the category &lt;code&gt;t-shirt/top&lt;/code&gt;). The true label for that sample was a &lt;code&gt;0&lt;/code&gt; too so the model got this prediction correct!&lt;/p&gt;

&lt;h2&gt;
  
  
  Training the XGBoost Model
&lt;/h2&gt;

&lt;p&gt;Now that we've seen how to create and serve a single model using MLServer, let's take a look at how we'd handle multiple models trained in different frameworks. &lt;/p&gt;

&lt;p&gt;We'll be using the same Fashion MNIST dataset but, this time, we'll train an &lt;a href="https://xgboost.readthedocs.io/en/stable/"&gt;XGBoost&lt;/a&gt; model instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;xgboost&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;xgb&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;

&lt;span class="c1"&gt;#Load Training Data
&lt;/span&gt;&lt;span class="n"&gt;train&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'../../data/fashion-mnist_train.csv'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;y_train&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'label'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;X_train&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s"&gt;'label'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;dtrain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;xgb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DMatrix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;#Train Model
&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'max_depth'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'eta'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'verbosity'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'objective'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'multi:softmax'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'num_class'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;num_round&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;

&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;bstmodel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;xgb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dtrain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_round&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;evals&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;dtrain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'label'&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt; &lt;span class="n"&gt;verbose_eval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;exec_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'Execution time: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;exec_time&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; seconds'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;#Save Model
&lt;/span&gt;&lt;span class="n"&gt;bstmodel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Fashion_MNIST.json'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above, used to train the XGBoost model, is similar to the code we used earlier to train the scikit-learn model but this time our model has been saved in an XGBoost-compatible format as &lt;code&gt;Fashion_MNIST.json&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serving Multiple Models
&lt;/h2&gt;

&lt;p&gt;One of the cool things about MLServer is that it supports &lt;a href="https://mlserver.readthedocs.io/en/latest/examples/mms/README.html"&gt;multi-model serving&lt;/a&gt;. This means that you don't have to create or run a new server for each ML model you want to deploy. Using the models we built above, we'll use this feature to serve them both at once.&lt;/p&gt;

&lt;p&gt;When MLServer starts up, it will search the directory (and any subdirectories) for &lt;code&gt;model-settings.json&lt;/code&gt; files. If you've got multiple &lt;code&gt;model-settings.json&lt;/code&gt; files then it'll automatically serve them all. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: you still only need a single &lt;code&gt;settings.json&lt;/code&gt; (server config) file in the root directory&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's a breakdown of my directory structure for reference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── data
│   ├── fashion-mnist_test.csv
│   └── fashion-mnist_train.csv
├── models
│   ├── sklearn
│   │   ├── Fashion_MNIST.joblib
│   │   ├── model-settings.json
│   │   ├── test.py
│   │   └── train.py
│   └── xgboost
│       ├── Fashion_MNIST.json
│       ├── model-settings.json
│       ├── test.py
│       └── train.py
├── README.md
├── settings.json
└── test_models.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that there are two &lt;code&gt;model-settings.json&lt;/code&gt; files - one for the scikit-learn model and one for the XGBoost model. &lt;/p&gt;

&lt;p&gt;We can now just run &lt;code&gt;mlserver start .&lt;/code&gt; and it will start handling requests for both models.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;mlserver] INFO - Loaded model &lt;span class="s1"&gt;'fashion-sklearn'&lt;/span&gt; succesfully.
&lt;span class="o"&gt;[&lt;/span&gt;mlserver] INFO - Loaded model &lt;span class="s1"&gt;'fashion-xgboost'&lt;/span&gt; succesfully.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing Accuracy of Multiple Models
&lt;/h2&gt;

&lt;p&gt;With both models now up and running on MLServer, we can use the samples from our test set to validate how accurate each of our models is. &lt;/p&gt;

&lt;p&gt;The following code sends a batch request (containing the full test set) to each of the models and then compares the predictions received to the true labels. Doing this across the whole test set gives us a reasonably good measure for each model's accuracy, which gets printed at the end.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;json&lt;/span&gt;

&lt;span class="c1"&gt;#Import the test data and split the data from the labels
&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'./data/fashion-mnist_test.csv'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;y_test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'label'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;X_test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s"&gt;'label'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;#Build the inference request
&lt;/span&gt;&lt;span class="n"&gt;inference_request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"inputs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"predict"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s"&gt;"shape"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s"&gt;"datatype"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"FP64"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;#Send the prediction request to the relevant model, compare responses to training labels and calculate accuracy
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;infer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;endpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"http://localhost:8080/v2/models/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/versions/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/infer"&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;inference_request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;#calculate accuracy
&lt;/span&gt;    &lt;span class="n"&gt;correct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prediction&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s"&gt;'outputs'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;'data'&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;y_test&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;prediction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;correct&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;accuracy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;correct&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_test&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'Model Accuracy for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;accuracy&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;infer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"fashion-xgboost"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"v1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;infer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"fashion-sklearn"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"v1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The results show that the XGBoost model slightly outperforms the SVM scikit-learn one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Model Accuracy for fashion-xgboost: 0.8953
Model Accuracy for fashion-sklearn: 0.864
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Hopefully by now you've gained an understanding of how easy it is to serve models using &lt;a href="https://mlserver.readthedocs.io/en/latest/index.html"&gt;MLServer&lt;/a&gt;. For further info it's worth reading the &lt;a href="https://mlserver.readthedocs.io/en/latest/index.html"&gt;docs&lt;/a&gt; and taking a look at the &lt;a href="https://mlserver.readthedocs.io/en/latest/examples/index.html"&gt;examples for different frameworks&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;For &lt;a href="https://mlflow.org/"&gt;MLFlow&lt;/a&gt; users you can now serve &lt;a href="https://www.mlflow.org/docs/latest/models.html#serving-with-mlserver-experimental"&gt;models directly in MLFlow using MLServer&lt;/a&gt; and if you're a &lt;a href="https://kubernetes.io/"&gt;Kubernetes&lt;/a&gt; user you should definitely check out &lt;a href="https://docs.seldon.io/projects/seldon-core/en/latest/index.html"&gt;Seldon Core&lt;/a&gt; - an open source tool that deploys models to Kubernetes (it uses MLServer under the covers). &lt;/p&gt;

&lt;p&gt;All of the code from this example can be found &lt;a href="https://github.com/edshee/mlserver-example"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>python</category>
      <category>datascience</category>
      <category>devops</category>
    </item>
    <item>
      <title>6 Types of AI Bias Everyone Should Know</title>
      <dc:creator>Ed Shee</dc:creator>
      <pubDate>Mon, 11 Oct 2021 08:30:40 +0000</pubDate>
      <link>https://dev.to/ukcloudman/6-types-of-ai-bias-everyone-should-know-3i95</link>
      <guid>https://dev.to/ukcloudman/6-types-of-ai-bias-everyone-should-know-3i95</guid>
      <description>&lt;p&gt;In my previous blog we looked at &lt;a href="https://medium.com/r/?url=https%3A%2F%2Fpub.towardsai.net%2Fbias-vs-fairness-vs-explainability-in-ai-5e0f37ffb22"&gt;the difference between Bias, Fairness and Explainability in AI&lt;/a&gt;. I included a high level view of what Bias is but this time we'll go in to more detail.&lt;/p&gt;

&lt;p&gt;Bias appears in machine learning in lots of different forms. The important thing to consider is that training a machine learning model is a lot like bringing up a child.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pXPypISV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/24j32ngaekkebab9whwi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pXPypISV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/24j32ngaekkebab9whwi.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a child develops, they use senses like hearing, vision and touch to learn from the world around them. Their understanding of the world, their opinions, and the decisions they end up making are all heavily influenced by their upbringing. For example, a child that grows up and lives in a sexist community may never realise there is anything biased about the way they view different genders. Machine learning models are exactly the same. Instead of using senses as inputs, they use data - data that &lt;em&gt;we&lt;/em&gt; give them! This is why it's so important to try and avoid bias in the data used for training machine learning models. Let's take a closer look at some of the most common forms of bias in machine learning:&lt;/p&gt;

&lt;h3&gt;
  
  
  Historical Bias
&lt;/h3&gt;

&lt;p&gt;While gathering data for training a machine learning algorithm, grabbing historical data is almost always the easiest place to start. If we're not careful, however, it's very easy to include bias that was present in the historical data.&lt;/p&gt;

&lt;p&gt;Take Amazon, for example; In 2014 they set out to build a system for automatically screening job applicants. The idea was to just feed the system hundreds of CVs and have the top candidates picked out automatically. The system was trained on 10 years worth of job applications and their outcomes. The problem? Most employees at Amazon were male (particularly in technical roles). The algorithm learned that, because there were more men than women at Amazon, men were more suitable candidates and actively discriminated against non-male applications. By 2015 the whole project had to be scrapped. &lt;/p&gt;

&lt;h3&gt;
  
  
  Sample Bias
&lt;/h3&gt;

&lt;p&gt;Sample bias happens when your training data does not accurately reflect the makeup of the real world usage of your model. Usually one population is either heavily overrepresented or underrepresented.&lt;/p&gt;

&lt;p&gt;I recently saw a talk from David Keene and he gave a really good example of sample bias.&lt;/p&gt;

&lt;p&gt;When training a speech-to-text system, you need lots of audio clips together with their corresponding transcriptions. Where better to get lots of this data than audiobooks? What could be wrong with that approach?&lt;/p&gt;

&lt;p&gt;Well, it turns out that the vast majority of audiobooks are narrated by well educated, middle aged, white men. Unsurprisingly, speech recognition software trained using this approach underperforms when the user is from a different socio-economic or ethnic background.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uwUXRPcl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/edpnk6eg3vsje6tgblm3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uwUXRPcl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/edpnk6eg3vsje6tgblm3.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The chart above shows the word error rate [WER] for speech recognition systems from big tech companies. You can clearly see that all of the algorithms underperform for black voices vs white ones.&lt;/p&gt;

&lt;h3&gt;
  
  
  Label Bias
&lt;/h3&gt;

&lt;p&gt;A lot of the data required to train ML algorithms needs to be labelled before it is useful. You actually do this yourself quite a lot when you log in to websites. Been asked to identify the squares that contain traffic lights? You're actually confirming a set of labels for that image to help train visual recognition models. The way in which we label data, however, varies a lot and inconsistencies in labelling can introduce bias into the system.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wbohJfBb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e6luwsdtoml85ued1knq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wbohJfBb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e6luwsdtoml85ued1knq.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
Imagine you train a system by labeling lions using the boxes on the images above. You then show your system this image:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1Bqul3Sd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rqb3no4odap4nrwaskmz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1Bqul3Sd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rqb3no4odap4nrwaskmz.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
Annoyingly, it is unable to identify the very obvious lion in the picture. By labeling faces only, you've inadvertently made the system bias toward front-facing lion pictures!&lt;/p&gt;

&lt;h3&gt;
  
  
  Aggregation Bias
&lt;/h3&gt;

&lt;p&gt;Sometimes we aggregate data to simplify it, or present it in a particular fashion. This can lead to bias regardless of whether it happens before or after creating our model. Take a look at this chart, for example:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YcLy9Iou--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/si6htgrumtkjeazfacw8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YcLy9Iou--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/si6htgrumtkjeazfacw8.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
It shows how salary increases based on the number of years worked in a job. There's a pretty strong correlation here that the longer you work, the more you get paid. Let's now look at the data that was used to create this aggregate though:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YhpCULGp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k7meu4f1l7a6pw4v3q4p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YhpCULGp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k7meu4f1l7a6pw4v3q4p.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
We see that for athletes the complete opposite is true. They are able to earn high salaries early on in their careers while they are still at their physical peak but it then drops off as they stop competing. By aggregating them with other professions we're making our algorithm biased against them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Confirmation Bias
&lt;/h3&gt;

&lt;p&gt;Simply put, confirmation bias is our tendency to trust information that confirms our existing beliefs or discard information that doesn't. Theoretically, I could build the most accurate ML system ever, without bias in either the data or the modelling, but if you're going to change the result based on your own "gut feel", then it doesn't matter.&lt;/p&gt;

&lt;p&gt;Confirmation bias is particularly prevalent in applications of machine learning where human review is required before any action is taken. The use of AI in healthcare has seen doctors be dismissive of algorithmic diagnosis because it doesn't match their own experience or understanding. Often when investigated, it turns out that the doctors haven't read the most recent research literature which points to slightly different symptoms, techniques or diagnosis outcomes. Ultimately, there are only so many research journals that one doctor can read (particularly while saving lives full-time) but an ML system can ingest them all.&lt;/p&gt;

&lt;h3&gt;
  
  
  Evaluation Bias
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--scvs6R7n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fmb3deohygmzgwuasn61.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--scvs6R7n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fmb3deohygmzgwuasn61.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
Let's imagine you're building a machine learning model to predict voting turnout across the country during a general election. You're hoping that, by taking a series of features like age, profession, income and political alignment, you can accurately predict whether someone will vote or not. You build your model, use your local election to test it out, and are really pleased by your results. It seems you can correctly predict whether someone will vote or not 95% of the time.&lt;/p&gt;

&lt;p&gt;As the general election rolls around, you are suddenly very disappointed. The model you spent ages designing and testing was only correct 55% of the time - performing only marginally better than a random guess. The poor results are an example of evaluation bias. By only evaluating your model on people in your local area, you have inadvertently designed a system that only works well for them. Other areas of the country, with totally different voting patterns, haven't been properly accounted for, even if they were included in your initial training data. &lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;You've now seen six different ways that bias can impact machine learning. Whilst it's not an exhaustive list, it should give you a good understanding of the most common ways in which ML systems end up becoming biased. If you're interested in reading further, I'd recommend &lt;a href="https://medium.com/r/?url=https%3A%2F%2Farxiv.org%2Fpdf%2F1908.09635.pdf"&gt;this paper&lt;/a&gt; from Mehrabi et al.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>datascience</category>
      <category>python</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>Bias vs Fairness vs Explainability in AI</title>
      <dc:creator>Ed Shee</dc:creator>
      <pubDate>Tue, 31 Aug 2021 09:12:18 +0000</pubDate>
      <link>https://dev.to/ukcloudman/bias-vs-fairness-vs-explainability-in-ai-193k</link>
      <guid>https://dev.to/ukcloudman/bias-vs-fairness-vs-explainability-in-ai-193k</guid>
      <description>&lt;p&gt;Over the last few years, there has been a distinct focus on building machine learning systems that are, in some way, responsible and ethical. The terms “Bias”, “Fairness” and “Explainability” come up all over the place but their definitions are usually pretty fuzzy and they are widely misunderstood to mean the same thing. This blog aims to clear that up…&lt;/p&gt;

&lt;h2&gt;
  
  
  Bias
&lt;/h2&gt;

&lt;p&gt;Before we look at how bias appears in machine learning, let’s start with the dictionary definition for the word:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“inclination or prejudice for or against one person or group, especially in a way considered to be unfair”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Look! The definition of bias includes the word “unfair”. It’s easy to see why the terms bias and fairness get confused for each other a lot.&lt;/p&gt;

&lt;p&gt;Bias can impact machine learning systems at pretty much every stage. Here’s an example of how historical bias from the world around us can creep into your data:&lt;/p&gt;

&lt;p&gt;Imagine you’re building a model to predict the next word in a sequence of text. To make sure you’ve got lots of training data, you give it every book written in the last 50 years. You then ask it to predict the next word in this sentence:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“The CEOs name is ____”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You then notice, perhaps unsurprisingly, that your model is much more likely to predict male names for the CEO than female ones. What has happened is you’ve unintentionally taken the historical stereotypes that exist in our society and baked them into your model.&lt;/p&gt;

&lt;p&gt;Bias doesn’t just occur in the data though, it can appear in the model too. If the data used to test a model doesn’t accurately represent the real world, you end up with what’s called evaluation bias.&lt;/p&gt;

&lt;p&gt;A good example of this would be training a facial recognition system and then using photos from Instagram to test it. Your model might have really high accuracy on the test set but it is likely to underperform in the real world because the majority of Instagram users are between the ages of 18 and 35. Your model is now biased towards that age group and will perform worse on the faces of older or younger people.&lt;/p&gt;

&lt;p&gt;There are actually loads of different types of bias in machine learning, I’ll cover all of those in a separate blog.&lt;/p&gt;

&lt;p&gt;The word bias almost always comes with negative connotations but it’s important to note that this isn’t always the case in machine learning. Having prior knowledge of the problem you’re trying to solve can help you to select relevant features during modeling. This introduces human bias but can often speed up or improve the modeling process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UkEH6VK4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vrnxxpbsyv0mf6qlz7tj.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UkEH6VK4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vrnxxpbsyv0mf6qlz7tj.jpeg" alt="question mark"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Explainability
&lt;/h2&gt;

&lt;p&gt;Sometimes referred to as interpretability, explainability attempts to explain &lt;em&gt;how&lt;/em&gt; a machine learning model makes predictions. It is about interrogating a model, gathering information on why a particular prediction (or series of predictions) was made, and then presenting this information back to humans in a comprehensible manner.&lt;/p&gt;

&lt;p&gt;There are typically two situations you’ll be in when trying to explain how a model works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Black Box&lt;/strong&gt; — You have no access or information about the underlying model. The inputs and outputs of the model are all you can use to generate an explanation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;White Box&lt;/strong&gt; — You have access to the underlying model so it’s easier to provide information about exactly why a certain prediction was made.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the whole, “white box” models tend to be simpler in design, sometimes deliberately, so that explanations can be easily generated. The downside is that using a simpler, more interpretable model might fail to capture the complexity of the relationships in your data which means you could be faced with a tradeoff between interpretability and model performance.&lt;/p&gt;

&lt;p&gt;When doing explainability, we’re typically interested in one of two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model View&lt;/strong&gt; — Overall, what features are more important than others to the model?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instance View&lt;/strong&gt; — For a particular prediction, what factors contributed?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The techniques used for explainability depend on whether your model is a black box or white box, whether you’re interested in the model view or instance view, and also depends on the type of data you’re exploring. &lt;a href="https://docs.seldon.io/projects/alibi/en/latest/overview/algorithms.html"&gt;The open source library Alibi&lt;/a&gt; does a great job of explaining these techniques in further detail.&lt;/p&gt;

&lt;p&gt;Personally, I like to think of white-box models as “Interpretability” (because of the requirement for an interpretable model) and black-box models as “Explainability” (because we are attempting to explain the unknown). Sadly, however, there is no official definition and the words are often used interchangeably.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XSqj4ugJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qehzh17uqj3f6g0f7nvh.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XSqj4ugJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qehzh17uqj3f6g0f7nvh.jpeg" alt="Weighing Scales"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Fairness
&lt;/h2&gt;

&lt;p&gt;Fairness is by far the most subjective of the three terms. As we did for bias, let’s glance at its everyday definition before looking at how it’s applied in machine learning:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“impartial and just treatment or behaviour without favouritism or discrimination.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Applying this to the context of machine learning, the definition I like to use is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“An algorithm is fair if it makes predictions that do not favour or discriminate against certain individuals or groups based on sensitive characteristics.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most definitions you’ll see (including mine above) tend to narrow the scope to machine learning that affects humans. Typically this is where AI can have disastrous consequences, and so fairness is super important. Something like a mortgage approval or a healthcare diagnosis is such a life-changing event that it’s critical we handle predictions in a fair and responsible way.&lt;/p&gt;

&lt;p&gt;You’re probably asking yourself “What’s a “sensitive characteristic” though?” which is a very good question. The interpretation of the definition depends heavily on what you class as sensitive. Some obvious examples tend to be things like race, gender, sexual orientation, disability, etc…&lt;/p&gt;

&lt;p&gt;One approach is to just remove all “sensitive” attributes when building a model. This seems like a sensible thing to do at first but there are actually multiple issues with this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The sensitive features might actually be critical to the model.&lt;/strong&gt; Imagine you’re trying to predict the height a child will be when they are fully grown. Removing sensitive attributes like age and sex will make your predictions useless.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fairness is not necessarily about being agnostic.&lt;/strong&gt; Sometimes it’s important to include sensitive features in order to favor those who might be discriminated against in other features. An example of this is university admissions, where raw grades alone may not be the best way to find the brightest pupils. Those who had access to fewer resources or a lower quality of education might have had better scores otherwise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sensitive features might be hidden in other attributes.&lt;/strong&gt; It is often possible to determine the values for sensitive features using a combination of non-sensitive ones. For example, an applicant’s full name might allow a machine learning model to infer their race, nationality, or gender.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The reality is that AI fairness is an incredibly difficult field. It requires policymakers to define what “fair” looks like for each use case which can sometimes be very subjective. Often there is also a trade-off between group fairness and individual fairness. Using the university admissions example from earlier, making your algorithm fairer for an underprivileged group who didn’t have the same educational resources (group fairness) comes at the cost of those who had a good educational background and whose grades are now no longer quite good enough (individual fairness).&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In summary, bias, explainability, and fairness are &lt;strong&gt;not&lt;/strong&gt; the same thing. Whilst trying to explain all or part of a machine learning model, you might find that the model contains bias. The existence of that bias might even mean that your model is unfair. That doesn’t, however, mean that explainability, bias, and fairness are the same thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bias&lt;/strong&gt; is a preference or prejudice against a particular group, individual, or feature and comes in many forms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explainability&lt;/strong&gt; is the ability to explain how or why a model makes a predictions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fairness&lt;/strong&gt; is the subjective practice of using AI without favoritism or discrimination, particularly pertaining to humans.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>datascience</category>
      <category>python</category>
    </item>
    <item>
      <title>Developer Relations Explained</title>
      <dc:creator>Ed Shee</dc:creator>
      <pubDate>Fri, 06 Aug 2021 07:19:12 +0000</pubDate>
      <link>https://dev.to/ukcloudman/developer-relations-explained-2an4</link>
      <guid>https://dev.to/ukcloudman/developer-relations-explained-2an4</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5Ri_tR02--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9gipq380voyid7871rir.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5Ri_tR02--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9gipq380voyid7871rir.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A couple of weeks ago I published a &lt;a href="https://faun.pub/what-is-mlops-9c1ad1723c1b"&gt;blog about MLOps&lt;/a&gt; and mentioned how I'd "given up trying to explain what I do to non-technical friends and family". I foolishly implied that the fault is theirs for not understanding the technology I work with or my niche job role. The reality is that it's &lt;strong&gt;totally my fault&lt;/strong&gt; because I clearly haven't figured out a concise way to explain what I do. The more I think about it, the more I realise that being able to explain my job in simple terms actually helps &lt;em&gt;me&lt;/em&gt; to define my role far more than it helps anyone else. Being totally honest, you probably don't even care what I do anyway. So here goes…&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer Relations
&lt;/h2&gt;

&lt;p&gt;Let's start with, arguably, the easier part - Developer Relations. Sometimes called Developer Advocacy, Developer Evangelism or DevRel (if you're one of the cool kids 😎) the job is a weird blend of responsibilities.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Developer&lt;/code&gt; part of it is pretty easy to comprehend - basically everything DevRel does is related to software developers. This is actually a really important distinction because, as you'll come to see, a lot of the functions DevRel provides overlap with more traditional job roles.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Relations&lt;/code&gt; term is where it becomes a lot more unclear. I usually try to explain this bit using these three commonly understood jobs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Marketing &lt;/strong&gt;- driving awareness and usage of your product or brand&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Software Engineering&lt;/strong&gt; - writing code and documentation for your product &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Product Management&lt;/strong&gt; - gathering user feedback and understanding market trends to improve your product&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But those three jobs already exist so why do I need Developer Relations? Very good question! In fact, the answer is that very few companies &lt;em&gt;do&lt;/em&gt; need developer relations (I told you it was niche!). The ones that do are almost always those who offer highly technical products. When this is the case, the barriers in between the traditional roles tend to break down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Marketing can't reach the right audience when they are demanding highly technical content and actively avoid the usual sales or marketing channels.&lt;/li&gt;
&lt;li&gt;Product Managers struggle to understand new industry trends without being experts in the domain&lt;/li&gt;
&lt;li&gt;The Engineering team are busy building a product and may not have time or the skill set to do everything&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KL4sBcEX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n4d2zub8xa9t4donoogr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KL4sBcEX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n4d2zub8xa9t4donoogr.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Developer Relations is the department that glues everything together and solves these challenges. Experts in the product, the industry and with the relevant soft skills to do public speaking engagements and manage communities.&lt;/p&gt;

&lt;p&gt;People often ask what a typical day looks like for me but the reality is that no two days are ever the same. I might write a code sample one day, speak at a conference the next, and then help a customer architect a solution the day after. The variation is what makes the job so much fun 😀.&lt;/p&gt;

&lt;p&gt;Hopefully I've at least given you a rough idea of what &lt;strong&gt;i do&lt;/strong&gt;, now for the hard part; what &lt;strong&gt;my company does&lt;/strong&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Seldon
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bdu33zxy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hug6qka1g8nvcdgabi9d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bdu33zxy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hug6qka1g8nvcdgabi9d.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The simplest explanation is that we're an "AI startup". It definitely makes us sound cool, but it also doesn't disentangle us from the thousands of other AI startups out there. Most AI startups focus on a specific industry and then either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provide software that has machine learning built in to it&lt;/li&gt;
&lt;li&gt;Do machine learning for clients in the industry as consultants&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://seldon.io"&gt;Seldon&lt;/a&gt; does neither of those. In fact, if you work at one of those AI startups there's a good chance you've heard of Seldon because what we do is provide tools for people who do AI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NSySrXX2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/040mdp8umh9cnknj691k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NSySrXX2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/040mdp8umh9cnknj691k.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's an analogy; imagine machine learning is pizza instead 🍕. While most companies in the pizza industry are busy making pizza, coming up with recipes and sourcing the best ingredients, we're the ones who supply the wood-fired ovens, the paddles and the pizza cutting wheels. It doesn't really matter if you're making italian-style, deep dish, sourdough or calzone, having an awesome oven lets you cook more pizza, faster and more reliably.&lt;/p&gt;

&lt;p&gt;What does that mean in terms of machine learning? Well, the output of machine learning is what we call a model. It's the set of complex algorithms that allow you to predict or classify something. In order to actually use that model we do what's called "putting it into production" (&lt;code&gt;production&lt;/code&gt; is just a term used in the software industry for stuff that's running &lt;em&gt;for real&lt;/em&gt; rather than as an &lt;em&gt;experiment or prototype&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Running models "in production" is actually &lt;em&gt;really&lt;/em&gt; hard. Seldon provides tools that make it a lot easier, particularly at scale (think hundreds of thousands of bank transactions being monitored every second for fraud, for example).&lt;/p&gt;

&lt;p&gt;So there you have it, hopefully, a relatively simple explanation of what I get up to and what my company does.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; - I do lots of nerdy stuff that looks a bit like marketing, product management and software development all at once for an AI startup in London. 💻&lt;/p&gt;

</description>
      <category>devrel</category>
      <category>ai</category>
      <category>machinelearning</category>
      <category>startup</category>
    </item>
    <item>
      <title>What is MLOps?</title>
      <dc:creator>Ed Shee</dc:creator>
      <pubDate>Tue, 20 Jul 2021 15:50:02 +0000</pubDate>
      <link>https://dev.to/ukcloudman/what-is-mlops-37lm</link>
      <guid>https://dev.to/ukcloudman/what-is-mlops-37lm</guid>
      <description>&lt;p&gt;I recently started a new job at a Machine Learning startup. I've given up trying to explain what I do to non-technical friends and family (my mum still just tells people I work with computers). For those of you who at least understand that "AI" is just an overused marketing term for Machine Learning, I can break it down for you using the latest buzzword in the field:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;MLOps&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The term "MLOps" (a compound of Machine Learning and Operations) refers to the practice of deploying, managing and monitoring machine learning models in production. It takes best practices from the field of DevOps and utilises them for the unique challenges that arise running machine learning systems in production.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mvFEOSn3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tiqsjood75zj9b0qy45c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mvFEOSn3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tiqsjood75zj9b0qy45c.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Search interest for “MLOps” over the past 5 years. Source: Google Trends&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The term is relatively new and has grown rapidly in usage over the last year and is a direct result of a maturing Machine Learning landscape. As businesses get good at collecting data, designing and training ML models, their focus shifts towards integrating those models into their software estates. This brings all sorts of new challenges around infrastructure, scalability, performance and monitoring that most data science teams are not traditionally equipped to deal with.&lt;/p&gt;

&lt;p&gt;One approach is to segregate duties between Data Science and DevOps like so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data Science - design, build and evaluate the models&lt;/li&gt;
&lt;li&gt;DevOps - deploy, monitor and manage the models&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This seems like a good idea at first but we only need to start asking some questions to see where we might struggle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When do we retrain a model and deploy a new version?&lt;/li&gt;
&lt;li&gt;What are the expected input/output formats of the model? Do we need to validate them?&lt;/li&gt;
&lt;li&gt;Can the model performance be optimsed by utilizing a GPU?&lt;/li&gt;
&lt;li&gt;How do we allow models to be continually tested?
Answering any of these questions requires knowledge of both the model itself and the complex environment it’s deployed in.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The reality is that the whole lifecycle of an ML system is tightly coupled and highly iterative in nature. Production ML is hard and requires expertise in Data Engineering, Data Science and DevOps. The umbrella term “MLOps” provides an easy way to refer to the techniques, tools and skilled engineers who inhabit the growing space between these disciplines.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k2VzukL5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jkawq1jtfqjmpvc9nu4m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k2VzukL5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jkawq1jtfqjmpvc9nu4m.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Mandatory Venn diagram - Source: Wikipedia&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Is MLOps just another buzzword? Absolutely! But for now it’s the best we’ve got and it serves an important purpose. &lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>devops</category>
      <category>datascience</category>
      <category>cloudnative</category>
    </item>
  </channel>
</rss>
