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

Ultralytics Code Refactor https://ultralytics.com/actions #13152

Merged
merged 2 commits into from
Jun 30, 2024
Merged
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
1 change: 1 addition & 0 deletions classify/train.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ def train(opt, device):

# lf = lambda x: ((1 + math.cos(x * math.pi / epochs)) / 2) * (1 - lrf) + lrf # cosine
def lf(x):
"""Linear learning rate scheduler function, scaling learning rate from initial value to `lrf` over `epochs`."""
return (1 - x / epochs) * (1 - lrf) + lrf # linear

scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf)
Expand Down
4 changes: 3 additions & 1 deletion export.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ def try_export(inner_func):
inner_args = get_default_args(inner_func)

def outer_func(*args, **kwargs):
"""Logs success/failure and execution details of model export functions wrapped with @try_export decorator."""
prefix = inner_args["prefix"]
try:
with Profile() as dt:
Expand Down Expand Up @@ -224,7 +225,7 @@ def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr("ONNX

@try_export
def export_openvino(file, metadata, half, int8, data, prefix=colorstr("OpenVINO:")):
# YOLOv5 OpenVINO export
"""Exports a YOLOv5 model to OpenVINO format with optional FP16 and INT8 quantization; see https://pypi.org/project/openvino-dev/."""
check_requirements("openvino-dev>=2023.0") # requires openvino-dev: https://pypi.org/project/openvino-dev/
import openvino.runtime as ov # noqa
from openvino.tools import mo # noqa
Expand All @@ -244,6 +245,7 @@ def export_openvino(file, metadata, half, int8, data, prefix=colorstr("OpenVINO:
from utils.dataloaders import create_dataloader

def gen_dataloader(yaml_path, task="train", imgsz=640, workers=4):
"""Generates a DataLoader for model training or validation based on the given YAML dataset configuration."""
data_yaml = check_yaml(yaml_path)
data = check_dataset(data_yaml)
dataloader = create_dataloader(
Expand Down
1 change: 1 addition & 0 deletions segment/train.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ def train(hyp, opt, device, callbacks):
else:

def lf(x):
"""Linear learning rate scheduler decreasing from 1 to hyp['lrf'] over 'epochs'."""
return (1 - x / epochs) * (1.0 - hyp["lrf"]) + hyp["lrf"] # linear

scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # plot_lr_scheduler(optimizer, scheduler, epochs)
Expand Down
1 change: 1 addition & 0 deletions segment/val.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ def save_one_json(predn, jdict, path, class_map, pred_masks):
from pycocotools.mask import encode

def single_encode(x):
"""Encodes binary mask arrays into RLE (Run-Length Encoding) format for JSON serialization."""
rle = encode(np.asarray(x[:, :, None], order="F", dtype="uint8"))[0]
rle["counts"] = rle["counts"].decode("utf-8")
return rle
Expand Down
1 change: 1 addition & 0 deletions train.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ def train(hyp, opt, device, callbacks):
else:

def lf(x):
"""Linear learning rate scheduler function with decay calculated by epoch proportion."""
return (1 - x / epochs) * (1.0 - hyp["lrf"]) + hyp["lrf"] # linear

scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # plot_lr_scheduler(optimizer, scheduler, epochs)
Expand Down
1 change: 1 addition & 0 deletions utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def threaded(func):
"""Decorator @threaded to run a function in a separate thread, returning the thread instance."""

def wrapper(*args, **kwargs):
"""Runs the decorated function in a separate daemon thread and returns the thread instance."""
thread = threading.Thread(target=func, args=args, kwargs=kwargs, daemon=True)
thread.start()
return thread
Expand Down
4 changes: 4 additions & 0 deletions utils/autoanchor.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def check_anchors(dataset, model, thr=4.0, imgsz=640):
wh = torch.tensor(np.concatenate([l[:, 3:5] * s for s, l in zip(shapes * scale, dataset.labels)])).float() # wh

def metric(k): # compute metric
"""Computes ratio metric, anchors above threshold, and best possible recall for YOLOv5 anchor evaluation."""
r = wh[:, None] / k[None]
x = torch.min(r, 1 / r).min(2)[0] # ratio metric
best = x.max(1)[0] # best_x
Expand Down Expand Up @@ -86,16 +87,19 @@ def kmean_anchors(dataset="./data/coco128.yaml", n=9, img_size=640, thr=4.0, gen
thr = 1 / thr

def metric(k, wh): # compute metrics
"""Computes ratio metric, anchors above threshold, and best possible recall for YOLOv5 anchor evaluation."""
r = wh[:, None] / k[None]
x = torch.min(r, 1 / r).min(2)[0] # ratio metric
# x = wh_iou(wh, torch.tensor(k)) # iou metric
return x, x.max(1)[0] # x, best_x

def anchor_fitness(k): # mutation fitness
"""Evaluates fitness of YOLOv5 anchors by computing recall and ratio metrics for an anchor evolution process."""
_, best = metric(torch.tensor(k, dtype=torch.float32), wh)
return (best * (best > thr).float()).mean() # fitness

def print_results(k, verbose=True):
"""Sorts and logs kmeans-evolved anchor metrics and best possible recall values for YOLOv5 anchor evaluation."""
k = k[np.argsort(k.prod(1))] # sort small to large
x, best = metric(k, wh0)
bpr, aat = (best > thr).float().mean(), (x > thr).float().mean() * n # best possible recall, anch > thr
Expand Down
2 changes: 1 addition & 1 deletion utils/downloads.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def attempt_download(file, repo="ultralytics/yolov5", release="v7.0"):
from utils.general import LOGGER

def github_assets(repository, version="latest"):
# Return GitHub repo tag (i.e. 'v7.0') and assets (i.e. ['yolov5s.pt', 'yolov5m.pt', ...])
"""Fetches GitHub repository release tag and asset names using the GitHub API."""
if version != "latest":
version = f"tags/{version}" # i.e. tags/v7.0
response = requests.get(f"https://github.com/gitapi/repos/{repository}/releases/{version}").json() # github api
Expand Down
6 changes: 3 additions & 3 deletions utils/general.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ def check_online():
import socket

def run_once():
# Check once
"""Checks internet connectivity by attempting to create a connection to "1.1.1.1" on port 443."""
try:
socket.create_connection(("1.1.1.1", 443), 5) # check host accessibility
return True
Expand Down Expand Up @@ -587,7 +587,7 @@ def check_amp(model):
from models.common import AutoShape, DetectMultiBackend

def amp_allclose(model, im):
# All close FP32 vs AMP results
"""Compares FP32 and AMP model inference outputs, ensuring they are close within a 10% absolute tolerance."""
m = AutoShape(model, verbose=False) # model
a = m(im).xywhn[0] # FP32 inference
m.amp = True
Expand Down Expand Up @@ -652,7 +652,7 @@ def download(url, dir=".", unzip=True, delete=True, curl=False, threads=1, retry
"""Downloads and optionally unzips files concurrently, supporting retries and curl fallback."""

def download_one(url, dir):
# Download 1 file
"""Downloads a single file from `url` to `dir`, with retry support and optional curl fallback."""
success = True
if os.path.isfile(url):
f = Path(url) # filename
Expand Down
3 changes: 3 additions & 0 deletions utils/loggers/comet/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ class CometLogger:
"""Log metrics, parameters, source code, models and much more with Comet."""

def __init__(self, opt, hyp, run_id=None, job_type="Training", **experiment_kwargs) -> None:
"""Initializes CometLogger with given options, hyperparameters, run ID, job type, and additional experiment
arguments.
"""
self.job_type = job_type
self.opt = opt
self.hyp = hyp
Expand Down
3 changes: 3 additions & 0 deletions utils/plots.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ def butter_lowpass_filtfilt(data, cutoff=1500, fs=50000, order=5):

# https://stackoverflow.com/questions/28536191/how-to-filter-smooth-with-scipy-numpy
def butter_lowpass(cutoff, fs, order):
"""Applies a low-pass Butterworth filter to a signal with specified cutoff frequency, sample rate, and filter
order.
"""
nyq = 0.5 * fs
normal_cutoff = cutoff / nyq
return butter(order, normal_cutoff, btype="low", analog=False)
Expand Down
6 changes: 6 additions & 0 deletions utils/segment/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ def ap_per_class_box_and_mask(

class Metric:
def __init__(self) -> None:
"""Initializes performance metric attributes for precision, recall, F1 score, average precision, and class
indices.
"""
self.p = [] # (nc, )
self.r = [] # (nc, )
self.f1 = [] # (nc, )
Expand Down Expand Up @@ -151,6 +154,9 @@ class Metrics:
"""Metric for boxes and masks."""

def __init__(self) -> None:
"""Initializes Metric objects for bounding boxes and masks to compute performance metrics in the Metrics
class.
"""
self.metric_box = Metric()
self.metric_mask = Metric()

Expand Down
1 change: 1 addition & 0 deletions utils/torch_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def smart_inference_mode(torch_1_9=check_version(torch.__version__, "1.9.0")):
"""Applies torch.inference_mode() if torch>=1.9.0, else torch.no_grad() as a decorator for functions."""

def decorate(fn):
"""Applies torch.inference_mode() if torch>=1.9.0, else torch.no_grad() to the decorated function."""
return (torch.inference_mode if torch_1_9 else torch.no_grad)()(fn)

return decorate
Expand Down
Loading