Skip to content

Commit

Permalink
object detection recipe and MS tests
Browse files Browse the repository at this point in the history
Signed-off-by: greg pereira <[email protected]>
Signed-off-by: Gregory-Pereira <[email protected]>
Signed-off-by: greg pereira <[email protected]>
  • Loading branch information
Gregory-Pereira committed May 1, 2024
1 parent d4870e4 commit ebd5b42
Show file tree
Hide file tree
Showing 19 changed files with 258 additions and 39 deletions.
36 changes: 21 additions & 15 deletions .github/workflows/model_servers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,29 @@ jobs:
strategy:
matrix:
include:
- image_name: llamacpp_python
model: granite
# - image_name: llamacpp_python
# model: granite
# flavor: base
# directory: llamacpp_python
# platforms: linux/amd64,linux/arm64
# no_gpu: 1
# - image_name: llamacpp_python_cuda
# model: granite
# flavor: cuda
# directory: llamacpp_python
# platforms: linux/amd64
# cuda: 1
# - image_name: whispercpp
# model: whisper-small
# flavor: base
# directory: whispercpp
# platforms: linux/amd64,linux/arm64
# no_gpu: 1
- image_name: object_detection_python
model: facebook-detr-resnet-101
flavor: base
directory: llamacpp_python
platforms: linux/amd64,linux/arm64
no_gpu: 1
- image_name: llamacpp_python_cuda
model: granite
flavor: cuda
directory: llamacpp_python
directory: object_detection_python
platforms: linux/amd64
cuda: 1
- image_name: whispercpp
model: whisper-small
flavor: base
directory: whispercpp
platforms: linux/amd64,linux/arm64
no_gpu: 1
runs-on: ubuntu-22.04
permissions:
Expand Down
2 changes: 1 addition & 1 deletion model_servers/common/Makefile.common
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ endif

.PHONY: build
build:
podman build --squash-all --build-arg $(PORT) -t $(IMAGE) . -f base/Containerfile
podman build --squash-all --build-arg PORT=$(PORT) -t $(IMAGE) . -f base/Containerfile

.PHONY: install
install:
Expand Down
40 changes: 26 additions & 14 deletions model_servers/object_detection_python/Makefile
Original file line number Diff line number Diff line change
@@ -1,35 +1,47 @@
APP := object_detection_python
PORT ?= 8000

include ../common/Makefile.common
REGISTRY ?= ghcr.io
REGISTRY_ORG ?= containers

IMAGE_NAME ?= $(REGISTRY_ORG)/$(COMPONENT)/$(APP):latest
MODEL_NAME ?= facebook/detr-resnet-101
MODELS_DIR := /app/models

# include ../common/Makefile.common

IMAGE_NAME ?= $(REGISTRY_ORG)/$(APP):latest
IMAGE := $(REGISTRY)/$(IMAGE_NAME)
CUDA_IMAGE := $(REGISTRY)/$(REGISTRY_ORG)/$(COMPONENT)/$(APP)_cuda:latest
VULKAN_IMAGE := $(REGISTRY)/$(REGISTRY_ORG)/$(COMPONENT)/$(APP)_vulkan:latest
# CUDA_IMAGE := $(REGISTRY)/$(REGISTRY_ORG)/$(APP)_cuda:latest
# VULKAN_IMAGE := $(REGISTRY)/$(REGISTRY_ORG)/$(APP)_vulkan:latest

BIND_MOUNT_OPTIONS := ro
OS := $(shell uname -s)
ifeq ($(OS),Linux)
BIND_MOUNT_OPTIONS := Z,ro
endif

MODEL_NAME ?= facebook/detr-resnet-101
MODELS_DIR := /models
.PHONY: build
build:
podman build --squash-all --build-arg PORT=$(PORT) -t $(IMAGE) . -f base/Containerfile

.PHONY: install
install:
pip install -r tests/requirements.txt

.PHONY: run
run:
cd ../../models && \
podman run -it -d -p $(PORT):$(PORT) -v ./$(MODEL_NAME):$(MODELS_DIR)/$(MODEL_NAME):$(BIND_MOUNT_OPTIONS) -e MODEL_PATH=$(MODELS_DIR)/$(MODEL_NAME) -e HOST=0.0.0.0 -e PORT=$(PORT) $(IMAGE)


.PHONY: all
all: build download-model-facebook-detr-resnet-101 run

.PHONY: download-model-facebook-detr-resnet-101
download-model-facebook-detr-resnet-101:
pip install -r ../../convert_models/requirements.txt
cd ../../convert_models/ && \
python3.11 download_huggingface.py -m facebook/detr-resnet-101
cp -r ../../convert_models/converted_models/facebook ../../models/
cd ../../models && \
make download-model-facebook-detr-resnet-101

