ultralytics / ultralytics

NEW - YOLOv8 πŸš€ in PyTorch > ONNX > OpenVINO > CoreML > TFLite
https://docs.ultralytics.com
GNU Affero General Public License v3.0
24.46k stars 4.86k forks source link

About Dockerfile Big Image Size #8465

Closed SedatUnalCointral closed 1 month ago

SedatUnalCointral commented 3 months ago

Search before asking

Question

Hello everyone, I have an AI model trained using YOLOv8n.pt . I want to turn this model into a web service using FastAPI. I am using Docker. However, whenever I add Ultralytics to the requirements.txt file, the Docker image size becomes 7GB. Is there any way to reduce the size of this Docker image?

Additional

No response

github-actions[bot] commented 3 months ago

πŸ‘‹ Hello @SedatUnalCointral, thank you for your interest in Ultralytics YOLOv8 πŸš€! We recommend a visit to the Docs for new users where you can find many Python and CLI usage examples and where many of the most common questions may already be answered.

If this is a πŸ› Bug Report, please provide a minimum reproducible example to help us debug it.

If this is a custom training ❓ Question, please provide as much information as possible, including dataset image examples and training logs, and verify you are following our Tips for Best Training Results.

Join the vibrant Ultralytics Discord 🎧 community for real-time conversations and collaborations. This platform offers a perfect space to inquire, showcase your work, and connect with fellow Ultralytics users.

Install

Pip install the ultralytics package including all requirements in a Python>=3.8 environment with PyTorch>=1.8.

pip install ultralytics

Environments

YOLOv8 may be run in any of the following up-to-date verified environments (with all dependencies including CUDA/CUDNN, Python and PyTorch preinstalled):

Status

Ultralytics CI

If this badge is green, all Ultralytics CI tests are currently passing. CI tests verify correct operation of all YOLOv8 Modes and Tasks on macOS, Windows, and Ubuntu every 24 hours and on every commit.

glenn-jocher commented 3 months ago

