Ultralytics CI #61
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Ultralytics YOLO 🚀, AGPL-3.0 license | |
# YOLO Continuous Integration (CI) GitHub Actions tests | |
name: Ultralytics CI | |
on: | |
push: | |
branches: [main] | |
pull_request: | |
branches: [main] | |
schedule: | |
- cron: "0 0 * * *" # runs at 00:00 UTC every day | |
workflow_dispatch: | |
inputs: | |
hub: | |
description: "Run HUB" | |
default: false | |
type: boolean | |
benchmarks: | |
description: "Run Benchmarks" | |
default: false | |
type: boolean | |
tests: | |
description: "Run Tests" | |
default: false | |
type: boolean | |
gpu: | |
description: "Run GPU" | |
default: false | |
type: boolean | |
raspberrypi: | |
description: "Run Raspberry Pi" | |
default: false | |
type: boolean | |
conda: | |
description: "Run Conda" | |
default: false | |
type: boolean | |
jobs: | |
Docs: | |
# TODO: break this job out into it's own action with pull_request_target to allow changes to user forks | |
if: github.repository == 'ultralytics/ultralytics' | |
runs-on: macos-14 | |
steps: | |
- name: Checkout Repository | |
uses: actions/checkout@v4 | |
with: | |
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} | |
token: ${{ secrets.GITHUB_TOKEN }} | |
ref: ${{ github.head_ref || github.ref }} | |
fetch-depth: 0 | |
- name: Set up Python | |
uses: actions/setup-python@v5 | |
with: | |
python-version: "3.x" | |
cache: "pip" # caching pip dependencies | |
- name: Install Dependencies | |
run: pip install tqdm mkdocs-material "mkdocstrings[python]" mkdocs-jupyter mkdocs-redirects mkdocs-ultralytics-plugin | |
- name: Update Docs Reference Section | |
run: python docs/build_reference.py | |
- name: Commit and Push Reference Section Changes | |
run: | | |
git pull origin ${{ github.head_ref || github.ref }} | |
git add . | |
git reset HEAD -- .github/workflows/ # workflow changes are not permitted with default token | |
git config --global user.name "UltralyticsAssistant" | |
git config --global user.email "[email protected]" | |
if ! git diff --staged --quiet; then | |
git commit -m "Auto-update Ultralytics Docs Reference Section by https://ultralytics.com/actions" | |
git push | |
else | |
echo "No changes to commit" | |
fi | |
- name: Build Docs and Check for Warnings | |
run: python docs/build_docs.py | |
- name: Commit and Push Docs changes | |
continue-on-error: true | |
if: always() && github.event_name == 'pull_request' | |
run: | | |
git pull origin ${{ github.head_ref || github.ref }} | |
git add --update # only add updated files | |
git reset HEAD -- .github/workflows/ # workflow changes are not permitted with default token | |
if ! git diff --staged --quiet; then | |
git commit -m "Auto-update Ultralytics Docs by https://ultralytics.com/actions" | |
git push | |
else | |
echo "No changes to commit" | |
fi | |
HUB: | |
if: github.repository == 'ultralytics/ultralytics' && (github.event_name == 'schedule' || github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.hub == 'true')) | |
runs-on: ${{ matrix.os }} | |
strategy: | |
fail-fast: false | |
matrix: | |
os: [ubuntu-latest] | |
python-version: ["3.11"] | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: ${{ matrix.python-version }} | |
cache: "pip" # caching pip dependencies | |
- name: Install requirements | |
shell: bash # for Windows compatibility | |
run: | | |
python -m pip install --upgrade pip wheel | |
pip install -e . --extra-index-url https://download.pytorch.org/whl/cpu | |
- name: Check environment | |
run: | | |
yolo checks | |
pip list | |
- name: Test HUB training | |
shell: python | |
env: | |
API_KEY: ${{ secrets.ULTRALYTICS_HUB_API_KEY }} | |
MODEL_ID: ${{ secrets.ULTRALYTICS_HUB_MODEL_ID }} | |
run: | | |
import os | |
from ultralytics import YOLO, hub | |
api_key, model_id = os.environ['API_KEY'], os.environ['MODEL_ID'] | |
hub.login(api_key) | |
hub.reset_model(model_id) | |
model = YOLO('https://hub.ultralytics.com/models/' + model_id) | |
model.train() | |
- name: Test HUB inference API | |
shell: python | |
env: | |
API_KEY: ${{ secrets.ULTRALYTICS_HUB_API_KEY }} | |
MODEL_ID: ${{ secrets.ULTRALYTICS_HUB_MODEL_ID }} | |
run: | | |
import os | |
import requests | |
import json | |
api_key, model_id = os.environ['API_KEY'], os.environ['MODEL_ID'] | |
url = f"https://api.ultralytics.com/v1/predict/{model_id}" | |
headers = {"x-api-key": api_key} | |
data = {"size": 320, "confidence": 0.25, "iou": 0.45} | |
with open("ultralytics/assets/zidane.jpg", "rb") as f: | |
response = requests.post(url, headers=headers, data=data, files={"image": f}) | |
assert response.status_code == 200, f'Status code {response.status_code}, Reason {response.reason}' | |
print(json.dumps(response.json(), indent=2)) | |
Benchmarks: | |
if: github.event_name != 'workflow_dispatch' || github.event.inputs.benchmarks == 'true' | |
runs-on: ${{ matrix.os }} | |
strategy: | |
fail-fast: false | |
matrix: | |
os: [ubuntu-latest, macos-14] | |
python-version: ["3.11"] | |
model: [yolov8n] | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: ${{ matrix.python-version }} | |
cache: "pip" # caching pip dependencies | |
- name: Install requirements | |
shell: bash # for Windows compatibility | |
run: | | |
python -m pip install --upgrade pip wheel | |
pip install -e ".[export]" "coverage[toml]" --extra-index-url https://download.pytorch.org/whl/cpu | |
- name: Check environment | |
run: | | |
yolo checks | |
pip list | |
- name: Benchmark ClassificationModel | |
shell: bash | |
run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}-cls.pt' imgsz=160 verbose=0.166 | |
- name: Benchmark YOLOWorld DetectionModel | |
shell: bash | |
run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/yolov8s-worldv2.pt' imgsz=160 verbose=0.318 | |
- name: Benchmark SegmentationModel | |
shell: bash | |
run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}-seg.pt' imgsz=160 verbose=0.279 | |
- name: Benchmark PoseModel | |
shell: bash | |
run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}-pose.pt' imgsz=160 verbose=0.183 | |
- name: Benchmark OBBModel | |
shell: bash | |
run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}-obb.pt' imgsz=160 verbose=0.472 | |
- name: Benchmark YOLOv10Model | |
shell: bash | |
run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/yolov10n.pt' imgsz=160 verbose=0.178 | |
- name: Merge Coverage Reports | |
run: | | |
coverage xml -o coverage-benchmarks.xml | |
- name: Upload Coverage Reports to CodeCov | |
if: github.repository == 'ultralytics/ultralytics' | |
uses: codecov/codecov-action@v4 | |
with: | |
flags: Benchmarks | |
env: | |
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} | |
- name: Benchmark Summary | |
run: | | |
cat benchmarks.log | |
echo "$(cat benchmarks.log)" >> $GITHUB_STEP_SUMMARY | |
Tests: | |
if: github.event_name != 'workflow_dispatch' || github.event.inputs.tests == 'true' | |
timeout-minutes: 360 | |
runs-on: ${{ matrix.os }} | |
strategy: | |
fail-fast: false | |
matrix: | |
os: [ubuntu-latest, windows-latest, macos-14] | |
python-version: ["3.11"] | |
torch: [latest] | |
include: | |
- os: ubuntu-latest | |
python-version: "3.8" # torch 1.8.0 requires python >=3.6, <=3.8 | |
torch: "1.8.0" # min torch version CI https://pypi.org/project/torchvision/ | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: ${{ matrix.python-version }} | |
cache: "pip" # caching pip dependencies | |
- name: Install requirements | |
shell: bash # for Windows compatibility | |
run: | | |
# CoreML must be installed before export due to protobuf error from AutoInstall | |
python -m pip install --upgrade pip wheel | |
slow="" | |
torch="" | |
if [ "${{ matrix.torch }}" == "1.8.0" ]; then | |
torch="torch==1.8.0 torchvision==0.9.0" | |
fi | |
if [[ "${{ github.event_name }}" =~ ^(schedule|workflow_dispatch)$ ]]; then | |
slow="pycocotools mlflow ray[tune]" | |
fi | |
pip install -e ".[export]" $torch $slow pytest-cov --extra-index-url https://download.pytorch.org/whl/cpu | |
- name: Check environment | |
run: | | |
yolo checks | |
pip list | |
- name: Pytest tests | |
shell: bash # for Windows compatibility | |
run: | | |
slow="" | |
if [[ "${{ github.event_name }}" =~ ^(schedule|workflow_dispatch)$ ]]; then | |
slow="--slow" | |
fi | |
pytest $slow --cov=ultralytics/ --cov-report xml tests/ | |
- name: Upload Coverage Reports to CodeCov | |
if: github.repository == 'ultralytics/ultralytics' # && matrix.os == 'ubuntu-latest' && matrix.python-version == '3.11' | |
uses: codecov/codecov-action@v4 | |
with: | |
flags: Tests | |
env: | |
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} | |
GPU: | |
if: github.repository == 'ultralytics/ultralytics' && (github.event_name != 'workflow_dispatch' || github.event.inputs.gpu == 'true') | |
timeout-minutes: 360 | |
runs-on: gpu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Install requirements | |
run: pip install -e . pytest-cov | |
- name: Check environment | |
run: | | |
yolo checks | |
pip list | |
- name: Pytest tests | |
run: | | |
slow="" | |
if [[ "${{ github.event_name }}" =~ ^(schedule|workflow_dispatch)$ ]]; then | |
slow="--slow" | |
fi | |
pytest $slow --cov=ultralytics/ --cov-report xml tests/test_cuda.py | |
- name: Upload Coverage Reports to CodeCov | |
uses: codecov/codecov-action@v4 | |
with: | |
flags: GPU | |
env: | |
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} | |
RaspberryPi: | |
if: github.repository == 'ultralytics/ultralytics' && (github.event_name == 'schedule' || github.event.inputs.raspberrypi == 'true') | |
timeout-minutes: 120 | |
runs-on: raspberry-pi | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Activate Virtual Environment | |
run: | | |
python3.11 -m venv env | |
source env/bin/activate | |
echo PATH=$PATH >> $GITHUB_ENV | |
- name: Install requirements | |
run: | | |
python -m pip install --upgrade pip wheel | |
pip install -e ".[export]" pytest mlflow pycocotools "ray[tune]" | |
- name: Check environment | |
run: | | |
yolo checks | |
pip list | |
- name: Pytest tests | |
run: pytest --slow tests/ | |
- name: Benchmark ClassificationModel | |
run: python -m ultralytics.cfg.__init__ benchmark model='yolov8n-cls.pt' imgsz=160 verbose=0.166 | |
- name: Benchmark YOLOWorld DetectionModel | |
run: python -m ultralytics.cfg.__init__ benchmark model='yolov8s-worldv2.pt' imgsz=160 verbose=0.318 | |
- name: Benchmark SegmentationModel | |
run: python -m ultralytics.cfg.__init__ benchmark model='yolov8n-seg.pt' imgsz=160 verbose=0.267 | |
- name: Benchmark PoseModel | |
run: python -m ultralytics.cfg.__init__ benchmark model='yolov8n-pose.pt' imgsz=160 verbose=0.179 | |
- name: Benchmark OBBModel | |
run: python -m ultralytics.cfg.__init__ benchmark model='yolov8n-obb.pt' imgsz=160 verbose=0.472 | |
- name: Benchmark Summary | |
run: | | |
cat benchmarks.log | |
echo "$(cat benchmarks.log)" >> $GITHUB_STEP_SUMMARY | |
- name: Reboot # run a reboot command in the background to free resources for next run and not crash main thread | |
run: sudo bash -c "sleep 10; reboot" & | |
Conda: | |
if: github.repository == 'ultralytics/ultralytics' && (github.event_name == 'schedule' || github.event.inputs.conda == 'true') | |
runs-on: ${{ matrix.os }} | |
strategy: | |
fail-fast: false | |
matrix: | |
os: [ubuntu-latest] | |
python-version: ["3.11"] | |
defaults: | |
run: | |
shell: bash -el {0} | |
steps: | |
- uses: conda-incubator/setup-miniconda@v3 | |
with: | |
python-version: ${{ matrix.python-version }} | |
mamba-version: "*" | |
channels: conda-forge,defaults | |
channel-priority: true | |
activate-environment: anaconda-client-env | |
- name: Install Linux packages | |
run: | | |
# Fix cv2 ImportError: 'libEGL.so.1: cannot open shared object file: No such file or directory' | |
sudo apt-get update | |
sudo apt-get install -y libegl1 libopengl0 | |
- name: Install Libmamba | |
run: | | |
conda config --set solver libmamba | |
- name: Install Ultralytics package from conda-forge | |
run: | | |
conda install -c pytorch -c conda-forge pytorch torchvision ultralytics openvino | |
- name: Install pip packages | |
run: | | |
# CoreML must be installed before export due to protobuf error from AutoInstall | |
pip install pytest "coremltools>=7.0; platform_system != 'Windows' and python_version <= '3.11'" | |
- name: Check environment | |
run: | | |
conda list | |
- name: Test CLI | |
run: | | |
yolo predict model=yolov8n.pt imgsz=320 | |
yolo train model=yolov8n.pt data=coco8.yaml epochs=1 imgsz=32 | |
yolo val model=yolov8n.pt data=coco8.yaml imgsz=32 | |
yolo export model=yolov8n.pt format=torchscript imgsz=160 | |
- name: Test Python | |
run: | | |
python -c " | |
from ultralytics import YOLO | |
model = YOLO('yolov8n.pt') | |
results = model.train(data='coco8.yaml', epochs=3, imgsz=160) | |
results = model.val(imgsz=160) | |
results = model.predict(imgsz=160) | |
results = model.export(format='onnx', imgsz=160) | |
" | |
- name: PyTest | |
run: | | |
git clone https://github.com/ultralytics/ultralytics | |
pytest ultralytics/tests | |
Summary: | |
runs-on: ubuntu-latest | |
needs: [HUB, Benchmarks, Tests, GPU, RaspberryPi, Conda] # Add job names that you want to check for failure | |
if: always() # This ensures the job runs even if previous jobs fail | |
steps: | |
- name: Check for failure and notify | |
if: (needs.HUB.result == 'failure' || needs.Benchmarks.result == 'failure' || needs.Tests.result == 'failure' || needs.GPU.result == 'failure' || needs.RaspberryPi.result == 'failure' || needs.Conda.result == 'failure' ) && github.repository == 'ultralytics/ultralytics' && (github.event_name == 'schedule' || github.event_name == 'push') | |
uses: slackapi/[email protected] | |
with: | |
payload: | | |
{"text": "<!channel> GitHub Actions error for ${{ github.workflow }} ❌\n\n\n*Repository:* https://github.com/${{ github.repository }}\n*Action:* https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Author:* ${{ github.actor }}\n*Event:* ${{ github.event_name }}\n"} | |
env: | |
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL_YOLO }} |