From 3cb0ddf75022fb0c0aa648bc24fe8cc523d97fc3 Mon Sep 17 00:00:00 2001 From: Alex Norell Date: Tue, 14 Jan 2025 09:07:57 -0800 Subject: [PATCH 1/2] UV Refactor with Docker CPU --- .isort.cfg | 3 - docker/dockerfiles/Dockerfile.onnx.cpu | 116 +++++++++---------- pyproject.toml | 138 +++++++++++++++++++++++ pytest.ini | 3 - requirements/_requirements.txt | 4 +- requirements/requirements.container.txt | 2 + requirements/requirements.gaze.txt | 2 +- requirements/requirements.http.txt | 8 +- requirements/requirements.sdk.http.txt | 4 +- requirements/requirements.yolo_world.txt | 6 +- setup.py | 72 ------------ 11 files changed, 205 insertions(+), 153 deletions(-) delete mode 100644 .isort.cfg create mode 100644 pyproject.toml delete mode 100644 pytest.ini create mode 100644 requirements/requirements.container.txt delete mode 100644 setup.py diff --git a/.isort.cfg b/.isort.cfg deleted file mode 100644 index ccf49f2922..0000000000 --- a/.isort.cfg +++ /dev/null @@ -1,3 +0,0 @@ -[settings] -profile = black -skip = **/__init__.py, **/node_modules/** diff --git a/docker/dockerfiles/Dockerfile.onnx.cpu b/docker/dockerfiles/Dockerfile.onnx.cpu index 707b4c40a5..16f839a898 100644 --- a/docker/dockerfiles/Dockerfile.onnx.cpu +++ b/docker/dockerfiles/Dockerfile.onnx.cpu @@ -1,80 +1,70 @@ -FROM python:3.9 as base - +# Builder stage +FROM python:3.13-slim AS builder ARG DEBIAN_FRONTEND=noninteractive -RUN apt update -y && apt install -y \ - libxext6 \ - libopencv-dev \ - uvicorn \ - python3-pip \ - git \ - libgdal-dev \ - cmake \ +# Install system dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + libxext6 libopencv-dev git libgdal-dev cmake make ninja-build gcc g++ curl \ && rm -rf /var/lib/apt/lists/* -COPY requirements/requirements.sam.txt \ - requirements/requirements.clip.txt \ - requirements/requirements.cpu.txt \ - requirements/requirements.vino.txt \ - requirements/requirements.http.txt \ - requirements/requirements.waf.txt \ - requirements/requirements.gaze.txt \ - requirements/requirements.doctr.txt \ - requirements/requirements.groundingdino.txt \ - requirements/requirements.yolo_world.txt \ - requirements/requirements.transformers.txt \ - requirements/_requirements.txt \ - ./ +WORKDIR /builder -RUN pip3 install --upgrade pip && pip3 install \ - -r _requirements.txt \ - -r requirements.sam.txt \ - -r requirements.clip.txt \ - -r requirements.cpu.txt \ - -r requirements.http.txt \ - -r requirements.waf.txt \ - -r requirements.gaze.txt \ - -r requirements.doctr.txt \ - -r requirements.groundingdino.txt \ - -r requirements.yolo_world.txt \ - -r requirements.transformers.txt \ - jupyterlab \ - "setuptools<=75.5.0" \ - --upgrade \ - && rm -rf ~/.cache/pip +# Copy project configuration +COPY pyproject.toml . +COPY inference inference/ -FROM scratch -ARG TARGETPLATFORM +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ +RUN uv sync --compile-bytecode -COPY --from=base / / +# Install all dependencies using UV +# Using separate commands to better utilize layer caching +RUN uv pip install --upgrade pip && \ + uv pip install . && \ + uv pip install .[clip,container,cpu,doctr,gaze,groundingdino,http,sam,transformers,waf,yolo_world] -WORKDIR /build -COPY . . +# Build wheels +COPY . /builder RUN make create_wheels -RUN pip3 install dist/inference_cli*.whl dist/inference_core*.whl dist/inference_cpu*.whl dist/inference_sdk*.whl "setuptools<=75.5.0" -RUN if [ "${TARGETPLATFORM}" = "linux/amd64" ]; then pip3 install -r requirements/requirements.vino.txt; rm -rf ~/.cache/pip; fi +# Final stage +FROM python:3.13-slim +ARG TARGETPLATFORM +WORKDIR /app + +# Install system dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + libxext6 libopencv-dev git libgdal-dev cmake make ninja-build gcc g++ curl \ + && rm -rf /var/lib/apt/lists/* +COPY --from=ghcr.io/astral-sh/uv:0.5.18 /uv /uvx /bin/ -WORKDIR /notebooks -COPY examples/notebooks . +# Copy and install wheels +COPY --from=builder /builder/dist /tmp/dist +RUN uv pip install --upgrade pip && \ + uv pip install \ + /tmp/dist/inference_cli*.whl \ + /tmp/dist/inference_core*.whl \ + /tmp/dist/inference_cpu*.whl \ + /tmp/dist/inference_sdk*.whl && \ + if [ "${TARGETPLATFORM}" = "linux/amd64" ]; then \ + uv pip install .[vino]; \ + fi WORKDIR /app -COPY inference inference COPY docker/config/cpu_http.py cpu_http.py -ENV VERSION_CHECK_MODE=continuous -ENV PROJECT=roboflow-platform -ENV NUM_WORKERS=1 -ENV HOST=0.0.0.0 -ENV PORT=9001 -ENV WORKFLOWS_STEP_EXECUTION_MODE=local -ENV WORKFLOWS_MAX_CONCURRENT_STEPS=4 -ENV API_LOGGING_ENABLED=True -ENV CORE_MODEL_SAM2_ENABLED=True -ENV CORE_MODEL_OWLV2_ENABLED=True -ENV ENABLE_STREAM_API=True -ENV ENABLE_WORKFLOWS_PROFILING=True -ENV ENABLE_PROMETHEUS=True +ENV API_LOGGING_ENABLED=True \ + CORE_MODEL_OWLV2_ENABLED=True \ + CORE_MODEL_SAM2_ENABLED=True \ + ENABLE_PROMETHEUS=True \ + ENABLE_STREAM_API=True \ + ENABLE_WORKFLOWS_PROFILING=True \ + HOST=0.0.0.0 \ + NUM_WORKERS=1 \ + PORT=9001 \ + PROJECT=roboflow-platform \ + VERSION_CHECK_MODE=continuous \ + WORKFLOWS_MAX_CONCURRENT_STEPS=4 \ + WORKFLOWS_STEP_EXECUTION_MODE=local -ENTRYPOINT uvicorn cpu_http:app --workers $NUM_WORKERS --host $HOST --port $PORT \ No newline at end of file +ENTRYPOINT ["uvicorn", "cpu_http:app", "--workers", "1", "--host", "0.0.0.0", "--port", "9001"] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000..817f21af94 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,138 @@ +[project] +name = "inference-development" +description = "With no prior knowledge of machine learning or device-specific deployment, you can deploy a computer vision model to a range of devices and environments using Roboflow Inference." +authors = [{ name = "Roboflow", email = "help@roboflow.com" }] +requires-python = ">=3.8" +readme = "README.md" +license = { text = "Apache-2.0" } +classifiers = [ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", +] +dynamic = ["version"] + +# Core dependencies +dependencies = [ + "PyYAML~=6.0.0", + "accelerate>=0.25.0,<=0.32.1", + "transformers>=4.41.1", + "pandas>=2.0.0,<2.3.0", + "requests", + "opencv-python>=4.8.1.78,<=4.10.0.84", + "onnxruntime-gpu>=1.15.1,<1.20.0", + "xformers", + "backoff~=2.2.0", + "py-cpuinfo~=9.0.0", + "python-dotenv<=2.0.0", + "pytest", + "einops>=0.7.0,<=0.8.0", + "torchvision>=0.15.0", + "rf-clip==1.1", + "requests_toolbelt", + "numpy<=1.26.4", + "supervision>=0.25.1,<=0.30.0", + "nvidia-ml-py<13.0.0", + "pybase64~=1.0.0", + "pillow", + "aiohttp>=3.9.0,<=3.10.11", + "rich>=13.0.0,<13.10.0", + "httpx>=0.25.1,<0.28.0", + "torch>=2.0.1,<=2.4.0", +] + +[project.optional-dependencies] +cloud_deploy = ["skypilot[aws,gcp]==0.5.0", "cryptography>=43.0.1"] +code_analysis = ["flake8==7.0.0", "black==24.3.0", "isort==5.13.2"] +test-unit = [ + "pytest-timeout>=2.2.0", + "aioresponses>=0.7.6", + "requests-mock==1.11.0", + "pytest-asyncio<=0.21.1", + "uvicorn<=0.22.0", +] +cli = [ + "tqdm>=4.0.0,<5.0.0", + "typer>=0.9.0,<=0.12.5", + "docker>=7.0.0,<8.0.0", + "rich~=13.0.0", +] +container = ["setuptools<76.0.0", "jupyterlab<4.4.0"] +docs = [ + "mkdocs-jupyter", + "mkdocs", + "mistune==2.0.4", + "mike", + "nbconvert==7.7.4", + "mkdocs-literate-nav", + "mkdocs-material", + "cairosvg", + "mkdocs-gen-files", + "mkdocs-ezlinks-plugin", + "mkdocs-swagger-ui-tag", + "mkdocs-macros-plugin", + "mkdocstrings[python]", + "mkdocs-material[imaging]", +] +doctr = ["tf2onnx~=1.16.0", "python-doctr[torch]>=0.7.0,<=0.10.0"] +jetson = ["pypdfium2~=4.0.0", "jupyterlab>=4.3.0,<5.0.0"] +waf = ["metlo>=0.0.17,<=0.1.5"] +transformers = ["timm~=1.0.0", "peft~=0.11.1"] +cpu = ["onnxruntime>=1.15.1,<1.20.0"] +gaze = ["mediapipe>=0.9"] +hosted = ["elasticache_auto_discovery~=1.0.0", "pymemcache~=4.0.0"] +parallel = ["celery>=5.4.0,<6.0.0", "gunicorn~=23.0.0"] +test-integration = ["pytest-retry<=1.6.3"] +sam = ["rasterio~=1.3", "rf-segment-anything==1.0", "samv2==0.0.4"] +vino = ["onnxruntime-openvino>=1.15.0,<1.20.0"] +groundingdino = ["rf_groundingdino==0.2.0"] +cogvlm = ["bitsandbytes<=0.41.3", "sentencepiece<=0.1.99"] +sdk-http = ["dataclasses-json~=0.6.0"] +yolo_world = ["dill<0.4.0", "ultralytics<8.4.0"] +http = [ + "fastapi-cprofile<=0.0.2", + "python-multipart<0.1.0", + "asgi_correlation_id~=4.3.4", + "uvicorn[standard]<1.0.0", + "orjson>=3.9.10,<=3.11.0", +] +pali-flash-attn = ["flash-attn==2.5.9.post1"] + +[project.scripts] +inference = "inference_cli.main:app" + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.version] +path = "inference/core/version.py" +expression = "__version__" + +[tool.hatch.build.targets.wheel] +packages = ["inference"] +exclude = [ + "docker", + "docs", + "requirements", + "tests", + "tests.*", + "development", + "development.*", +] + +[tool.hatch.metadata] +allow-direct-references = true + +[tool.uv] +compile-bytecode = true + +[tool.isort] +profile = "black" +skip = ["**/__init__.py", "**/node_modules/**"] + +[tool.pytest.ini_options] +markers = ["slow: marks tests as slow (deselect with '-m \"not slow\"')"] + +[project.urls] +Homepage = "https://github.com/roboflow/inference" diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 761785364d..0000000000 --- a/pytest.ini +++ /dev/null @@ -1,3 +0,0 @@ -[pytest] -markers = - slow: marks tests as slow (deselect with '-m "not slow"') diff --git a/requirements/_requirements.txt b/requirements/_requirements.txt index c99c7a9f5e..f345eaaca7 100644 --- a/requirements/_requirements.txt +++ b/requirements/_requirements.txt @@ -3,10 +3,10 @@ APScheduler>=3.10.1,<4.0.0 asyncua~=1.1.5 cython~=3.0.0 python-dotenv~=1.0.0 -fastapi>=0.100,<0.111 +fastapi>=0.100 numpy<=1.26.4 opencv-python>=4.8.1.78,<=4.10.0.84 -pillow<11.0 +pillow prometheus-fastapi-instrumentator<=6.0.0 redis~=5.0.0 requests>=2.32.0,<3.0.0 diff --git a/requirements/requirements.container.txt b/requirements/requirements.container.txt new file mode 100644 index 0000000000..9ca2fa2f7f --- /dev/null +++ b/requirements/requirements.container.txt @@ -0,0 +1,2 @@ +jupyterlab<4.4.0 +setuptools<76.0.0 diff --git a/requirements/requirements.gaze.txt b/requirements/requirements.gaze.txt index c7a90b5dcc..e5b938dd81 100644 --- a/requirements/requirements.gaze.txt +++ b/requirements/requirements.gaze.txt @@ -1 +1 @@ -mediapipe>=0.9,<0.11 +mediapipe>=0.9 diff --git a/requirements/requirements.http.txt b/requirements/requirements.http.txt index c61a8eb148..3c912ddb0c 100644 --- a/requirements/requirements.http.txt +++ b/requirements/requirements.http.txt @@ -1,5 +1,5 @@ -uvicorn[standard]<=0.22.0 -python-multipart==0.0.19 +uvicorn[standard]<1.0.0 +python-multipart<0.1.0 fastapi-cprofile<=0.0.2 -orjson>=3.9.10,<=3.10.11 -asgi_correlation_id~=4.3.1 +orjson>=3.9.10,<=3.11.0 +asgi_correlation_id~=4.3.4 diff --git a/requirements/requirements.sdk.http.txt b/requirements/requirements.sdk.http.txt index 3d947edd95..5fabcebf89 100644 --- a/requirements/requirements.sdk.http.txt +++ b/requirements/requirements.sdk.http.txt @@ -1,9 +1,9 @@ requests>=2.32.0,<3.0.0 dataclasses-json~=0.6.0 opencv-python>=4.8.1.78,<=4.10.0.84 -pillow>=9.0.0,<11.0 +pillow>=9.0.0,<12.0.0 supervision>=0.25.1,<=0.30.0 numpy<=1.26.4 -aiohttp>=3.9.0,<=3.10.11 +aiohttp>=3.9.0,<=3.12.0 backoff~=2.2.0 py-cpuinfo~=9.0.0 diff --git a/requirements/requirements.yolo_world.txt b/requirements/requirements.yolo_world.txt index 368b32c280..7748b08d0d 100644 --- a/requirements/requirements.yolo_world.txt +++ b/requirements/requirements.yolo_world.txt @@ -1,3 +1,3 @@ -ultralytics>=8.1.27,<=8.3.40 -dill==0.3.8 -rf-clip==1.1 \ No newline at end of file +ultralytics<8.4.0 +dill<0.4.0 +rf-clip==1.1 diff --git a/setup.py b/setup.py deleted file mode 100644 index abd150c32b..0000000000 --- a/setup.py +++ /dev/null @@ -1,72 +0,0 @@ -import setuptools -from setuptools import find_packages - - -with open("README.md", "r", encoding='utf-8') as fh: - long_description = fh.read() - - -def read_requirements(path): - if not isinstance(path, list): - path = [path] - requirements = [] - for p in path: - with open(p) as fh: - requirements.extend([line.strip() for line in fh]) - return requirements - - -setuptools.setup( - name="inference-development", - author="Roboflow", - author_email="help@roboflow.com", - description="With no prior knowledge of machine learning or device-specific deployment, you can deploy a computer vision model to a range of devices and environments using Roboflow Inference.", - long_description=long_description, - long_description_content_type="text/markdown", - url="https://github.com/roboflow/inference", - packages=find_packages( - where=".", - exclude=( - "docker", - "docs", - "requirements", - "tests", - "tests.*", - "development", - "development.*", - ), - ), - entry_points={ - "console_scripts": [ - "inference=inference_cli.main:app", - ], - }, - install_requires=read_requirements( - [ - "requirements/_requirements.txt", - "requirements/requirements.cpu.txt", - "requirements/requirements.cli.txt", - "requirements/requirements.clip.txt", - "requirements/requirements.http.txt", - "requirements/requirements.sdk.http.txt", - "requirements/requirements.gaze.txt", - "requirements/requirements.groundingdino.txt", - "requirements/requirements.hosted.txt", - "requirements/requirements.waf.txt", - "requirements/requirements.yolo_world.txt", - "requirements/requirements.code_analysis.txt", - "requirements/requirements.test.unit.txt", - "requirements/requirements.test.integration.txt", - "requirements/requirements.transformers.txt", - ] - ), - extras_require={ - "sam": read_requirements("requirements/requirements.sam.txt"), - }, - classifiers=[ - "Programming Language :: Python :: 3", - "License :: OSI Approved :: Apache Software License", - "Operating System :: OS Independent", - ], - python_requires=">=3.8", -) From 89ab81c9444e7e32ad3bf91cb6958796c90cd1f8 Mon Sep 17 00:00:00 2001 From: Alex Norell Date: Tue, 14 Jan 2025 16:41:32 -0800 Subject: [PATCH 2/2] Update python package description Co-authored-by: Thomas Hansen --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 817f21af94..1a3004ac1d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "inference-development" -description = "With no prior knowledge of machine learning or device-specific deployment, you can deploy a computer vision model to a range of devices and environments using Roboflow Inference." +description = "Inference turns any computer or edge device into a command center for your computer vision projects" authors = [{ name = "Roboflow", email = "help@roboflow.com" }] requires-python = ">=3.8" readme = "README.md"