Deploy Deep Learning Model Using Docker, Tensorflow Serving, Nginx and Flask (Part 2)

Ashish Kumar
TheCyPhy
Published in
5 min readAug 29, 2020

Hello Curious Person, Welcome back to the second part of our series Deploy Deep Learning. In this part as I promised We will be writing few HTML pages and a Dockerfile for our first service i.e. web. So put your fingers on the keyboard and let’s get started.

First we will create a folder named “static” inside “flask” folder. We store static files inside this folder to be used by our Web application. I am storing “index.png” file in it which will get displayed when user login into our Web application.

Now we will create a folder named “Template” inside “flask” folder. We will store our HTML pages here, namely “base.html”, “index.html”, “login.html”, “result.html”, “signup.html” and “start.html”

So let us create our first page “base.html”. Every other page will extend this “base.html” page. This page will provide the layout for all the other pages to extend. It provides buttons in the top right corner of the web page for Login, Signup and Home

<!DOCTYPE html><html><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Flask Auth Example</title><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css" /></head><body><section class="hero is-primary is-fullheight"><div class="hero-head"><nav class="navbar"><div class="container"><div id="navbarMenuHeroA" class="navbar-menu"><div class="navbar-end"><a href="{{ url_for('index') }}" class="navbar-item">  Home </a>{% if current_user.is_authenticated %}<a href="{{ url_for('predict') }}" class="navbar-item">Application</a>{% endif %}{% if not current_user.is_authenticated %}<a href="{{ url_for('login') }}" class="navbar-item">Login</a><a href="{{ url_for('signup') }}" class="navbar-item">Sign Up</a>{% endif %}{% if current_user.is_authenticated %}<a href="{{ url_for('logout') }}" class="navbar-item">  Logout </a>{% endif %}</div></div></div></nav></div><div class="hero-body"><div class="container has-text-centered">{% block content %}{% endblock %}</div></div></section></body></html>

Now we will write “index.html”. This page will appear when the user log in to our Web App. This page will provide layout for the user to upload an image into our Web App

{% extends "base.html" %}{% block content %}<head><style>.button {background-color: #4CAF50;border: none;color: white;padding: 15px 32px;text-align: center;text-decoration: none;display: inline-block;font-size: 16px;margin: 4px 2px;cursor: pointer;}</style></head><div class="container"><h1>Upload File Here</h1><hr><img src="{{ result.image_path }}" class="img-rounded" width="400" height="200"><form class="form-inline" action="/app" method="post" enctype="multipart/form-data"><div class="form-group"><input type="file" name="file" class="btn btn-default"></div><div class="form-group"><input type="submit" value="Upload" class="button"></div></form></div>{% endblock %}

Next we will create “login.html”. This page will provide the layout for the user to log in to our Web App i.e. enter his username and password and a submit button to login

{% extends "base.html" %}{% block content %}<div class="column is-4 is-offset-4"><h3 class="title">Login</h3><div class="box">{% with messages = get_flashed_messages() %}{% if messages %}<div class="notification is-danger">{{ messages[0] }}</div>{% endif %}{% endwith %}<form method="POST" action="/login"><div class="field"><div class="control"><input class="input is-large" type="email" name="email" placeholder="Your Email" autofocus=""></div></div><div class="field"><div class="control"><input class="input is-large" type="password" name="password" placeholder="Your Password"></div></div><div class="field"><label class="checkbox"><input type="checkbox">Remember me</label></div><button class="button is-block is-info is-large is-fullwidth">Login</button></form></div></div>{% endblock %}

Now we will write “result.html”. This page will provide the layout when our Web App will display the classification result for the uploaded image, i.e. whether the uploaded image is of a Cat or a Dog

{% extends "base.html" %}{% block content %}<div class="container"><h1>Predicted Class: {{ result.class_name }}</h1><hr><div><img src="{{ result.image_path }}" class="img-rounded" width="400" height="200"></div><a href="{{ url_for('predict') }}" class="btn btn-default">Back</a></div>{% endblock %}

Next we will write “signup.html”. This page will provide the layout for the user to sign up for our Web App. Users can upload images in our Web app only if they have logged in.

{% extends "base.html" %}{% block content %}<div class="column is-4 is-offset-4"><h3 class="title">Sign Up</h3><div class="box">{% with messages = get_flashed_messages() %}{% if messages %}<div class="notification is-danger">{{ messages[0] }}. Go to <a href="{{ url_for('login') }}">login page</a>.</div>{% endif %}{% endwith %}<form method="POST" action="/signup"><div class="field"><div class="control"><input class="input is-large" type="email" name="email" placeholder="Email" autofocus=""></div></div><div class="field"><div class="control"><input class="input is-large" type="text" name="name" placeholder="Name" autofocus=""></div></div><div class="field"><div class="control"><input class="input is-large" type="password" name="password" placeholder="Password"></div></div><button class="button is-block is-info is-large is-fullwidth">Sign Up</button></form></div></div>{% endblock %}

And at the last we will write “start.html”. When our user first opens our Web App via a web browser. This is the first page which the user will see.

{% extends "base.html" %}{% block content %}<h1 class="title">Flask Web App</h1><h2 class="subtitle">Flask Web App</h2>{% endblock %}

We have written so many HTML pages, at last we are done with the pages. To deploy our Web App in the docker container, we have to write “requirements.txt” file. Basically this file contains all the python packages which are required by our python codes to run.

Flask>=1.1.2
Flask-Bootstrap>=3.3.7.1
waitress>=1.4.3
tensorflow-cpu==2.1.0
numpy>=1.18.3
requests>=2.23.0
Pillow==7.1.0
gunicorn==20.0.4
Flask-SQLAlchemy==2.4.3
Flask-Login==0.5.0
pandas==1.0.5
grpcio==1.31.0
tensorflow-serving-api==2.1.0

Now we can write a more cooler file that is our Dockerfile. For this create a file named “Dockerfile.flask” inside “flask” folder

FROM python:3.7-slim-busterCOPY . /appWORKDIR /appRUN pip install -r requirements.txt

Our Dockerfile is pretty much small but it did all the things which is required for our first service i.e Web. Please Note, I am running the docker container with root user as I am running my docker container in Windows which has some issues when I use command “chown” in dockerfile. For security purpose it is recommended to run docker container with a non root user.

Let us see our folder structure for our first service, i.e Web

services
|---web
|---flask
|---database
|---static
| |---index.png
|---Template
| |---base.html
| |---index.html
| |---login.html
| |---result.html
| |---signup.html
| |---start.html
|---app.py
|---database.py
|---dbmodels.py
|---Dockerfile.flask
|---manage.py
|---model.py
|---requirements.txt

Note: In the above folder structure we can see that database folder is empty. data2.db file will be created inside it when our Web application will start for the first time. This file will store User name and hashed passwords.

If your Folder structure looks like the above, then congratulations you have created your first service. i.e Web. You can relax yourself now and lift your fingers away from the keyboard.

In the next part of this series. We will create other services for our Web App. i.e Tensorflow-Serving and Nginx.

Till then enjoy your Day :)

If you are ready to go ahead, here is the link for Part 3

References-

  1. https://www.digitalocean.com/community/tutorials/how-to-add-authentication-to-your-app-with-flask-login

--

--

Ashish Kumar
TheCyPhy

I write and share interesting articles. Follow me if you are an avid reader. Connect with me at https://topmate.io/ashish_kumar17