規約¶
MMDetection を独自のプロジェクトとして変更したい場合は、以下の規約を確認してください。
画像形状の順序について¶
OpenMMLab 2.0 では、OpenCV の入力引数と一貫性を持たせるために、データ変換パイプラインにおける画像形状に関する引数は常に (width, height) の順序になります。一方、計算の便宜上、データパイプラインとモデルを通過するフィールドの順序は (height, width) です。具体的には、各データ変換パイプラインで処理された結果では、フィールドとその値の意味は以下のようになります。
img_shape: (高さ, 幅)
ori_shape: (高さ, 幅)
pad_shape: (高さ, 幅)
batch_input_shape: (高さ, 幅)
例として、Mosaic の初期化引数は以下のようになります。
@TRANSFORMS.register_module()
class Mosaic(BaseTransform):
def __init__(self,
img_scale: Tuple[int, int] = (640, 640),
center_ratio_range: Tuple[float, float] = (0.5, 1.5),
bbox_clip_border: bool = True,
pad_val: float = 114.0,
prob: float = 1.0) -> None:
...
# img_scale order should be (width, height)
self.img_scale = img_scale
def transform(self, results: dict) -> dict:
...
results['img'] = mosaic_img
# (height, width)
results['img_shape'] = mosaic_img.shape[:2]
損失¶
MMDetection では、損失とメトリックを含む dict が model(**data) によって返されます。
例えば、bbox ヘッドでは、
class BBoxHead(nn.Module):
...
def loss(self, ...):
losses = dict()
# classification loss
losses['loss_cls'] = self.loss_cls(...)
# classification accuracy
losses['acc'] = accuracy(...)
# bbox regression loss
losses['loss_bbox'] = self.loss_bbox(...)
return losses
bbox_head.loss() はモデルのフォワード中に呼び出されます。返される dict には、'loss_bbox'、'loss_cls'、'acc' が含まれます。'loss_bbox' と 'loss_cls' のみがバックプロパゲーション中に使用され、'acc' はトレーニングプロセスを監視するためのメトリックとしてのみ使用されます。
デフォルトでは、キーに 'loss' を含む値のみがバックプロパゲートされます。この動作は、BaseDetector.train_step() を変更することで変更できます。
空の提案¶
MMDetection では、2段階の空の提案に対する特別な処理とユニットテストを追加しました。バッチ全体と単一画像の空の提案を同時に処理する必要があります。例えば、CascadeRoIHead では、
# simple_test method
...
# There is no proposal in the whole batch
if rois.shape[0] == 0:
bbox_results = [[
np.zeros((0, 5), dtype=np.float32)
for _ in range(self.bbox_head[-1].num_classes)
]] * num_imgs
if self.with_mask:
mask_classes = self.mask_head[-1].num_classes
segm_results = [[[] for _ in range(mask_classes)]
for _ in range(num_imgs)]
results = list(zip(bbox_results, segm_results))
else:
results = bbox_results
return results
...
# There is no proposal in the single image
for i in range(self.num_stages):
...
if i < self.num_stages - 1:
for j in range(num_imgs):
# Handle empty proposal
if rois[j].shape[0] > 0:
bbox_label = cls_score[j][:, :-1].argmax(dim=1)
refine_roi = self.bbox_head[i].regress_by_class(
rois[j], bbox_label, bbox_pred[j], img_metas[j])
refine_roi_list.append(refine_roi)
カスタム RoIHead を作成した場合は、上記のメソッドを参照して空の提案を処理できます。
Coco Panoptic データセット¶
MMDetection では、COCO Panoptic データセットをサポートしています。ここでは、CocoPanopticDataset の実装に関するいくつかの規約を明確にします。
mmdet<=2.16.0 では、セマンティックセグメンテーションにおける前景と背景のラベルの範囲が MMDetection のデフォルト設定とは異なります。ラベル
0はVOIDラベルを表し、カテゴリラベルは1から始まります。mmdet=2.17.0 以降では、セマンティックセグメンテーションのカテゴリラベルは0から始まり、ラベル255はバウンディングボックスのラベルとの整合性を保つためにVOIDを表します。これを実現するために、Padパイプラインはsegのパディング値を設定することをサポートしています。評価では、パノプティックの結果は元の画像と同じ形状のマップになります。結果マップの各値は、
instance_id * INSTANCE_OFFSET + category_idの形式を持ちます。