yolov5/models/experimental.py
Ultralytics Assistant 3ec95f9e3d
Update header line in Python files (#13072)
* Add license line to .github/ISSUE_TEMPLATE/bug-report.yml

* Add license line to .github/ISSUE_TEMPLATE/config.yml

* Add license line to .github/ISSUE_TEMPLATE/feature-request.yml

* Add license line to .github/ISSUE_TEMPLATE/question.yml

* Add license line to .github/dependabot.yml

* Add license line to .github/workflows/ci-testing.yml

* Add license line to .github/workflows/cla.yml

* Add license line to .github/workflows/codeql-analysis.yml

* Add license line to .github/workflows/docker.yml

* Add license line to .github/workflows/format.yml

* Add license line to .github/workflows/greetings.yml

* Add license line to .github/workflows/links.yml

* Add license line to .github/workflows/merge-main-into-prs.yml

* Add license line to .github/workflows/stale.yml

* Add license line to benchmarks.py

* Add license line to classify/predict.py

* Add license line to classify/train.py

* Add license line to classify/val.py

* Add license line to data/Argoverse.yaml

* Add license line to data/GlobalWheat2020.yaml

* Add license line to data/ImageNet.yaml

* Add license line to data/ImageNet10.yaml

* Add license line to data/ImageNet100.yaml

* Add license line to data/ImageNet1000.yaml

* Add license line to data/Objects365.yaml

* Add license line to data/SKU-110K.yaml

* Add license line to data/VOC.yaml

* Add license line to data/VisDrone.yaml

* Add license line to data/coco.yaml

* Add license line to data/coco128-seg.yaml

* Add license line to data/coco128.yaml

* Add license line to data/hyps/hyp.Objects365.yaml

* Add license line to data/hyps/hyp.VOC.yaml

* Add license line to data/hyps/hyp.no-augmentation.yaml

* Add license line to data/hyps/hyp.scratch-high.yaml

* Add license line to data/hyps/hyp.scratch-low.yaml

* Add license line to data/hyps/hyp.scratch-med.yaml

* Add license line to data/xView.yaml

* Add license line to detect.py

* Add license line to export.py

* Add license line to hubconf.py

* Add license line to models/common.py

* Add license line to models/experimental.py

* Add license line to models/hub/anchors.yaml

* Add license line to models/hub/yolov3-spp.yaml

* Add license line to models/hub/yolov3-tiny.yaml

* Add license line to models/hub/yolov3.yaml

* Add license line to models/hub/yolov5-bifpn.yaml

* Add license line to models/hub/yolov5-fpn.yaml

* Add license line to models/hub/yolov5-p2.yaml

* Add license line to models/hub/yolov5-p34.yaml

* Add license line to models/hub/yolov5-p6.yaml

* Add license line to models/hub/yolov5-p7.yaml

* Add license line to models/hub/yolov5-panet.yaml

* Add license line to models/hub/yolov5l6.yaml

* Add license line to models/hub/yolov5m6.yaml

* Add license line to models/hub/yolov5n6.yaml

* Add license line to models/hub/yolov5s-LeakyReLU.yaml

* Add license line to models/hub/yolov5s-ghost.yaml

* Add license line to models/hub/yolov5s-transformer.yaml

* Add license line to models/hub/yolov5s6.yaml

* Add license line to models/hub/yolov5x6.yaml

* Add license line to models/segment/yolov5l-seg.yaml

* Add license line to models/segment/yolov5m-seg.yaml

* Add license line to models/segment/yolov5n-seg.yaml

* Add license line to models/segment/yolov5s-seg.yaml

* Add license line to models/segment/yolov5x-seg.yaml

* Add license line to models/tf.py

* Add license line to models/yolo.py

* Add license line to models/yolov5l.yaml

* Add license line to models/yolov5m.yaml

* Add license line to models/yolov5n.yaml

* Add license line to models/yolov5s.yaml

* Add license line to models/yolov5x.yaml

* Add license line to pyproject.toml

* Add license line to segment/predict.py

* Add license line to segment/train.py

* Add license line to segment/val.py

* Add license line to train.py

* Add license line to utils/__init__.py

* Add license line to utils/activations.py

* Add license line to utils/augmentations.py

* Add license line to utils/autoanchor.py

* Add license line to utils/autobatch.py

* Add license line to utils/aws/resume.py

* Add license line to utils/callbacks.py

* Add license line to utils/dataloaders.py

* Add license line to utils/downloads.py

* Add license line to utils/flask_rest_api/example_request.py

* Add license line to utils/flask_rest_api/restapi.py

* Add license line to utils/general.py

* Add license line to utils/google_app_engine/app.yaml

* Add license line to utils/loggers/__init__.py

* Add license line to utils/loggers/clearml/clearml_utils.py

* Add license line to utils/loggers/clearml/hpo.py

* Add license line to utils/loggers/comet/__init__.py

* Add license line to utils/loggers/comet/comet_utils.py

* Add license line to utils/loggers/comet/hpo.py

* Add license line to utils/loggers/wandb/wandb_utils.py

* Add license line to utils/loss.py

* Add license line to utils/metrics.py

* Add license line to utils/plots.py

* Add license line to utils/segment/augmentations.py

* Add license line to utils/segment/dataloaders.py

* Add license line to utils/segment/general.py

* Add license line to utils/segment/loss.py

* Add license line to utils/segment/metrics.py

* Add license line to utils/segment/plots.py

* Add license line to utils/torch_utils.py

* Add license line to utils/triton.py

* Add license line to val.py

* Auto-format by https://ultralytics.com/actions

* Update ImageNet1000.yaml

Signed-off-by: Glenn Jocher <glenn.jocher@ultralytics.com>

* Auto-format by https://ultralytics.com/actions

---------

Signed-off-by: Glenn Jocher <glenn.jocher@ultralytics.com>
Co-authored-by: Glenn Jocher <glenn.jocher@ultralytics.com>
2024-06-08 22:29:29 +02:00

131 lines
5.0 KiB
Python

# Ultralytics YOLOv5 🚀, AGPL-3.0 license
"""Experimental modules."""
import math
import numpy as np
import torch
import torch.nn as nn
from utils.downloads import attempt_download
class Sum(nn.Module):
"""Weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070."""
def __init__(self, n, weight=False):
"""Initializes a module to sum outputs of layers with number of inputs `n` and optional weighting, supporting 2+
inputs.
"""
super().__init__()
self.weight = weight # apply weights boolean
self.iter = range(n - 1) # iter object
if weight:
self.w = nn.Parameter(-torch.arange(1.0, n) / 2, requires_grad=True) # layer weights
def forward(self, x):
"""Processes input through a customizable weighted sum of `n` inputs, optionally applying learned weights."""
y = x[0] # no weight
if self.weight:
w = torch.sigmoid(self.w) * 2
for i in self.iter:
y = y + x[i + 1] * w[i]
else:
for i in self.iter:
y = y + x[i + 1]
return y
class MixConv2d(nn.Module):
"""Mixed Depth-wise Conv https://arxiv.org/abs/1907.09595."""
def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True):
"""Initializes MixConv2d with mixed depth-wise convolutional layers, taking input and output channels (c1, c2),
kernel sizes (k), stride (s), and channel distribution strategy (equal_ch).
"""
super().__init__()
n = len(k) # number of convolutions
if equal_ch: # equal c_ per group
i = torch.linspace(0, n - 1e-6, c2).floor() # c2 indices
c_ = [(i == g).sum() for g in range(n)] # intermediate channels
else: # equal weight.numel() per group
b = [c2] + [0] * n
a = np.eye(n + 1, n, k=-1)
a -= np.roll(a, 1, axis=1)
a *= np.array(k) ** 2
a[0] = 1
c_ = np.linalg.lstsq(a, b, rcond=None)[0].round() # solve for equal weight indices, ax = b
self.m = nn.ModuleList(
[nn.Conv2d(c1, int(c_), k, s, k // 2, groups=math.gcd(c1, int(c_)), bias=False) for k, c_ in zip(k, c_)]
)
self.bn = nn.BatchNorm2d(c2)
self.act = nn.SiLU()
def forward(self, x):
"""Performs forward pass by applying SiLU activation on batch-normalized concatenated convolutional layer
outputs.
"""
return self.act(self.bn(torch.cat([m(x) for m in self.m], 1)))
class Ensemble(nn.ModuleList):
"""Ensemble of models."""
def __init__(self):
"""Initializes an ensemble of models to be used for aggregated predictions."""
super().__init__()
def forward(self, x, augment=False, profile=False, visualize=False):
"""Performs forward pass aggregating outputs from an ensemble of models.."""
y = [module(x, augment, profile, visualize)[0] for module in self]
# y = torch.stack(y).max(0)[0] # max ensemble
# y = torch.stack(y).mean(0) # mean ensemble
y = torch.cat(y, 1) # nms ensemble
return y, None # inference, train output
def attempt_load(weights, device=None, inplace=True, fuse=True):
"""
Loads and fuses an ensemble or single YOLOv5 model from weights, handling device placement and model adjustments.
Example inputs: weights=[a,b,c] or a single model weights=[a] or weights=a.
"""
from models.yolo import Detect, Model
model = Ensemble()
for w in weights if isinstance(weights, list) else [weights]:
ckpt = torch.load(attempt_download(w), map_location="cpu") # load
ckpt = (ckpt.get("ema") or ckpt["model"]).to(device).float() # FP32 model
# Model compatibility updates
if not hasattr(ckpt, "stride"):
ckpt.stride = torch.tensor([32.0])
if hasattr(ckpt, "names") and isinstance(ckpt.names, (list, tuple)):
ckpt.names = dict(enumerate(ckpt.names)) # convert to dict
model.append(ckpt.fuse().eval() if fuse and hasattr(ckpt, "fuse") else ckpt.eval()) # model in eval mode
# Module updates
for m in model.modules():
t = type(m)
if t in (nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU, Detect, Model):
m.inplace = inplace
if t is Detect and not isinstance(m.anchor_grid, list):
delattr(m, "anchor_grid")
setattr(m, "anchor_grid", [torch.zeros(1)] * m.nl)
elif t is nn.Upsample and not hasattr(m, "recompute_scale_factor"):
m.recompute_scale_factor = None # torch 1.11.0 compatibility
# Return model
if len(model) == 1:
return model[-1]
# Return detection ensemble
print(f"Ensemble created with {weights}\n")
for k in "names", "nc", "yaml":
setattr(model, k, getattr(model[0], k))
model.stride = model[torch.argmax(torch.tensor([m.stride.max() for m in model])).int()].stride # max stride
assert all(model[0].nc == m.nc for m in model), f"Models have different class counts: {[m.nc for m in model]}"
return model