Learn how to quickly get started using fastai, Hugging Face, and Gradio to deploy a demo ML app
This “quick start” is based on the outstanding course by fast.ai: Practical Deep Learning for Coders.
Follow these steps to properly install Python and deploy a demo ML app on Hugging Face, using Gradio.
Here’s my example demo app: tree leaf classifier app (source code)
Install Python using mamba. Anywhere you see instructions for conda
, you can use mamba
instead (it’s faster). Why not pip
? If you’re doing ML, mamba
/conda
makes it easier to have everything you need (including Python), and to optimize packages for your GPU.
# First:
# Install mamba for your machine: https://github.com/conda-forge/miniforge#mambaforge
# Or use this script: https://github.com/fastai/fastsetup/blob/master/setup-conda.sh
# Then:
# Install dependencies
# https://github.com/fastai/fastai/
mamba install -y -c fastchan \
jupyter \
ipywidgets \
notebook \
numpy \
pandas \
pytorch \
fastai \
graphviz
# Start notebook, will auto-open in web browser
jupyter notebook
Personally, I prefer using VSCode for viewing, editing, and running Jupyter Notebooks. So, you can skip that last jupyter notebook
step above.
Go to Hugging Face and create an account.
Then create a new Space and select Gradio (other options: MIT license, Public)
Then git clone
your new space to your local machine, following their instructions.
Next, install the Hugging Face CLI.
mamba install -c fastchan huggingface_hub
# Log in to HF so you can `git push` your changes to your repo
huggingface-cli login
From Practical Deep Learning for Coders, watch lesson 1 and lesson 2 especially.
See train.ipynb
in my demo classifier for reference: https://huggingface.co/spaces/BrianSigafoos/fastai_trees/tree/main
Once you run the model in your code locally, and output the model.pkl
file you’ll be ready to run app.ipynb
, and use that outputted model.
But first, this is a good time to make sure you have git-lfs
set up:
# Install git-lfs
brew install git-lfs
git lfs install
git lfs track "*.pkl"
git add .gitattributes
git commit -m "update .gitattributes so git lfs will track .pkl files"
See app.ipynb
to go from your output model.pkl
to a published classifier app.
Make sure you have nbdev
installed. This will help turn a working Jupyter notebook into an app.py
file that the Hugging Face space will use to power your app using Gradio.
# https://github.com/fastai/nbdev/
mamba install -c fastchan nbdev
Note all the comments that start with #|
in the app.ipynb
file: https://huggingface.co/spaces/BrianSigafoos/fastai_trees/tree/main
Everything with #|export
will be dumped into your app.py
file.
Once you git push
these changes, including the generated app.py
(from the nb_export
cell), you should have your app now published and running on Hugging Face Spaces.
A great Hugging Face feature is the ability to use it’s API backend with your own frontend.
From the bottom of your running app, click “Use the API” to bring up the API instructions. For example, from my demo app: https://briansigafoos-fastai-trees.hf.space/?view=api
Select one or many images of a tree leaves. Ideally, pick of these 5 types of tree leaves that this demo model has been trained on: ash, chestnut, ginkgo biloba, silver maple, or willow oak.
Below is the Javascript (and HTML) that fully powers the demo above, using the Hugging Face backend API to return the results.
<input id="predict_photos" type="file" multiple="" />
<div id="predict_results"></div>
<script>
// Replace with your own HF Space's /predict endpoint
HF_PREDICT_ENDPOINT =
'https://briansigafoos-fastai-trees.hf.space/run/predict/'
async function get_pred(file) {
return new Promise(async (resolve) => {
const reader = new FileReader()
reader.onload = async () => {
data = JSON.stringify({ data: [reader.result] })
post = {
method: 'POST',
body: data,
headers: { 'Content-Type': 'application/json' }
}
const response = await fetch(HF_PREDICT_ENDPOINT, post)
const json = await response.json()
const results = json['data'][0]
const prediction = results['confidences'][0]
const predictionConfidence = parseFloat(
prediction['confidence'] * 100
).toFixed(2)
const altPrediction = results['confidences'][1]
const altPredictionConfidence = parseFloat(
altPrediction['confidence'] * 100
).toFixed(2)
const div = document.createElement('div')
div.innerHTML = `
<img class="prediction" src="${reader.result}" width="300">
<p>
${prediction['label']} - ${predictionConfidence}%
(${altPrediction['label']} - ${altPredictionConfidence}%)
</p>
`
predict_results.append(div)
return resolve(prediction)
}
reader.readAsDataURL(file)
})
}
predict_photos.addEventListener('input', async () => {
predict_results.innerHTML = ''
await Promise.allSettled([...predict_photos.files].map(get_pred))
})
</script>
The snippet above is based on this code in fastai/tinypets
for parallel predictions.