From c0cf12c74a6c9257939261a4e2394be330a83d46 Mon Sep 17 00:00:00 2001 From: Onuralp SEZER Date: Wed, 6 Aug 2025 03:55:52 +0300 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=F0=9F=9A=80=20add=20YOLOv8s=20Worl?= =?UTF-8?q?dV2=20deployment=20workflow=20and=20model=20predictor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/yolov8s-worldv2-push.yml | 68 ++++++++++++++++++++++ yolov8s-worldv2/README.md | 30 ++++++++++ yolov8s-worldv2/cog.yaml | 20 +++++++ yolov8s-worldv2/predict.py | 53 +++++++++++++++++ 4 files changed, 171 insertions(+) create mode 100644 .github/workflows/yolov8s-worldv2-push.yml create mode 100644 yolov8s-worldv2/README.md create mode 100644 yolov8s-worldv2/cog.yaml create mode 100644 yolov8s-worldv2/predict.py diff --git a/.github/workflows/yolov8s-worldv2-push.yml b/.github/workflows/yolov8s-worldv2-push.yml new file mode 100644 index 0000000..2886b77 --- /dev/null +++ b/.github/workflows/yolov8s-worldv2-push.yml @@ -0,0 +1,68 @@ +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + +name: Push YOLOv8s WorldV2 to Replicate + +on: + push: + branches: [main] + paths: + - yolov8s-worldv2/** + pull_request: + branches: [main] + paths: + - yolov8s-worldv2/** + workflow_dispatch: + +jobs: + build_test_push: + name: Build, Test & Push Model + runs-on: ubuntu-latest + steps: + #- name: Cleanup disk space + # uses: ultralytics/actions/cleanup-disk@main + + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: 3.12 + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + + - name: Install dependencies + run: uv pip install --system ultralytics --extra-index-url https://download.pytorch.org/whl/cpu + + - name: Setup Cog + uses: replicate/setup-cog@v2 + with: + token: ${{ secrets.REPLICATE_API_TOKEN }} + + - name: Download YOLOv8s WorldV2 weights + run: | + python << 'EOF' + from ultralytics import YOLOWorld + model = YOLOWorld('yolov8s-worldv2.pt') + EOF + ls -la yolov8s-worldv2* + mv yolov8s-worldv2.pt yolov8s-worldv2/ + echo "Files in yolov8s-worldv2 directory:" + ls -la yolov8s-worldv2/ + + - name: Build model image + run: | + cd yolov8s-worldv2 + cog build + + - name: Test model + run: | + cd yolov8s-worldv2 + cog predict -i image=@../assets/bus.jpg -i conf=0.25 -i iou=0.45 + + - name: Push to Replicate + if: github.ref == 'refs/heads/main' + run: | + cd yolov8s-worldv2 + cog push diff --git a/yolov8s-worldv2/README.md b/yolov8s-worldv2/README.md new file mode 100644 index 0000000..6ca8df1 --- /dev/null +++ b/yolov8s-worldv2/README.md @@ -0,0 +1,30 @@ +# YOLOv8s WorldV2 Demo Deployment + +Deploy the official YOLOv8s WorldV2 model to Replicate with PyTorch inference at https://replicate.com/ultralytics/yolov8s-worldv2. + +## Setup + +1. **Deploy to Replicate:** + + ```bash + cog push r8.im/ultralytics/yolov8s-worldv2 + ``` + +## Model Details + +- **Model**: YOLOv8s WorldV2 (Small) +- **Parameters**: 12.7M +- **Format**: PyTorch (.pt) +- **Use Case**: Demonstration of official Ultralytics model deployment + +## Model Files + +**Note:** The model weights (`yolov8s-worldv2.pt`) will be automatically downloaded by ultralytics when the container starts. + +## Configuration + +- **GPU**: Disabled by default (CPU inference) +- **Python**: 3.12 with PyTorch 2.3.1+ +- **Framework**: Ultralytics 8.3+ +- **Input**: Single image with configurable confidence/IoU thresholds +- **Output**: Annotated image with detected objects diff --git a/yolov8s-worldv2/cog.yaml b/yolov8s-worldv2/cog.yaml new file mode 100644 index 0000000..6fa0ea0 --- /dev/null +++ b/yolov8s-worldv2/cog.yaml @@ -0,0 +1,20 @@ +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + +build: + gpu: false + python_version: "3.12" + system_packages: + - "libgl1-mesa-glx" + - "libglib2.0-0" + - "ffmpeg" + python_packages: + - "ultralytics>=8.3.0" + - "torch==2.3.1" + - "torchvision" + - "numpy>=1.24.0" + - "opencv-python" + - "pillow" + - "clip @ git+https://github.com/ultralytics/CLIP.git@main#egg=clip" + +predict: predict.py:Predictor +image: r8.im/ultralytics/yolov8s-worldv2 diff --git a/yolov8s-worldv2/predict.py b/yolov8s-worldv2/predict.py new file mode 100644 index 0000000..7293a04 --- /dev/null +++ b/yolov8s-worldv2/predict.py @@ -0,0 +1,53 @@ +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + +import json +from typing import Optional +from ultralytics import YOLOWorld +from cog import BasePredictor, Input, Path, BaseModel + + +class Output(BaseModel): + """ Output model for predictions.""" + + image: Optional[Path] = None + json_str: Optional[str] = None + + +class Predictor(BasePredictor): + """YOLOv8s WorldV2 model predictor for Replicate deployment.""" + + def setup(self) -> None: + """Load YOLOWorld model into memory.""" + self.model = YOLOWorld("yolov8s-worldv2.pt") + + def re_init_model(self, class_names: str) -> None: + """Re-Initialize model with class names.""" + self.model = YOLOWorld("yolov8s-worldv2.pt") + class_list = class_names.split(", ") + self.model.set_classes(class_list) + + def predict( + self, + image: Path = Input(description="Input image"), + conf: float = Input(description="Confidence threshold", default=0.25, ge=0.0, le=1.0), + iou: float = Input(description="IoU threshold for NMS", default=0.45, ge=0.0, le=1.0), + imgsz: int = Input(description="Image size", default=640, choices=[320, 416, 512, 640, 832, 1024, 1280]), + class_names: str = Input( + description="Comma-separated list of class names to filter results (e.g., 'person, bus, sign') You can also leave it empty to detect classes automatically.", + default="person, bus, sign", + ), + return_json: bool = Input(description="Return detection results as JSON", default=False), + ) -> Output: + """Run inference and return annotated image with optional JSON results.""" + self.re_init_model(class_names) + result = self.model(str(image), conf=conf, iou=iou, imgsz=imgsz)[0] + image_path = "output.png" + result.save(image_path) + + if return_json: + return Output( + image=Path(image_path), + json_str=result.to_json() + ) + else: + return Output(image=Path(image_path)) From bb0283566fcba5be4c8254e9ceae7d4a65ede369 Mon Sep 17 00:00:00 2001 From: UltralyticsAssistant Date: Wed, 6 Aug 2025 00:57:00 +0000 Subject: [PATCH 2/4] Auto-format by https://ultralytics.com/actions --- yolo11n/predict.py | 9 +++------ yolov8s-worldv2/predict.py | 11 ++++------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/yolo11n/predict.py b/yolo11n/predict.py index 4d80c42..3f23445 100644 --- a/yolo11n/predict.py +++ b/yolo11n/predict.py @@ -1,9 +1,9 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license -import json from typing import Optional + +from cog import BaseModel, BasePredictor, Input, Path from ultralytics import YOLO -from cog import BasePredictor, Input, Path, BaseModel class Output(BaseModel): @@ -32,9 +32,6 @@ def predict( result.save(image_path) if return_json: - return Output( - image=Path(image_path), - json_str=result.to_json() - ) + return Output(image=Path(image_path), json_str=result.to_json()) else: return Output(image=Path(image_path)) diff --git a/yolov8s-worldv2/predict.py b/yolov8s-worldv2/predict.py index 7293a04..3288bb8 100644 --- a/yolov8s-worldv2/predict.py +++ b/yolov8s-worldv2/predict.py @@ -1,13 +1,13 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license -import json from typing import Optional + +from cog import BaseModel, BasePredictor, Input, Path from ultralytics import YOLOWorld -from cog import BasePredictor, Input, Path, BaseModel class Output(BaseModel): - """ Output model for predictions.""" + """Output model for predictions.""" image: Optional[Path] = None json_str: Optional[str] = None @@ -45,9 +45,6 @@ def predict( result.save(image_path) if return_json: - return Output( - image=Path(image_path), - json_str=result.to_json() - ) + return Output(image=Path(image_path), json_str=result.to_json()) else: return Output(image=Path(image_path)) From 7548f1f32aafbac672591ec5b51c34c87d08900e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 6 Aug 2025 20:48:10 +0200 Subject: [PATCH 3/4] Update push.yml Signed-off-by: Glenn Jocher --- .github/workflows/push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index f1fba58..eda90a9 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -31,7 +31,7 @@ jobs: uses: replicate/setup-cog@v2 with: token: ${{ secrets.REPLICATE_API_TOKEN }} - - name: Download YOLO11n weights + - name: Download model weights run: python ${{ matrix.model }}/download.py - name: Build model image working-directory: ${{ matrix.model }} From 7ffb2c08bc92e9b5b8294f0b53f49d92115f9a3a Mon Sep 17 00:00:00 2001 From: Onuralp SEZER Date: Thu, 7 Aug 2025 10:23:36 +0300 Subject: [PATCH 4/4] =?UTF-8?q?feat:=20=F0=9F=9A=80=20update=20YOLOv8s=20W?= =?UTF-8?q?orldV2=20workflow=20and=20add=20download=20script?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Onuralp SEZER --- .github/workflows/push.yml | 2 +- .github/workflows/yolov8s-worldv2-push.yml | 68 ---------------------- yolov8s-worldv2/cog.yaml | 5 -- yolov8s-worldv2/download.py | 20 +++++++ 4 files changed, 21 insertions(+), 74 deletions(-) delete mode 100644 .github/workflows/yolov8s-worldv2-push.yml create mode 100644 yolov8s-worldv2/download.py diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index eda90a9..f78f7df 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - model: [yolo11n] + model: [yolo11n,yolov8s-worldv2] steps: - name: Checkout uses: actions/checkout@v4 diff --git a/.github/workflows/yolov8s-worldv2-push.yml b/.github/workflows/yolov8s-worldv2-push.yml deleted file mode 100644 index 2886b77..0000000 --- a/.github/workflows/yolov8s-worldv2-push.yml +++ /dev/null @@ -1,68 +0,0 @@ -# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - -name: Push YOLOv8s WorldV2 to Replicate - -on: - push: - branches: [main] - paths: - - yolov8s-worldv2/** - pull_request: - branches: [main] - paths: - - yolov8s-worldv2/** - workflow_dispatch: - -jobs: - build_test_push: - name: Build, Test & Push Model - runs-on: ubuntu-latest - steps: - #- name: Cleanup disk space - # uses: ultralytics/actions/cleanup-disk@main - - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: 3.12 - - - name: Setup uv - uses: astral-sh/setup-uv@v6 - - - name: Install dependencies - run: uv pip install --system ultralytics --extra-index-url https://download.pytorch.org/whl/cpu - - - name: Setup Cog - uses: replicate/setup-cog@v2 - with: - token: ${{ secrets.REPLICATE_API_TOKEN }} - - - name: Download YOLOv8s WorldV2 weights - run: | - python << 'EOF' - from ultralytics import YOLOWorld - model = YOLOWorld('yolov8s-worldv2.pt') - EOF - ls -la yolov8s-worldv2* - mv yolov8s-worldv2.pt yolov8s-worldv2/ - echo "Files in yolov8s-worldv2 directory:" - ls -la yolov8s-worldv2/ - - - name: Build model image - run: | - cd yolov8s-worldv2 - cog build - - - name: Test model - run: | - cd yolov8s-worldv2 - cog predict -i image=@../assets/bus.jpg -i conf=0.25 -i iou=0.45 - - - name: Push to Replicate - if: github.ref == 'refs/heads/main' - run: | - cd yolov8s-worldv2 - cog push diff --git a/yolov8s-worldv2/cog.yaml b/yolov8s-worldv2/cog.yaml index 6fa0ea0..f01edbf 100644 --- a/yolov8s-worldv2/cog.yaml +++ b/yolov8s-worldv2/cog.yaml @@ -9,11 +9,6 @@ build: - "ffmpeg" python_packages: - "ultralytics>=8.3.0" - - "torch==2.3.1" - - "torchvision" - - "numpy>=1.24.0" - - "opencv-python" - - "pillow" - "clip @ git+https://github.com/ultralytics/CLIP.git@main#egg=clip" predict: predict.py:Predictor diff --git a/yolov8s-worldv2/download.py b/yolov8s-worldv2/download.py new file mode 100644 index 0000000..eec4bc4 --- /dev/null +++ b/yolov8s-worldv2/download.py @@ -0,0 +1,20 @@ +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + +from pathlib import Path + +from ultralytics import YOLOWorld + + +def main(): + """Download YOLOv8s-worldv2 weights and move to model directory.""" + current_dir = Path(__file__).parent + YOLOWorld(current_dir / "yolov8s-worldv2.pt") + + # List files in model directory + print(f"Files in {current_dir.name} directory:") + for file in sorted(current_dir.iterdir()): + print(f" {file.stat().st_size:>10} {file.name}") + + +if __name__ == "__main__": + main()