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

Add support for Pascal Context 59 classes #459

Merged
merged 12 commits into from
Apr 20, 2021
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -113,5 +113,9 @@ data
*.log.json
work_dirs/

# temp file or folder
/temp*/
/temp*.*

# Pytorch
*.pth
60 changes: 60 additions & 0 deletions configs/_base_/datasets/pascal_context_59.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# dataset settings
dataset_type = 'PascalContextDataset59'
data_root = 'data/VOCdevkit/VOC2010/'
img_norm_cfg = dict(
mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)

img_scale = (520, 520)
crop_size = (480, 480)

train_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='LoadAnnotations', reduce_zero_label=True),
dict(type='Resize', img_scale=img_scale, ratio_range=(0.5, 2.0)),
dict(type='RandomCrop', crop_size=crop_size, cat_max_ratio=0.75),
dict(type='RandomFlip', prob=0.5),
dict(type='PhotoMetricDistortion'),
dict(type='Normalize', **img_norm_cfg),
dict(type='Pad', size=crop_size, pad_val=0, seg_pad_val=255),
dict(type='DefaultFormatBundle'),
dict(type='Collect', keys=['img', 'gt_semantic_seg']),
]
test_pipeline = [
dict(type='LoadImageFromFile'),
dict(
type='MultiScaleFlipAug',
img_scale=img_scale,
# img_ratios=[0.5, 0.75, 1.0, 1.25, 1.5, 1.75],
flip=False,
transforms=[
dict(type='Resize', keep_ratio=True),
dict(type='RandomFlip'),
dict(type='Normalize', **img_norm_cfg),
dict(type='ImageToTensor', keys=['img']),
dict(type='Collect', keys=['img']),
])
]
data = dict(
samples_per_gpu=4,
workers_per_gpu=4,
train=dict(
type=dataset_type,
data_root=data_root,
img_dir='JPEGImages',
ann_dir='SegmentationClassContext',
split='ImageSets/SegmentationContext/train.txt',
pipeline=train_pipeline),
clownrat6 marked this conversation as resolved.
Show resolved Hide resolved
val=dict(
type=dataset_type,
data_root=data_root,
img_dir='JPEGImages',
ann_dir='SegmentationClassContext',
split='ImageSets/SegmentationContext/val.txt',
pipeline=test_pipeline),
test=dict(
type=dataset_type,
data_root=data_root,
img_dir='JPEGImages',
ann_dir='SegmentationClassContext',
split='ImageSets/SegmentationContext/val.txt',
pipeline=test_pipeline))
9 changes: 9 additions & 0 deletions configs/_base_/schedules/schedule_160k_epochwise.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# optimizer
optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0005)
optimizer_config = dict()
# learning policy
lr_config = dict(policy='poly', power=0.9, min_lr=1e-4, by_epoch=False)
# runtime settings
runner = dict(type='IterBasedRunner', max_iters=160000)
checkpoint_config = dict(by_epoch=True, interval=16000)
evaluation = dict(interval=16000, metric='mIoU')
9 changes: 9 additions & 0 deletions configs/_base_/schedules/schedule_20k_epochwise.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# optimizer
optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0005)
optimizer_config = dict()
# learning policy
lr_config = dict(policy='poly', power=0.9, min_lr=1e-4, by_epoch=True)
# runtime settings
runner = dict(type='IterBasedRunner', max_iters=20000)
checkpoint_config = dict(by_epoch=True, interval=2000)
evaluation = dict(interval=2000, metric='mIoU')
xvjiarui marked this conversation as resolved.
Show resolved Hide resolved
9 changes: 9 additions & 0 deletions configs/_base_/schedules/schedule_40k_epochwise.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# optimizer
optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0005)
optimizer_config = dict()
# learning policy
lr_config = dict(policy='poly', power=0.9, min_lr=1e-4, by_epoch=True)
# runtime settings
runner = dict(type='IterBasedRunner', max_iters=40000)
checkpoint_config = dict(by_epoch=True, interval=4000)
evaluation = dict(interval=4000, metric='mIoU')
9 changes: 9 additions & 0 deletions configs/_base_/schedules/schedule_80k_epochwisse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# optimizer
optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0005)
optimizer_config = dict()
# learning policy
lr_config = dict(policy='poly', power=0.9, min_lr=1e-4, by_epoch=False)
# runtime settings
runner = dict(type='IterBasedRunner', max_iters=80000)
checkpoint_config = dict(by_epoch=True, interval=8000)
evaluation = dict(interval=8000, metric='mIoU')
9 changes: 9 additions & 0 deletions configs/fcn/fcn_r50-d8_480x480_40k_pascal_context_59.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
_base_ = [
'../_base_/models/fcn_r50-d8.py',
'../_base_/datasets/pascal_context_59.py', '../_base_/default_runtime.py',
'../_base_/schedules/schedule_40k.py'
]
model = dict(
decode_head=dict(num_classes=59),
test_cfg=dict(mode='slide', crop_size=(480, 480), stride=(320, 320)))
optimizer = dict(type='SGD', lr=0.004, momentum=0.9, weight_decay=0.0001)
8 changes: 8 additions & 0 deletions configs/hrnet/fcn_hr18_480x480_40k_pascal_context_59.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
_base_ = [
'../_base_/models/fcn_hr18.py', '../_base_/datasets/pascal_context_59.py',
'../_base_/default_runtime.py', '../_base_/schedules/schedule_40k.py'
]
model = dict(
decode_head=dict(num_classes=59),
test_cfg=dict(mode='slide', crop_size=(480, 480), stride=(320, 320)))
optimizer = dict(type='SGD', lr=0.004, momentum=0.9, weight_decay=0.0001)
8 changes: 8 additions & 0 deletions configs/hrnet/fcn_hr18_480x480_80k_pascal_context_59.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
_base_ = [
'../_base_/models/fcn_hr18.py', '../_base_/datasets/pascal_context_59.py',
'../_base_/default_runtime.py', '../_base_/schedules/schedule_80k.py'
]
model = dict(
decode_head=dict(num_classes=59),
test_cfg=dict(mode='slide', crop_size=(480, 480), stride=(320, 320)))
optimizer = dict(type='SGD', lr=0.004, momentum=0.9, weight_decay=0.0001)
9 changes: 9 additions & 0 deletions configs/hrnet/fcn_hr18s_480x480_40k_pascal_context_59.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
_base_ = './fcn_hr18_480x480_40k_pascal_context_59.py'
model = dict(
pretrained='open-mmlab://msra/hrnetv2_w18_small',
backbone=dict(
extra=dict(
stage1=dict(num_blocks=(2, )),
stage2=dict(num_blocks=(2, 2)),
stage3=dict(num_modules=3, num_blocks=(2, 2, 2)),
stage4=dict(num_modules=2, num_blocks=(2, 2, 2, 2)))))
xvjiarui marked this conversation as resolved.
Show resolved Hide resolved
9 changes: 9 additions & 0 deletions configs/hrnet/fcn_hr18s_480x480_80k_pascal_context_59.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
_base_ = './fcn_hr18_480x480_80k_pascal_context_59.py'
model = dict(
pretrained='open-mmlab://msra/hrnetv2_w18_small',
backbone=dict(
extra=dict(
stage1=dict(num_blocks=(2, )),
stage2=dict(num_blocks=(2, 2)),
stage3=dict(num_modules=3, num_blocks=(2, 2, 2)),
stage4=dict(num_modules=2, num_blocks=(2, 2, 2, 2)))))
10 changes: 10 additions & 0 deletions configs/hrnet/fcn_hr48_480x480_40k_pascal_context_59.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
_base_ = './fcn_hr18_480x480_40k_pascal_context_59.py'
model = dict(
pretrained='open-mmlab://msra/hrnetv2_w48',
backbone=dict(
extra=dict(
stage2=dict(num_channels=(48, 96)),
stage3=dict(num_channels=(48, 96, 192)),
stage4=dict(num_channels=(48, 96, 192, 384)))),
decode_head=dict(
in_channels=[48, 96, 192, 384], channels=sum([48, 96, 192, 384])))
10 changes: 10 additions & 0 deletions configs/hrnet/fcn_hr48_480x480_80k_pascal_context_59.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
_base_ = './fcn_hr18_480x480_80k_pascal_context_59.py'
model = dict(
pretrained='open-mmlab://msra/hrnetv2_w48',
backbone=dict(
extra=dict(
stage2=dict(num_channels=(48, 96)),
stage3=dict(num_channels=(48, 96, 192)),
stage4=dict(num_channels=(48, 96, 192, 384)))),
decode_head=dict(
in_channels=[48, 96, 192, 384], channels=sum([48, 96, 192, 384])))
7 changes: 7 additions & 0 deletions demo/MMSegmentation_Tutorial.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -1411,6 +1411,13 @@
}
}
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
]
}
6 changes: 3 additions & 3 deletions mmseg/core/evaluation/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ def intersect_and_union(pred_label,

intersect = pred_label[pred_label == label]
area_intersect = torch.histc(
intersect.float(), bins=(num_classes), min=0, max=num_classes)
intersect.float(), bins=num_classes, min=0, max=num_classes - 1)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may need to test whether the results are consistent for other models.
We could make another PR for this modification, we may also include impact range in the new PR.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may merge master and resolve conflicts.

