Frontend
If you have gone over the deployment module you should be at the point where you have a machine learning model running in the cloud. The model can be interacted with by sending HTTP requests to the API endpoint. In general we refer to this as the backend of the application. It is the part of our application that are behind-the-scene that the user does not see and it is not really that user-friendly. Instead we want to create a frontend that the user can interact with in a more user-friendly way. This is what we will be doing in this module.
Another point of splitting our application into a frontend and a backend has to do with scalability. If we have a lot of users interacting with our application, we might want to scale only the backend and not the frontend, because that is the part that will be running our heavy machine learning model. In general dividing a application into smaller pieces are the pattern that is used in microservice architectures.
Frontends have for the longest time been created using HTML, CSS and JavaScript. This is still the case, but there are now a lot of frameworks that can help us create a frontend in Python:
In this module we will be looking at streamlit
. streamlit
is a easy to use framework that allows us to create
interactive web applications in Python. It is not at all as powerful as a framework like Django
, but it is very easy
to get started with and it is very easy to integrate with our machine learning models.
❔ Exercises
In these exercises we go through the process of setting up a backend using fastapi
and a frontend using streamlit
,
containerizing both applications and then deploying them to the cloud. We have already created an example of this
which can be found in the samples/frontend_backend
folder.
-
Lets start by creating the backend application in a
backend.py
file. You can use essentially any backend you want, but we will be using a simple imagenet classifier that we have created in thesamples/frontend_backend/backend
folder.-
Create a new file called
backend.py
and implement a FastAPI interface with a single/predict
endpoint that takes a image as input and returns the predicted class (and probabilities) of the image.Solution
-
Run the backend using
uvicorn
-
Test the backend by sending a request to the
/predict
endpoint, preferably usingcurl
commandSolution
In this example we are sending a request to the
/predict
endpoint with a file calledmy_cat.jpg
. The response should be "tabby cat" for the solution we have provided. -
Create a
requirements_backend.txt
file with the dependencies needed for the backend. -
Containerize the backend into a file called
backend.dockerfile
.Solution
-
Build the backend image
-
Recheck that the backend works by running the image in a container
and test that it works by sending a request to the
/predict
endpoint. -
Deploy the backend to Cloud run using the
gcloud
commandSolution
Assuming that we have created an artifact registry called
frontend_backend
we can deploy the backend to Cloud Run using the following commands:docker tag \ backend:latest \ <region>-docker.pkg.dev/<project>/frontend-backend/backend:latest docker push \ <region>.pkg.dev/<project>/frontend-backend/backend:latest gcloud run deploy backend \ --image=europe-west1-docker.pkg.dev/<project>/frontend-backend/backend:latest \ --region=europe-west1 \ --platform=managed \
where
<region>
and<project>
should be replaced with the appropriate values. -
Finally, test that the deployed backend works as expected by sending a request to the
/predict
endpointSolution
In this solution we are first extracting the url of the deployed backend and then sending a request to the
/predict
endpoint.
-
-
With the backend taken care of lets now write our frontend. Our frontend just needs to be a "nice" interface to our backend. Its main functionality will be to send a request to the backend and display the result. streamlit documentation
-
Start by installing
streamlit
-
Now create a file called
frontend.py
and implement a streamlit application. You can design it as you want, but we recommend that the following can be done in the frontend:-
Have a file uploader that allows the user to upload an image
-
Display the image that the user uploaded
-
Have a button that sends the image to the backend and displays the result
For now just assume that a environment variable called
BACKEND
is available that contains the URL of the backend. We will in the next step show how to get this URL automatically.Solution
-
-
We need to make sure that the frontend knows where the backend is located, and we want that to happen automatically so we do not have to hardcode the URL into our frontend. We can do this by using the Python SDK for Google Cloud Run. The following code snippet shows how to get the URL of the backend service or fall back to an environment variable if the service is not found.
from google.cloud import run_v2 import streamlit as st @st.cache_resource # (1)! def get_backend_url(): """Get the URL of the backend service.""" parent = "projects/<project>/locations/<region>" client = run_v2.ServicesClient() services = client.list_services(parent=parent) for service in services: if service.name.split("/")[-1] == "production-model": return service.uri name = os.environ.get("BACKEND", None) return name
- The
st.cache_resource
is a decorator that tellsstreamlit
to cache the result of the function. This is useful if the function is expensive to run and we want to avoid running it multiple times.
Add the above code snippet to the top of your
frontend.py
file and replace<project>
and<region>
with the appropriate values. You will need to installpip install google-cloud-run
to be able to use the code snippet. - The
-
Run the frontend using
streamlit
-
Create a
requirements_frontend.txt
file with the dependencies needed for the frontend. -
Containerize the frontend into a file called
frontend.dockerfile
.Solution
-
Build the frontend image
-
Run the frontend image
and check in your web browser that the frontend works as expected.
-
Deploy the frontend to Cloud run using the
gcloud
commandSolution
Assuming that we have created an artifact registry called
frontend_backend
we can deploy the backend to Cloud Run using the following commands:docker tag frontend:latest \ <region>-docker.pkg.dev/<project>/frontend-backend/frontend:latest docker push <region>.pkg.dev/<project>/frontend-backend/frontend:latest gcloud run deploy frontend \ --image=europe-west1-docker.pkg.dev/<project>/frontend-backend/frontend:latest \ --region=europe-west1 \ --platform=managed \
-
Test that frontend works as expected by opening the URL of the deployed frontend in your web browser.
-
-
(Optional) If you have gotten this far you have successfully created a frontend and a backend and deployed them to the cloud. Finally, it may be worth it to load test your application to see how it performs under load. Write a locust file which is covered in this module and run it against your frontend. Make sure that it can handle the load you expect it to handle.
-
(Optional) Feel free to experiment further with streamlit and see what you can create. For example, you can try to create a option for the user to upload a video and then display the video with the predicted class overlaid on top of the video.
🧠 Knowledge check
-
We have created separate requirements files for the frontend and the backend. Why is this a good idea?
Solution
This is a good idea because the frontend and the backend may have different dependencies. By having separate requirements files we can make sure that we only install the dependencies that are needed for the specific application. This also has the positive side effect that we can keep the docker images smaller. For example, the frontend does not need the
torch
library which is huge and only needed for the backend.
This ends the exercises for this module.