Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make installable pip package #465

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 32 additions & 11 deletions .github/workflows/ci-testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: [3.8]
python-version: [3.7, 3.8]
model: ['yolov5s'] # models to test

# Timeout: https://stackoverflow.com/a/59076067/4521646
Expand Down Expand Up @@ -53,23 +53,44 @@ jobs:

- name: Download data
run: |
python -c "from utils.google_utils import * ; gdrive_download('1n_oKgR81BJtqk75b00eAjdv03qVCQn2f', 'coco128.zip')"
python -c "from yolo5.utils.google_utils import * ; gdrive_download('1n_oKgR81BJtqk75b00eAjdv03qVCQn2f', 'coco128.zip')"
mv ./coco128 ../

- name: PyTest
run: |
pip install -q coverage pytest pytest-flake8
# todo: make code PEP8 complient and uncoment this Flake8 check
coverage run --source yolo5 -m pytest yolo5 --doctest-modules # --flake8
coverage report

- name: Tests workflow
run: |
export PYTHONPATH="$PWD" # to run *.py. files in subdirectories
di=cpu # inference devices # define device

# train
python train.py --img 256 --batch 8 --weights weights/${{ matrix.model }}.pt --cfg models/${{ matrix.model }}.yaml --epochs 1 --device $di
python yolo5/train.py --img 256 --batch 8 --weights ./weights/${{ matrix.model }}.pt --cfg ./models/${{ matrix.model }}.yaml --epochs 1 --device $di
# detect
python detect.py --weights weights/${{ matrix.model }}.pt --device $di
python detect.py --weights runs/exp0/weights/last.pt --device $di
python yolo5/detect.py --weights ./weights/${{ matrix.model }}.pt --device $di
python yolo5/detect.py --weights ./runs/exp0/weights/last.pt --device $di
# test
python test.py --img 256 --batch 8 --weights weights/${{ matrix.model }}.pt --device $di
python test.py --img 256 --batch 8 --weights runs/exp0/weights/last.pt --device $di

python models/yolo.py --cfg models/${{ matrix.model }}.yaml # inspect
python models/export.py --img 256 --batch 1 --weights weights/${{ matrix.model }}.pt # export
python yolo5/test.py --img 256 --batch 8 --weights ./weights/${{ matrix.model }}.pt --device $di
python yolo5/test.py --img 256 --batch 8 --weights ./runs/exp0/weights/last.pt --device $di
# inspect
python yolo5/models/yolo.py --cfg ./models/${{ matrix.model }}.yaml
# export
python yolo5/export.py --img 256 --batch 1 --weights ./weights/${{ matrix.model }}.pt
shell: bash

- name: Test Install
run: |
pip install -q check-manifest twine

check-manifest
python setup.py check --metadata --strict

# Build the package
python setup.py sdist bdist_wheel
twine check ./dist/*

# Dry run install
python setup.py install --dry-run
39 changes: 39 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Manifest syntax https://docs.python.org/2/distutils/sourcedist.html
graft wheelhouse

recursive-exclude __pycache__ *.pyc *.pyo *.orig

# Include the README
include *.md

# Include the license file
include LICENSE

# Include the Requirements
include requirements.txt

# Include package
recursive-include yolo5 *.py *.yaml

# Include setup
include setup.*

# Exclude testing
exclude pytest.*
recursive-exclude tests *
exclude tests

# Exclude experiments
exclude */*.sh
exclude *.ipynb
exclude Dockerfile .dockerignore