@SedatUnalCointral hello! πŸ‘‹ It's great to hear you're deploying your YOLOv8 model with FastAPI! Docker image sizes can indeed get large, but there are a few strategies you might consider to reduce the size:

  1. Use a smaller base image: If you're using a base image like python:3.8, consider switching to a slimmer version like python:3.8-slim or even python:3.8-alpine. For example:

    FROM python:3.8-slim
  2. Minimize layers: Combine RUN commands and clean up in the same layer to avoid intermediate layer bloat. For instance:

    RUN pip install --no-cache-dir -r requirements.txt && \
       apt-get clean && \
       rm -rf /var/lib/apt/lists/*
  3. Multi-stage builds: You can use multi-stage builds to only keep what you need in the final image. For example, if you need to compile something or have build-time dependencies that aren't needed at runtime:

    FROM python:3.8 as builder
    # Install and build requirements
    
    FROM python:3.8-slim
    COPY --from=builder /app /app
  4. Review your requirements.txt: Sometimes, dependencies can pull in a lot of additional packages. Make sure you only include what you really need. For Ultralytics YOLO, ensure you're using the latest version as we continuously work on optimizations.

Reducing Docker image sizes can be a bit of trial and error, but these strategies should give you a good starting point. Happy coding! πŸš€

SedatUnalCointral commented 3 months ago

Hello @glenn-jocher , first of all, thank you very much for responding :) . I've solved this problem by using slim python and also by removing ultralytics from the requirements.txt file and installing it when fastapi boots up. So;

  1. Dockerfile FROM python:3.12-slim

  2. main.py import os os.system("pip install ultralytics")

As a result, the size of my Docker image decreased from 7GB to 1.65GB.

glenn-jocher commented 3 months ago

Hello @SedatUnalCointral! πŸŽ‰ That's fantastic news! I'm thrilled to hear you've significantly reduced your Docker image size. Using a slim Python image and dynamically installing Ultralytics YOLO at runtime is a clever approach. Your solution not only optimizes the image size but also keeps your setup flexible. Great job, and thank you for sharing your method with the community! If you have any more questions or need further assistance, feel free to reach out. Happy coding! πŸš€

chrismuntean commented 3 months ago

Hello @glenn-jocher , first of all, thank you very much for responding :) . I've solved this problem by using slim python and also by removing ultralytics from the requirements.txt file and installing it when fastapi boots up. So;

1. Dockerfile
   `FROM python:3.12-slim`

2. main.py
   `import os os.system("pip install ultralytics") `

As a result, the size of my Docker image decreased from 7GB to 1.65GB.

Thanks for putting your solution here. I'm gonna do the same thing for my docker image :)

glenn-jocher commented 3 months ago

That's fantastic to hear, @chrismuntean! πŸŽ‰ Your approach to slimming down the Docker image is clever and efficient. Thanks for sharing your solution; it's a great tip for the community. If you have any more insights or questions as you continue your work, don't hesitate to reach out. Happy coding! πŸš€

prajyotpawaratrevergon commented 2 months ago

I am using AWS lambda base image i.e. FROM amazon/aws-lambda-python:3.9 Hence, my Dockerfile looks like this :

FROM amazon/aws-lambda-python:3.9
RUN yum install -y mesa-libGLw
RUN export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python
COPY requirements.txt ${LAMBDA_TASK_ROOT}

RUN --mount=type=cache,target=/root/.cache pip install  -r requirements.txt --target "${LAMBDA_TASK_ROOT}" 
RUN rm -rf /var/lib/apt/lists/*

I am not able to reduce the size from 5.71GB, because even If I put FROM python:3.12-slim I am not able to RUN yum install -y mesa-libGLw Apart from this , my requirements.txt looks like this :

numpy==1.22.2  # Adjust the version range based on compatibility
boto3==1.20.23
boto3-stubs == 1.21.0
aws_lambda_typing==2.9.2
requests==2.25.1
protobuf==4.25.3
pytz == 2023.3
torch == 2.0.1
opencv-python == 4.9.0.80
dateTime == 5.4
pybase64 ==1.3.2
# ultralytics ==8.1.0
typing-extensions == 3.10.0.2

and importing of packages at application.py is following :

import cv2
import numpy as np
import os 
os.system("pip install ultralytics")
# import mediapipe as mp
import boto3
import base64
import json
import torch
import math 
import pytz
from datetime import datetime

Please guide me through this since I am being stuck for longer time than I expected on this issue

glenn-jocher commented 2 months ago

@prajyotpawaratrevergon hello! πŸ‘‹ It looks like you're doing a great job optimizing your Docker image for AWS Lambda. Since you're bound to the AWS Lambda base image and can't switch to python:3.12-slim, let's focus on optimizing within your current setup.

One approach to potentially reduce the image size is to clean up after each yum install command to remove unnecessary cache files. You can modify your RUN yum install -y mesa-libGLw command as follows:

RUN yum install -y mesa-libGLw && yum clean all

Regarding the dynamic installation of ultralytics, it's a clever workaround. However, consider the cold start time implications, as installing packages at runtime can increase the initialization time of your Lambda function.

For your requirements.txt, everything seems in order. Just ensure all packages are necessary for your application to avoid bloating the image with unused dependencies.

Lastly, since you're importing ultralytics dynamically in application.py, ensure that this doesn't lead to unexpected behavior, especially in the AWS Lambda environment where the filesystem is read-only except for the /tmp directory.

If you're still facing issues with image size, consider reviewing each package's necessity in requirements.txt and exploring if any of them have lighter alternatives.

Keep up the great work, and don't hesitate to reach out if you have more questions! πŸš€

github-actions[bot] commented 1 month ago

πŸ‘‹ Hello there! We wanted to give you a friendly reminder that this issue has not had any recent activity and may be closed soon, but don't worry - you can always reopen it if needed. If you still have any questions or concerns, please feel free to let us know how we can help.

For additional resources and information, please see the links below:

Feel free to inform us of any other issues you discover or feature requests that come to mind in the future. Pull Requests (PRs) are also always welcomed!

Thank you for your contributions to YOLO πŸš€ and Vision AI ⭐

Narenk9 commented 2 weeks ago

@glenn-jocher This is my requirements file ultralytics google-cloud-vision streamlit opencv-python pathlib numpy setuptools==69.5.1 wheel==0.43.0 pillow==10.3.0 ipython

I wanted create a docker file for my streamlit web app, but the generated image size is about 9GB!! I need help to reduce the size of image.

glenn-jocher commented 2 weeks ago

@Narenk9 hey there! πŸš€ To help reduce your Docker image size for your Streamlit app, consider using a slimmer base image like python:3.8-slim or python:3.8-alpine. Also, make sure to clean up unnecessary files and cache after package installations. Here's a refined version of a Dockerfile that might help:

FROM python:3.8-slim

RUN apt-get update && apt-get install -y --no-install-recommends \
    libopencv-dev python-opencv && \
    rm -rf /var/lib/apt/lists/*

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .
CMD ["streamlit", "run", "your_app.py"]

This setup uses a slim Python image and cleans up apt cache to reduce the image size. Adjust your actual dependencies as necessary. Hope this helps, and happy coding! πŸ’‘

Narenk9 commented 1 week ago

@glenn-jocher Thank you for replying! Due to dependency issues, I had to stay with python 3.12.3-slim but now my docker image size is about 2.5 GB. Here is the docker file:

# Base image with minimal dependencies
FROM python:3.12.3-slim
# Expose the required port
EXPOSE 8080
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        ffmpeg \
        libsm6 \
        libxext6 && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* && \
    pip install --no-cache-dir \
        numpy \
        pillow && \
    pip install --no-cache-dir \
        ipython\
        opencv-python \
        google-cloud-vision \
        streamlit && \
    pip install --no-cache-dir \
        torch torchvision --index-url https://download.pytorch.org/whl/cpu && \
    pip install --no-cache-dir \
        ultralytics\
        moviepy
# Set the working directory
WORKDIR /app
# Copy the application code
COPY . .
# Command to run the Streamlit app
ENTRYPOINT ["streamlit", "run", "app.py", "–server.port=8080", "–server.address=0.0.0.0", "--server.fileWatcherType", "none"]

I want to deploy the app on GCP cloud run using port 8080.

glenn-jocher commented 1 week ago

Hey @Narenk9! πŸ‘‹ Your Dockerfile looks well-structured and optimized for size given the constraints. Since you're deploying to GCP Cloud Run, the setup seems appropriate. If you're still looking to reduce the image size further, consider multi-stage builds to separate the build environment from the runtime environment, which can help minimize the final image size. Here’s a quick example:

# Build stage for compiling dependencies
FROM python:3.12.3-slim as builder
RUN apt-get update && apt-get install -y --no-install-recommends \
    ffmpeg libsm6 libxext6
RUN pip install --no-cache-dir numpy pillow ipython opencv-python google-cloud-vision streamlit torch torchvision --index-url https://download.pytorch.org/whl/cpu ultralytics moviepy

# Final stage with only necessary binaries and libraries
FROM python:3.12.3-slim
COPY --from=builder /usr/local /usr/local
WORKDIR /app
COPY . .
EXPOSE 8080
ENTRYPOINT ["streamlit", "run", "app.py", "–server.port=8080", "–server.address=0.0.0.0", "--server.fileWatcherType", "none"]

This approach ensures that only the necessary runtime components are included in the final image. Good luck with your deployment on GCP Cloud Run! πŸš€