.PHONY: test
test:
$(MAKE) download-model-facebook-detr-resnet-101
ln -s ../../models/detr-resnet-101 ./
PORT=$(PORT) MODEL_NAME=$(MODEL_NAME) MODELS_PATH=$(MODELS_PATH) IMAGE=$(IMAGE) PULL_ALWAYS=0 pytest -s -vvv
cp -r ../../models/facebook ./
REGISTRY=$(REGISTRY) MODEL_NAME=$(MODEL_NAME) MODELS_DIR=$(MODELS_DIR) IMAGE_NAME=$(IMAGE_NAME) PORT=$(PORT) pytest -s -vvv
5 changes: 2 additions & 3 deletions model_servers/object_detection_python/base/Containerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
FROM registry.access.redhat.com/ubi9/python-311:1-52.1712567218
ARG PORT=8000
WORKDIR /app
COPY src/requirements.txt .
COPY src .
RUN pip install --upgrade pip && \
pip install --no-cache-dir --upgrade -r requirements.txt
COPY src/object_detection_server.py .
EXPOSE $PORT
ENTRYPOINT [ "uvicorn", "object_detection_server:app", "--host", "0.0.0.0" ]
ENTRYPOINT [ "sh", "./run.sh" ]
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@


app = FastAPI()
model = os.getenv("MODEL_PATH", default="facebook/detr-resnet-101")
model = os.getenv("MODEL_PATH", default="/app/models/facebook/detr-resnet-101")
revision = os.getenv("MODEL_REVISION", default="no_timm")

if os.path.isfile(model):
Expand All @@ -30,6 +30,10 @@
class Item(BaseModel):
image: bytes

@app.get("/health")
def tests_alive():
return {"alive": True}

@app.post("/detection")
def detection(item: Item):
b64_image = item.image
Expand Down
10 changes: 10 additions & 0 deletions model_servers/object_detection_python/src/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

if [ ${MODEL_PATH} ]; then
PORT=${PORT} MODEL_PATH=${MODEL_PATH} uvicorn object_detection_server:app --host ${HOST:=0.0.0.0}
exit 0
fi

echo "Please set either a MODEL_PATH"
exit 1

Empty file.
45 changes: 45 additions & 0 deletions model_servers/object_detection_python/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import pytest_container
import os

REGISTRY = os.getenv("REGISTRY", "quay.io")
IMAGE_NAME = os.getenv("IMAGE_NAME", "ai-lab/object_detection_python:latest")
MODEL_NAME = os.getenv("MODEL_NAME", "facebook/detr-resnet-101")
MODELS_DIR = os.getenv("MODELS_DIR", "/app/models")

MODEL_PATH = f"{MODELS_DIR}/{MODEL_NAME}"

PORT = os.getenv("PORT", 8000)
if type(PORT) == str:
try:
PORT = int(PORT)
except:
PORT = 8000

MS = pytest_container.Container(
url=f"containers-storage:{REGISTRY}/{IMAGE_NAME}",
volume_mounts=[
pytest_container.container.BindMount(
container_path=f"{MODEL_PATH}",
host_path=f"./{MODEL_NAME}",
flags=["ro"]
)
],
entry_point="auto",
extra_environment_variables={
"MODEL_PATH": f"{MODEL_PATH}",
"HOST": "0.0.0.0",
"PORT": f"{PORT}"
},
forwarded_ports=[
pytest_container.PortForwarding(
container_port=PORT,
host_port=PORT
)
],
)

def pytest_generate_tests(metafunc):
pytest_container.auto_container_parametrize(metafunc)

def pytest_addoption(parser):
pytest_container.add_logging_level_options(parser)
8 changes: 8 additions & 0 deletions model_servers/object_detection_python/tests/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
pip==24.0
pytest-container==0.4.0
pytest-selenium==4.1.0
pytest-testinfra==10.1.0
pytest==8.1.1
requests==2.31.0
selenium==4.19.0
tenacity==8.2.3
17 changes: 17 additions & 0 deletions model_servers/object_detection_python/tests/test_alive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import pytest_container
from .conftest import MS
# import os

# MODEL_PATH = os.getenv("MODEL_PATH", "/app/models/facebook/detr-resnet-101")

CONTAINER_IMAGES = [MS]

def test_etc_os_release_present(auto_container: pytest_container.container.ContainerData):
assert auto_container.connection.file("/etc/os-release").exists

# def test_model_present(auto_container: pytest_container.container.ContainerData):
# assert auto_container.connection.dir(MODEL_PATH).exists

def test_alive(auto_container: pytest_container.container.ContainerData, host):
# host.run_expect([0],f"curl http://localhost:{PORT}/health",).stdout.strip()
host.run_expect([0],f"curl http://localhost:{auto_container.forwarded_ports[0].host_port}/health",).stdout.strip()
7 changes: 7 additions & 0 deletions models/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ download-model-mistral:
download-model-mistral-code:
$(MAKE) MODEL_NAME=mistral-7b-code-16k-qlora.Q4_K_M.gguf MODEL_URL=https://huggingface.co/TheBloke/Mistral-7B-Code-16K-qlora-GGUF/resolve/main/mistral-7b-code-16k-qlora.Q4_K_M.gguf download-model

