Deploy ML Model as a Docker Service
Ship a forest fire detection model as a live Docker service on HF Spaces.
Introduction
30 Second Summary
Training a model in a Jupyter notebook is only half the journey. The real challenge is getting that model into people's hands so anyone can use it without installing Python or downloading your code.
In this project, you will take a trained forest fire detection model and deploy it as a live web service inside a Docker container on Hugging Face Spaces. You'll use an AI coding agent to help you write production-grade inference code, Dockerize it, and ship it to a public URL.
What You'll Build
You'll have a public URL where anyone can upload a forest or landscape image and instantly see whether it contains fire, smoke, or neither, along with a Grad-CAM heatmap showing exactly which regions the model focused on to make its decision.
By the end of this project, you'll have:
- A live inference service at a public URL that classifies uploaded images as fire, smoke, or no_fire with confidence percentages for all three classes.
- A Grad-CAM explainability overlay that generates a heatmap on the original image, showing what the model "looked at" to reach its prediction.
- A production Docker container deployed to Hugging Face Spaces, built collaboratively with OpenCode and MiMo V2.5 Pro, reproducible on any machine.
- Secret Mission: Add a prediction history panel that logs the last 10 predictions with timestamps and confidence scores.
Are there any prerequisites?
This project assumes you have a trained FirenetCNN1.h5 model file locally, Docker Desktop installed, a Hugging Face account, and the OpenCode CLI set up with MiMo V2.5 Pro access.
You should also be comfortable with basic Python and Git commands.
Before We Start
Before We Start...
Before diving into code, let's commit to what you're building and why.
You're taking a trained notebook prototype and shipping it as a live, publicly-accessible Docker service, built collaboratively with an AI coding agent.
Set Up the Project Structure and OpenCode
A production ML project lives in a clean file layout, not a monolithic notebook. Separating concerns into distinct files (inference code, dependencies, container config) is what makes a project deployable and maintainable.
In this step, you will create the project directory structure and initialize OpenCode so it can analyze your project and assist with code generation in later steps.
In this step, get ready to:
- Create the project directory with placeholder files and your trained model.
- Initialize OpenCode and confirm MiMo V2.5 Pro is the active model.
- Write pinned dependencies into requirements.txt.
Create the project directory and file structure
Your project needs a dedicated folder with a clear structure that OpenCode can analyze. You will create the directory, add placeholder files for each component, and copy your trained model into it.
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder and move into it by running these commands:
mkdir forest-fire-docker
cd forest-fire-docker
- Create the empty placeholder files by running:
touch app.py requirements.txt Dockerfile README.md
What do these files do?
- app.py will hold the Gradio inference application.
- requirements.txt lists the Python packages your app depends on.
- Dockerfile defines how to package your app into a container.
- README.md will contain metadata for Hugging Face Spaces.
- Copy your trained model file into the project folder by running this command (adjust the source path to where your FirenetCNN1.h5 file is located):
cp [[MODEL_SOURCE_PATH="path/to/your/FirenetCNN1.h5"]] .
- Confirm all your files are in place by running:
ls
You should see app.py, Dockerfile, FirenetCNN1.h5, README.md, and requirements.txt in the output.
Don't see FirenetCNN1.h5?
Make sure the path in the cp command points to the actual location of your trained model file. Common locations include your Downloads folder or the directory where you ran your training notebook.
help me find where my FirenetCNN1.h5 model file is stored on my computer
Initialize OpenCode in the project
OpenCode is an AI coding agent that runs in your terminal. When you initialize it in your project directory, it scans the file structure and creates an AGENTS.md file summarizing the project conventions.
- Launch OpenCode in your project directory by running:
opencode
The OpenCode TUI (terminal user interface) opens and takes over your terminal window. You should see a prompt area at the bottom where you can type commands.
- Check that the model indicator in the TUI header shows MiMo V2.5 Pro as the active model.
- Run the initialization command by typing this into the OpenCode prompt and pressing Enter:
/init
OpenCode scans your project and creates an AGENTS.md file in your project root. You should see a confirmation message in the TUI indicating the file was generated.
What is AGENTS.md?
This file gives OpenCode context about your project structure and conventions. It helps the agent generate code that fits your project layout rather than producing generic boilerplate.
- Exit OpenCode by typing this into the prompt:
/exit
OpenCode not connecting to MiMo V2.5 Pro?
If you see a different model name in the header, your OpenCode configuration may need updating. MiMo Auto is built in as a free-for-limited-time channel, so it should be available with zero configuration.
help me configure OpenCode to use MiMo V2.5 Pro as the active model
Write pinned dependencies to requirements.txt
Pinning exact versions in requirements.txt ensures reproducible builds. This file also tells OpenCode what libraries are available when it generates code in the next step.
- Write the dependency list into requirements.txt by running:
cat << 'EOF' > requirements.txt
tensorflow==2.21.0
gradio==6.20.0
matplotlib
numpy
EOF
Why pin TensorFlow and Gradio versions?
TensorFlow and Gradio are pinned to 2.21.0 and 6.20.0 respectively because these versions are tested and compatible with your model. Unpinned versions could introduce breaking API changes that silently break your inference code.
- Verify the file contents by running:
cat requirements.txt
You should see the four dependencies printed, with TensorFlow and Gradio showing their version pins.
File looks empty or incorrect?
Make sure you copied the entire cat << 'EOF' block including the closing EOF line. The single quotes around EOF prevent the shell from interpreting any special characters inside the block.
help me write content to requirements.txt from my terminal
✔️ Awesome, I've got everything!
Great. Double check you have all five files plus AGENTS.md (six total) in your forest-fire-docker folder by running ls one more time.
ⓧ I'd like to double check the full code
Your requirements.txt should contain exactly this:
tensorflow==2.21.0
gradio==6.20.0
matplotlib
numpy
And running ls in forest-fire-docker/ should show: AGENTS.md, app.py, Dockerfile, FirenetCNN1.h5, README.md, requirements.txt.
Your project structure is locked in and OpenCode knows the lay of the land. Next up, you will use OpenCode to generate the full inference application with Grad-CAM explainability.
Build the Inference App with OpenCode
Your project structure is ready and OpenCode is connected to MiMo V2.5 Pro. Now it is time to build the actual inference application.
Instead of writing every line of code yourself, you will direct the AI agent with a clear, detailed prompt. You review what it produces, understand the key patterns, and iterate if needed. This is the same AI-assisted workflow used in professional ML engineering.
In this step, get ready to:
- Prompt OpenCode to generate a complete Gradio inference app with Grad-CAM visualization.
- Review and understand the key sections of the generated code.
- Test the app locally to confirm predictions and heatmaps work end-to-end.
Prompt OpenCode to generate app.py
A good prompt to an AI coding agent is specific about architecture, not vague about intent. You will tell OpenCode exactly what model file to load, what preprocessing to apply, what visualization to produce, and what UI framework to use.
- Switch back to the OpenCode TUI in your terminal.
- Type the following prompt into the input area and press Enter to submit it:
Create app.py - a Gradio app that loads FirenetCNN1.h5 (a MobileNetV2-based model fine-tuned for 3-class classification: fire, smoke, no_fire). It should accept an image upload, preprocess it to 224x224, run prediction, generate a Grad-CAM heatmap from the last convolutional layer, and return: the class label with confidence, a bar chart of all class probabilities, and the original image with Grad-CAM overlay. Use gr.Interface. Bind the server to 0.0.0.0 on port 7860 for container compatibility.
What happens when you submit this prompt?
OpenCode reads your project files (including requirements.txt and AGENTS.md) for context, then generates the complete app.py file.
The agent will ask for permission to write to app.py. Accept the permission when prompted.
Watch the TUI output as it generates code. This typically takes 15-30 seconds depending on model response time.
- When OpenCode asks for permission to edit app.py, accept it.
- Wait for the agent to finish writing the file. You will see a confirmation in the TUI output.
Prompt length matters
Longer, more specific prompts produce better first-draft code from AI agents. Vague prompts like "make a Gradio app" force multiple rounds of iteration. Investing time in the prompt saves time in review.
Review and understand the key sections
The agent wrote your entire inference app. Before running it, review the generated code to confirm it follows best practices. Open app.py in your editor to inspect it.
- Open app.py in your code editor and check for the following sections.
First, check the model loading section at the top of the file:
# Load model once at startup
MODEL_PATH = "FirenetCNN1.h5"
model = tf.keras.models.load_model(MODEL_PATH)
CLASS_NAMES = ["fire", "no_fire", "smoke"]
IMG_SIZE = (224, 224)
Why load the model at module level?
Loading a TensorFlow model is expensive (several seconds). Placing it at module level means it loads once when the app starts, not every time a user uploads an image.
If the model were loaded inside the prediction function, every single request would wait seconds before returning a result.
Next, look for the generate_gradcam function. The core pattern uses tf.GradientTape to compute gradients:
# Create a model that outputs both conv layer output and predictions
grad_model = tf.keras.Model(
inputs=model.input,
outputs=[last_conv_layer.output, model.output]
)
# Compute gradients
with tf.GradientTape() as tape:
conv_outputs, predictions = grad_model(img_array)
loss = predictions[:, pred_index]
grads = tape.gradient(loss, conv_outputs)
What is Grad-CAM doing here?
Grad-CAM stands for Gradient-weighted Class Activation Mapping. It shows which image regions contributed most to the model's prediction.
The code creates a secondary model that exposes the last convolutional layer's output alongside the final prediction. Then tf.GradientTape computes how much each spatial location in that layer influenced the predicted class. The result is a heatmap you overlay on the original image.
Finally, check the Gradio interface definition at the bottom of the file:
demo = gr.Interface(
fn=predict,
inputs=gr.Image(type="pil", label="Upload Forest/Landscape Image"),
outputs=[
gr.Label(num_top_classes=3, label="Classification"),
gr.Image(type="pil", label="Grad-CAM Visualization"),
],
title="Forest Fire Detection with Explainable AI",
description="Upload an image to classify it as fire, smoke, or no_fire. The Grad-CAM heatmap shows which regions the model focused on for its prediction.",
examples=None,
)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=7860)
What does this Gradio setup do?
gr.Interface wires everything together: an image upload input, a predict function that runs classification and Grad-CAM, and two outputs (a label with confidence scores and the heatmap overlay).
server_name="0.0.0.0" binds to all network interfaces instead of just localhost. This is essential for Docker containers, where the app runs in an isolated network namespace.
Code looks different from what's shown here?
AI agents produce slightly different code each time. The exact variable names or comment wording may differ. What matters is the structure: model loaded at the top, tf.GradientTape used for Grad-CAM, and gr.Interface at the bottom with the correct server binding.
If the generated code is missing a key section or has a different structure, ask OpenCode to fix it: type a follow-up prompt describing what needs to change and press Enter.
help me fix my app.py so it matches the expected structure
Test the app locally
The code looks good on paper. Time to prove it actually works by running it and uploading a real image.
- Open a new terminal in your forest-fire-docker/ directory (keep the OpenCode TUI running in the other terminal).
- Install the project dependencies by running:
pip install -r requirements.txt
What does this install?
This installs tensorflow==2.21.0, gradio==6.20.0, matplotlib, and numpy as specified in your requirements.txt. TensorFlow is the largest package and may take a few minutes to download.
Installation taking a long time or failing?
TensorFlow is a large package (~500MB). Give it a few minutes on slower connections. If you see version resolution errors, make sure your Python version is 3.10 or higher (TensorFlow 2.21.0 requires it).
help me fix my pip install errors for this project
Before you run the app, what do you think will happen when you execute python app.py? Will it start immediately, or will there be a noticeable delay?
- Start the app by running:
python app.py
You will see a short delay as TensorFlow loads the model into memory. Then Gradio prints a local URL.
- Open your browser and navigate to http://localhost:7860.
- Upload a test image (any forest or landscape photo from your computer).
- Check that you see two outputs: a classification label with confidence percentages for all three classes, and a Grad-CAM heatmap overlaid on your image.
What should I see?
The Gradio interface shows an image upload area on the left. After you upload, the right side displays a classification bar (fire, no_fire, smoke with percentage confidence) and the same image with a colored heatmap overlay showing what the model focused on.
The heatmap uses warm colors (red, yellow) to highlight regions that contributed most to the prediction. Cool colors (blue) indicate areas the model largely ignored.
App not loading or prediction failing?
If the terminal shows an error about FirenetCNN1.h5 not found, make sure the model file is in the same directory where you ran python app.py.
If you see a shape mismatch error during prediction, the model expects 224x224 RGB images. Confirm the preprocess_image function resizes to (224, 224) before prediction.
help me debug my Gradio app that is not working
✔️ Awesome, I've got everything!
Great. Make sure the app is still running in your terminal for now. You can stop it later with Ctrl+C when you are ready to move to the next step.
ⓧ I'd like to double check the full code
Open app.py and confirm these sections are present in order:
- Imports: numpy, tensorflow, matplotlib.cm, gradio, PIL.Image.
- Model loading: MODEL_PATH = "FirenetCNN1.h5" with tf.keras.models.load_model() at module level.
- Constants: CLASS_NAMES = ["fire", "no_fire", "smoke"] and IMG_SIZE = (224, 224).
- preprocess_image() function: resizes to 224x224, normalizes to [0,1], expands dims.
- generate_gradcam() function: finds last Conv2D layer, uses tf.GradientTape to compute heatmap.
- overlay_heatmap() function: applies jet colormap and blends with original image.
- predict() function: returns confidences dict and gradcam_image.
- gr.Interface with gr.Image input and gr.Label + gr.Image outputs.
- demo.launch(server_name="0.0.0.0", server_port=7860) inside if __name__ == "__main__".
If any section is missing, ask OpenCode to add it by typing a follow-up prompt describing what is needed.
Your inference app is running locally and producing real predictions with explainable heatmaps. Next up, you will wrap this app in a Docker container so it can run identically on any machine.
Dockerize the App
Your app runs locally, which proves the code works. But if you wanted to share this with a colleague or deploy it anywhere else, they would need to install Python, TensorFlow, and all the same dependencies. Docker solves this by packaging everything into a single container that runs identically on any machine.
In this step, you will containerize your app and iterate on the Dockerfile until it is production-ready for Hugging Face Spaces. Along the way, you will hit a real deployment gotcha that trips up even experienced engineers: slim Docker images are missing system libraries your Python packages depend on.
In this step, get ready to:
- Prompt OpenCode to generate a Dockerfile for your app.
- Build and run the Docker container, hitting a missing library error.
- Harden the Dockerfile for Hugging Face Spaces and verify it works.
Prompt OpenCode to create a basic Dockerfile
You will ask OpenCode to generate a simple, naive Dockerfile first. This is how you would naturally start when containerizing any app for the first time.
- Switch back to the OpenCode TUI in your terminal.
- Enter this prompt:
Create a Dockerfile using python:3.10-slim base image. Install requirements.txt, copy the app code and model, expose port 7860, and run app.py.
- Review what OpenCode generates. It should produce something similar to this basic Dockerfile:
FROM python:3.10-slim
WORKDIR /app
# Install Python dependencies
COPY requirements.txt .
RUN pip install -r requirements.txt
# Copy application code and model
COPY . .
EXPOSE 7860
CMD ["python", "app.py"]
What does this Dockerfile do?
This is a minimal containerization: start from a Python base image, install your pip dependencies, copy everything in, and run the app. It looks reasonable, but slim Docker images strip out system libraries to save space.
Your Python packages (TensorFlow, Gradio, matplotlib) depend on system-level shared libraries that exist on your local machine but are missing inside python:3.10-slim.
- Save the Dockerfile that OpenCode generated (or create it manually with the content above).
Build and run the container
Time to build the image and see what happens when you try to run the app inside a container.
- Build the Docker image by running this command:
docker build -t forest-fire-app .
What does this command do?
The -t forest-fire-app flag tags the image with the name forest-fire-app so you can reference it easily. The . tells Docker to use the current directory as the build context.
The build will take a few minutes because TensorFlow is a large package. Once it finishes, you will see a success message.
- Before you run the container, predict: do you think the app will start successfully, or will something go wrong?
- Run the container by executing:
docker run -p 7860:7860 forest-fire-app
The container crashes. You will see an error in the terminal about a missing shared library file. The app cannot start because the slim base image is missing system libraries that your Python packages need at runtime.
Why does it crash?
The python:3.10-slim image removes non-essential system packages to keep the image small. Libraries like TensorFlow and matplotlib link against shared objects (libGL, libglib) that exist on your local machine but are stripped from the slim image.
This is one of the most common Docker deployment issues for ML applications. It works on your machine because those system libraries are already installed. Inside the container, they do not exist.
- Press Ctrl+C to stop the crashed container.
Upgrade the Dockerfile for production and rebuild
The naive Dockerfile fails locally and also does not meet Hugging Face Spaces requirements. HF Spaces Docker containers must run as a non-root user with UID 1000 for security.
- Switch back to the OpenCode TUI and enter this prompt:
The app crashes in the container because of missing system libraries. Fix the Dockerfile: add apt-get install for libgl1-mesa-glx and libglib2.0-0, create a non-root user with UID 1000 (required by Hugging Face Spaces), set WORKDIR to /app, use --chown=user on COPY commands, add GRADIO_SERVER_NAME and GRADIO_SERVER_PORT environment variables, and use --no-cache-dir on pip install.
- Review the updated Dockerfile OpenCode generates. It should now include system dependencies, a non-root user, and proper environment variables. Replace your Dockerfile with the following production-ready version:
FROM python:3.10-slim
# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
libgl1-mesa-glx \
libglib2.0-0 \
&& rm -rf /var/lib/apt/lists/*
# Create non-root user (required by HF Spaces)
RUN useradd -m -u 1000 user
WORKDIR /app
# Install Python dependencies
COPY --chown=user requirements.txt .
RUN pip install --no-cache-dir --upgrade -r requirements.txt
# Copy application code and model
COPY --chown=user . /app
# Switch to non-root user
USER user
ENV HOME=/home/user \
PATH=/home/user/.local/bin:$PATH \
GRADIO_SERVER_NAME=0.0.0.0 \
GRADIO_SERVER_PORT=7860
EXPOSE 7860
CMD ["python", "app.py"]
What changed in the production Dockerfile?
- System dependencies: libgl1-mesa-glx and libglib2.0-0 provide the shared libraries TensorFlow and matplotlib need at runtime.
- Non-root user: HF Spaces runs containers as UID 1000. Creating the user yourself avoids permission errors during deployment.
- Environment variables: GRADIO_SERVER_NAME=0.0.0.0 ensures Gradio binds to all network interfaces inside the container, reinforcing the server_name setting in your code.
- Cache cleanup: rm -rf /var/lib/apt/lists/* and --no-cache-dir keep the final image as small as possible.
- Save the Dockerfile.
- Rebuild the image by running:
docker build -t forest-fire-app .
The build will take a few minutes again because it needs to install system packages and pip dependencies in the new image layers.
- Once the build completes, run the container:
docker run -p 7860:7860 forest-fire-app
This time, you should see Gradio log output in the terminal indicating the server has started on port 7860.
- Open your browser and navigate to http://localhost:7860.
- Upload a test image and confirm you get a classification result with confidence scores and a Grad-CAM heatmap overlay.
App still crashing or not loading?
- Check the terminal output for error messages. If you still see a missing library error, make sure the apt-get install line in your Dockerfile matches exactly what is shown above.
- If the build fails with a network error, ensure Docker Desktop is running and has internet access.
- If the page loads but predictions fail, check that FirenetCNN1.h5 is in the same directory as your Dockerfile. The COPY . /app command includes all files in the build context.
Help me debug my Docker container
✔️ Awesome, I've got everything!
Great. Double check you have saved your Dockerfile and that the container is running successfully at http://localhost:7860.
ⓧ I'd like to double check the full code
Here is the complete Dockerfile you should have:
FROM python:3.10-slim
# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
libgl1-mesa-glx \
libglib2.0-0 \
&& rm -rf /var/lib/apt/lists/*
# Create non-root user (required by HF Spaces)
RUN useradd -m -u 1000 user
WORKDIR /app
# Install Python dependencies
COPY --chown=user requirements.txt .
RUN pip install --no-cache-dir --upgrade -r requirements.txt
# Copy application code and model
COPY --chown=user . /app
# Switch to non-root user
USER user
ENV HOME=/home/user \
PATH=/home/user/.local/bin:$PATH \
GRADIO_SERVER_NAME=0.0.0.0 \
GRADIO_SERVER_PORT=7860
EXPOSE 7860
CMD ["python", "app.py"]
Your containerized ML service now runs exactly the same way on any machine with Docker installed. Next up, you will deploy this container to Hugging Face Spaces and get a live public URL anyone can access.
Deploy to Hugging Face Spaces
Your Docker container runs perfectly on your machine. Anyone who wants to try your model would need Docker installed, your image, and the patience to build it themselves.
Deploying to Hugging Face Spaces gives you a public URL that anyone can visit in their browser. No installs, no setup. This is the actual production delivery that ML engineers do.
In this step, get ready to:
- Create a Hugging Face Space with the Docker SDK.
- Push your project files to the Space repository.
- Verify the live app at a public URL.
Create the Hugging Face Space and clone it locally
Hugging Face Spaces are Git repositories that auto-build your app whenever you push. You will create a new Space, clone it, and copy your project files into it.
- Open your browser and go to huggingface.co/new-space.
- Enter forest-fire-detection as the Space name.
- Select Docker as the SDK.
- Set visibility to Public.
- Click Create Space.
Docker Spaces require a paid plan
Hugging Face requires a PRO plan ($9/month) for personal accounts to create Docker Spaces. If you do not have a PRO plan, you will be prompted to upgrade before the Space is created.
Free personal accounts can host up to 2 Gradio Spaces on ZeroGPU, but Docker Spaces run on compute and require a paid plan.
Now clone the empty Space repository to your Desktop so you can add your project files.
- Open your terminal and move to your Desktop by running this command:
cd ~/Desktop
- Clone the Space repo by running this command:
git clone https://huggingface.co/spaces/[[HF_USERNAME="your-huggingface-username"]]/forest-fire-detection
What does cloning a Space do?
Hugging Face Spaces are Git repositories. Cloning creates a local copy you can push files to. Every push triggers an automatic Docker build on Hugging Face's servers.
- Hugging Face will prompt you for credentials. Enter your Hugging Face username and an access token (you can create one from your HF Settings page under Access Tokens).
Next, copy your project files from the forest-fire-docker folder into the cloned Space repo.
- Copy the core project files into the Space by running these commands:
cp forest-fire-docker/app.py forest-fire-detection/
cp forest-fire-docker/requirements.txt forest-fire-detection/
cp forest-fire-docker/Dockerfile forest-fire-detection/
cp forest-fire-docker/FirenetCNN1.h5 forest-fire-detection/
- Confirm the files are in the Space folder by running:
ls forest-fire-detection/
You should see app.py, requirements.txt, Dockerfile, and FirenetCNN1.h5 listed.
Don't see the files?
Make sure both forest-fire-docker and forest-fire-detection folders are on your Desktop. If the clone failed, check that your Hugging Face username and token are correct.
Help me troubleshoot copying files to my Space repo.
Configure the Space README.md metadata
Hugging Face Spaces use YAML frontmatter in the README.md file to configure how the Space builds and runs. This is where you tell HF to use Docker and which port your app listens on.
- Move into the Space directory by running:
cd forest-fire-detection
- Replace the contents of README.md with the following deployment configuration. Open README.md in your editor and paste this:
---
title: Forest Fire Detection
emoji: 🔥
colorFrom: red
colorTo: orange
sdk: docker
app_port: 7860
---
# Forest Fire Detection with Explainable AI
A production ML service that classifies forest/landscape images as **fire**, **smoke**, or **no_fire** using a fine-tuned MobileNetV2 model. Includes Grad-CAM visualization for model explainability.
## Model Details
- Architecture: MobileNetV2 (transfer learning)
- Classes: fire, smoke, no_fire
- Input: 224x224 RGB images
- Accuracy: 82% on test set (405 images)
What does the YAML frontmatter do?
- sdk: docker tells Hugging Face to build your Dockerfile instead of using a built-in Gradio or Streamlit runtime.
- app_port: 7860 tells HF which port your app listens on, matching the EXPOSE 7860 in your Dockerfile.
- The title, emoji, colorFrom, and colorTo fields control how the Space appears on your profile page.
- Save README.md.
Your model file FirenetCNN1.h5 is larger than 10MB, so Hugging Face requires Git LFS to track it. Set up LFS before committing.
- Initialize Git LFS and track the model file by running these commands:
git lfs install
git lfs track "*.h5"
- Now commit and push everything to the Space by running:
git add .
git commit -m "Deploy forest fire detection model"
git push
You should see Git upload your files including the LFS-tracked model. The push output confirms the files reached Hugging Face.
Push rejected for files larger than 10 MiB?
This means Git LFS is not properly tracking FirenetCNN1.h5. Make sure you ran git lfs install and git lfs track "*.h5" before git add. If you already committed without LFS, remove the file from git tracking and re-add it after setting up LFS.
Help me fix Git LFS tracking for my model file.
Space repo storage limits
Hugging Face Space repositories have a 1 GB storage cap. Your model file needs to fit within this limit. If your FirenetCNN1.h5 file is very large (hundreds of MB), consider hosting it in a separate HF model repository and downloading it at runtime instead.
Monitor the build and verify the live app
After pushing, Hugging Face automatically builds your Docker image in the cloud. You can watch it happen in real time.
- Open your Space page in the browser at:
https://huggingface.co/spaces/[[HF_USERNAME="your-huggingface-username"]]/forest-fire-detection
- Click the Logs button to watch the Docker build output.
- Wait for the build to complete. This typically takes 3-5 minutes because TensorFlow is a large dependency.
What am I looking for in the logs?
You will see each Dockerfile step execute: installing system packages, creating the user, installing Python dependencies, and copying your files. When the build succeeds, the status changes from Building to Running.
Before you test the live app, predict: do you expect the exact same behavior you saw locally, or might something differ in the cloud environment?
- Once the status shows Running, upload a test image directly in the Space interface.
- Verify you see a classification result with confidence scores and a Grad-CAM heatmap overlay.
You should see the same three-class prediction (fire, smoke, no_fire) with confidence percentages, plus the colored heatmap showing which image regions the model focused on. The app behaves identically to your local Docker test.
Space stuck on Building or showing an error?
Check the Logs tab for the exact error. Common causes:
- Missing sdk: docker in your README.md frontmatter. Double check the YAML block starts with --- and ends with ---.
- The model file did not upload correctly. Check that FirenetCNN1.h5 shows as an LFS file in the Space's file list (it should display a file size, not a pointer).
- TensorFlow install timed out. Retry by clicking Restart in the Space settings.
Help me debug my Hugging Face Space build failure.
✔️ Awesome, I've got everything!
Great. Double check you have saved README.md and that your Space status shows Running.
ⓧ I'd like to double check the full code
Your README.md in the Space repo should contain exactly this:
---
title: Forest Fire Detection
emoji: 🔥
colorFrom: red
colorTo: orange
sdk: docker
app_port: 7860
---
# Forest Fire Detection with Explainable AI
A production ML service that classifies forest/landscape images as **fire**, **smoke**, or **no_fire** using a fine-tuned MobileNetV2 model. Includes Grad-CAM visualization for model explainability.
## Model Details
- Architecture: MobileNetV2 (transfer learning)
- Classes: fire, smoke, no_fire
- Input: 224x224 RGB images
- Accuracy: 82% on test set (405 images)
Your Space should also contain the exact same app.py, requirements.txt, Dockerfile, and FirenetCNN1.h5 that you tested locally in the previous step. No changes were made to those files.
You now have a live, publicly-accessible ML service. Anyone with the URL can classify forest images in their browser without installing anything. Next, you will take on the Secret Mission to add even more production-grade features.
Secret mission
Add Prediction History with Timestamps
Production ML services need observability. Can you add a prediction history panel that logs the last 10 predictions with timestamps and confidence scores? This requires refactoring your app from gr.Interface to gr.Blocks and managing session-level state.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs on Hugging Face's free tier, so there are no ongoing costs for leaving the Space live.
Resources you used:
- Hugging Face Space (forest-fire-detection) running your Docker container.
- Local Docker image (forest-fire-app), approximately 2-3GB on disk.
- Local project folder (forest-fire-docker/) on your Desktop.
Keep everything running
No action needed. Choose this if you are still actively building or want your live URL to remain accessible.
- Your Hugging Face Space stays live indefinitely on the free tier at no cost. Anyone with the URL can use it.
- Your local Docker image stays cached for fast rebuilds.
- Your project files remain on your Desktop ready for further development.
Pause - I'll come back to this later
Shut down local processes to free up memory while keeping all your files and the Space intact.
- Stop any running Docker containers by pressing Ctrl+C in the terminal where the container is running.
- Your Hugging Face Space stays live on the free tier. No pause action is needed since there is no cost.
- Your local project files and Docker image remain on disk for when you return.
Delete - I don't want to use this again
Remove all project resources and start fresh. This cannot be undone.
- Delete the Hugging Face Space:
- Open your Space page at huggingface.co/spaces/YOUR_USERNAME/forest-fire-detection.
- Click the three-dot menu near the top of the page.
- Click Settings.
- Scroll to the bottom and click Delete this Space.
- Confirm by clicking I understand, delete this space.
Remove the local Docker image by running:
docker rmi forest-fire-app
Delete the local project folder:
macOS
rm -rf ~/Desktop/forest-fire-docker
Windows
rmdir /s /q %USERPROFILE%\Desktop\forest-fire-docker
That's a Wrap!
That's a Wrap!
Nice work! You just took a trained model from a Jupyter Notebook and shipped it as a live, publicly-accessible production service that anyone can use from their browser.
You've learned how to:
- Build a Dockerized Gradio application with image classification and Grad-CAM explainability, turning a notebook prototype into a production-structured Python project.
- Use OpenCode with MiMo V2.5 Pro as an AI coding agent to write, debug, and iterate on production code collaboratively.
- Deploy a live ML service on Hugging Face Spaces inside a Docker container, solving real container networking issues like host binding along the way.
- Secret Mission: Added session-level prediction history with timestamps using Gradio Blocks and State.
Ready to quiz yourself?