YOLOv5 segmentation model support (#9052)

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Fix duplicate plots.py

* Fix check_font()

* # torch.use_deterministic_algorithms(True)

* update doc detect->predict

* Resolve precommit for segment/train and segment/val

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Resolve precommit for utils/segment

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Resolve precommit min_wh

* Resolve precommit utils/segment/plots

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Resolve precommit utils/segment/general

* Align NMS-seg closer to NMS

* restore deterministic init_seeds code

* remove easydict dependency

* update

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* restore output_to_target mask

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* update

* cleanup

* Remove unused ImageFont import

* Unified NMS

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* DetectMultiBackend compatibility

* segment/predict.py update

* update plot colors

* fix bbox shifted

* sort bbox by confidence

* enable overlap by default

* Merge detect/segment output_to_target() function

* Start segmentation CI

* fix plots

* Update ci-testing.yml

* fix training whitespace

* optimize process mask functions (can we merge both?)

* Update predict/detect

* Update plot_images

* Update plot_images_and_masks

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix

* Add train to CI

* fix precommit

* fix precommit CI

* fix precommit pycocotools

* fix val float issues

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix masks float float issues

* suppress errors

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix no-predictions plotting bug

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Add CSV Logger

* fix val len(plot_masks)

* speed up evaluation

* fix process_mask

* fix plots

* update segment/utils build_targets

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* optimize utils/segment/general crop()

* optimize utils/segment/general crop() 2

* minor updates

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* torch.where revert

* downsample only if different shape

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* loss cleanup

* loss cleanup 2

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* loss cleanup 3

* update project names

* Rename -seg yamls from _underscore to -dash

* prepare for yolov5n-seg.pt

* precommit space fix

* add coco128-seg.yaml

* update coco128-seg comments

* cleanup val.py

* Major val.py cleanup

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* precommit fix

* precommit fix

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* optional pycocotools

* remove CI pip install pycocotools (auto-installed now)

* seg yaml fix

* optimize mask_iou() and masks_iou()

* threaded fix

* Major train.py update

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Major segments/val/process_batch() update

* yolov5/val updates from segment

* process_batch numpy/tensor fix

* opt-in to pycocotools with --save-json

* threaded pycocotools ops for 2x speed increase

* Avoid permute contiguous if possible

* Add max_det=300 argument to both val.py and segment/val.py

* fix onnx_dynamic

* speed up pycocotools ops

* faster process_mask(upsample=True) for predict

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* eliminate permutations for process_mask(upsample=True)

* eliminate permute-contiguous in crop(), use native dimension order

* cleanup comment

* Add Proto() module

* fix class count

* fix anchor order

* broadcast mask_gti in loss for speed

* Cleanup seg loss

* faster indexing

* faster indexing fix

* faster indexing fix2

* revert faster indexing

* fix validation plotting

* Loss cleanup and mxyxy simplification

* Loss cleanup and mxyxy simplification 2

* revert validation plotting

* replace missing tanh

* Eliminate last permutation

* delete unneeded .float()

* Remove MaskIOULoss and crop(if HWC)

* Final v6.3 SegmentationModel architecture updates

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Add support for TF export

* remove debugger trace

* add call

* update

* update

* Merge master

* Merge master

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Update dataloaders.py

* Restore CI

* Update dataloaders.py

* Fix TF/TFLite export for segmentation model

* Merge master

* Cleanup predict.py mask plotting

* cleanup scale_masks()

* rename scale_masks to scale_image

* cleanup/optimize plot_masks

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Add Annotator.masks()

* Annotator.masks() fix

* Update plots.py

* Annotator mask optimization

* Rename crop() to crop_mask()

* Do not crop in predict.py

* crop always

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Merge master

* Add vid-stride from master PR

* Update seg model outputs

* Update seg model outputs

* Add segmentation benchmarks

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Add segmentation benchmarks

* Add segmentation benchmarks

* Add segmentation benchmarks

* Fix DetectMultiBackend for OpenVINO

* update Annotator.masks

* fix val plot

* revert val plot

* clean up

* revert pil

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Fix CI error

* fix predict log

* remove upsample

* update interpolate

* fix validation plot logging

* Annotator.masks() cleanup

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Remove segmentation_model definition

* Restore 0.99999 decimals

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Glenn Jocher <glenn.jocher@ultralytics.com>
Co-authored-by: Laughing-q <1185102784@qq.com>
Co-authored-by: Jiacong Fang <zldrobit@126.com>
This commit is contained in:
authored and GitHub committed 2022-09-16 00:12:46 +02:00
1 parent abea53ea5b
commit f9869f7ffd
27 files changed
+3091 -71

No files matched your search

+64 -7
View File
@@ -23,6 +23,7 @@ from utils import TryExcept, threaded
from utils.general import (CONFIG_DIR, FONT, LOGGER, check_font, check_requirements, clip_coords, increment_path,
is_ascii, xywh2xyxy, xyxy2xywh)
from utils.metrics import fitness
from utils.segment.general import scale_image
# Settings
RANK = int(os.getenv('RANK', -1))
@@ -113,6 +114,52 @@ class Annotator:
thickness=tf,
lineType=cv2.LINE_AA)
def masks(self, masks, colors, im_gpu=None, alpha=0.5):
"""Plot masks at once.
Args:
masks (tensor): predicted masks on cuda, shape: [n, h, w]
colors (List[List[Int]]): colors for predicted masks, [[r, g, b] * n]
im_gpu (tensor): img is in cuda, shape: [3, h, w], range: [0, 1]
alpha (float): mask transparency: 0.0 fully transparent, 1.0 opaque
"""
if self.pil:
# convert to numpy first
self.im = np.asarray(self.im).copy()
if im_gpu is None:
# Add multiple masks of shape(h,w,n) with colors list([r,g,b], [r,g,b], ...)
if len(masks) == 0:
return
if isinstance(masks, torch.Tensor):
masks = torch.as_tensor(masks, dtype=torch.uint8)
masks = masks.permute(1, 2, 0).contiguous()
masks = masks.cpu().numpy()
# masks = np.ascontiguousarray(masks.transpose(1, 2, 0))
masks = scale_image(masks.shape[:2], masks, self.im.shape)
masks = np.asarray(masks, dtype=np.float32)
colors = np.asarray(colors, dtype=np.float32) # shape(n,3)
s = masks.sum(2, keepdims=True).clip(0, 1) # add all masks together
masks = (masks @ colors).clip(0, 255) # (h,w,n) @ (n,3) = (h,w,3)
self.im[:] = masks * alpha + self.im * (1 - s * alpha)
else:
if len(masks) == 0:
self.im[:] = im_gpu.permute(1, 2, 0).contiguous().cpu().numpy() * 255
colors = torch.tensor(colors, device=im_gpu.device, dtype=torch.float32) / 255.0
colors = colors[:, None, None] # shape(n,1,1,3)
masks = masks.unsqueeze(3) # shape(n,h,w,1)
masks_color = masks * (colors * alpha) # shape(n,h,w,3)
inv_alph_masks = (1 - masks * alpha).cumprod(0) # shape(n,h,w,1)
mcs = (masks_color * inv_alph_masks).sum(0) * 2 # mask color summand shape(n,h,w,3)
im_gpu = im_gpu.flip(dims=[0]) # flip channel
im_gpu = im_gpu.permute(1, 2, 0).contiguous() # shape(h,w,3)
im_gpu = im_gpu * inv_alph_masks[-1] + mcs
im_mask = (im_gpu * 255).byte().cpu().numpy()
self.im[:] = scale_image(im_gpu.shape, im_mask, self.im.shape)
if self.pil:
# convert im back to PIL and update draw
self.fromarray(self.im)
def rectangle(self, xy, fill=None, outline=None, width=1):
# Add rectangle to image (PIL-only)
self.draw.rectangle(xy, fill, outline, width)
@@ -124,6 +171,11 @@ class Annotator:
xy[1] += 1 - h
self.draw.text(xy, text, fill=txt_color, font=self.font)
def fromarray(self, im):
# Update self.im from a numpy array
self.im = im if isinstance(im, Image.Image) else Image.fromarray(im)
self.draw = ImageDraw.Draw(self.im)
def result(self):
# Return annotated image as array
return np.asarray(self.im)
@@ -180,26 +232,31 @@ def butter_lowpass_filtfilt(data, cutoff=1500, fs=50000, order=5):
return filtfilt(b, a, data) # forward-backward filter
def output_to_target(output):
# Convert model output to target format [batch_id, class_id, x, y, w, h, conf]
def output_to_target(output, max_det=300):
# Convert model output to target format [batch_id, class_id, x, y, w, h, conf] for plotting
targets = []
for i, o in enumerate(output):
targets.extend([i, cls, *list(*xyxy2xywh(np.array(box)[None])), conf] for *box, conf, cls in o.cpu().numpy())
return np.array(targets)
box, conf, cls = o[:max_det, :6].cpu().split((4, 1, 1), 1)
j = torch.full((conf.shape[0], 1), i)
targets.append(torch.cat((j, cls, xyxy2xywh(box), conf), 1))
return torch.cat(targets, 0).numpy()
@threaded
def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max_size=1920, max_subplots=16):
def plot_images(images, targets, paths=None, fname='images.jpg', names=None):
# Plot image grid with labels
if isinstance(images, torch.Tensor):
images = images.cpu().float().numpy()
if isinstance(targets, torch.Tensor):
targets = targets.cpu().numpy()
if np.max(images[0]) <= 1:
images *= 255 # de-normalise (optional)
max_size = 1920 # max image size
max_subplots = 16 # max image subplots, i.e. 4x4
bs, _, h, w = images.shape # batch size, _, height, width
bs = min(bs, max_subplots) # limit plot images
ns = np.ceil(bs ** 0.5) # number of subplots (square)
if np.max(images[0]) <= 1:
images *= 255 # de-normalise (optional)
# Build Image
mosaic = np.full((int(ns * h), int(ns * w), 3), 255, dtype=np.uint8) # init