area_pred_label = torch.histc(
pred_label.float(), bins=(num_classes), min=0, max=num_classes)
pred_label.float(), bins=num_classes, min=0, max=num_classes - 1)
area_label = torch.histc(
label.float(), bins=(num_classes), min=0, max=num_classes)
label.float(), bins=num_classes, min=0, max=num_classes - 1)
area_union = area_pred_label + area_label - area_intersect
return area_intersect, area_union, area_pred_label, area_label

Expand Down
5 changes: 3 additions & 2 deletions mmseg/datasets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
from .dataset_wrappers import ConcatDataset, RepeatDataset
from .drive import DRIVEDataset
from .hrf import HRFDataset
from .pascal_context import PascalContextDataset
from .pascal_context import PascalContextDataset, PascalContextDataset59
from .stare import STAREDataset
from .voc import PascalVOCDataset

__all__ = [
'CustomDataset', 'build_dataloader', 'ConcatDataset', 'RepeatDataset',
'DATASETS', 'build_dataset', 'PIPELINES', 'CityscapesDataset',
'PascalVOCDataset', 'ADE20KDataset', 'PascalContextDataset',
'ChaseDB1Dataset', 'DRIVEDataset', 'HRFDataset', 'STAREDataset'
'PascalContextDataset59', 'ChaseDB1Dataset', 'DRIVEDataset', 'HRFDataset',
'STAREDataset'
]
67 changes: 58 additions & 9 deletions mmseg/datasets/pascal_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ class PascalContextDataset(CustomDataset):
split (str): Split txt file for PascalContext.
"""

CLASSES = ('background', 'aeroplane', 'bicycle', 'bird', 'boat', 'bottle',
'bus', 'car', 'cat', 'chair', 'cow', 'table', 'dog', 'horse',
'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train',
'tvmonitor', 'bag', 'bed', 'bench', 'book', 'building',
'cabinet', 'ceiling', 'cloth', 'computer', 'cup', 'door',
'fence', 'floor', 'flower', 'food', 'grass', 'ground',
'keyboard', 'light', 'mountain', 'mouse', 'curtain', 'platform',
'sign', 'plate', 'road', 'rock', 'shelves', 'sidewalk', 'sky',
'snow', 'bedclothes', 'track', 'tree', 'truck', 'wall', 'water',
CLASSES = ('background', 'aeroplane', 'bag', 'bed', 'bedclothes', 'bench',
'bicycle', 'bird', 'boat', 'book', 'bottle', 'building', 'bus',
'cabinet', 'car', 'cat', 'ceiling', 'chair', 'cloth',
'computer', 'cow', 'cup', 'curtain', 'dog', 'door', 'fence',
'floor', 'flower', 'food', 'grass', 'ground', 'horse',
'keyboard', 'light', 'motorbike', 'mountain', 'mouse', 'person',
'plate', 'platform', 'pottedplant', 'road', 'rock', 'sheep',
'shelves', 'sidewalk', 'sign', 'sky', 'snow', 'sofa', 'table',
'track', 'train', 'tree', 'truck', 'tvmonitor', 'wall', 'water',
'window', 'wood')

PALETTE = [[120, 120, 120], [180, 120, 120], [6, 230, 230], [80, 50, 50],
Expand All @@ -52,3 +52,52 @@ def __init__(self, split, **kwargs):
reduce_zero_label=False,
**kwargs)
assert osp.exists(self.img_dir) and self.split is not None


@DATASETS.register_module()
class PascalContextDataset59(CustomDataset):
"""PascalContext dataset.

