mirror of
https://github.com/THU-MIG/yolov10.git
synced 2025-05-23 05:24:22 +08:00
ultralytics 8.0.47
Docker and reformat updates (#1153)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
d4be4cb24b
commit
a58f766f94
4
.github/workflows/ci.yaml
vendored
4
.github/workflows/ci.yaml
vendored
@ -38,7 +38,7 @@ jobs:
|
|||||||
if [ "${{ matrix.os }}" == "macos-latest" ]; then
|
if [ "${{ matrix.os }}" == "macos-latest" ]; then
|
||||||
pip install -e . coremltools openvino-dev tensorflow-macos --extra-index-url https://download.pytorch.org/whl/cpu
|
pip install -e . coremltools openvino-dev tensorflow-macos --extra-index-url https://download.pytorch.org/whl/cpu
|
||||||
else
|
else
|
||||||
pip install -e . coremltools openvino-dev tensorflow-cpu paddlepaddle x2paddle --extra-index-url https://download.pytorch.org/whl/cpu
|
pip install -e . coremltools openvino-dev tensorflow-cpu --extra-index-url https://download.pytorch.org/whl/cpu
|
||||||
fi
|
fi
|
||||||
yolo export format=tflite
|
yolo export format=tflite
|
||||||
- name: Check environment
|
- name: Check environment
|
||||||
@ -66,7 +66,7 @@ jobs:
|
|||||||
shell: python
|
shell: python
|
||||||
run: |
|
run: |
|
||||||
from ultralytics.yolo.utils.benchmarks import benchmark
|
from ultralytics.yolo.utils.benchmarks import benchmark
|
||||||
benchmark(model='${{ matrix.model }}-cls.pt', imgsz=160, half=False, hard_fail=0.70)
|
benchmark(model='${{ matrix.model }}-cls.pt', imgsz=160, half=False, hard_fail=0.60)
|
||||||
- name: Benchmark Summary
|
- name: Benchmark Summary
|
||||||
run: cat benchmarks.log
|
run: cat benchmarks.log
|
||||||
|
|
||||||
|
@ -223,10 +223,11 @@ Ultralytics [发布页](https://github.com/ultralytics/ultralytics/releases) 自
|
|||||||
|
|
||||||
## <div align="center">License</div>
|
## <div align="center">License</div>
|
||||||
|
|
||||||
- YOLOv8 在两种不同的 License 下可用:
|
YOLOv8 在两种不同的 License 下可用:
|
||||||
- **GPL-3.0 License**: 查看 [License](https://github.com/ultralytics/ultralytics/blob/main/LICENSE) 文件的详细信息。
|
|
||||||
- **企业License**:在没有 GPL-3.0 开源要求的情况下为商业产品开发提供更大的灵活性。典型用例是将 Ultralytics 软件和 AI
|
- **GPL-3.0 License**: 查看 [License](https://github.com/ultralytics/ultralytics/blob/main/LICENSE) 文件的详细信息。
|
||||||
模型嵌入到商业产品和应用程序中。在以下位置申请企业许可证 [Ultralytics 许可](https://ultralytics.com/license) 。
|
- **企业License**:在没有 GPL-3.0 开源要求的情况下为商业产品开发提供更大的灵活性。典型用例是将 Ultralytics 软件和 AI
|
||||||
|
模型嵌入到商业产品和应用程序中。在以下位置申请企业许可证 [Ultralytics 许可](https://ultralytics.com/license) 。
|
||||||
|
|
||||||
## <div align="center">联系我们</div>
|
## <div align="center">联系我们</div>
|
||||||
|
|
||||||
|
@ -29,9 +29,8 @@ WORKDIR /usr/src/ultralytics
|
|||||||
RUN git clone https://github.com/ultralytics/ultralytics /usr/src/ultralytics
|
RUN git clone https://github.com/ultralytics/ultralytics /usr/src/ultralytics
|
||||||
|
|
||||||
# Install pip packages
|
# Install pip packages
|
||||||
COPY requirements.txt .
|
|
||||||
RUN python3 -m pip install --upgrade pip wheel
|
RUN python3 -m pip install --upgrade pip wheel
|
||||||
RUN pip install --no-cache ultralytics[export] albumentations comet gsutil notebook
|
RUN pip install --no-cache '.[export]' albumentations comet gsutil notebook
|
||||||
|
|
||||||
# Set environment variables
|
# Set environment variables
|
||||||
ENV OMP_NUM_THREADS=1
|
ENV OMP_NUM_THREADS=1
|
||||||
|
@ -24,9 +24,8 @@ WORKDIR /usr/src/ultralytics
|
|||||||
RUN git clone https://github.com/ultralytics/ultralytics /usr/src/ultralytics
|
RUN git clone https://github.com/ultralytics/ultralytics /usr/src/ultralytics
|
||||||
|
|
||||||
# Install pip packages
|
# Install pip packages
|
||||||
COPY requirements.txt .
|
|
||||||
RUN python3 -m pip install --upgrade pip wheel
|
RUN python3 -m pip install --upgrade pip wheel
|
||||||
RUN pip install --no-cache ultralytics albumentations gsutil notebook
|
RUN pip install --no-cache . albumentations gsutil notebook
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
ENV DEBIAN_FRONTEND teletype
|
ENV DEBIAN_FRONTEND teletype
|
||||||
|
@ -24,9 +24,8 @@ WORKDIR /usr/src/ultralytics
|
|||||||
RUN git clone https://github.com/ultralytics/ultralytics /usr/src/ultralytics
|
RUN git clone https://github.com/ultralytics/ultralytics /usr/src/ultralytics
|
||||||
|
|
||||||
# Install pip packages
|
# Install pip packages
|
||||||
COPY requirements.txt .
|
|
||||||
RUN python3 -m pip install --upgrade pip wheel
|
RUN python3 -m pip install --upgrade pip wheel
|
||||||
RUN pip install --no-cache ultralytics[export] albumentations gsutil notebook \
|
RUN pip install --no-cache '.[export]' albumentations gsutil notebook \
|
||||||
--extra-index-url https://download.pytorch.org/whl/cpu
|
--extra-index-url https://download.pytorch.org/whl/cpu
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
|
@ -97,8 +97,8 @@ Class reference documentation for `Results` module and its components can be fou
|
|||||||
|
|
||||||
## Plotting results
|
## Plotting results
|
||||||
|
|
||||||
You can use `plot()` function of `Result` object to plot results on in image object. It plots all components(boxes, masks,
|
You can use `plot()` function of `Result` object to plot results on in image object. It plots all components(boxes,
|
||||||
classification logits, etc) found in the results object
|
masks, classification logits, etc) found in the results object
|
||||||
|
|
||||||
```python
|
```python
|
||||||
res = model(img)
|
res = model(img)
|
||||||
|
@ -42,11 +42,15 @@ Use a trained YOLOv8n/YOLOv8n-seg model to run tracker on video streams.
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
As in the above usage, we support both the detection and segmentation models for tracking and the only thing you need to do is loading the corresponding(detection or segmentation) model.
|
As in the above usage, we support both the detection and segmentation models for tracking and the only thing you need to
|
||||||
|
do is loading the corresponding (detection or segmentation) model.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
### Tracking
|
### Tracking
|
||||||
Tracking shares the configuration with predict, i.e `conf`, `iou`, `show`. More configurations please refer to [predict page](https://docs.ultralytics.com/cfg/#prediction).
|
|
||||||
|
Tracking shares the configuration with predict, i.e `conf`, `iou`, `show`. More configurations please refer
|
||||||
|
to [predict page](https://docs.ultralytics.com/cfg/#prediction).
|
||||||
!!! example ""
|
!!! example ""
|
||||||
|
|
||||||
=== "Python"
|
=== "Python"
|
||||||
@ -65,7 +69,10 @@ Tracking shares the configuration with predict, i.e `conf`, `iou`, `show`. More
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Tracker
|
### Tracker
|
||||||
We also support using a modified tracker config file, just copy a config file i.e `custom_tracker.yaml` from [ultralytics/tracker/cfg](https://github.com/ultralytics/ultralytics/tree/main/ultralytics/tracker/cfg) and modify any configurations(expect the `tracker_type`) you need to.
|
|
||||||
|
We also support using a modified tracker config file, just copy a config file i.e `custom_tracker.yaml`
|
||||||
|
from [ultralytics/tracker/cfg](https://github.com/ultralytics/ultralytics/tree/main/ultralytics/tracker/cfg) and modify
|
||||||
|
any configurations(expect the `tracker_type`) you need to.
|
||||||
!!! example ""
|
!!! example ""
|
||||||
|
|
||||||
=== "Python"
|
=== "Python"
|
||||||
@ -82,5 +89,7 @@ We also support using a modified tracker config file, just copy a config file i.
|
|||||||
yolo track model=yolov8n.pt source="https://youtu.be/Zgi9g1ksQHc" tracker='custom_tracker.yaml'
|
yolo track model=yolov8n.pt source="https://youtu.be/Zgi9g1ksQHc" tracker='custom_tracker.yaml'
|
||||||
|
|
||||||
```
|
```
|
||||||
Please refer to [ultralytics/tracker/cfg](https://github.com/ultralytics/ultralytics/tree/main/ultralytics/tracker/cfg) page.
|
|
||||||
|
Please refer to [ultralytics/tracker/cfg](https://github.com/ultralytics/ultralytics/tree/main/ultralytics/tracker/cfg)
|
||||||
|
page.
|
||||||
|
|
||||||
|
@ -37,7 +37,6 @@ seaborn>=0.11.0
|
|||||||
# Extras --------------------------------------
|
# Extras --------------------------------------
|
||||||
psutil # system utilization
|
psutil # system utilization
|
||||||
thop>=0.1.1 # FLOPs computation
|
thop>=0.1.1 # FLOPs computation
|
||||||
wheel>=0.38.0 # Snyk vulnerability fix
|
|
||||||
# ipython # interactive notebook
|
# ipython # interactive notebook
|
||||||
# albumentations>=1.0.3
|
# albumentations>=1.0.3
|
||||||
# pycocotools>=2.0.6 # COCO mAP
|
# pycocotools>=2.0.6 # COCO mAP
|
||||||
|
12
setup.cfg
12
setup.cfg
@ -25,17 +25,19 @@ verbose = 2
|
|||||||
# https://pep8.readthedocs.io/en/latest/intro.html#error-codes
|
# https://pep8.readthedocs.io/en/latest/intro.html#error-codes
|
||||||
format = pylint
|
format = pylint
|
||||||
# see: https://www.flake8rules.com/
|
# see: https://www.flake8rules.com/
|
||||||
ignore = E731,F405,E402,F401,W504,E127,E231,E501,F403
|
ignore = E731,F405,E402,W504,E501
|
||||||
# E731: Do not assign a lambda expression, use a def
|
# E731: Do not assign a lambda expression, use a def
|
||||||
# F405: name may be undefined, or defined from star imports: module
|
# F405: name may be undefined, or defined from star imports: module
|
||||||
# E402: module level import not at top of file
|
# E402: module level import not at top of file
|
||||||
# F401: module imported but unused
|
|
||||||
# W504: line break after binary operator
|
# W504: line break after binary operator
|
||||||
# E127: continuation line over-indented for visual indent
|
|
||||||
# E231: missing whitespace after ‘,’, ‘;’, or ‘:’
|
|
||||||
# E501: line too long
|
# E501: line too long
|
||||||
|
# removed:
|
||||||
|
# F401: module imported but unused
|
||||||
|
# E231: missing whitespace after ‘,’, ‘;’, or ‘:’
|
||||||
|
# E127: continuation line over-indented for visual indent
|
||||||
# F403: ‘from module import *’ used; unable to detect undefined names
|
# F403: ‘from module import *’ used; unable to detect undefined names
|
||||||
|
|
||||||
|
|
||||||
[isort]
|
[isort]
|
||||||
# https://pycqa.github.io/isort/docs/configuration/options.html
|
# https://pycqa.github.io/isort/docs/configuration/options.html
|
||||||
line_length = 120
|
line_length = 120
|
||||||
@ -48,7 +50,7 @@ spaces_before_comment = 2
|
|||||||
COLUMN_LIMIT = 120
|
COLUMN_LIMIT = 120
|
||||||
COALESCE_BRACKETS = True
|
COALESCE_BRACKETS = True
|
||||||
SPACES_AROUND_POWER_OPERATOR = True
|
SPACES_AROUND_POWER_OPERATOR = True
|
||||||
SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET = False
|
SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET = True
|
||||||
SPLIT_BEFORE_CLOSING_BRACKET = False
|
SPLIT_BEFORE_CLOSING_BRACKET = False
|
||||||
SPLIT_BEFORE_FIRST_ARGUMENT = False
|
SPLIT_BEFORE_FIRST_ARGUMENT = False
|
||||||
# EACH_DICT_ENTRY_ON_SEPARATE_LINE = False
|
# EACH_DICT_ENTRY_ON_SEPARATE_LINE = False
|
||||||
|
2
setup.py
2
setup.py
@ -59,7 +59,7 @@ setup(
|
|||||||
'Topic :: Scientific/Engineering :: Image Recognition',
|
'Topic :: Scientific/Engineering :: Image Recognition',
|
||||||
'Operating System :: POSIX :: Linux',
|
'Operating System :: POSIX :: Linux',
|
||||||
'Operating System :: MacOS',
|
'Operating System :: MacOS',
|
||||||
'Operating System :: Microsoft :: Windows',],
|
'Operating System :: Microsoft :: Windows', ],
|
||||||
keywords='machine-learning, deep-learning, vision, ML, DL, AI, YOLO, YOLOv3, YOLOv5, YOLOv8, HUB, Ultralytics',
|
keywords='machine-learning, deep-learning, vision, ML, DL, AI, YOLO, YOLOv3, YOLOv5, YOLOv8, HUB, Ultralytics',
|
||||||
entry_points={
|
entry_points={
|
||||||
'console_scripts': ['yolo = ultralytics.yolo.cfg:entrypoint', 'ultralytics = ultralytics.yolo.cfg:entrypoint']})
|
'console_scripts': ['yolo = ultralytics.yolo.cfg:entrypoint', 'ultralytics = ultralytics.yolo.cfg:entrypoint']})
|
||||||
|
@ -22,7 +22,7 @@ def test_special_modes():
|
|||||||
|
|
||||||
# Train checks ---------------------------------------------------------------------------------------------------------
|
# Train checks ---------------------------------------------------------------------------------------------------------
|
||||||
def test_train_det():
|
def test_train_det():
|
||||||
run(f'yolo train detect model={CFG}.yaml data=coco8.yaml imgsz=32 epochs=1')
|
run(f'yolo train detect model={CFG}.yaml data=coco8.yaml imgsz=32 epochs=1 v5loader')
|
||||||
|
|
||||||
|
|
||||||
def test_train_seg():
|
def test_train_seg():
|
||||||
@ -48,7 +48,7 @@ def test_val_classify():
|
|||||||
|
|
||||||
# Predict checks -------------------------------------------------------------------------------------------------------
|
# Predict checks -------------------------------------------------------------------------------------------------------
|
||||||
def test_predict_detect():
|
def test_predict_detect():
|
||||||
run(f"yolo predict model={MODEL}.pt source={ROOT / 'assets'} imgsz=32 save")
|
run(f"yolo predict model={MODEL}.pt source={ROOT / 'assets'} imgsz=32 save save_crop save_txt")
|
||||||
if checks.check_online():
|
if checks.check_online():
|
||||||
run(f'yolo predict model={MODEL}.pt source=https://ultralytics.com/images/bus.jpg imgsz=32')
|
run(f'yolo predict model={MODEL}.pt source=https://ultralytics.com/images/bus.jpg imgsz=32')
|
||||||
run(f'yolo predict model={MODEL}.pt source=https://ultralytics.com/assets/decelera_landscape_min.mov imgsz=32')
|
run(f'yolo predict model={MODEL}.pt source=https://ultralytics.com/assets/decelera_landscape_min.mov imgsz=32')
|
||||||
|
@ -162,9 +162,8 @@ def test_workflow():
|
|||||||
|
|
||||||
|
|
||||||
def test_predict_callback_and_setup():
|
def test_predict_callback_and_setup():
|
||||||
|
# test callback addition for prediction
|
||||||
def on_predict_batch_end(predictor):
|
def on_predict_batch_end(predictor): # results -> List[batch_size]
|
||||||
# results -> List[batch_size]
|
|
||||||
path, _, im0s, _, _ = predictor.batch
|
path, _, im0s, _, _ = predictor.batch
|
||||||
# print('on_predict_batch_end', im0s[0].shape)
|
# print('on_predict_batch_end', im0s[0].shape)
|
||||||
im0s = im0s if isinstance(im0s, list) else [im0s]
|
im0s = im0s if isinstance(im0s, list) else [im0s]
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
# Ultralytics YOLO 🚀, GPL-3.0 license
|
# Ultralytics YOLO 🚀, GPL-3.0 license
|
||||||
|
|
||||||
__version__ = '8.0.46'
|
__version__ = '8.0.47'
|
||||||
|
|
||||||
from ultralytics.yolo.engine.model import YOLO
|
from ultralytics.yolo.engine.model import YOLO
|
||||||
from ultralytics.yolo.utils.checks import check_yolo as checks
|
from ultralytics.yolo.utils.checks import check_yolo as checks
|
||||||
|
|
||||||
__all__ = ['__version__', 'YOLO', 'checks'] # allow simpler import
|
__all__ = '__version__', 'YOLO', 'checks' # allow simpler import
|
||||||
|
@ -154,11 +154,12 @@ class Traces:
|
|||||||
'python': platform.python_version(),
|
'python': platform.python_version(),
|
||||||
'release': __version__,
|
'release': __version__,
|
||||||
'environment': ENVIRONMENT}
|
'environment': ENVIRONMENT}
|
||||||
self.enabled = SETTINGS['sync'] and \
|
self.enabled = \
|
||||||
RANK in {-1, 0} and \
|
SETTINGS['sync'] and \
|
||||||
check_online() and \
|
RANK in {-1, 0} and \
|
||||||
not TESTS_RUNNING and \
|
check_online() and \
|
||||||
(is_pip_package() or get_git_origin_url() == 'https://github.com/ultralytics/ultralytics.git')
|
not TESTS_RUNNING and \
|
||||||
|
(is_pip_package() or get_git_origin_url() == 'https://github.com/ultralytics/ultralytics.git')
|
||||||
|
|
||||||
def __call__(self, cfg, all_keys=False, traces_sample_rate=1.0):
|
def __call__(self, cfg, all_keys=False, traces_sample_rate=1.0):
|
||||||
"""
|
"""
|
||||||
|
@ -136,7 +136,7 @@ class AutoBackend(nn.Module):
|
|||||||
batch_dim = get_batch(network)
|
batch_dim = get_batch(network)
|
||||||
if batch_dim.is_static:
|
if batch_dim.is_static:
|
||||||
batch_size = batch_dim.get_length()
|
batch_size = batch_dim.get_length()
|
||||||
executable_network = ie.compile_model(network, device_name='CPU') # device_name="MYRIAD" for Intel NCS2
|
executable_network = ie.compile_model(network, device_name='CPU') # device_name="MYRIAD" for NCS2
|
||||||
elif engine: # TensorRT
|
elif engine: # TensorRT
|
||||||
LOGGER.info(f'Loading {w} for TensorRT inference...')
|
LOGGER.info(f'Loading {w} for TensorRT inference...')
|
||||||
import tensorrt as trt # https://developer.nvidia.com/nvidia-tensorrt-download
|
import tensorrt as trt # https://developer.nvidia.com/nvidia-tensorrt-download
|
||||||
@ -176,6 +176,8 @@ class AutoBackend(nn.Module):
|
|||||||
LOGGER.info(f'Loading {w} for CoreML inference...')
|
LOGGER.info(f'Loading {w} for CoreML inference...')
|
||||||
import coremltools as ct
|
import coremltools as ct
|
||||||
model = ct.models.MLModel(w)
|
model = ct.models.MLModel(w)
|
||||||
|
names, stride, task = (model.user_defined_metadata.get(k) for k in ('names', 'stride', 'task'))
|
||||||
|
names, stride = eval(names), int(stride)
|
||||||
elif saved_model: # TF SavedModel
|
elif saved_model: # TF SavedModel
|
||||||
LOGGER.info(f'Loading {w} for TensorFlow SavedModel inference...')
|
LOGGER.info(f'Loading {w} for TensorFlow SavedModel inference...')
|
||||||
import tensorflow as tf
|
import tensorflow as tf
|
||||||
@ -185,18 +187,13 @@ class AutoBackend(nn.Module):
|
|||||||
LOGGER.info(f'Loading {w} for TensorFlow GraphDef inference...')
|
LOGGER.info(f'Loading {w} for TensorFlow GraphDef inference...')
|
||||||
import tensorflow as tf
|
import tensorflow as tf
|
||||||
|
|
||||||
|
from ultralytics.yolo.engine.exporter import gd_outputs
|
||||||
|
|
||||||
def wrap_frozen_graph(gd, inputs, outputs):
|
def wrap_frozen_graph(gd, inputs, outputs):
|
||||||
x = tf.compat.v1.wrap_function(lambda: tf.compat.v1.import_graph_def(gd, name=''), []) # wrapped
|
x = tf.compat.v1.wrap_function(lambda: tf.compat.v1.import_graph_def(gd, name=''), []) # wrapped
|
||||||
ge = x.graph.as_graph_element
|
ge = x.graph.as_graph_element
|
||||||
return x.prune(tf.nest.map_structure(ge, inputs), tf.nest.map_structure(ge, outputs))
|
return x.prune(tf.nest.map_structure(ge, inputs), tf.nest.map_structure(ge, outputs))
|
||||||
|
|
||||||
def gd_outputs(gd):
|
|
||||||
name_list, input_list = [], []
|
|
||||||
for node in gd.node: # tensorflow.core.framework.node_def_pb2.NodeDef
|
|
||||||
name_list.append(node.name)
|
|
||||||
input_list.extend(node.input)
|
|
||||||
return sorted(f'{x}:0' for x in list(set(name_list) - set(input_list)) if not x.startswith('NoOp'))
|
|
||||||
|
|
||||||
gd = tf.Graph().as_graph_def() # TF GraphDef
|
gd = tf.Graph().as_graph_def() # TF GraphDef
|
||||||
with open(w, 'rb') as f:
|
with open(w, 'rb') as f:
|
||||||
gd.ParseFromString(f.read())
|
gd.ParseFromString(f.read())
|
||||||
@ -319,10 +316,17 @@ class AutoBackend(nn.Module):
|
|||||||
self.context.execute_v2(list(self.binding_addrs.values()))
|
self.context.execute_v2(list(self.binding_addrs.values()))
|
||||||
y = [self.bindings[x].data for x in sorted(self.output_names)]
|
y = [self.bindings[x].data for x in sorted(self.output_names)]
|
||||||
elif self.coreml: # CoreML
|
elif self.coreml: # CoreML
|
||||||
im = im.cpu().numpy()
|
im = im[0].cpu().numpy()
|
||||||
im = Image.fromarray((im[0] * 255).astype('uint8'))
|
if self.task == 'classify':
|
||||||
|
from ultralytics.yolo.data.utils import IMAGENET_MEAN, IMAGENET_STD
|
||||||
|
|
||||||
|
# im_pil = Image.fromarray(((im / 6 + 0.5) * 255).astype('uint8'))
|
||||||
|
for i in range(3):
|
||||||
|
im[..., i] *= IMAGENET_STD[i]
|
||||||
|
im[..., i] += IMAGENET_MEAN[i]
|
||||||
|
im_pil = Image.fromarray((im * 255).astype('uint8'))
|
||||||
# im = im.resize((192, 320), Image.ANTIALIAS)
|
# im = im.resize((192, 320), Image.ANTIALIAS)
|
||||||
y = self.model.predict({'image': im}) # coordinates are xywh normalized
|
y = self.model.predict({'image': im_pil}) # coordinates are xywh normalized
|
||||||
if 'confidence' in y:
|
if 'confidence' in y:
|
||||||
box = xywh2xyxy(y['coordinates'] * [[w, h, w, h]]) # xyxy pixels
|
box = xywh2xyxy(y['coordinates'] * [[w, h, w, h]]) # xyxy pixels
|
||||||
conf, cls = y['confidence'].max(1), y['confidence'].argmax(1).astype(np.float)
|
conf, cls = y['confidence'].max(1), y['confidence'].argmax(1).astype(np.float)
|
||||||
|
@ -11,7 +11,7 @@ import torch.nn as nn
|
|||||||
from ultralytics.nn.modules import (C1, C2, C3, C3TR, SPP, SPPF, Bottleneck, BottleneckCSP, C2f, C3Ghost, C3x, Classify,
|
from ultralytics.nn.modules import (C1, C2, C3, C3TR, SPP, SPPF, Bottleneck, BottleneckCSP, C2f, C3Ghost, C3x, Classify,
|
||||||
Concat, Conv, ConvTranspose, Detect, DWConv, DWConvTranspose2d, Ensemble, Focus,
|
Concat, Conv, ConvTranspose, Detect, DWConv, DWConvTranspose2d, Ensemble, Focus,
|
||||||
GhostBottleneck, GhostConv, Segment)
|
GhostBottleneck, GhostConv, Segment)
|
||||||
from ultralytics.yolo.utils import DEFAULT_CFG_DICT, DEFAULT_CFG_KEYS, LOGGER, RANK, colorstr, yaml_load
|
from ultralytics.yolo.utils import DEFAULT_CFG_DICT, DEFAULT_CFG_KEYS, LOGGER, RANK, colorstr, emojis, yaml_load
|
||||||
from ultralytics.yolo.utils.checks import check_requirements, check_yaml
|
from ultralytics.yolo.utils.checks import check_requirements, check_yaml
|
||||||
from ultralytics.yolo.utils.torch_utils import (fuse_conv_and_bn, fuse_deconv_and_bn, initialize_weights,
|
from ultralytics.yolo.utils.torch_utils import (fuse_conv_and_bn, fuse_deconv_and_bn, initialize_weights,
|
||||||
intersect_dicts, make_divisible, model_info, scale_img, time_sync)
|
intersect_dicts, make_divisible, model_info, scale_img, time_sync)
|
||||||
@ -76,7 +76,7 @@ class BaseModel(nn.Module):
|
|||||||
None
|
None
|
||||||
"""
|
"""
|
||||||
c = m == self.model[-1] # is final layer, copy input as inplace fix
|
c = m == self.model[-1] # is final layer, copy input as inplace fix
|
||||||
o = thop.profile(m, inputs=(x.clone() if c else x,), verbose=False)[0] / 1E9 * 2 if thop else 0 # FLOPs
|
o = thop.profile(m, inputs=[x.clone() if c else x], verbose=False)[0] / 1E9 * 2 if thop else 0 # FLOPs
|
||||||
t = time_sync()
|
t = time_sync()
|
||||||
for _ in range(10):
|
for _ in range(10):
|
||||||
m(x.clone() if c else x)
|
m(x.clone() if c else x)
|
||||||
@ -339,14 +339,20 @@ def torch_safe_load(weight):
|
|||||||
file = attempt_download_asset(weight) # search online if missing locally
|
file = attempt_download_asset(weight) # search online if missing locally
|
||||||
try:
|
try:
|
||||||
return torch.load(file, map_location='cpu'), file # load
|
return torch.load(file, map_location='cpu'), file # load
|
||||||
except ModuleNotFoundError as e:
|
except ModuleNotFoundError as e: # e.name is missing module name
|
||||||
if e.name == 'omegaconf': # e.name is missing module name
|
if e.name == 'models':
|
||||||
LOGGER.warning(f'WARNING ⚠️ {weight} requires {e.name}, which is not in ultralytics requirements.'
|
raise TypeError(
|
||||||
f'\nAutoInstall will run now for {e.name} but this feature will be removed in the future.'
|
emojis(f'ERROR ❌️ {weight} appears to be an Ultralytics YOLOv5 model originally trained '
|
||||||
f'\nRecommend fixes are to train a new model using updated ultralytics package or to '
|
f'with https://github.com/ultralytics/yolov5.\nThis model is NOT forwards compatible with '
|
||||||
f'download updated models from https://github.com/ultralytics/assets/releases/tag/v0.0.0')
|
f'YOLOv8 at https://github.com/ultralytics/ultralytics.'
|
||||||
if e.name != 'models':
|
f"\nRecommend fixes are to train a new model using the latest 'ultralytics' package or to "
|
||||||
check_requirements(e.name) # install missing module
|
f"run a command with an official YOLOv8 model, i.e. 'yolo predict model=yolov8n.pt'")) from e
|
||||||
|
LOGGER.warning(f"WARNING ⚠️ {weight} appears to require '{e.name}', which is not in ultralytics requirements."
|
||||||
|
f"\nAutoInstall will run now for '{e.name}' but this feature will be removed in the future."
|
||||||
|
f"\nRecommend fixes are to train a new model using the latest 'ultralytics' package or to "
|
||||||
|
f"run a command with an official YOLOv8 model, i.e. 'yolo predict model=yolov8n.pt'")
|
||||||
|
check_requirements(e.name) # install missing module
|
||||||
|
|
||||||
return torch.load(file, map_location='cpu'), file # load
|
return torch.load(file, map_location='cpu'), file # load
|
||||||
|
|
||||||
|
|
||||||
@ -437,22 +443,21 @@ def parse_model(d, ch, verbose=True): # model_dict, input_channels(3)
|
|||||||
args[j] = eval(a) if isinstance(a, str) else a # eval strings
|
args[j] = eval(a) if isinstance(a, str) else a # eval strings
|
||||||
|
|
||||||
n = n_ = max(round(n * gd), 1) if n > 1 else n # depth gain
|
n = n_ = max(round(n * gd), 1) if n > 1 else n # depth gain
|
||||||
if m in {
|
if m in (Classify, Conv, ConvTranspose, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, Focus,
|
||||||
Classify, Conv, ConvTranspose, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, Focus,
|
BottleneckCSP, C1, C2, C2f, C3, C3TR, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x):
|
||||||
BottleneckCSP, C1, C2, C2f, C3, C3TR, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x}:
|
|
||||||
c1, c2 = ch[f], args[0]
|
c1, c2 = ch[f], args[0]
|
||||||
if c2 != nc: # if c2 not equal to number of classes (i.e. for Classify() output)
|
if c2 != nc: # if c2 not equal to number of classes (i.e. for Classify() output)
|
||||||
c2 = make_divisible(c2 * gw, 8)
|
c2 = make_divisible(c2 * gw, 8)
|
||||||
|
|
||||||
args = [c1, c2, *args[1:]]
|
args = [c1, c2, *args[1:]]
|
||||||
if m in {BottleneckCSP, C1, C2, C2f, C3, C3TR, C3Ghost, C3x}:
|
if m in (BottleneckCSP, C1, C2, C2f, C3, C3TR, C3Ghost, C3x):
|
||||||
args.insert(2, n) # number of repeats
|
args.insert(2, n) # number of repeats
|
||||||
n = 1
|
n = 1
|
||||||
elif m is nn.BatchNorm2d:
|
elif m is nn.BatchNorm2d:
|
||||||
args = [ch[f]]
|
args = [ch[f]]
|
||||||
elif m is Concat:
|
elif m is Concat:
|
||||||
c2 = sum(ch[x] for x in f)
|
c2 = sum(ch[x] for x in f)
|
||||||
elif m in {Detect, Segment}:
|
elif m in (Detect, Segment):
|
||||||
args.append([ch[x] for x in f])
|
args.append([ch[x] for x in f])
|
||||||
if m is Segment:
|
if m is Segment:
|
||||||
args[2] = make_divisible(args[2] * gw, 8)
|
args[2] = make_divisible(args[2] * gw, 8)
|
||||||
@ -490,11 +495,11 @@ def guess_model_task(model):
|
|||||||
def cfg2task(cfg):
|
def cfg2task(cfg):
|
||||||
# Guess from YAML dictionary
|
# Guess from YAML dictionary
|
||||||
m = cfg['head'][-1][-2].lower() # output module name
|
m = cfg['head'][-1][-2].lower() # output module name
|
||||||
if m in ['classify', 'classifier', 'cls', 'fc']:
|
if m in ('classify', 'classifier', 'cls', 'fc'):
|
||||||
return 'classify'
|
return 'classify'
|
||||||
if m in ['detect']:
|
if m == 'detect':
|
||||||
return 'detect'
|
return 'detect'
|
||||||
if m in ['segment']:
|
if m == 'segment':
|
||||||
return 'segment'
|
return 'segment'
|
||||||
|
|
||||||
# Guess from model cfg
|
# Guess from model cfg
|
||||||
|
@ -2,3 +2,5 @@
|
|||||||
|
|
||||||
from .track import register_tracker
|
from .track import register_tracker
|
||||||
from .trackers import BOTSORT, BYTETracker
|
from .trackers import BOTSORT, BYTETracker
|
||||||
|
|
||||||
|
__all__ = 'register_tracker', 'BOTSORT', 'BYTETracker' # allow simpler import
|
||||||
|
@ -2,3 +2,5 @@
|
|||||||
|
|
||||||
from .bot_sort import BOTSORT
|
from .bot_sort import BOTSORT
|
||||||
from .byte_tracker import BYTETracker
|
from .byte_tracker import BYTETracker
|
||||||
|
|
||||||
|
__all__ = 'BOTSORT', 'BYTETracker' # allow simpler import
|
||||||
|
@ -213,7 +213,7 @@ class GMC:
|
|||||||
prev_pt = np.array(self.prevKeyPoints[m.queryIdx].pt, dtype=np.int_)
|
prev_pt = np.array(self.prevKeyPoints[m.queryIdx].pt, dtype=np.int_)
|
||||||
curr_pt = np.array(keypoints[m.trainIdx].pt, dtype=np.int_)
|
curr_pt = np.array(keypoints[m.trainIdx].pt, dtype=np.int_)
|
||||||
curr_pt[0] += W
|
curr_pt[0] += W
|
||||||
color = np.random.randint(0, 255, (3,))
|
color = np.random.randint(0, 255, 3)
|
||||||
color = (int(color[0]), int(color[1]), int(color[2]))
|
color = (int(color[0]), int(color[1]), int(color[2]))
|
||||||
|
|
||||||
matches_img = cv2.line(matches_img, prev_pt, curr_pt, tuple(color), 1, cv2.LINE_AA)
|
matches_img = cv2.line(matches_img, prev_pt, curr_pt, tuple(color), 1, cv2.LINE_AA)
|
||||||
|
@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
from . import v8
|
from . import v8
|
||||||
|
|
||||||
__all__ = ['v8']
|
__all__ = 'v8', # tuple or list
|
||||||
|
@ -269,6 +269,11 @@ def entrypoint(debug=''):
|
|||||||
checks.check_yolo()
|
checks.check_yolo()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Task
|
||||||
|
task = overrides.get('task')
|
||||||
|
if task and task not in TASKS:
|
||||||
|
raise ValueError(f"Invalid 'task={task}'. Valid tasks are {TASKS}.\n{CLI_HELP_MSG}")
|
||||||
|
|
||||||
# Model
|
# Model
|
||||||
model = overrides.pop('model', DEFAULT_CFG.model)
|
model = overrides.pop('model', DEFAULT_CFG.model)
|
||||||
if model is None:
|
if model is None:
|
||||||
@ -276,15 +281,11 @@ def entrypoint(debug=''):
|
|||||||
LOGGER.warning(f"WARNING ⚠️ 'model' is missing. Using default 'model={model}'.")
|
LOGGER.warning(f"WARNING ⚠️ 'model' is missing. Using default 'model={model}'.")
|
||||||
from ultralytics.yolo.engine.model import YOLO
|
from ultralytics.yolo.engine.model import YOLO
|
||||||
overrides['model'] = model
|
overrides['model'] = model
|
||||||
model = YOLO(model)
|
model = YOLO(model, task=task)
|
||||||
|
|
||||||
# Task
|
# Task Update
|
||||||
task = overrides.get('task', model.task)
|
task = task or model.task
|
||||||
if task is not None:
|
overrides['task'] = task
|
||||||
if task not in TASKS:
|
|
||||||
raise ValueError(f"Invalid 'task={task}'. Valid tasks are {TASKS}.\n{CLI_HELP_MSG}")
|
|
||||||
else:
|
|
||||||
model.task = task
|
|
||||||
|
|
||||||
# Mode
|
# Mode
|
||||||
if mode in {'predict', 'track'} and 'source' not in overrides:
|
if mode in {'predict', 'track'} and 'source' not in overrides:
|
||||||
|
@ -5,12 +5,5 @@ from .build import build_classification_dataloader, build_dataloader, load_infer
|
|||||||
from .dataset import ClassificationDataset, SemanticDataset, YOLODataset
|
from .dataset import ClassificationDataset, SemanticDataset, YOLODataset
|
||||||
from .dataset_wrappers import MixAndRectDataset
|
from .dataset_wrappers import MixAndRectDataset
|
||||||
|
|
||||||
__all__ = [
|
__all__ = ('BaseDataset', 'ClassificationDataset', 'MixAndRectDataset', 'SemanticDataset', 'YOLODataset',
|
||||||
'BaseDataset',
|
'build_classification_dataloader', 'build_dataloader', 'load_inference_source')
|
||||||
'ClassificationDataset',
|
|
||||||
'MixAndRectDataset',
|
|
||||||
'SemanticDataset',
|
|
||||||
'YOLODataset',
|
|
||||||
'build_classification_dataloader',
|
|
||||||
'build_dataloader',
|
|
||||||
'load_inference_source',]
|
|
||||||
|
@ -564,7 +564,7 @@ class Albumentations:
|
|||||||
A.CLAHE(p=0.01),
|
A.CLAHE(p=0.01),
|
||||||
A.RandomBrightnessContrast(p=0.0),
|
A.RandomBrightnessContrast(p=0.0),
|
||||||
A.RandomGamma(p=0.0),
|
A.RandomGamma(p=0.0),
|
||||||
A.ImageCompression(quality_lower=75, p=0.0),] # transforms
|
A.ImageCompression(quality_lower=75, p=0.0)] # transforms
|
||||||
self.transform = A.Compose(T, bbox_params=A.BboxParams(format='yolo', label_fields=['class_labels']))
|
self.transform = A.Compose(T, bbox_params=A.BboxParams(format='yolo', label_fields=['class_labels']))
|
||||||
|
|
||||||
LOGGER.info(prefix + ', '.join(f'{x}'.replace('always_apply=False, ', '') for x in T if x.p))
|
LOGGER.info(prefix + ', '.join(f'{x}'.replace('always_apply=False, ', '') for x in T if x.p))
|
||||||
@ -671,14 +671,14 @@ def v8_transforms(dataset, imgsz, hyp):
|
|||||||
shear=hyp.shear,
|
shear=hyp.shear,
|
||||||
perspective=hyp.perspective,
|
perspective=hyp.perspective,
|
||||||
pre_transform=LetterBox(new_shape=(imgsz, imgsz)),
|
pre_transform=LetterBox(new_shape=(imgsz, imgsz)),
|
||||||
),])
|
)])
|
||||||
return Compose([
|
return Compose([
|
||||||
pre_transform,
|
pre_transform,
|
||||||
MixUp(dataset, pre_transform=pre_transform, p=hyp.mixup),
|
MixUp(dataset, pre_transform=pre_transform, p=hyp.mixup),
|
||||||
Albumentations(p=1.0),
|
Albumentations(p=1.0),
|
||||||
RandomHSV(hgain=hyp.hsv_h, sgain=hyp.hsv_s, vgain=hyp.hsv_v),
|
RandomHSV(hgain=hyp.hsv_h, sgain=hyp.hsv_s, vgain=hyp.hsv_v),
|
||||||
RandomFlip(direction='vertical', p=hyp.flipud),
|
RandomFlip(direction='vertical', p=hyp.flipud),
|
||||||
RandomFlip(direction='horizontal', p=hyp.fliplr),]) # transforms
|
RandomFlip(direction='horizontal', p=hyp.fliplr)]) # transforms
|
||||||
|
|
||||||
|
|
||||||
# Classification augmentations -----------------------------------------------------------------------------------------
|
# Classification augmentations -----------------------------------------------------------------------------------------
|
||||||
@ -719,8 +719,8 @@ def classify_albumentations(
|
|||||||
if vflip > 0:
|
if vflip > 0:
|
||||||
T += [A.VerticalFlip(p=vflip)]
|
T += [A.VerticalFlip(p=vflip)]
|
||||||
if jitter > 0:
|
if jitter > 0:
|
||||||
color_jitter = (float(jitter),) * 3 # repeat value for brightness, contrast, saturation, 0 hue
|
jitter = float(jitter)
|
||||||
T += [A.ColorJitter(*color_jitter, 0)]
|
T += [A.ColorJitter(jitter, jitter, jitter, 0)] # brightness, contrast, saturation, 0 hue
|
||||||
else: # Use fixed crop for eval set (reproducibility)
|
else: # Use fixed crop for eval set (reproducibility)
|
||||||
T = [A.SmallestMaxSize(max_size=size), A.CenterCrop(height=size, width=size)]
|
T = [A.SmallestMaxSize(max_size=size), A.CenterCrop(height=size, width=size)]
|
||||||
T += [A.Normalize(mean=mean, std=std), ToTensorV2()] # Normalize and convert to Tensor
|
T += [A.Normalize(mean=mean, std=std), ToTensorV2()] # Normalize and convert to Tensor
|
||||||
|
@ -24,20 +24,18 @@ class BaseDataset(Dataset):
|
|||||||
label_path (str): label path, this can also be an ann_file or other custom label path.
|
label_path (str): label path, this can also be an ann_file or other custom label path.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(self,
|
||||||
self,
|
img_path,
|
||||||
img_path,
|
imgsz=640,
|
||||||
imgsz=640,
|
cache=False,
|
||||||
cache=False,
|
augment=True,
|
||||||
augment=True,
|
hyp=None,
|
||||||
hyp=None,
|
prefix='',
|
||||||
prefix='',
|
rect=False,
|
||||||
rect=False,
|
batch_size=None,
|
||||||
batch_size=None,
|
stride=32,
|
||||||
stride=32,
|
pad=0.5,
|
||||||
pad=0.5,
|
single_cls=False):
|
||||||
single_cls=False,
|
|
||||||
):
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.img_path = img_path
|
self.img_path = img_path
|
||||||
self.imgsz = imgsz
|
self.imgsz = imgsz
|
||||||
|
@ -335,8 +335,8 @@ def classify_albumentations(
|
|||||||
if vflip > 0:
|
if vflip > 0:
|
||||||
T += [A.VerticalFlip(p=vflip)]
|
T += [A.VerticalFlip(p=vflip)]
|
||||||
if jitter > 0:
|
if jitter > 0:
|
||||||
color_jitter = (float(jitter),) * 3 # repeat value for brightness, contrast, satuaration, 0 hue
|
jitter = float(jitter)
|
||||||
T += [A.ColorJitter(*color_jitter, 0)]
|
T += [A.ColorJitter(jitter, jitter, jitter, 0)] # brightness, contrast, satuaration, 0 hue
|
||||||
else: # Use fixed crop for eval set (reproducibility)
|
else: # Use fixed crop for eval set (reproducibility)
|
||||||
T = [A.SmallestMaxSize(max_size=size), A.CenterCrop(height=size, width=size)]
|
T = [A.SmallestMaxSize(max_size=size), A.CenterCrop(height=size, width=size)]
|
||||||
T += [A.Normalize(mean=mean, std=std), ToTensorV2()] # Normalize and convert to Tensor
|
T += [A.Normalize(mean=mean, std=std), ToTensorV2()] # Normalize and convert to Tensor
|
||||||
|
@ -4,13 +4,16 @@ from itertools import repeat
|
|||||||
from multiprocessing.pool import ThreadPool
|
from multiprocessing.pool import ThreadPool
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
import torch
|
||||||
import torchvision
|
import torchvision
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
from ..utils import NUM_THREADS, TQDM_BAR_FORMAT, is_dir_writeable
|
from ..utils import NUM_THREADS, TQDM_BAR_FORMAT, is_dir_writeable
|
||||||
from .augment import *
|
from .augment import Compose, Format, Instances, LetterBox, classify_albumentations, classify_transforms, v8_transforms
|
||||||
from .base import BaseDataset
|
from .base import BaseDataset
|
||||||
from .utils import HELP_URL, LOCAL_RANK, get_hash, img2label_paths, verify_image_label
|
from .utils import HELP_URL, LOCAL_RANK, LOGGER, get_hash, img2label_paths, verify_image_label
|
||||||
|
|
||||||
|
|
||||||
class YOLODataset(BaseDataset):
|
class YOLODataset(BaseDataset):
|
||||||
|
@ -50,7 +50,6 @@ TensorFlow.js:
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import re
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
import warnings
|
import warnings
|
||||||
@ -90,9 +89,9 @@ def export_formats():
|
|||||||
['TensorFlow SavedModel', 'saved_model', '_saved_model', True, True],
|
['TensorFlow SavedModel', 'saved_model', '_saved_model', True, True],
|
||||||
['TensorFlow GraphDef', 'pb', '.pb', True, True],
|
['TensorFlow GraphDef', 'pb', '.pb', True, True],
|
||||||
['TensorFlow Lite', 'tflite', '.tflite', True, False],
|
['TensorFlow Lite', 'tflite', '.tflite', True, False],
|
||||||
['TensorFlow Edge TPU', 'edgetpu', '_edgetpu.tflite', False, False],
|
['TensorFlow Edge TPU', 'edgetpu', '_edgetpu.tflite', True, False],
|
||||||
['TensorFlow.js', 'tfjs', '_web_model', False, False],
|
['TensorFlow.js', 'tfjs', '_web_model', True, False],
|
||||||
['PaddlePaddle', 'paddle', '_paddle_model', True, True],]
|
['PaddlePaddle', 'paddle', '_paddle_model', True, True], ]
|
||||||
return pd.DataFrame(x, columns=['Format', 'Argument', 'Suffix', 'CPU', 'GPU'])
|
return pd.DataFrame(x, columns=['Format', 'Argument', 'Suffix', 'CPU', 'GPU'])
|
||||||
|
|
||||||
|
|
||||||
@ -100,6 +99,15 @@ EXPORT_FORMATS_LIST = list(export_formats()['Argument'][1:])
|
|||||||
EXPORT_FORMATS_TABLE = str(export_formats())
|
EXPORT_FORMATS_TABLE = str(export_formats())
|
||||||
|
|
||||||
|
|
||||||
|
def gd_outputs(gd):
|
||||||
|
# TensorFlow GraphDef model output node names
|
||||||
|
name_list, input_list = [], []
|
||||||
|
for node in gd.node: # tensorflow.core.framework.node_def_pb2.NodeDef
|
||||||
|
name_list.append(node.name)
|
||||||
|
input_list.extend(node.input)
|
||||||
|
return sorted(f'{x}:0' for x in list(set(name_list) - set(input_list)) if not x.startswith('NoOp'))
|
||||||
|
|
||||||
|
|
||||||
def try_export(inner_func):
|
def try_export(inner_func):
|
||||||
# YOLOv8 export decorator, i..e @try_export
|
# YOLOv8 export decorator, i..e @try_export
|
||||||
inner_args = get_default_args(inner_func)
|
inner_args = get_default_args(inner_func)
|
||||||
@ -164,10 +172,10 @@ class Exporter:
|
|||||||
# Checks
|
# Checks
|
||||||
model.names = check_class_names(model.names)
|
model.names = check_class_names(model.names)
|
||||||
self.imgsz = check_imgsz(self.args.imgsz, stride=model.stride, min_dim=2) # check image size
|
self.imgsz = check_imgsz(self.args.imgsz, stride=model.stride, min_dim=2) # check image size
|
||||||
if model.task == 'classify':
|
|
||||||
self.args.nms = self.args.agnostic_nms = False
|
|
||||||
if self.args.optimize:
|
if self.args.optimize:
|
||||||
assert self.device.type == 'cpu', '--optimize not compatible with cuda devices, i.e. use --device cpu'
|
assert self.device.type == 'cpu', '--optimize not compatible with cuda devices, i.e. use --device cpu'
|
||||||
|
if edgetpu and not LINUX:
|
||||||
|
raise SystemError('Edge TPU export only supported on Linux. See https://coral.ai/docs/edgetpu/compiler/')
|
||||||
|
|
||||||
# Input
|
# Input
|
||||||
im = torch.zeros(self.args.batch, 3, *self.imgsz).to(self.device)
|
im = torch.zeros(self.args.batch, 3, *self.imgsz).to(self.device)
|
||||||
@ -208,7 +216,7 @@ class Exporter:
|
|||||||
self.file = file
|
self.file = file
|
||||||
self.output_shape = tuple(y.shape) if isinstance(y, torch.Tensor) else tuple(tuple(x.shape) for x in y)
|
self.output_shape = tuple(y.shape) if isinstance(y, torch.Tensor) else tuple(tuple(x.shape) for x in y)
|
||||||
self.pretty_name = self.file.stem.replace('yolo', 'YOLO')
|
self.pretty_name = self.file.stem.replace('yolo', 'YOLO')
|
||||||
description = f'Ultralytics {self.pretty_name} model' + f'trained on {Path(self.args.data).name}' \
|
description = f'Ultralytics {self.pretty_name} model ' + f'trained on {Path(self.args.data).name}' \
|
||||||
if self.args.data else '(untrained)'
|
if self.args.data else '(untrained)'
|
||||||
self.metadata = {
|
self.metadata = {
|
||||||
'description': description,
|
'description': description,
|
||||||
@ -239,8 +247,7 @@ class Exporter:
|
|||||||
'Please consider contributing to the effort if you have TF expertise. Thank you!')
|
'Please consider contributing to the effort if you have TF expertise. Thank you!')
|
||||||
nms = False
|
nms = False
|
||||||
self.args.int8 |= edgetpu
|
self.args.int8 |= edgetpu
|
||||||
f[5], s_model = self._export_saved_model(nms=nms or self.args.agnostic_nms or tfjs,
|
f[5], s_model = self._export_saved_model()
|
||||||
agnostic_nms=self.args.agnostic_nms or tfjs)
|
|
||||||
if pb or tfjs: # pb prerequisite to tfjs
|
if pb or tfjs: # pb prerequisite to tfjs
|
||||||
f[6], _ = self._export_pb(s_model)
|
f[6], _ = self._export_pb(s_model)
|
||||||
if tflite:
|
if tflite:
|
||||||
@ -386,7 +393,7 @@ class Exporter:
|
|||||||
check_requirements('coremltools>=6.0')
|
check_requirements('coremltools>=6.0')
|
||||||
import coremltools as ct # noqa
|
import coremltools as ct # noqa
|
||||||
|
|
||||||
class iOSModel(torch.nn.Module):
|
class iOSDetectModel(torch.nn.Module):
|
||||||
# Wrap an Ultralytics YOLO model for iOS export
|
# Wrap an Ultralytics YOLO model for iOS export
|
||||||
def __init__(self, model, im):
|
def __init__(self, model, im):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@ -405,29 +412,36 @@ class Exporter:
|
|||||||
LOGGER.info(f'\n{prefix} starting export with coremltools {ct.__version__}...')
|
LOGGER.info(f'\n{prefix} starting export with coremltools {ct.__version__}...')
|
||||||
f = self.file.with_suffix('.mlmodel')
|
f = self.file.with_suffix('.mlmodel')
|
||||||
|
|
||||||
|
bias = [0.0, 0.0, 0.0]
|
||||||
|
scale = 1 / 255
|
||||||
|
classifier_config = None
|
||||||
if self.model.task == 'classify':
|
if self.model.task == 'classify':
|
||||||
bias = [-x for x in IMAGENET_MEAN]
|
bias = [-x for x in IMAGENET_MEAN]
|
||||||
scale = 1 / 255 / (sum(IMAGENET_STD) / 3)
|
scale = 1 / 255 / (sum(IMAGENET_STD) / 3)
|
||||||
classifier_config = ct.ClassifierConfig(list(self.model.names.values())) if self.args.nms else None
|
classifier_config = ct.ClassifierConfig(list(self.model.names.values())) if self.args.nms else None
|
||||||
else:
|
model = self.model
|
||||||
bias = [0.0, 0.0, 0.0]
|
elif self.model.task == 'detect':
|
||||||
scale = 1 / 255
|
model = iOSDetectModel(self.model, self.im) if self.args.nms else self.model
|
||||||
classifier_config = None
|
elif self.model.task == 'segment':
|
||||||
model = iOSModel(self.model, self.im).eval() if self.args.nms else self.model
|
# TODO CoreML Segmentation model pipelining
|
||||||
ts = torch.jit.trace(model, self.im, strict=False) # TorchScript model
|
model = self.model
|
||||||
|
|
||||||
|
ts = torch.jit.trace(model.eval(), self.im, strict=False) # TorchScript model
|
||||||
ct_model = ct.convert(ts,
|
ct_model = ct.convert(ts,
|
||||||
inputs=[ct.ImageType('image', shape=self.im.shape, scale=scale, bias=bias)],
|
inputs=[ct.ImageType('image', shape=self.im.shape, scale=scale, bias=bias)],
|
||||||
classifier_config=classifier_config)
|
classifier_config=classifier_config)
|
||||||
bits, mode = (8, 'kmeans_lut') if self.args.int8 else (16, 'linear') if self.args.half else (32, None)
|
bits, mode = (8, 'kmeans_lut') if self.args.int8 else (16, 'linear') if self.args.half else (32, None)
|
||||||
if bits < 32:
|
if bits < 32:
|
||||||
ct_model = ct.models.neural_network.quantization_utils.quantize_weights(ct_model, bits, mode)
|
ct_model = ct.models.neural_network.quantization_utils.quantize_weights(ct_model, bits, mode)
|
||||||
if self.args.nms:
|
if self.args.nms and self.model.task == 'detect':
|
||||||
ct_model = self._pipeline_coreml(ct_model)
|
ct_model = self._pipeline_coreml(ct_model)
|
||||||
|
|
||||||
ct_model.short_description = self.metadata['description']
|
m = self.metadata # metadata dict
|
||||||
ct_model.author = self.metadata['author']
|
ct_model.short_description = m['description']
|
||||||
ct_model.license = self.metadata['license']
|
ct_model.author = m['author']
|
||||||
ct_model.version = self.metadata['version']
|
ct_model.license = m['license']
|
||||||
|
ct_model.version = m['version']
|
||||||
|
ct_model.user_defined_metadata.update({k: str(v) for k, v in m.items() if k in ('stride', 'task', 'names')})
|
||||||
ct_model.save(str(f))
|
ct_model.save(str(f))
|
||||||
return f, ct_model
|
return f, ct_model
|
||||||
|
|
||||||
@ -497,14 +511,7 @@ class Exporter:
|
|||||||
return f, None
|
return f, None
|
||||||
|
|
||||||
@try_export
|
@try_export
|
||||||
def _export_saved_model(self,
|
def _export_saved_model(self, prefix=colorstr('TensorFlow SavedModel:')):
|
||||||
nms=False,
|
|
||||||
agnostic_nms=False,
|
|
||||||
topk_per_class=100,
|
|
||||||
topk_all=100,
|
|
||||||
iou_thres=0.45,
|
|
||||||
conf_thres=0.25,
|
|
||||||
prefix=colorstr('TensorFlow SavedModel:')):
|
|
||||||
|
|
||||||
# YOLOv8 TensorFlow SavedModel export
|
# YOLOv8 TensorFlow SavedModel export
|
||||||
try:
|
try:
|
||||||
@ -562,6 +569,9 @@ class Exporter:
|
|||||||
@try_export
|
@try_export
|
||||||
def _export_tflite(self, keras_model, nms, agnostic_nms, prefix=colorstr('TensorFlow Lite:')):
|
def _export_tflite(self, keras_model, nms, agnostic_nms, prefix=colorstr('TensorFlow Lite:')):
|
||||||
# YOLOv8 TensorFlow Lite export
|
# YOLOv8 TensorFlow Lite export
|
||||||
|
import tensorflow as tf # noqa
|
||||||
|
|
||||||
|
LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...')
|
||||||
saved_model = Path(str(self.file).replace(self.file.suffix, '_saved_model'))
|
saved_model = Path(str(self.file).replace(self.file.suffix, '_saved_model'))
|
||||||
if self.args.int8:
|
if self.args.int8:
|
||||||
f = saved_model / (self.file.stem + 'yolov8n_integer_quant.tflite') # fp32 in/out
|
f = saved_model / (self.file.stem + 'yolov8n_integer_quant.tflite') # fp32 in/out
|
||||||
@ -572,9 +582,6 @@ class Exporter:
|
|||||||
return str(f), None # noqa
|
return str(f), None # noqa
|
||||||
|
|
||||||
# OLD VERSION BELOW ---------------------------------------------------------------
|
# OLD VERSION BELOW ---------------------------------------------------------------
|
||||||
import tensorflow as tf # noqa
|
|
||||||
|
|
||||||
LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...')
|
|
||||||
batch_size, ch, *imgsz = list(self.im.shape) # BCHW
|
batch_size, ch, *imgsz = list(self.im.shape) # BCHW
|
||||||
f = str(self.file).replace(self.file.suffix, '-fp16.tflite')
|
f = str(self.file).replace(self.file.suffix, '-fp16.tflite')
|
||||||
|
|
||||||
@ -619,7 +626,9 @@ class Exporter:
|
|||||||
LOGGER.info(f'\n{prefix} export requires Edge TPU compiler. Attempting install from {help_url}')
|
LOGGER.info(f'\n{prefix} export requires Edge TPU compiler. Attempting install from {help_url}')
|
||||||
sudo = subprocess.run('sudo --version >/dev/null', shell=True).returncode == 0 # sudo installed on system
|
sudo = subprocess.run('sudo --version >/dev/null', shell=True).returncode == 0 # sudo installed on system
|
||||||
for c in (
|
for c in (
|
||||||
'curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -',
|
# 'curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -', # errors
|
||||||
|
'wget --no-check-certificate -q -O - https://packages.cloud.google.com/apt/doc/apt-key.gpg | '
|
||||||
|
'sudo apt-key add -',
|
||||||
'echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" | ' # no comma
|
'echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" | ' # no comma
|
||||||
'sudo tee /etc/apt/sources.list.d/coral-edgetpu.list',
|
'sudo tee /etc/apt/sources.list.d/coral-edgetpu.list',
|
||||||
'sudo apt-get update',
|
'sudo apt-get update',
|
||||||
@ -639,30 +648,36 @@ class Exporter:
|
|||||||
def _export_tfjs(self, prefix=colorstr('TensorFlow.js:')):
|
def _export_tfjs(self, prefix=colorstr('TensorFlow.js:')):
|
||||||
# YOLOv8 TensorFlow.js export
|
# YOLOv8 TensorFlow.js export
|
||||||
check_requirements('tensorflowjs')
|
check_requirements('tensorflowjs')
|
||||||
|
import tensorflow as tf
|
||||||
import tensorflowjs as tfjs # noqa
|
import tensorflowjs as tfjs # noqa
|
||||||
|
|
||||||
LOGGER.info(f'\n{prefix} starting export with tensorflowjs {tfjs.__version__}...')
|
LOGGER.info(f'\n{prefix} starting export with tensorflowjs {tfjs.__version__}...')
|
||||||
f = str(self.file).replace(self.file.suffix, '_web_model') # js dir
|
f = str(self.file).replace(self.file.suffix, '_web_model') # js dir
|
||||||
f_pb = self.file.with_suffix('.pb') # *.pb path
|
f_pb = self.file.with_suffix('.pb') # *.pb path
|
||||||
f_json = Path(f) / 'model.json' # *.json path
|
|
||||||
|
|
||||||
cmd = f'tensorflowjs_converter --input_format=tf_frozen_model ' \
|
gd = tf.Graph().as_graph_def() # TF GraphDef
|
||||||
f'--output_node_names=Identity,Identity_1,Identity_2,Identity_3 {f_pb} {f}'
|
with open(f_pb, 'rb') as file:
|
||||||
|
gd.ParseFromString(file.read())
|
||||||
|
outputs = ','.join(gd_outputs(gd))
|
||||||
|
LOGGER.info(f'\n{prefix} output node names: {outputs}')
|
||||||
|
|
||||||
|
cmd = f'tensorflowjs_converter --input_format=tf_frozen_model --output_node_names={outputs} {f_pb} {f}'
|
||||||
subprocess.run(cmd.split(), check=True)
|
subprocess.run(cmd.split(), check=True)
|
||||||
|
|
||||||
with open(f_json, 'w') as j: # sort JSON Identity_* in ascending order
|
# f_json = Path(f) / 'model.json' # *.json path
|
||||||
subst = re.sub(
|
# with open(f_json, 'w') as j: # sort JSON Identity_* in ascending order
|
||||||
r'{"outputs": {"Identity.?.?": {"name": "Identity.?.?"}, '
|
# subst = re.sub(
|
||||||
r'"Identity.?.?": {"name": "Identity.?.?"}, '
|
# r'{"outputs": {"Identity.?.?": {"name": "Identity.?.?"}, '
|
||||||
r'"Identity.?.?": {"name": "Identity.?.?"}, '
|
# r'"Identity.?.?": {"name": "Identity.?.?"}, '
|
||||||
r'"Identity.?.?": {"name": "Identity.?.?"}}}',
|
# r'"Identity.?.?": {"name": "Identity.?.?"}, '
|
||||||
r'{"outputs": {"Identity": {"name": "Identity"}, '
|
# r'"Identity.?.?": {"name": "Identity.?.?"}}}',
|
||||||
r'"Identity_1": {"name": "Identity_1"}, '
|
# r'{"outputs": {"Identity": {"name": "Identity"}, '
|
||||||
r'"Identity_2": {"name": "Identity_2"}, '
|
# r'"Identity_1": {"name": "Identity_1"}, '
|
||||||
r'"Identity_3": {"name": "Identity_3"}}}',
|
# r'"Identity_2": {"name": "Identity_2"}, '
|
||||||
f_json.read_text(),
|
# r'"Identity_3": {"name": "Identity_3"}}}',
|
||||||
)
|
# f_json.read_text(),
|
||||||
j.write(subst)
|
# )
|
||||||
|
# j.write(subst)
|
||||||
yaml_save(Path(f) / 'metadata.yaml', self.metadata) # add metadata.yaml
|
yaml_save(Path(f) / 'metadata.yaml', self.metadata) # add metadata.yaml
|
||||||
return f, None
|
return f, None
|
||||||
|
|
||||||
@ -680,7 +695,7 @@ class Exporter:
|
|||||||
model_meta.license = self.metadata['license']
|
model_meta.license = self.metadata['license']
|
||||||
|
|
||||||
# Label file
|
# Label file
|
||||||
tmp_file = file.parent / 'temp_meta.txt'
|
tmp_file = Path(file).parent / 'temp_meta.txt'
|
||||||
with open(tmp_file, 'w') as f:
|
with open(tmp_file, 'w') as f:
|
||||||
f.write(str(self.metadata))
|
f.write(str(self.metadata))
|
||||||
|
|
||||||
@ -718,7 +733,7 @@ class Exporter:
|
|||||||
b.Finish(model_meta.Pack(b), _metadata.MetadataPopulator.METADATA_FILE_IDENTIFIER)
|
b.Finish(model_meta.Pack(b), _metadata.MetadataPopulator.METADATA_FILE_IDENTIFIER)
|
||||||
metadata_buf = b.Output()
|
metadata_buf = b.Output()
|
||||||
|
|
||||||
populator = _metadata.MetadataPopulator.with_model_file(file)
|
populator = _metadata.MetadataPopulator.with_model_file(str(file))
|
||||||
populator.load_metadata_buffer(metadata_buf)
|
populator.load_metadata_buffer(metadata_buf)
|
||||||
populator.load_associated_files([str(tmp_file)])
|
populator.load_associated_files([str(tmp_file)])
|
||||||
populator.populate()
|
populator.populate()
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List
|
|
||||||
|
|
||||||
from ultralytics import yolo # noqa
|
from ultralytics import yolo # noqa
|
||||||
from ultralytics.nn.tasks import (ClassificationModel, DetectionModel, SegmentationModel, attempt_load_one_weight,
|
from ultralytics.nn.tasks import (ClassificationModel, DetectionModel, SegmentationModel, attempt_load_one_weight,
|
||||||
@ -68,7 +67,7 @@ class YOLO:
|
|||||||
list(ultralytics.yolo.engine.results.Results): The prediction results.
|
list(ultralytics.yolo.engine.results.Results): The prediction results.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, model='yolov8n.pt') -> None:
|
def __init__(self, model='yolov8n.pt', task=None) -> None:
|
||||||
"""
|
"""
|
||||||
Initializes the YOLO model.
|
Initializes the YOLO model.
|
||||||
|
|
||||||
@ -91,9 +90,9 @@ class YOLO:
|
|||||||
if not suffix and Path(model).stem in GITHUB_ASSET_STEMS:
|
if not suffix and Path(model).stem in GITHUB_ASSET_STEMS:
|
||||||
model, suffix = Path(model).with_suffix('.pt'), '.pt' # add suffix, i.e. yolov8n -> yolov8n.pt
|
model, suffix = Path(model).with_suffix('.pt'), '.pt' # add suffix, i.e. yolov8n -> yolov8n.pt
|
||||||
if suffix == '.yaml':
|
if suffix == '.yaml':
|
||||||
self._new(model)
|
self._new(model, task)
|
||||||
else:
|
else:
|
||||||
self._load(model)
|
self._load(model, task)
|
||||||
|
|
||||||
def __call__(self, source=None, stream=False, **kwargs):
|
def __call__(self, source=None, stream=False, **kwargs):
|
||||||
return self.predict(source, stream, **kwargs)
|
return self.predict(source, stream, **kwargs)
|
||||||
@ -102,17 +101,18 @@ class YOLO:
|
|||||||
name = self.__class__.__name__
|
name = self.__class__.__name__
|
||||||
raise AttributeError(f"'{name}' object has no attribute '{attr}'. See valid attributes below.\n{self.__doc__}")
|
raise AttributeError(f"'{name}' object has no attribute '{attr}'. See valid attributes below.\n{self.__doc__}")
|
||||||
|
|
||||||
def _new(self, cfg: str, verbose=True):
|
def _new(self, cfg: str, task=None, verbose=True):
|
||||||
"""
|
"""
|
||||||
Initializes a new model and infers the task type from the model definitions.
|
Initializes a new model and infers the task type from the model definitions.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
cfg (str): model configuration file
|
cfg (str): model configuration file
|
||||||
|
task (str) or (None): model task
|
||||||
verbose (bool): display model info on load
|
verbose (bool): display model info on load
|
||||||
"""
|
"""
|
||||||
self.cfg = check_yaml(cfg) # check YAML
|
self.cfg = check_yaml(cfg) # check YAML
|
||||||
cfg_dict = yaml_load(self.cfg, append_filename=True) # model dict
|
cfg_dict = yaml_load(self.cfg, append_filename=True) # model dict
|
||||||
self.task = guess_model_task(cfg_dict)
|
self.task = task or guess_model_task(cfg_dict)
|
||||||
self.model = TASK_MAP[self.task][0](cfg_dict, verbose=verbose and RANK == -1) # build model
|
self.model = TASK_MAP[self.task][0](cfg_dict, verbose=verbose and RANK == -1) # build model
|
||||||
self.overrides['model'] = self.cfg
|
self.overrides['model'] = self.cfg
|
||||||
|
|
||||||
@ -121,12 +121,13 @@ class YOLO:
|
|||||||
self.model.args = {k: v for k, v in args.items() if k in DEFAULT_CFG_KEYS} # attach args to model
|
self.model.args = {k: v for k, v in args.items() if k in DEFAULT_CFG_KEYS} # attach args to model
|
||||||
self.model.task = self.task
|
self.model.task = self.task
|
||||||
|
|
||||||
def _load(self, weights: str, task=''):
|
def _load(self, weights: str, task=None):
|
||||||
"""
|
"""
|
||||||
Initializes a new model and infers the task type from the model head.
|
Initializes a new model and infers the task type from the model head.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
weights (str): model checkpoint to be loaded
|
weights (str): model checkpoint to be loaded
|
||||||
|
task (str) or (None): model task
|
||||||
"""
|
"""
|
||||||
suffix = Path(weights).suffix
|
suffix = Path(weights).suffix
|
||||||
if suffix == '.pt':
|
if suffix == '.pt':
|
||||||
@ -137,7 +138,7 @@ class YOLO:
|
|||||||
else:
|
else:
|
||||||
weights = check_file(weights)
|
weights = check_file(weights)
|
||||||
self.model, self.ckpt = weights, None
|
self.model, self.ckpt = weights, None
|
||||||
self.task = guess_model_task(weights)
|
self.task = task or guess_model_task(weights)
|
||||||
self.ckpt_path = weights
|
self.ckpt_path = weights
|
||||||
self.overrides['model'] = weights
|
self.overrides['model'] = weights
|
||||||
|
|
||||||
|
@ -32,7 +32,6 @@ from collections import defaultdict
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import cv2
|
import cv2
|
||||||
import torch
|
|
||||||
|
|
||||||
from ultralytics.nn.autobackend import AutoBackend
|
from ultralytics.nn.autobackend import AutoBackend
|
||||||
from ultralytics.yolo.cfg import get_cfg
|
from ultralytics.yolo.cfg import get_cfg
|
||||||
|
@ -242,7 +242,7 @@ class BaseTrainer:
|
|||||||
metric_keys = self.validator.metrics.keys + self.label_loss_items(prefix='val')
|
metric_keys = self.validator.metrics.keys + self.label_loss_items(prefix='val')
|
||||||
self.metrics = dict(zip(metric_keys, [0] * len(metric_keys))) # TODO: init metrics for plot_results()?
|
self.metrics = dict(zip(metric_keys, [0] * len(metric_keys))) # TODO: init metrics for plot_results()?
|
||||||
self.ema = ModelEMA(self.model)
|
self.ema = ModelEMA(self.model)
|
||||||
if self.args.plots:
|
if self.args.plots and not self.args.v5loader:
|
||||||
self.plot_training_labels()
|
self.plot_training_labels()
|
||||||
self.resume_training(ckpt)
|
self.resume_training(ckpt)
|
||||||
self.scheduler.last_epoch = self.start_epoch - 1 # do not move
|
self.scheduler.last_epoch = self.start_epoch - 1 # do not move
|
||||||
|
@ -18,7 +18,6 @@ from typing import Union
|
|||||||
import cv2
|
import cv2
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import requests
|
|
||||||
import torch
|
import torch
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
@ -517,10 +516,7 @@ def set_sentry():
|
|||||||
((is_pip_package() and not is_git_dir()) or
|
((is_pip_package() and not is_git_dir()) or
|
||||||
(get_git_origin_url() == 'https://github.com/ultralytics/ultralytics.git' and get_git_branch() == 'main')):
|
(get_git_origin_url() == 'https://github.com/ultralytics/ultralytics.git' and get_git_branch() == 'main')):
|
||||||
|
|
||||||
import hashlib
|
|
||||||
|
|
||||||
import sentry_sdk # noqa
|
import sentry_sdk # noqa
|
||||||
|
|
||||||
sentry_sdk.init(
|
sentry_sdk.init(
|
||||||
dsn='https://f805855f03bb4363bc1e16cb7d87b654@o4504521589325824.ingest.sentry.io/4504521592406016',
|
dsn='https://f805855f03bb4363bc1e16cb7d87b654@o4504521589325824.ingest.sentry.io/4504521592406016',
|
||||||
debug=False,
|
debug=False,
|
||||||
|
@ -30,14 +30,14 @@ import pandas as pd
|
|||||||
|
|
||||||
from ultralytics import YOLO
|
from ultralytics import YOLO
|
||||||
from ultralytics.yolo.engine.exporter import export_formats
|
from ultralytics.yolo.engine.exporter import export_formats
|
||||||
from ultralytics.yolo.utils import LOGGER, ROOT, SETTINGS
|
from ultralytics.yolo.utils import LINUX, LOGGER, ROOT, SETTINGS
|
||||||
from ultralytics.yolo.utils.checks import check_yolo
|
from ultralytics.yolo.utils.checks import check_yolo
|
||||||
from ultralytics.yolo.utils.downloads import download
|
from ultralytics.yolo.utils.downloads import download
|
||||||
from ultralytics.yolo.utils.files import file_size
|
from ultralytics.yolo.utils.files import file_size
|
||||||
from ultralytics.yolo.utils.torch_utils import select_device
|
from ultralytics.yolo.utils.torch_utils import select_device
|
||||||
|
|
||||||
|
|
||||||
def benchmark(model=Path(SETTINGS['weights_dir']) / 'yolov8n.pt', imgsz=160, half=False, device='cpu', hard_fail=0.30):
|
def benchmark(model=Path(SETTINGS['weights_dir']) / 'yolov8n.pt', imgsz=160, half=False, device='cpu', hard_fail=False):
|
||||||
device = select_device(device, verbose=False)
|
device = select_device(device, verbose=False)
|
||||||
if isinstance(model, (str, Path)):
|
if isinstance(model, (str, Path)):
|
||||||
model = YOLO(model)
|
model = YOLO(model)
|
||||||
@ -45,11 +45,10 @@ def benchmark(model=Path(SETTINGS['weights_dir']) / 'yolov8n.pt', imgsz=160, hal
|
|||||||
y = []
|
y = []
|
||||||
t0 = time.time()
|
t0 = time.time()
|
||||||
for i, (name, format, suffix, cpu, gpu) in export_formats().iterrows(): # index, (name, format, suffix, CPU, GPU)
|
for i, (name, format, suffix, cpu, gpu) in export_formats().iterrows(): # index, (name, format, suffix, CPU, GPU)
|
||||||
|
emoji = '❌' # indicates export failure
|
||||||
try:
|
try:
|
||||||
assert i not in (9, 10), 'inference not supported' # Edge TPU and TF.js are unsupported
|
assert i != 11, 'paddle exports coming soon'
|
||||||
assert i != 5 or platform.system() == 'Darwin', 'inference only supported on macOS>=10.13' # CoreML
|
assert i != 9 or LINUX, 'Edge TPU export only supported on Linux'
|
||||||
assert i != 11 or model.task != 'classify', 'paddle-classify bug'
|
|
||||||
|
|
||||||
if 'cpu' in device.type:
|
if 'cpu' in device.type:
|
||||||
assert cpu, 'inference not supported on CPU'
|
assert cpu, 'inference not supported on CPU'
|
||||||
if 'cuda' in device.type:
|
if 'cuda' in device.type:
|
||||||
@ -61,13 +60,16 @@ def benchmark(model=Path(SETTINGS['weights_dir']) / 'yolov8n.pt', imgsz=160, hal
|
|||||||
export = model # PyTorch format
|
export = model # PyTorch format
|
||||||
else:
|
else:
|
||||||
filename = model.export(imgsz=imgsz, format=format, half=half, device=device) # all others
|
filename = model.export(imgsz=imgsz, format=format, half=half, device=device) # all others
|
||||||
export = YOLO(filename)
|
export = YOLO(filename, task=model.task)
|
||||||
assert suffix in str(filename), 'export failed'
|
assert suffix in str(filename), 'export failed'
|
||||||
|
emoji = '❎' # indicates export succeeded
|
||||||
|
|
||||||
# Predict
|
# Predict
|
||||||
|
assert i not in (9, 10), 'inference not supported' # Edge TPU and TF.js are unsupported
|
||||||
|
assert i != 5 or platform.system() == 'Darwin', 'inference only supported on macOS>=10.13' # CoreML
|
||||||
if not (ROOT / 'assets/bus.jpg').exists():
|
if not (ROOT / 'assets/bus.jpg').exists():
|
||||||
download(url='https://ultralytics.com/images/bus.jpg', dir=ROOT / 'assets')
|
download(url='https://ultralytics.com/images/bus.jpg', dir=ROOT / 'assets')
|
||||||
export.predict(ROOT / 'assets/bus.jpg', imgsz=imgsz, device=device, half=half) # test
|
export.predict(ROOT / 'assets/bus.jpg', imgsz=imgsz, device=device, half=half)
|
||||||
|
|
||||||
# Validate
|
# Validate
|
||||||
if model.task == 'detect':
|
if model.task == 'detect':
|
||||||
@ -84,17 +86,16 @@ def benchmark(model=Path(SETTINGS['weights_dir']) / 'yolov8n.pt', imgsz=160, hal
|
|||||||
if hard_fail:
|
if hard_fail:
|
||||||
assert type(e) is AssertionError, f'Benchmark hard_fail for {name}: {e}'
|
assert type(e) is AssertionError, f'Benchmark hard_fail for {name}: {e}'
|
||||||
LOGGER.warning(f'ERROR ❌️ Benchmark failure for {name}: {e}')
|
LOGGER.warning(f'ERROR ❌️ Benchmark failure for {name}: {e}')
|
||||||
y.append([name, '❌', None, None, None]) # mAP, t_inference
|
y.append([name, emoji, None, None, None]) # mAP, t_inference
|
||||||
|
|
||||||
# Print results
|
# Print results
|
||||||
check_yolo(device=device) # print system info
|
check_yolo(device=device) # print system info
|
||||||
c = ['Format', 'Status❔', 'Size (MB)', key, 'Inference time (ms/im)']
|
df = pd.DataFrame(y, columns=['Format', 'Status❔', 'Size (MB)', key, 'Inference time (ms/im)'])
|
||||||
df = pd.DataFrame(y, columns=c)
|
|
||||||
|
|
||||||
name = Path(model.ckpt_path).name
|
name = Path(model.ckpt_path).name
|
||||||
s = f'\nBenchmarks complete for {name} on {data} at imgsz={imgsz} ({time.time() - t0:.2f}s)\n{df}\n'
|
s = f'\nBenchmarks complete for {name} on {data} at imgsz={imgsz} ({time.time() - t0:.2f}s)\n{df}\n'
|
||||||
LOGGER.info(s)
|
LOGGER.info(s)
|
||||||
with open('benchmarks.log', 'a') as f:
|
with open('benchmarks.log', 'a', errors='ignore', encoding='utf-8') as f:
|
||||||
f.write(s)
|
f.write(s)
|
||||||
|
|
||||||
if hard_fail and isinstance(hard_fail, float):
|
if hard_fail and isinstance(hard_fail, float):
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
from .base import add_integration_callbacks, default_callbacks
|
from .base import add_integration_callbacks, default_callbacks
|
||||||
|
|
||||||
__all__ = [
|
__all__ = 'add_integration_callbacks', 'default_callbacks'
|
||||||
'add_integration_callbacks',
|
|
||||||
'default_callbacks',]
|
|
||||||
|
@ -137,7 +137,6 @@ def check_latest_pypi_version(package_name='ultralytics'):
|
|||||||
def check_pip_update():
|
def check_pip_update():
|
||||||
from ultralytics import __version__
|
from ultralytics import __version__
|
||||||
latest = check_latest_pypi_version()
|
latest = check_latest_pypi_version()
|
||||||
latest = '9.0.0'
|
|
||||||
if pkg.parse_version(__version__) < pkg.parse_version(latest):
|
if pkg.parse_version(__version__) < pkg.parse_version(latest):
|
||||||
LOGGER.info(f'New https://pypi.org/project/ultralytics/{latest} available 😃 '
|
LOGGER.info(f'New https://pypi.org/project/ultralytics/{latest} available 😃 '
|
||||||
f"Update with 'pip install -U ultralytics'")
|
f"Update with 'pip install -U ultralytics'")
|
||||||
@ -239,7 +238,7 @@ def check_requirements(requirements=ROOT.parent / 'requirements.txt', exclude=()
|
|||||||
LOGGER.warning(f'{prefix} ❌ {e}')
|
LOGGER.warning(f'{prefix} ❌ {e}')
|
||||||
|
|
||||||
|
|
||||||
def check_suffix(file='yolov8n.pt', suffix=('.pt',), msg=''):
|
def check_suffix(file='yolov8n.pt', suffix='.pt', msg=''):
|
||||||
# Check file(s) for acceptable suffix
|
# Check file(s) for acceptable suffix
|
||||||
if file and suffix:
|
if file and suffix:
|
||||||
if isinstance(suffix, str):
|
if isinstance(suffix, str):
|
||||||
|
@ -10,9 +10,8 @@ import numpy as np
|
|||||||
from .ops import ltwh2xywh, ltwh2xyxy, resample_segments, xywh2ltwh, xywh2xyxy, xyxy2ltwh, xyxy2xywh
|
from .ops import ltwh2xywh, ltwh2xyxy, resample_segments, xywh2ltwh, xywh2xyxy, xyxy2ltwh, xyxy2xywh
|
||||||
|
|
||||||
|
|
||||||
# From PyTorch internals
|
|
||||||
def _ntuple(n):
|
def _ntuple(n):
|
||||||
|
# From PyTorch internals
|
||||||
def parse(x):
|
def parse(x):
|
||||||
return x if isinstance(x, abc.Iterable) else tuple(repeat(x, n))
|
return x if isinstance(x, abc.Iterable) else tuple(repeat(x, n))
|
||||||
|
|
||||||
@ -26,7 +25,7 @@ to_4tuple = _ntuple(4)
|
|||||||
# `ltwh` means left top and width, height(coco format)
|
# `ltwh` means left top and width, height(coco format)
|
||||||
_formats = ['xyxy', 'xywh', 'ltwh']
|
_formats = ['xyxy', 'xywh', 'ltwh']
|
||||||
|
|
||||||
__all__ = ['Bboxes']
|
__all__ = 'Bboxes', # tuple or list
|
||||||
|
|
||||||
|
|
||||||
class Bboxes:
|
class Bboxes:
|
||||||
|
@ -207,8 +207,7 @@ def plot_labels(boxes, cls, names=(), save_dir=Path('')):
|
|||||||
|
|
||||||
def save_one_box(xyxy, im, file=Path('im.jpg'), gain=1.02, pad=10, square=False, BGR=False, save=True):
|
def save_one_box(xyxy, im, file=Path('im.jpg'), gain=1.02, pad=10, square=False, BGR=False, save=True):
|
||||||
# Save image crop as {file} with crop size multiple {gain} and {pad} pixels. Save and/or return crop
|
# Save image crop as {file} with crop size multiple {gain} and {pad} pixels. Save and/or return crop
|
||||||
xyxy = torch.Tensor(xyxy).view(-1, 4)
|
b = xyxy2xywh(xyxy.view(-1, 4)) # boxes
|
||||||
b = xyxy2xywh(xyxy) # boxes
|
|
||||||
if square:
|
if square:
|
||||||
b[:, 2:] = b[:, 2:].max(1)[0].unsqueeze(1) # attempt rectangle to square
|
b[:, 2:] = b[:, 2:].max(1)[0].unsqueeze(1) # attempt rectangle to square
|
||||||
b[:, 2:] = b[:, 2:] * gain + pad # box wh * gain + pad
|
b[:, 2:] = b[:, 2:] * gain + pad # box wh * gain + pad
|
||||||
|
@ -195,7 +195,7 @@ def get_flops(model, imgsz=640):
|
|||||||
p = next(model.parameters())
|
p = next(model.parameters())
|
||||||
stride = max(int(model.stride.max()), 32) if hasattr(model, 'stride') else 32 # max stride
|
stride = max(int(model.stride.max()), 32) if hasattr(model, 'stride') else 32 # max stride
|
||||||
im = torch.empty((1, p.shape[1], stride, stride), device=p.device) # input image in BCHW format
|
im = torch.empty((1, p.shape[1], stride, stride), device=p.device) # input image in BCHW format
|
||||||
flops = thop.profile(deepcopy(model), inputs=(im,), verbose=False)[0] / 1E9 * 2 # stride GFLOPs
|
flops = thop.profile(deepcopy(model), inputs=[im], verbose=False)[0] / 1E9 * 2 # stride GFLOPs
|
||||||
imgsz = imgsz if isinstance(imgsz, list) else [imgsz, imgsz] # expand if int/float
|
imgsz = imgsz if isinstance(imgsz, list) else [imgsz, imgsz] # expand if int/float
|
||||||
flops = flops * imgsz[0] / stride * imgsz[1] / stride # 640x640 GFLOPs
|
flops = flops * imgsz[0] / stride * imgsz[1] / stride # 640x640 GFLOPs
|
||||||
return flops
|
return flops
|
||||||
@ -374,7 +374,7 @@ def profile(input, ops, n=10, device=None):
|
|||||||
m = m.half() if hasattr(m, 'half') and isinstance(x, torch.Tensor) and x.dtype is torch.float16 else m
|
m = m.half() if hasattr(m, 'half') and isinstance(x, torch.Tensor) and x.dtype is torch.float16 else m
|
||||||
tf, tb, t = 0, 0, [0, 0, 0] # dt forward, backward
|
tf, tb, t = 0, 0, [0, 0, 0] # dt forward, backward
|
||||||
try:
|
try:
|
||||||
flops = thop.profile(m, inputs=(x,), verbose=False)[0] / 1E9 * 2 # GFLOPs
|
flops = thop.profile(m, inputs=[x], verbose=False)[0] / 1E9 * 2 # GFLOPs
|
||||||
except Exception:
|
except Exception:
|
||||||
flops = 0
|
flops = 0
|
||||||
|
|
||||||
|
@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
from ultralytics.yolo.v8 import classify, detect, segment
|
from ultralytics.yolo.v8 import classify, detect, segment
|
||||||
|
|
||||||
__all__ = ['classify', 'segment', 'detect']
|
__all__ = 'classify', 'segment', 'detect'
|
||||||
|
@ -4,4 +4,4 @@ from ultralytics.yolo.v8.classify.predict import ClassificationPredictor, predic
|
|||||||
from ultralytics.yolo.v8.classify.train import ClassificationTrainer, train
|
from ultralytics.yolo.v8.classify.train import ClassificationTrainer, train
|
||||||
from ultralytics.yolo.v8.classify.val import ClassificationValidator, val
|
from ultralytics.yolo.v8.classify.val import ClassificationValidator, val
|
||||||
|
|
||||||
__all__ = ['ClassificationPredictor', 'predict', 'ClassificationTrainer', 'train', 'ClassificationValidator', 'val']
|
__all__ = 'ClassificationPredictor', 'predict', 'ClassificationTrainer', 'train', 'ClassificationValidator', 'val'
|
||||||
|
@ -4,4 +4,4 @@ from .predict import DetectionPredictor, predict
|
|||||||
from .train import DetectionTrainer, train
|
from .train import DetectionTrainer, train
|
||||||
from .val import DetectionValidator, val
|
from .val import DetectionValidator, val
|
||||||
|
|
||||||
__all__ = ['DetectionPredictor', 'predict', 'DetectionTrainer', 'train', 'DetectionValidator', 'val']
|
__all__ = 'DetectionPredictor', 'predict', 'DetectionTrainer', 'train', 'DetectionValidator', 'val'
|
||||||
|
@ -4,4 +4,4 @@ from .predict import SegmentationPredictor, predict
|
|||||||
from .train import SegmentationTrainer, train
|
from .train import SegmentationTrainer, train
|
||||||
from .val import SegmentationValidator, val
|
from .val import SegmentationValidator, val
|
||||||
|
|
||||||
__all__ = ['SegmentationPredictor', 'predict', 'SegmentationTrainer', 'train', 'SegmentationValidator', 'val']
|
__all__ = 'SegmentationPredictor', 'predict', 'SegmentationTrainer', 'train', 'SegmentationValidator', 'val'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user