This is how to deploy a machine learning model with Anvil
Tags: python, machinelearning, ai, programming
Published: 2023-01-04 17:24:59

# Deploying your model to the web

Deploying machine learning models is tricky. The skills used to create a model are very different to the skills needed to deploy the model for end-users to interact with. With Anvil, it’s easy to deploy ML models to the web, and we can do it **entirely in Python - no need to wrestle with HTML, CSS, JavaScript or web hosting**. 

In this short tutorial, we'll use Anvil to turn an ML model into an interactive web application. We will use the classic [iris classification problem](https://en.wikipedia.org/wiki/Iris_flower_data_set), for which I have a pre-trained model using [`sklearn`](https://scikit-learn.org) and [`joblib`](https://joblib.readthedocs.io) (if you want to see how I trained this model, [check out this tutorial](https://anvil.works/learn/tutorials/google-colab-to-web-app)).

We will create an interactive web app that collects the iris measurements from the user, use our model to classify the flower, and return the classification back to our user. Here's what it will look like:

<figure>
  <img src="https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/deploy-a-machine-learning-model/app-demo.gif">
  <figcaption>Demo of the finished app</figcaption>
</figure>

For this tutorial you will need to know basic Python.

These are the steps that we will cover:

- [Step 1 - Create your Anvil app](#step-1-create-your-anvil-app)
- [Step 2 - Design your page](#step-2-design-your-page)
- [Step 3 - Run Python code when you click the button](#step-3-run-python-code-when-you-click-the-button)
- [Step 4 - Upload our model](#step-4-upload-our-model)
- [Step 5 - Configure our server environment](#step-5-configure-our-server-environment)
- [Step 6 - Use our model](#step-6-access-our-saved-model-file)
- [Step 7 - Publish our app](#step-7-publish-our-app)

Let's get started.

---

## Step 1 - Create your Anvil app

[Log in](/login) to Anvil and click 'New Blank App'. Choose the Material Design theme.

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3wcmv2z6j1i9ltmumtje.png">
  <figcaption>Location of the Create App button</figcaption>
</figure>

First, name the app. Click on the name at the top of the screen and give it a name.

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ixkqi77b4ot5wo1fx7iy.png">
  <figcaption>Rename your app by clicking on the title</figcaption>
</figure>

---

## Step 2 - Design your page

To classify the species of iris a flower comes from, we need to collect several measurements, so let's design the user interface for entering that data.

We construct the UI by dragging-and-dropping components from the Toolbox. Let's start by dropping a Card into our form -- this will be a neat container for the other components. Then let's add a Label and a TextBox into the card component:

<figure>
  <img src="https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/deploy-a-machine-learning-model/drag-drop-textbox.gif">
  <figcaption>Dragging a Card component, Label component and TextBox component into Form1</figcaption>
</figure>

Next we will set up the label and TextBox components to collect the sepal length. Select the `Label` we just added and, in the properties panel on the right, change the text to 'Sepal length: '. Then select the `TextBox` we added and change the name to `sepal_length`, and the placeholder text to '(cm)'.

<figure>
  <img src="https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/deploy-a-machine-learning-model/editing-textbox.gif">
  <figcaption>Editing the Label and TextBox</figcaption>
</figure>

Repeat this process adding labels and text boxes for the other parameters we need: **sepal width**, **petal length** and **petal width**. This will capture all the information we need to classify each iris flower.

Next, let's add a Button to run the classifier. Name it `categorise_button` and change the text to 'Categorise'. Clicking this button will trigger a Python function to classify the iris measurements using our model. (We'll set that up in a moment.)

Finally, let's add a Label where we'll display our results. Put it below the button, call it `species_label` and untick the `visible` tick box in the properties panel so it doesn't appear immediately. In step 3 we will create an event handler function that makes the label visible, and uses it to display data returned from our model.

Our app should now look like this:

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/goxp4rlp77gfhnjqhdk5.png">
  <figcaption>How our app's UI should look</figcaption>
</figure>

In the next step we will add some code to control what happens when a user pushes the **Categorise** button.

---

## Step 3 - Run Python code when you click the button

We want our `categorise_button` to do something when it's clicked, so let's add a click event.

With the button selected, go to the bottom of the properties panel. Then click the blue button with two arrows in it next to the click event box. This will open our code view and create a function called `categorise_button_click()`. From now on, every time the button is clicked by a user, this function will be called.

<figure>
  <img src="https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/deploy-a-machine-learning-model/click-event.gif">
  <figcaption>Click event being added to the Categorise button</figcaption>
</figure>

We want to call a function on our app's server side to interact with our model, and pass it the measurements the user has entered into our web app. When the server function returns our answer, we'll display it as text on the `species_label`:

To do this we add the following:

``` Python
def categorise_button_click(self, **event_args):
    """This method is called when the button is clicked"""
    # Call the server function and pass it the iris measurements
    iris_category = anvil.server.call('predict_iris', 
                                self.sepal_length.text,
                                self.sepal_width.text,
                                self.petal_length.text,
                                self.petal_width.text)
    # If a category is returned set our species 
    if iris_category:
      self.species_label.visible = True
      self.species_label.text = "The species is " + iris_category.capitalize()
```


Now we have a basic UI and functionality, let's upload our model to our example app.

---

## Step 4 - Upload our model

Data Files are files that you, as the app developer, can attach to your app. These files are available in your [Server Modules](/docs/server). You can do this via the built-in [Data File Service](/docs/working-with-files/data-files). The Data Files service is useful for machine learning models, large datasets and data that stays constant.

In our Anvil app, click the **+** button in the Sidebar Menu, and select **Data Files**:

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gjnfhvky4evgvv97yw7t.png">
  <figcaption>Click the + button in the Sidebar Menu, and select Data Files</figcaption>
</figure>

Then, let's upload a classification model for our UI to use. For this guide, I've created an example iris classifier model - download it here:

https://anvil.works/learn/tutorials/img/deploy-a-machine-learning-model/knn.skmodel

Once you've downloaded this file to your computer, upload it into your app's Data Files by clicking the **Upload** button and selecting the model from your files.

<figure>
  <img src="https://anvil-website-static.s3.eu-west-2.amazonaws.com/docs/working-with-files/data-files/uploading-a-file.gif">
  <figcaption>Uploading the model to our Data Files</figcaption>
</figure>

Next, let's create a server function that uses the model to classify our user's data.

---

## Step 5 - Configure our server environment

Now that our model is uploaded, we need to configure the [server environment](https://anvil.works/docs/server/custom-packages) to include all the packages we need to run it.

We'll start by selecting settings from the Sidebar Menu and opening 'Python versions'.

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ghlltzivunfba7e0h59u.png">
  <figcaption>Selecting the Python version</figcaption>
</figure>


Then, in the Python version dropdown, select 'Python 3.10'. Under 'Base packages', select 'Edit requirements.txt directly'.

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mnkemrti3l7rxwvsspjs.png">
  <figcaption>Editing our app's environment</figcaption>
</figure>

Finally, paste the following list of requirements into the text box:

```
joblib==1.1.0
numpy==1.21.6
scikit-learn==1.1.2
scipy==1.9.0
sklearn==0.0
threadpoolctl==3.1.0
```

With our server environment configured, it's time to start using our model in a function.

---

## Step 6 - Access our saved model file

We can access our saved model file using the [`data_files`](https://anvil.works/docs/api/anvil.files) API in a [Server Module](https://anvil.works/docs/server). Then we can load it into [scikit-learn](https://scikit-learn.org).

To start, let's add a Server Module to our app by clicking '+ Add Server Module' in the [App Browser](https://anvil.works/docs/editor#app-browser).

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h31furbmgctymwjf5655.png">
  <figcaption>Position of the '+ Add Server Module' button in the App Browser</figcaption>
</figure>

At the top of our server module, let's import the `joblib` library we need to load our model and import `load_iris` from `sklearn`'s built-in iris dataset.

``` Python
from sklearn.datasets import load_iris
import joblib

# Loading sklearn's built-in iris dataset
iris = load_iris()
```

With the dataset loaded, we can create a function that takes our iris data and returns the name of the iris species. Let’s create a `predict_iris` function and add the [`@anvil.server.callable`](https://anvil.works/docs/server#calling-server-functions-from-client-code) decorator so the function can be called from our app's client-side code.

``` Python
@anvil.server.callable
def predict_iris(sepal_length, sepal_width, petal_length, petal_width):
  pass

```

Inside the `predict_iris` function, we'll load our model from the Data Files service. To do this, we will get the path to the model file on disk using `data_files['knn.skmodel']`, we can then use [`joblib.load()`](https://joblib.readthedocs.io/en/latest/generated/joblib.load.html) to reconstruct our model from the file.

Once we have reconstructed our model, pass our iris flower data to [`model.predict()`](https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsClassifier.html#sklearn.neighbors.KNeighborsClassifier.predict) and return the name of the flower.


``` Python
@anvil.server.callable
def predict_iris(sepal_length, sepal_width, petal_length, petal_width):
  model = joblib.load(data_files['knn.skmodel'])
  classification = model.predict([[sepal_length, sepal_width, petal_length, petal_width]])
  return iris.target_names[classification][0]
```

Back in step 3 of this tutorial, we wrote `anvil.server.call('predict_iris', ...)` in our `categorise_button_click()` function on the [client side](https://anvil.works/articles/client-vs-server). Adding the [`@anvil.server.callable`](https://anvil.works/docs/server#calling-server-functions-from-client-code) decorator to our server-side `predict_iris()` function means it can be called from the client.

---

## Step 7 - Publish our app

Now we've finished our app, all we have to do is test it and [publish](https://anvil.works/beta-docs/deployment-new-ide/quickstart#publish-your-app) it online for people to use.

Let's quickly test the app to make sure it works. We can click the 'Run' button in the top right of the [Anvil Editor](https://anvil.works/beta-docs/editor#the-anvil-editor) to run the app in split view and try it out.

<figure>
  <img src="https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/deploy-a-machine-learning-model/Testing-data-files-app.gif">
  <figcaption>Running the app in the editor</figcaption>
</figure>

If there is an issue, the App Console will appear and show the exception that was thrown. You can click on the exception and the editor will take you to the line of code that caused it.

<figure>
  <img src="https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/deploy-a-machine-learning-model/fixing-a-bug.gif">
  <figcaption>Fixing a bug</figcaption>
</figure>

With the app tested, we can click the 'Publish' button at the top right of the editor. Then select 'Publish this app' and use the public URL provided or enter your own.

<figure>
  <img src="https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/deploy-a-machine-learning-model/publishing-app.gif">
  <figcaption>Publishing the finished app</figcaption>
</figure>

That's it, our app is now finished and online for anyone to use!

---

## Conclusion

We now have an interactive app based on our machine learning model. We've designed a UI, written client-side Python, uploaded our machine learning model, written server-side code that uses our model and deployed the app online for anyone to use - all with nothing but Python!

### Clone the App

For those of you who want to see the source code for this app:

https://anvil.works/build#clone:GMXRQOGCBCX6YXWT%3dZC4GCEYQEOO5B7V3PMDOGZT5


> I've added some images to improve the final app. To do this I simply added an [image component](https://anvil.works/docs/client/components/basic#image) to the app and set its source based on the returned iris classification. The sources I used are in the below challenges section.


---

## What next?

Head to the [Anvil Learning Centre](https://anvil.works/learn) for more tutorials, or head to our [examples page](https://anvil.works/learn/examples) to see how to build some complex apps in Anvil.

Why not check out the [Anvil Community Forum](https://anvil.works/forum)? There are a lot of knowledgeable people there, and it's a great place to get help.


### Optional: Challenge yourself

**This part is optional!** The best way to learn any new technology is to challenge your understanding. Why not challenge yourself to reinforce what you’ve learnt and learn more?

#### Challenge 1 - Add an image to your app

Add an [`Image` component](https://anvil.works/docs/client/components/basic#image) to your app's interface and set its source based on the returned iris classification. You can set the source of the image to one of the following three URLs in the `categorise_button_click` function:

- Virginica: https://upload.wikimedia.org/wikipedia/commons/f/f8/Iris_virginica_2.jpg
- Versicolor: https://upload.wikimedia.org/wikipedia/commons/2/27/Blue_Flag%2C_Ottawa.jpg
- Setosa: https://upload.wikimedia.org/wikipedia/commons/5/56/Kosaciec_szczecinkowaty_Iris_setosa.jpg


#### Challenge 2 - Store your results in a Data Table

Try storing the classification results in Anvil's built-in database.

Hint: Add a [Data Table](https://anvil.works/docs/data-tables) to your app to store the classification results. Then, use Anvil's [`add_row()`](https://anvil.works/docs/api/anvil.tables#Table) in your app's `predict_iris` function. This will add a row to your database each time a classification is completed.

#### Challenge 3 - Turn the app into an HTTP API

You can build an HTTP API for your app by decorating the `predict_iris` function with the [`@anvil.server.http_endpoint` decorator](https://anvil.works/docs/http-apis/creating-http-endpoints#the-http-endpoint-decorator). Why not try creating an API for your app for other people to use?

---

## New to Anvil?

If you're new to Anvil, welcome! [Anvil](https://anvil.works/) is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just **build it all in Python**.

Yes – Python that runs in the browser. Python that runs on the server. Python that builds your UI. A drag-and-drop UI editor. We even have a built-in Python database, in case you don’t have your own.

Why not have a play with the app builder? **It's free!** Click here to get started:

https://anvil.works/build

---

{% user codingwithryan %}