In segmentation map annotation for PascalContext, 0 stands for background,
which is included in 60 categories. ``reduce_zero_label`` is fixed to
False. The ``img_suffix`` is fixed to '.jpg' and ``seg_map_suffix`` is
fixed to '.png'.

Args:
split (str): Split txt file for PascalContext.
"""

CLASSES = ('aeroplane', 'bag', 'bed', 'bedclothes', 'bench', 'bicycle',
'bird', 'boat', 'book', 'bottle', 'building', 'bus', 'cabinet',
'car', 'cat', 'ceiling', 'chair', 'cloth', 'computer', 'cow',
'cup', 'curtain', 'dog', 'door', 'fence', 'floor', 'flower',
'food', 'grass', 'ground', 'horse', 'keyboard', 'light',
'motorbike', 'mountain', 'mouse', 'person', 'plate', 'platform',
'pottedplant', 'road', 'rock', 'sheep', 'shelves', 'sidewalk',
'sign', 'sky', 'snow', 'sofa', 'table', 'track', 'train',
'tree', 'truck', 'tvmonitor', 'wall', 'water', 'window', 'wood')

PALETTE = [[180, 120, 120], [6, 230, 230], [80, 50, 50], [4, 200, 3],
[120, 120, 80], [140, 140, 140], [204, 5, 255], [230, 230, 230],
[4, 250, 7], [224, 5, 255], [235, 255, 7], [150, 5, 61],
[120, 120, 70], [8, 255, 51], [255, 6, 82], [143, 255, 140],
[204, 255, 4], [255, 51, 7], [204, 70, 3], [0, 102, 200],
[61, 230, 250], [255, 6, 51], [11, 102, 255], [255, 7, 71],
[255, 9, 224], [9, 7, 230], [220, 220, 220], [255, 9, 92],
[112, 9, 255], [8, 255, 214], [7, 255, 224], [255, 184, 6],
[10, 255, 71], [255, 41, 10], [7, 255, 255], [224, 255, 8],
[102, 8, 255], [255, 61, 6], [255, 194, 7], [255, 122, 8],
[0, 255, 20], [255, 8, 41], [255, 5, 153], [6, 51, 255],
[235, 12, 255], [160, 150, 20], [0, 163, 255], [140, 140, 140],
[250, 10, 15], [20, 255, 0], [31, 255, 0], [255, 31, 0],
[255, 224, 0], [153, 255, 0], [0, 0, 255], [255, 71, 0],
[0, 235, 255], [0, 173, 255], [31, 0, 255]]

def __init__(self, split, **kwargs):
super(PascalContextDataset59, self).__init__(
img_suffix='.jpg',
seg_map_suffix='.png',
split=split,
reduce_zero_label=True,
**kwargs)
assert osp.exists(self.img_dir) and self.split is not None