Machine Learning Web App with Python | Towards Data Science

Deep Learning is a great model for handling unstructured data, especially on images. The progress of this field is really fast, and one of the progress is something called Transfer Learning.
Transfer Learning is a method to train the neural network that has already trained on a different dataset, so we don’t have to train it from scratch because it could take several days or weeks to train them.
If we use the transfer learning to our dataset, it only takes several hours to train because we only train the final layer. Therefore, we can use it to train on the other dataset with already pre-trained model and its given architecture.
To make the model is useful to use, we have to deploy them, in example by building a web app that makes it more user friendly. Thankfully, we can do that using PyTorch to build a deep learning model and Flask to build a web application.
In this article, I will show you on how to build a web application for image classification on an Apple leaf to classify whether is it healthy or not and if it doesn’t, which disease the leaf has. To build that, we can use transfer learning using PyTorch, and also how to build a simple web application using Flask. Here is the preview of the web application,
The first task that we have to do is to build an image classifier. It consists of several steps to do, they are,
Download the data,
Preparing the data,
Build the model,
Test the model,
Save the model.
For the dataset, we can use the PlantVillage datasets to retrieve our dataset to use. You can download the dataset from this GitHub repository here.
Right after we download the data, we can prepare the dataset first. First, we have to structure our dataset into separate folders.
If we see the dataset that we have downloaded, we can see that there are so many images from different plants. In this case, we only pick the plant that relates to Apple.
So, we take the folder that consists of Apple leaf images to it.
Then, we divide each folder into 3 different folders, they are train, val, and test. Then, we divide each group by 80% for train data (divide them for train and validation with 90:10 proportion) and 20% for test data. The amount of each folder will look like this,
Finally, the folder will have a structure will look like this,
After we have a folder structure like above, we can build the model for image classification. Before we can build that, we have to import the dataset, and also we have to transform the data, so it has the same representation that gets into the model. The code will look like this,
As we can see above, there are several steps on how to prepare the dataset. First, we have to transform the dataset. It is a must because the model cannot process the data that don’t have the required size. Therefore, we have to resize it and also crop the dataset with the same dimension with the first layer of the model.
Then, after we transform the image, we can load it to our code using ImageFolder method to do it. Also, we apply the transform to the dataset to it. We can train the model by using all of the training dataset, but it will take a lot of time. Therefore, we have to create batches to reduce the computation time. To make sure that the batches are random, we have to set the shuffle parameter to true.
Finally, we retrieve the number of the images and the class names, and also we can enable the GPU using the torch.device function. After we do all the steps, we can move into the modelling section.
Because we build the model based on the pre-trained model, the first thing we have to do is to download the model. In this case, I only use VGG-16, ResNet-18, and AlexNet architecture, and then we compare the model which one is the best and make sure that you set the pretrained parameter to true.
Because we use that, we have to set the parameters to not calculate the gradient except the final layer which is the fully-connected layer. Then, we can change the final layer’s output neurons based on the number of class on the dataset. And then, we can train the model.
Here is the code,
Make sure that you know where the location of the final layer because each model has a different method on how to access it. With ResNet, we can access the fc index to access the final layer, but on the VGG and AlexNet, we access it by index classifier and index number 6.
You can see the outline of each model by calling it on the block code, and here is the code and the output,
When we train the model, it occurs on several epochs. Epochs describe how many iterations to train the model. On each epoch, there are several steps to train the model. First, the model feedforwards the image, and get the best output. Then, it compares the output and the true label and calculates the loss. After that, it calculates the gradient on each parameter, and then update each weight based on the amount of gradient of the model. It repeats until it reaches the final epoch, and we will get the best model from all epochs.
Here is the best result on each model,
""" For VGG-16, Training complete in 27m 4s Best val Acc: 0.964706  For ResNet-18, Training complete in 10m 7s Best val Acc: 0.968627  For AlexNet, Training complete in 7m 40s Best val Acc: 0.976471 """
To determine which model to use, we have to consider based on our needs. Of course, we need a model with great accuracy to it. But if we want to deploy to the web application, make sure that your model has a small size, so we can deploy that on GitHub and Heroku.
Based on those results, we conclude that the AlexNet is the best and the fastest model to classify the disease on the apple in 7 minutes and 40 seconds. Also, we can see that the VGG-16 model is the slowest and the lowest accuracy score. The ResNet-18 is in the middle position. It’s not slower than the AlexNet, and it’s also has a great accuracy than VGG-16. But, when we deploy those models, the ResNet-18 has the smallest size. Therefore, we will use the ResNet-18 model as our classifier.
If we want to test the model, we can call the dataloader on test dataset to test whether the model can predict the image accurately. The code will look like this,
After that, we have the output that looks like this,
""" GroundTruth:  Cedar Apple Rust, Healthy, Black Rot, Healthy Predicted:  Cedar Apple Rust, Healthy, Black Rot, Healthy"""
So, if we are confident with our new model, we can save it. To do that, we can use this code below,
# Save The Model PATH = ‘./fix_resnet18.pth’ torch.save(model_resnet.state_dict(), PATH)
It will save your model to .pth format. If we want to use it in the other session, we can use this command,
And that’s how to build an image classifier using PyTorch!
Right after we create the model, we can build the web application using Flask. In general, we will work on two things. They are working on the server and create the page to display that.
First, we have to build a file called app.py. It will handle the website, and it includes showing the page, and also it will process the input. In this case, we have an image input. The code inside of it will look like this,
Let me explain each line of it. Line 1–8 imports the libraries that we need, including Flask, PyTorch, string, and many more. Line 10 declares a Flask object. Line 12–36 do the modelling task with PyTorch. Line 38–43 declares a dictionary that displays the prediction result. Line 46–58 is the main process of our web app. Line 60–61 to make sure our app will run by using this command below,
python app.py
Some of you are probably new to the Flask. Let me explain to you how it works. Line 46 is to set our route on the website. In this case, on our website, if we want to show the main page, we will go to that root like http://127.0.0.1:5000/ where the last character of the URL describes our route.
Inside of it also describe the GET and POST methods. They describe on how we interact with the website. If we use the GET method, we only request to the server and not send any file there. The POST method will send files to the server, and also request the result from it.
On line 47, it declares a function called upload_file. It will work on our data. If we open the web at first, it will use the GET method to retrieve the web page only. After that, we give an image input and then upload them. Because we upload the data, it will use the POST method to process our data where it will predict which disease that exists on the leaf image. After it’s done, we receive a new page that shows what disease of the leaf has and the descriptions of it.
Now, we create the web pages that describe the main page and the prediction result page. We create three files they are layout.html, index.html, and result.html. Wait, we build two pages, but why we build another page?
There’s a concept on Flask called templates. In short, we don’t have to build a full web page. Instead, we build the additional page as the layout to all pages, so we don’t have to code a full HTML to it. Let me show you the layout.html file,
As we can see, the web page doesn’t have any content at all, except there is a {% block content %} command inside our body tag. It’s called a block, and it will contain the element from another file. Let me show you the index and the result page,
As we can see from both files, we don’t code the full web page. Instead, we call {% extends “layout.html” %} as our template for the website. Below of it, there is the block section to fill that. That’s why we don’t have to build from scratch, and it makes our time shorter than before.
After we build the code and run the command, we can go to http://127.0.0.1:5000/, and it will show the page on the website,
Transfer Learning is a useful concept to implement our own classifier without training them from scratch. In this article, I have already shown to you on how we can build it using transfer learning concept on PyTorch with different architectures. Also, I’ve already shown to you on how to build a web app using Flask. Make sure that your model doesn’t consume a huge size of storage, but still has a great accuracy to it, so you can deploy the model without any problem.
I hope it will be useful to you and thank you for reading my article. If you want to see the code, you can look at my GitHub repo here.