Add docstring

pull/41/head^2
huanghaian 2022-09-21 15:09:47 +08:00
parent 6882e09084
commit c26a12ed32
11 changed files with 230 additions and 6 deletions

View File

@ -37,7 +37,7 @@ conda install pytorch torchvision cpuonly -c pytorch
### 最佳实践
**步骤 0.** 使用 [MIM](https://github.com/open-mmlab/mim) 安装 [MMEngine](https://github.com/open-mmlab/mmengine)、 [MMCV](https://github.com/open-mmlab/mmcv) 和 [MMDetection](https://github.com/open-mmlab/mmdetection)。
**步骤 0.** 使用 [MIM](https://github.com/open-mmlab/mim) 安装 [MMEngine](https://github.com/open-mmlab/mmengine)、 [MMCV](https://github.com/open-mmlab/mmcv) 和 [MMDetection](https://github.com/open-mmlab/mmdetection)
```shell
pip install -U openmim
@ -52,7 +52,7 @@ pip install -r requirements/albu.txt
a. 在 MMCV-v2.x 中,`mmcv-full` 改名为 `mmcv`,如果你想安装不包含 CUDA 算子精简版,可以通过 `mim install mmcv-lite>=2.0.0rc1` 来安装。
b. 如果使用 albumentations我们建议使用 pip install -r requirements/albu.txt 或者 pip install -U albumentations --no-binary qudida,albumentations 进行安装。 如果简单地使用 pip install albumentations==1.0.1 进行安装,则会同时安装 opencv-python-headless即便已经安装了 opencv-python 也会再次安装)。我们建议在安装 albumentations 后检查环境,以确保没有同时安装 opencv-python 和 opencv-python-headless因为同时安装可能会导致一些问题。更多细节请参考官方文档。
b. 如果使用 albumentations我们建议使用 pip install -r requirements/albu.txt 或者 pip install -U albumentations --no-binary qudida,albumentations 进行安装。 如果简单地使用 pip install albumentations==1.0.1 进行安装,则会同时安装 opencv-python-headless即便已经安装了 opencv-python 也会再次安装)。我们建议在安装 albumentations 后检查环境,以确保没有同时安装 opencv-python 和 opencv-python-headless因为同时安装可能会导致一些问题。更多细节请参考 [官方文档](https://albumentations.ai/docs/getting_started/installation/#note-on-opencv-dependencies)
**步骤 1.** 安装 MMYOLO

View File

@ -132,6 +132,15 @@ class YOLOv6HeadModule(BaseModule):
kernel_size=1))
def forward(self, x: torch.Tensor) -> torch.Tensor:
"""Forward features from the upstream network.
Args:
x (Tuple[Tensor]): Features from the upstream network, each is
a 4D-tensor.
Returns:
Tuple[List]: A tuple of multi-level classification scores, bbox
predictions.
"""
assert len(x) == self.num_levels
return multi_apply(self.forward_single, x, self.stems, self.cls_convs,
self.cls_preds, self.reg_convs, self.reg_preds)
@ -219,8 +228,29 @@ class YOLOv6Head(YOLOv5Head):
self,
cls_scores: Sequence[Tensor],
bbox_preds: Sequence[Tensor],
objectnesses: Sequence[Tensor],
batch_gt_instances: Sequence[InstanceData],
batch_img_metas: Sequence[dict],
batch_gt_instances_ignore: OptInstanceList = None) -> dict:
"""Calculate the loss based on the features extracted by the detection
head.
Args:
cls_scores (Sequence[Tensor]): Box scores for each scale level,
each is a 4D-tensor, the channel number is
num_priors * num_classes.
bbox_preds (Sequence[Tensor]): Box energies / deltas for each scale
level, each is a 4D-tensor, the channel number is
num_priors * 4.
batch_gt_instances (list[:obj:`InstanceData`]): Batch of
gt_instance. It usually includes ``bboxes`` and ``labels``
attributes.
batch_img_metas (list[dict]): Meta information of each image, e.g.,
image size, scaling factor, etc.
batch_gt_instances_ignore (list[:obj:`InstanceData`], optional):
Batch of gt_instances_ignore. It includes ``bboxes`` attribute
data that is ignored during training and testing.
Defaults to None.
Returns:
dict[str, Tensor]: A dictionary of losses.
"""
raise NotImplementedError('Not implemented yet')

View File

@ -74,26 +74,32 @@ class BaseYOLONeck(BaseModule, metaclass=ABCMeta):
@abstractmethod
def build_reduce_layer(self, idx: int):
"""build reduce layer."""
pass
@abstractmethod
def build_upsample_layer(self, idx: int):
"""build upsample layer."""
pass
@abstractmethod
def build_top_down_layer(self, idx: int):
"""build top down layer."""
pass
@abstractmethod
def build_downsample_layer(self, idx: int):
"""build downsample layer."""
pass
@abstractmethod
def build_bottom_up_layer(self, idx: int):
"""build bottom up layer."""
pass
@abstractmethod
def build_out_layer(self, idx: int):
"""build out layer."""
pass
def _freeze_all(self):

View File

@ -64,6 +64,14 @@ class YOLOv5PAFPN(BaseYOLONeck):
m.reset_parameters()
def build_reduce_layer(self, idx: int) -> nn.Module:
"""build reduce layer.
Args:
idx (int): layer idx.
Returns:
nn.Module: The reduce layer.
"""
if idx == 2:
layer = ConvModule(
make_divisible(self.in_channels[idx], self.widen_factor),
@ -77,9 +85,18 @@ class YOLOv5PAFPN(BaseYOLONeck):
return layer
def build_upsample_layer(self, *args, **kwargs) -> nn.Module:
"""build upsample layer."""
return nn.Upsample(scale_factor=2, mode='nearest')
def build_top_down_layer(self, idx: int):
"""build top down layer.
Args:
idx (int): layer idx.
Returns:
nn.Module: The top down layer.
"""
if idx == 1:
return CSPLayer(
make_divisible(self.in_channels[idx - 1] * 2,
@ -111,6 +128,14 @@ class YOLOv5PAFPN(BaseYOLONeck):
act_cfg=self.act_cfg))
def build_downsample_layer(self, idx: int) -> nn.Module:
"""build downsample layer.
Args:
idx (int): layer idx.
Returns:
nn.Module: The downsample layer.
"""
return ConvModule(
make_divisible(self.in_channels[idx], self.widen_factor),
make_divisible(self.in_channels[idx], self.widen_factor),
@ -121,6 +146,14 @@ class YOLOv5PAFPN(BaseYOLONeck):
act_cfg=self.act_cfg)
def build_bottom_up_layer(self, idx: int) -> nn.Module:
"""build bottom up layer.
Args:
idx (int): layer idx.
Returns:
nn.Module: The bottom up layer.
"""
return CSPLayer(
make_divisible(self.in_channels[idx] * 2, self.widen_factor),
make_divisible(self.in_channels[idx + 1], self.widen_factor),
@ -130,4 +163,5 @@ class YOLOv5PAFPN(BaseYOLONeck):
act_cfg=self.act_cfg)
def build_out_layer(self, *args, **kwargs) -> nn.Module:
"""build out layer."""
return nn.Identity()

View File

@ -60,6 +60,14 @@ class YOLOv6RepPAFPN(BaseYOLONeck):
init_cfg=init_cfg)
def build_reduce_layer(self, idx: int) -> nn.Module:
"""build reduce layer.
Args:
idx (int): layer idx.
Returns:
nn.Module: The reduce layer.
"""
if idx == 2:
layer = ConvModule(
in_channels=make_divisible(self.in_channels[idx],
@ -76,6 +84,14 @@ class YOLOv6RepPAFPN(BaseYOLONeck):
return layer
def build_upsample_layer(self, idx: int) -> nn.Module:
"""build upsample layer.
Args:
idx (int): layer idx.
Returns:
nn.Module: The upsample layer.
"""
return nn.ConvTranspose2d(
in_channels=make_divisible(self.out_channels[idx - 1],
self.widen_factor),
@ -86,6 +102,14 @@ class YOLOv6RepPAFPN(BaseYOLONeck):
bias=True)
def build_top_down_layer(self, idx: int) -> nn.Module:
"""build top down layer.
Args:
idx (int): layer idx.
Returns:
nn.Module: The top down layer.
"""
layer0 = RepStageBlock(
in_channels=make_divisible(
self.out_channels[idx - 1] + self.in_channels[idx - 1],
@ -109,6 +133,14 @@ class YOLOv6RepPAFPN(BaseYOLONeck):
return nn.Sequential(layer0, layer1)
def build_downsample_layer(self, idx: int) -> nn.Module:
"""build downsample layer.
Args:
idx (int): layer idx.
Returns:
nn.Module: The downsample layer.
"""
return ConvModule(
in_channels=make_divisible(self.out_channels[idx],
self.widen_factor),
@ -121,6 +153,14 @@ class YOLOv6RepPAFPN(BaseYOLONeck):
act_cfg=self.act_cfg)
def build_bottom_up_layer(self, idx: int) -> nn.Module:
"""build bottom up layer.
Args:
idx (int): layer idx.
Returns:
nn.Module: The bottom up layer.
"""
return RepStageBlock(
in_channels=make_divisible(self.out_channels[idx] * 2,
self.widen_factor),
@ -130,6 +170,7 @@ class YOLOv6RepPAFPN(BaseYOLONeck):
block=self.block)
def build_out_layer(self, *args, **kwargs) -> nn.Module:
"""build out layer."""
return nn.Identity()
def init_weights(self):

View File

@ -57,6 +57,14 @@ class YOLOXPAFPN(BaseYOLONeck):
init_cfg=init_cfg)
def build_reduce_layer(self, idx: int) -> nn.Module:
"""build reduce layer.
Args:
idx (int): layer idx.
Returns:
nn.Module: The reduce layer.
"""
if idx == 2:
layer = ConvModule(
self.in_channels[idx],
@ -70,9 +78,18 @@ class YOLOXPAFPN(BaseYOLONeck):
return layer
def build_upsample_layer(self, *args, **kwargs) -> nn.Module:
"""build upsample layer."""
return nn.Upsample(scale_factor=2, mode='nearest')
def build_top_down_layer(self, idx: int) -> nn.Module:
"""build top down layer.
Args:
idx (int): layer idx.
Returns:
nn.Module: The top down layer.
"""
if idx == 1:
return CSPLayer(
self.in_channels[idx - 1] * 2,
@ -98,6 +115,14 @@ class YOLOXPAFPN(BaseYOLONeck):
act_cfg=self.act_cfg))
def build_downsample_layer(self, idx: int) -> nn.Module:
"""build downsample layer.
Args:
idx (int): layer idx.
Returns:
nn.Module: The downsample layer.
"""
return ConvModule(
self.in_channels[idx],
self.in_channels[idx],
@ -108,6 +133,14 @@ class YOLOXPAFPN(BaseYOLONeck):
act_cfg=self.act_cfg)
def build_bottom_up_layer(self, idx: int) -> nn.Module:
"""build bottom up layer.
Args:
idx (int): layer idx.
Returns:
nn.Module: The bottom up layer.
"""
return CSPLayer(
self.in_channels[idx] * 2,
self.in_channels[idx + 1],
@ -117,6 +150,14 @@ class YOLOXPAFPN(BaseYOLONeck):
act_cfg=self.act_cfg)
def build_out_layer(self, idx: int) -> nn.Module:
"""build out layer.
Args:
idx (int): layer idx.
Returns:
nn.Module: The out layer.
"""
return ConvModule(
self.in_channels[idx],
self.out_channels,

View File

@ -9,13 +9,20 @@ from mmyolo.registry import TASK_UTILS
@TASK_UTILS.register_module()
class YOLOv5BBoxCoder(BaseBBoxCoder):
"""YOLOv5 BBox coder.
This decoder decodes pred bboxes (delta_x, delta_x, w, h) to bboxes (tl_x,
tl_y, br_x, br_y).
"""
def encode(self, **kwargs):
"""Encode deltas between bboxes and ground truth boxes."""
pass
def decode(self, priors: torch.Tensor, pred_bboxes: torch.Tensor,
stride: Union[torch.Tensor, int]) -> torch.Tensor:
"""Apply transformation `pred_bboxes` to `decoded_bboxes`.
"""Decode regression results (delta_x, delta_x, w, h) to bboxes (tl_x,
tl_y, br_x, br_y).
Args:
priors (torch.Tensor): Basic boxes or points, e.g. anchors.

View File

@ -9,13 +9,20 @@ from mmyolo.registry import TASK_UTILS
@TASK_UTILS.register_module()
class YOLOXBBoxCoder(BaseBBoxCoder):
"""YOLOX BBox coder.
This decoder decodes pred bboxes (delta_x, delta_x, w, h) to bboxes (tl_x,
tl_y, br_x, br_y).
"""
def encode(self, **kwargs):
"""Encode deltas between bboxes and ground truth boxes."""
pass
def decode(self, priors: torch.Tensor, pred_bboxes: torch.Tensor,
stride: Union[torch.Tensor, int]) -> torch.Tensor:
"""Apply transformation `pred_bboxes` to `decoded_bboxes`.
"""Decode regression results (delta_x, delta_x, w, h) to bboxes (tl_x,
tl_y, br_x, br_y).
Args:
priors (torch.Tensor): Basic boxes or points, e.g. anchors.

View File

@ -0,0 +1,4 @@
# Copyright (c) OpenMMLab. All rights reserved.
from ._utils import get_detector_cfg
__all__ = ['get_detector_cfg']

View File

@ -0,0 +1,53 @@
# Copyright (c) OpenMMLab. All rights reserved.
import copy
from os.path import dirname, exists, join
import numpy as np
from mmengine.config import Config
def _get_config_directory():
"""Find the predefined detector config directory."""
try:
# Assume we are running in the source mmyolo repo
repo_dpath = dirname(dirname(dirname(__file__)))
except NameError:
# For IPython development when this __file__ is not defined
import mmyolo
repo_dpath = dirname(dirname(mmyolo.__file__))
config_dpath = join(repo_dpath, 'configs')
if not exists(config_dpath):
raise Exception('Cannot find config path')
return config_dpath
def _get_config_module(fname):
"""Load a configuration as a python module."""
config_dpath = _get_config_directory()
config_fpath = join(config_dpath, fname)
config_mod = Config.fromfile(config_fpath)
return config_mod
def get_detector_cfg(fname):
"""Grab configs necessary to create a detector.
These are deep copied to allow for safe modification of parameters without
influencing other tests.
"""
config = _get_config_module(fname)
model = copy.deepcopy(config.model)
return model
def _rand_bboxes(rng, num_boxes, w, h):
"""Randomly generate a specified number of bboxes."""
cx, cy, bw, bh = rng.rand(num_boxes, 4).T
tl_x = ((cx * w) - (w * bw / 2)).clip(0, w)
tl_y = ((cy * h) - (h * bh / 2)).clip(0, h)
br_x = ((cx * w) + (w * bw / 2)).clip(0, w)
br_y = ((cy * h) + (h * bh / 2)).clip(0, h)
bboxes = np.vstack([tl_x, tl_y, br_x, br_y]).T
return bboxes

View File

@ -5,10 +5,11 @@ from unittest import TestCase
import torch
from mmdet.structures import DetDataSample
from mmdet.testing import demo_mm_inputs, get_detector_cfg
from mmdet.testing import demo_mm_inputs
from mmengine.logging import MessageHub
from parameterized import parameterized
from mmyolo.testing import get_detector_cfg
from mmyolo.utils import register_all_modules