⚡Combining the power of Transformers with UNet for state-of-the-art image segmentation task💪
This is Module 2 of UNETR which covers backend development and deployment on the cloud
Module 1. UNETR-MachineLearning
Module 2. Develop and Deploy Backend of UNETR
Module 3. Develop and Deploy Frontend of UNTER
In October 2021, Ali Hatamizadeh et al. published a paper titled "UNETR: Transformers for 3D Medical Image Segmentation," introducing the UNETR architecture, which outperforms other segmentation models. In essence, UNETR utilizes a contracting-expanding pattern consisting of a stack of transformer as the encoder which is connected to the CNN-based decoder via skip connections, producing segmented image.
This project aims to implement the UNETR architecture as described in the paper, training it on a custom multi-class dataset for facial feature segmentation. The project involves developing the machine learning model, backend, and frontend for the application. The UNETR model is served via a REST API using Django REST framework to a Next.js frontend, with the frontend and backend deployed separately on Vercel and AWS, respectively. This tech stack selection ensures high scalability, performance, and an excellent UI/UX.
Read this note before reading ahead
In this module, I have shown, how to develop and deploy an interactive frontend using the below mentioned tech stack to use/consume the ML model built in Module 1. UNETR-MachineLearning which is being served by a Django backend built in Module 2. Develop and Deploy Backend of UNETR .
The main objective is to build a minimalistic yet beautiful UI in which we can upload images to inference on.
- Next.Js: A modern React.Js framework for building performant and interactive web applications.
- Tailwind CSS: A utility-first CSS framework that streamlines web development by providing a set of pre-designed utility classes.
- NextUI: Offers pre built, fully customizable UI components based on Tailwind CSS and Framer Motion.
- Vercel: Frontend-as-a-service for deploying Next.Js app on the edge.
- Convert the uploaded image to a Base64 string.
- Use regex to trim the string and format it appropriately, then preview it to the user.
- Temporarily store the image string and name.
- Send the data as a JSON object to the Django API.
- Display the inferred Base64 image string returned by the server to the user.
Workflow for implementing from scratch:
- Create Next app
- Setup up and configure NextUI
- Develop the required pages
- Deploy on Vercel
Workflow for implementing by cloning:
- Setup Next app
- Deploy on Vercel
For the implementation, I presume you are familiar with Next.Js
- Open the folder in a terminal in which you want to create the app.
- Run:
npx create-next-app
- Choose the following configurations
What is your project named? **frontend**
Would you like to use TypeScript? **Yes**
Would you like to use ESLint? **Yes**
Would you like to use Tailwind CSS? **Yes**
Would you like to use `src/` directory? **Yes**
Would you like to use App Router? (recommended) **Yes**
Would you like to use Turbopack for `next dev`? **Yes**
Would you like to customize the default import alias (@/*)? **No**
- Change the directory to
frontend
using:cd frontend
Use the command npm run dev
to run the Next app on local host, in any step, as required.
Follow the instruction provided by the official NextUI documentation
-
Install the dependencies using:
npm i @nextui-org/react framer-motion
-
Configure
tailwind.config.js
as follows:
import {nextui} from "@nextui-org/react"; // modified
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
"./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}", // modified
],
theme: {
extend: {},
},
plugins: [nextui()], // modified
};
- Create a file -
providers.jsx
inside theapp
directory. Add the following code in the file:
'use client'
import {NextUIProvider} from '@nextui-org/react'
export function Providers({children}) {
return (
<NextUIProvider>
{children}
</NextUIProvider>
)
}
- Add the provider to the
RootLayout
inlayout.js
as follows:
import { Providers } from "./providers";
...
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>
<Providers>
{children}
</Providers>
</body>
</html>
);
}
- Test the implementation: stop and restart the server as we have changed the
tailwind.config.js
file. Clearpage.js
then add a NextUI button as follows:
import {Button} from '@nextui-org/button';
const page = () => {
return (
<div>
<Button>Click me</Button>
</div>
)
}
If a NextUI button appears, we are good to go. Otherwise, re-iterate the process and look into the official docs.
This the file structure we intend to build inside the src
directory:
├───app
│ │ favicon.ico
│ │ globals.css
│ │ layout.js
│ │ page.js
│ │ providers.jsx
│ │
│ └───predict
│ page.jsx
│
└───components
└───Header
Acme.jsx
NavBar.jsx
1. Nav bar: First we will build the Nav bar.
1.1 Create the components
file structure as mentioned above
1.2 Copy the code for Acme.jsx
from here and for NavBar.jsx
from here.
1.3 Import and add this Navbar in layout.js
import { Providers } from "./providers";
import NavBar from "../components/Header/NavBar"
...
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>
<Providers>
<NavBar/>
{children}
</Providers>
</body>
</html>
);
}
2. Landing Page: Modify page.js
in app
directory. For this project I have kept it simple, you can customize it as you like or copy it from me from here.
3. Inference page: For this, implement the logic as explained in the above How it works? section.
Install react-icons
using: npm i react-icons
3.1 Create a file structure for predict
directory as mentioned above.
3.2 Copy and paste the code in page.jsx
inside predict
directory from
here.
Key states in the implementations:
const BASE_URL = "http://107.22.155.211:8000";
const [base64Image, setBase64Image] = useState(null);
const [fileName, setFileName] = useState("default")
const [loading, setLoading] = useState(false);
const [response, setResponse] = useState(null);
Key functions:
1. handleFileChange(event)
: Does the followings
1.1 fetches the first file uploaded from event.target.file
which happens to be an image in our use case.
1.2 Reads the file as a Data URL
using FileReader
class.
1.3 Converts image into a Base64 string and store in a useState
hook.
2. handlePredict()
: Does the followings
2.1 Manages Loading
state.
2.2 Prepare the object to be sent server. Trim the string based on regex.
2.3 Make a POST request using fetch
API to the Django server.
2.4 Manage and handle response and error respectively.
4. Custom pages: I have implemented an extra contact
page. Similarly, you can add any other pages as you like.
Just create a folder by the name of the route and add a page.js
file containing the code for it.
Follow the steps in the next to the next section
- First, fork the repo so you can push the changes into your own repo and eventually, deploy the app on Vercel.
- Use the following command to clone:
git clone [url of your repo]
- Change the directory:
cd UNetR-frontend
- Run the app:
npm run dev
You can also usenpm run build
to examine the final build that will be deployed. Usenpm run start
to serve the build.
Follow the steps in the next section
Deploying on Vercel is pretty easy also it offers a very generous free tier making it a prime choice for our Next app.
-
Push your code into your GitHub
1.1. Check your remote repository, and update if required.
git remote -v
1.2. Add all the changes to stage area:
git add .
1.3. Commit these change:
git commit -m "commit message
1.4. Push these changes:
git push
(if the upstream reference is set for the local and remote branch) orgit push -u [name of your remote repo] [main/master branch]
-
Configure Vercel
2.1. Login in to Vercel, and complete the initial setup. Connect it with your GitHub.
2.2. Add a new project by importing the repo from your GitHub by selecting it from the list of repos.
2.3. Configure the project (change name if required) and click onDeploy
.
2.4. Vercel will build the app for you. The logs can be found in the dashboard. -
Access the frontend with provided domain
-
In this full implementation of the project that is developing the ML model, developing and deploying the frontend and the backend, the project will only work if either the frontend is running on the localhost or if the backend is secured by
https
protocol. This is due toMixed Content
error:Mixed Content: The page at 'https://your-app.vercel.app' was loaded over HTTPS, but requested an insecure resource 'http://your.backend.aws.ip'. This request has been blocked; the content must be served over HTTPS.
While setting up the outbound rules for the backend we opted for a custom TCP protocol which is configured for onlyhttp
request, and forhttps
request we would needSSL/TCL
certificates. You can get these certificates by purchasing a domain and configuring it on AWS. At the moment, I am looking forward to implement SSL certificates viaLet's Encrypt
(link).
The solution would require setting up anNginx
reverse proxy for the Django backend configuring the certificates. -
The complete implementation is valid and just requires an additional Nginx setup.
Feat– feature
Fix– bug fixes
Docs– changes to the documentation like README
Style– style or formatting change
Perf – improves code performance
Test– test a feature