.PHONY: download-model-facebook-detr-resnet-101
download-model-facebook-detr-resnet-101:
pip install -r ../convert_models/requirements.txt
cd ../convert_models/ && \
python3 download_huggingface.py -m facebook/detr-resnet-101
cp -r ../convert_models/converted_models/facebook ./

.PHONY: clean
clean:
-rm -f *tmp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import io

st.title("🕵️‍♀️ Object Detection")
endpoint =os.getenv("MODEL_ENDPOINT", default = "http://0.0.0.0:8000")
endpoint =os.getenv("MODEL_ENDPOINT", default = "http://0.0.0.0:8000/detection")
headers = {"accept": "application/json",
"Content-Type": "application/json"}
image = st.file_uploader("Upload Image")
Expand All @@ -27,7 +27,7 @@
img_bytes = bytes_io.getvalue()
b64_image = base64.b64encode(img_bytes).decode('utf-8')
data = {'image': b64_image}
response = requests.post(f'{endpoint}/detection', headers=headers,json=data, verify=False)
response = requests.post(f'{endpoint}', headers=headers,json=data, verify=False)
# parse response and display outputs
response_json = response.json()
image = response_json["image"]
Expand Down
40 changes: 40 additions & 0 deletions recipes/computer_vision/object_detection/app/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
altair==5.3.0
attrs==23.2.0
blinker==1.7.0
cachetools==5.3.3
certifi==2024.2.2
charset-normalizer==3.3.2
click==8.1.7
gitdb==4.0.11
GitPython==3.1.43
idna==3.7
Jinja2==3.1.3
jsonschema==4.21.1
jsonschema-specifications==2023.12.1
markdown-it-py==3.0.0
MarkupSafe==2.1.5
mdurl==0.1.2
numpy==1.26.4
packaging==24.0
pandas==2.2.2
pillow==10.3.0
protobuf==4.25.3
pyarrow==15.0.2
pydeck==0.8.1b0
Pygments==2.17.2
python-dateutil==2.9.0.post0
pytz==2024.1
referencing==0.34.0
requests==2.31.0
rich==13.7.1
rpds-py==0.18.0
six==1.16.0
smmap==5.0.1
streamlit==1.33.0
tenacity==8.2.3
toml==0.10.2
toolz==0.12.1
tornado==6.4
typing_extensions==4.11.0
tzdata==2024.1
urllib3==2.2.1

This file was deleted.

Empty file.
54 changes: 54 additions & 0 deletions recipes/computer_vision/object_detection/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import pytest_container
import pytest
import os
import logging
import platform

if 'PORT' not in os.environ:
PORT = 8000
else:
PORT = os.environ['PORT']
try:
PORT = int(PORT)
except:
PORT = 8000

if 'IMAGE' not in os.environ:
IMAGE = 'ghcr.io/containers/model_servers/object_detection_python:latest'
else:
IMAGE = os.environ['IMAGE']

MODEL_NAME=os.environ['MODEL_NAME']
MODEL_PATH=os.environ['MODEL_PATH']

BIND_MOUNT_OPTIONS = 'ro'

MS = pytest_container.Container(
url=f"containers-storage:{IMAGE}",
volume_mounts=[
pytest_container.container.BindMount(
container_path=f"{MODEL_PATH}",
host_path=f"./{MODEL_NAME}",
flags=[BIND_MOUNT_OPTIONS]
)
],
extra_environment_variables={
"MODEL_NAME": f"{MODEL_NAME}",
"MODEL_PATH": f"{MODEL_PATH}",
"HOST": "0.0.0.0",
"PORT": f"{PORT}"
},
forwarded_ports=[
pytest_container.PortForwarding(
container_port=PORT,
host_port=PORT
)
],
)

def pytest_addoption(parser):
pytest_container.add_logging_level_options(parser)


def pytest_generate_tests(metafunc):
pytest_container.auto_container_parametrize(metafunc)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
pip==24.0
pytest-container==0.4.0
pytest-selenium==4.1.0
pytest-testinfra==10.1.0
pytest==8.1.1
requests==2.31.0
selenium==4.19.0
tenacity==8.2.3
12 changes: 12 additions & 0 deletions recipes/computer_vision/object_detection/tests/test_alive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import pytest_container
from .conftest import MS
import tenacity

CONTAINER_IMAGES = [MS]

def test_etc_os_release_present(auto_container: pytest_container.container.ContainerData):
assert auto_container.connection.file("/etc/os-release").exists

@tenacity.retry(stop=tenacity.stop_after_attempt(5), wait=tenacity.wait_exponential())
def test_alive(auto_container: pytest_container.container.ContainerData, host):
host.run_expect([0],f"curl http://localhost:{auto_container.forwarded_ports[0].host_port}",).stdout.strip()

0 comments on commit ebd5b42

Please sign in to comment.