prune .git
prune .github
prune run
prune venv
prune build
prune docs
prune tests
prune data
prune inference
31 changes: 19 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ Python 3.7 or later with all `requirements.txt` dependencies installed, includin
$ pip install -U -r requirements.txt
```

## Installation

You can install this package straight with pip
```bash
pip install git+https://github.com/ultralytics/yolov5.git
```


## Tutorials

Expand Down Expand Up @@ -68,19 +75,19 @@ YOLOv5 may be run in any of the following up-to-date verified environments (with

Inference can be run on most common media formats. Model [checkpoints](https://drive.google.com/open?id=1Drs_Aiu7xx6S-ix95f9kNsA6ueKRpN2J) are downloaded automatically if available. Results are saved to `./inference/output`.
```bash
$ python detect.py --source 0 # webcam
file.jpg # image
file.mp4 # video
path/ # directory
path/*.jpg # glob
rtsp://170.93.143.139/rtplive/470011e600ef003a004ee33696235daa # rtsp stream
http://112.50.243.8/PLTV/88888888/224/3221225900/1.m3u8 # http stream
$ python yolo5/detect.py --source 0 # webcam
file.jpg # image
file.mp4 # video
path/ # directory
path/*.jpg # glob
rtsp://170.93.143.139/rtplive/470011e600ef003a004ee33696235daa # rtsp stream
http://112.50.243.8/PLTV/88888888/224/3221225900/1.m3u8 # http stream
```

To run inference on examples in the `./inference/images` folder:

```bash
$ python detect.py --source ./inference/images/ --weights yolov5s.pt --conf 0.4
$ python yolo5/detect.py --source ./inference/images/ --weights yolov5s.pt --conf 0.4

Namespace(agnostic_nms=False, augment=False, classes=None, conf_thres=0.4, device='', fourcc='mp4v', half=False, img_size=640, iou_thres=0.5, output='inference/output', save_txt=False, source='./inference/images/', view_img=False, weights='yolov5s.pt')
Using CUDA device0 _CudaDeviceProperties(name='Tesla P100-PCIE-16GB', total_memory=16280MB)
Expand All @@ -99,10 +106,10 @@ Results saved to /content/yolov5/inference/output

Download [COCO](https://github.com/ultralytics/yolov5/blob/master/data/get_coco2017.sh), install [Apex](https://github.com/NVIDIA/apex) and run command below. Training times for YOLOv5s/m/l/x are 2/4/6/8 days on a single V100 (multi-GPU times faster). Use the largest `--batch-size` your GPU allows (batch sizes shown for 16 GB devices).
```bash
$ python train.py --data coco.yaml --cfg yolov5s.yaml --weights '' --batch-size 64
yolov5m 48
yolov5l 32
yolov5x 16
$ python yolo5/train.py --data coco.yaml --cfg yolov5s.yaml --weights '' --batch-size 64
yolov5m 48
yolov5l 32
yolov5x 16
```
<img src="https://user-images.githubusercontent.com/26833433/84186698-c4d54d00-aa45-11ea-9bde-c632c1230ccd.png" width="900">

Expand Down
30 changes: 30 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[metadata]
# This includes the license file(s) in the wheel.
# https://wheel.readthedocs.io/en/stable/user_guide.html#including-license-files-in-the-generated-wheel-file
license_files = LICENSE

[bdist_wheel]
# This flag says to generate wheels that support both Python 2 and Python
# 3. If your code will not run unchanged on both Python 2 and 3, you will
# need to generate separate wheels for each Python version that you
# support. Removing this line (or setting universal to 0) will prevent
# bdist_wheel from trying to make a universal wheel. For more see:
# https://packaging.python.org/guides/distributing-packages-using-setuptools/#wheels
universal=1

[flake8]
# http://flake8.pycqa.org/en/latest/user/configuration.html
ignore = E501
max-line-length = 100
exclude = *.egg,build,temp
select = E,W,F
doctests = True
verbose = 2
# max-complexity = 10

[tool:pytest]
log_cli = 1
log_cli_level = CRITICAL
log_file = pytest.log
log_file_level = DEBUG
filterwarnings = ignore::FutureWarning
136 changes: 136 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
"""A setuptools based setup module.

See:
https://packaging.python.org/guides/distributing-packages-using-setuptools/
https://github.com/pypa/sampleproject
"""

# Always prefer setuptools over distutils
from os import path
from setuptools import setup, find_packages

import yolo5

PATH_HERE = path.abspath(path.dirname(__file__))

with open(path.join(PATH_HERE, 'requirements.txt')) as fp:
install_reqs = [r.rstrip() for r in fp.readlines() if not r.startswith('#')]

# Get the long description from the README file
with open(path.join(PATH_HERE, 'README.md'), encoding='utf-8') as fp:
long_description = fp.read()

# Arguments marked as "Required" below must be included for upload to PyPI.
# Fields marked as "Optional" may be commented out.

setup(
# This is the name of your project. The first time you publish this
# package, this name will be registered for you. It will determine how
# users can install this project, e.g.:
#
# $ pip install YOLOv5
#
# And where it will live on PyPI: https://pypi.org/project/YOLOv5/
name='YOLOv5', # Required
version=yolo5.__version__, # Required
description=yolo5.__doc__, # Optional

# This is an optional longer description of your project that represents
# the body of text which users will see when they visit PyPI.
long_description=yolo5.__doc_long__, # Optional

# Denotes that our long_description is in Markdown; valid values are
# text/plain, text/x-rst, and text/markdown
long_description_content_type='text/markdown', # Optional (see note above)

# This should be a valid link to your project's main homepage.
url='https://github.com/ultralytics/yolov5', # Optional

# This should be your name or the name of the organization which owns the project.
author='Ultralytics', # Optional
# This should be a valid email address corresponding to the author listed above.
author_email='glenn.jocher@ultralytics.com', # Optional

# Classifiers help users find your project by categorizing it.
# For a list of valid classifiers, see https://pypi.org/classifiers/
classifiers=[ # Optional
# How mature is this project? Common values are
# 3 - Alpha
# 4 - Beta
# 5 - Production/Stable
'Development Status :: 5 - Production/Stable',

# Indicate who your project is intended for
'Intended Audience :: Developers',

# Operation system
'Operating System :: OS Independent',

# Topics
'Topic :: Education',
'Topic :: Scientific/Engineering',
'Topic :: Scientific/Engineering :: Artificial Intelligence',
'Topic :: Scientific/Engineering :: Image Recognition',

# Pick your license as you wish
'License :: OSI Approved :: Apache Software License',

# Specify the Python versions you support here. In particular, ensure
# that you indicate whether you support Python 2, Python 3 or both.
# These classifiers are *not* checked by 'pip install'. See instead
# 'python_requires' below.
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
],

# This field adds keywords for your project which will appear on the
# project page. What does your project relate to?
keywords='YOLO object-detection', # Optional

# You can just specify package directories manually here if your project is
# simple. Or you can use find_packages().
packages=find_packages(exclude=['contrib', 'docs', 'tests']), # Required

# Specify which Python versions you support. In contrast to the
# 'Programming Language' classifiers above, 'pip install' will check this
# and refuse to install the project if the version does not match. If you
# do not support Python 2, you can simplify this to '>=3.5' or similar, see
# https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires
python_requires='>=3.6, <4',
install_requires=install_reqs,

# This field lists other packages that your project depends on to run.
# Any package you put here will be installed by pip when your project is
# installed, so they must be valid existing projects.
# install_requires=[], # Optional

# Although 'package_data' is the preferred approach, in some case you may
# need to place data files outside of your packages. See:
# http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files
#
# In this case, 'data_file' will be installed into '<sys.prefix>/my_data'
data_files=[('models',
[f'yolo5/models/yolov5{n}.yaml' for n in 'smlx']
+ ['yolo5/models/hub/yolov3-spp.yaml']
+ [f'yolo5/models/hub/yolov5-{n}.yaml' for n in ('fpn', 'panet')]
)], # Optional

# To provide executable scripts, use entry points in preference to the
# "scripts" keyword. Entry points provide cross-platform support and allow
# `pip` to create the appropriate form of executable for the target
# platform.
# entry_points={ # Optional
# 'console_scripts': [
# 'sandbox=sandbox:main',
# ],
# },

# List additional URLs that are relevant to your project as a dict.
project_urls={ # Optional
'Bug Reports': 'https://github.com/ultralytics/yolov5/issues',
'Funding': 'https://www.ultralytics.com',
'Source': 'https://github.com/ultralytics/yolov5/',
},
)
12 changes: 12 additions & 0 deletions yolo5/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
__version__ = '2.0rc1'
__doc__ = "YOLO v5 - object detection network"
__doc_long__ = """
# YOLO v5

This repository represents Ultralytics open-source research into future object detection methods,
and incorporates our lessons learned and best practices evolved over training thousands of models
on custom client datasets with our previous YOLO repository https://github.com/ultralytics/yolov3.

**All code and models are under active development, and are subject to modification or deletion without notice.**
Use at your own risk.
"""
8 changes: 4 additions & 4 deletions detect.py β†’ yolo5/detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
import torch.backends.cudnn as cudnn
from numpy import random

from models.experimental import attempt_load
from utils.datasets import LoadStreams, LoadImages
from utils.general import check_img_size, non_max_suppression, apply_classifier, scale_coords, xyxy2xywh, plot_one_box
from utils.torch_utils import select_device, load_classifier, time_synchronized
from yolo5.models.experimental import attempt_load
from yolo5.utils.datasets import LoadStreams, LoadImages
from yolo5.utils.general import check_img_size, non_max_suppression, apply_classifier, scale_coords, xyxy2xywh, plot_one_box
from yolo5.utils.torch_utils import select_device, load_classifier, time_synchronized


def detect(save_img=False):
Expand Down
22 changes: 13 additions & 9 deletions models/export.py β†’ yolo5/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,10 @@

import torch

from utils.google_utils import attempt_download
from yolo5.utils.google_utils import attempt_download

if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--weights', type=str, default='./yolov5s.pt', help='weights path')
parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='image size')
parser.add_argument('--batch-size', type=int, default=1, help='batch size')
opt = parser.parse_args()
opt.img_size *= 2 if len(opt.img_size) == 1 else 1 # expand
print(opt)

def main(opt):
# Input
img = torch.zeros((opt.batch_size, 3, *opt.img_size)) # image size(1,3,320,192) iDetection

Expand Down Expand Up @@ -72,3 +65,14 @@

# Finish
print('\nExport complete. Visualize with https://github.com/lutzroeder/netron.')

if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--weights', type=str, default='./yolov5s.pt', help='weights path')
parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='image size')
parser.add_argument('--batch-size', type=int, default=1, help='batch size')
opt = parser.parse_args()
opt.img_size *= 2 if len(opt.img_size) == 1 else 1 # expand
print(opt)

main(opt)
Loading