open-mmlab / mmdetection

OpenMMLab Detection Toolbox and Benchmark
https://mmdetection.readthedocs.io
Apache License 2.0
29.21k stars 9.4k forks source link

AttributeError: 'SSDHead' object has no attribute 'loss_cls' #11063

Open dpdevi9 opened 11 months ago

dpdevi9 commented 11 months ago

error

Traceback (most recent call last): File "/content/mmdetection/tools/train.py", line 121, in main() File "/content/mmdetection/tools/train.py", line 117, in main runner.train() File "/usr/local/lib/python3.10/dist-packages/mmengine/runner/runner.py", line 1777, in train model = self.train_loop.run() # type: ignore File "/usr/local/lib/python3.10/dist-packages/mmengine/runner/loops.py", line 102, in run self.runner.val_loop.run() File "/usr/local/lib/python3.10/dist-packages/mmengine/runner/loops.py", line 363, in run self.run_iter(idx, data_batch) File "/usr/local/lib/python3.10/dist-packages/torch/utils/_contextlib.py", line 115, in decorate_context return func(args, kwargs) File "/usr/local/lib/python3.10/dist-packages/mmengine/runner/loops.py", line 383, in run_iter outputs = self.runner.model.val_step(data_batch) File "/usr/local/lib/python3.10/dist-packages/mmengine/model/base_model/base_model.py", line 133, in val_step return self._run_forward(data, mode='predict') # type: ignore File "/usr/local/lib/python3.10/dist-packages/mmengine/model/base_model/base_model.py", line 346, in _run_forward results = self(data, mode=mode) File "/usr/local/lib/python3.10/dist-packages/torch/nn/modules/module.py", line 1501, in _call_impl return forward_call(args, **kwargs) File "/content/mmdetection/mmdet/models/detectors/base.py", line 94, in forward return self.predict(inputs, data_samples) File "/content/mmdetection/mmdet/models/detectors/single_stage.py", line 110, in predict results_list = self.bbox_head.predict( File "/content/mmdetection/mmdet/models/dense_heads/base_dense_head.py", line 197, in predict predictions = self.predict_by_feat( File "/content/mmdetection/mmdet/models/dense_heads/base_dense_head.py", line 279, in predict_by_feat results = self._predict_by_feat_single( File "/content/mmdetection/mmdet/models/dense_heads/base_dense_head.py", line 376, in _predict_by_feat_single if getattr(self.loss_cls, 'custom_cls_channels', False): File "/usr/local/lib/python3.10/dist-packages/torch/nn/modules/module.py", line 1614, in getattr raise AttributeError("'{}' object has no attribute '{}'".format( AttributeError: 'SSDHead' object has no attribute 'loss_cls'

Reproduction python tools/train.py configs/ssd/ssd_my.py

ssd_my.py

#########################################################################################################
# MODEL

num_classes = 1
input_size = img_size = 512

model = dict(
    type='SingleStageDetector',
    data_preprocessor=dict(
        type='DetDataPreprocessor',
        mean=[123.675, 116.28, 103.53],
        std=[1, 1, 1],
        bgr_to_rgb=True,
        pad_size_divisor=1),
    backbone=dict(
        type='SSDVGG',
        depth=16,
        with_last_pool=False,
        ceil_mode=True,
        out_indices=(3, 4),
        out_feature_indices=(22, 34),
        init_cfg=dict(
            type='Pretrained', checkpoint='open-mmlab://vgg16_caffe')),
    neck=dict(
        type='SSDNeck',
        in_channels=(512, 1024),
        out_channels=(512, 1024, 512, 256, 256, 256),
        level_strides=(2, 2, 1, 1),
        level_paddings=(1, 1, 0, 0),
        l2_norm_scale=20),
    bbox_head=dict(
        type='SSDHead',
        in_channels=(512, 1024, 512, 256, 256, 256),
        num_classes=1,
        anchor_generator=dict(
            type='SSDAnchorGenerator',
            scale_major=False,
            input_size=input_size,
            basesize_ratio_range=(0.15, 0.9),
            strides=[8, 16, 32, 64, 100, 300],
            ratios=[[2], [2, 3], [2, 3], [2, 3], [2], [2]]),
        bbox_coder=dict(
            type='DeltaXYWHBBoxCoder',
            target_means=[.0, .0, .0, .0],
            target_stds=[0.1, 0.1, 0.2, 0.2])),
    # model training and testing settings
    train_cfg=dict(
        assigner=dict(
            type='MaxIoUAssigner',
            pos_iou_thr=0.5,
            neg_iou_thr=0.5,
            min_pos_iou=0.,
            ignore_iof_thr=-1,
            gt_max_assign_all=False),
        sampler=dict(type='PseudoSampler'),
        smoothl1_beta=1.,
        allowed_border=-1,
        pos_weight=-1,
        neg_pos_ratio=3,
        debug=False),
    test_cfg=dict(
        nms_pre=1000,
        nms=dict(type='nms', iou_threshold=0.45),
        min_bbox_size=0,
        score_thr=0.02,
        max_per_img=200))

#########################################################################################################
# DATASET

# dataset settings
dataset_type = 'CocoDataset'
data_root = 'data/balloon/'
backend_args = None
metainfo = {
    'classes': ('balloon', ),
    'palette': [
        (220, 20, 60),
    ]
}

train_pipeline = [
    dict(type='LoadImageFromFile', backend_args=backend_args),
    dict(type='LoadAnnotations', with_bbox=True),
    dict(type='Resize', scale=(img_size, img_size), keep_ratio=True),
    dict(type='RandomFlip', prob=0.5),
    dict(type='PackDetInputs')
]
test_pipeline = [
    dict(type='LoadImageFromFile', backend_args=backend_args),
    dict(type='Resize', scale=(img_size, img_size), keep_ratio=True),
    # If you don't have a gt annotation, delete the pipeline
    dict(type='LoadAnnotations', with_bbox=True),
    dict(
        type='PackDetInputs',
        meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape',
                   'scale_factor'))
]

# batch_sampler=dict(type='AspectRatioBatchSampler'),
train_dataloader = dict(
    batch_size=2,
    num_workers=2,
    persistent_workers=True,
    sampler=dict(type='DefaultSampler', shuffle=True),
    dataset=dict(
        metainfo=metainfo,
        type=dataset_type,
        data_root=data_root,
        ann_file='train.json',
        data_prefix=dict(img='train/'),
        filter_cfg=dict(filter_empty_gt=True, min_size=32),
        pipeline=train_pipeline,
        backend_args=backend_args))

val_dataloader = dict(
    batch_size=1,
    num_workers=2,
    persistent_workers=True,
    drop_last=False,
    sampler=dict(type='DefaultSampler', shuffle=False),
    dataset=dict(
        metainfo=metainfo,
        type=dataset_type,
        data_root=data_root,
        ann_file='val.json',
        data_prefix=dict(img='val/'),
        test_mode=True,
        pipeline=test_pipeline,
        backend_args=backend_args))
test_dataloader = val_dataloader

val_evaluator = dict(
    type='CocoMetric',
    ann_file=data_root + 'val.json',
    metric='bbox',
    format_only=False,
    backend_args=backend_args)

test_evaluator = val_evaluator

# inference on test dataset and
# format the output results for submission.
# test_dataloader = dict(
#     batch_size=1,
#     num_workers=2,
#     persistent_workers=True,
#     drop_last=False,
#     sampler=dict(type='DefaultSampler', shuffle=False),
#     dataset=dict(
#         type=dataset_type,
#         data_root=data_root,
#         ann_file=data_root + 'annotations/image_info_test-dev2017.json',
#         data_prefix=dict(img='test2017/'),
#         test_mode=True,
#         pipeline=test_pipeline))
# test_evaluator = dict(
#     type='CocoMetric',
#     metric='bbox',
#     format_only=True,
#     ann_file=data_root + 'annotations/image_info_test-dev2017.json',
#     outfile_prefix='./work_dirs/coco_detection/test')

#########################################################################################################
# training schedule for 1x
EPOCHS = 12
train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=EPOCHS, val_interval=1)
val_cfg = dict(type='ValLoop')
test_cfg = dict(type='TestLoop')

# learning rate
param_scheduler = [
    dict(
        type='LinearLR', start_factor=0.001, by_epoch=False, begin=0, end=500),
    dict(
        type='MultiStepLR',
        begin=0,
        end=12,
        by_epoch=True,
        milestones=[8, 11],
        gamma=0.1)
]

# optimizer
optim_wrapper = dict(
    type='OptimWrapper',
    optimizer=dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001))

# Default setting for scaling LR automatically
#   - `enable` means enable scaling LR automatically
#       or not by default.
#   - `base_batch_size` = (8 GPUs) x (2 samples per GPU).
auto_scale_lr = dict(enable=False, base_batch_size=16)

#########################################################################################################
default_scope = 'mmdet'

default_hooks = dict(
    timer=dict(type='IterTimerHook'),
    logger=dict(type='LoggerHook', interval=50),
    param_scheduler=dict(type='ParamSchedulerHook'),
    checkpoint=dict(type='CheckpointHook', interval=1),
    sampler_seed=dict(type='DistSamplerSeedHook'),
    visualization=dict(type='DetVisualizationHook'))

env_cfg = dict(
    cudnn_benchmark=False,
    mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0),
    dist_cfg=dict(backend='nccl'),
)

vis_backends = [dict(type='LocalVisBackend')]
visualizer = dict(
    type='DetLocalVisualizer', vis_backends=vis_backends, name='visualizer')
log_processor = dict(type='LogProcessor', window_size=50, by_epoch=True)

log_level = 'INFO'
load_from = None
resume = False

#########################################################################################################

#########################################################################################################
Regina971 commented 11 months ago

Have you resolved this issue? Can you provide me with some details, please?

pigfishgogogo commented 11 months ago

did you solve the problem? i have this problem too, can you git some suggenstion?

flywithliye commented 11 months ago

I encountered the same issue yesterday, and upon reviewing the code, I found a temporary solution (for the main branch).

TEMPORARY FIX

  1. Navigate to the code file mmdetection/mmdet/models/dense_heads/base_dense_head.py
  2. At line 376, within the if-statement, comment out getattr(self.loss_cls, 'custom_cls_channels', False): and replace it with False:

Before modification

if getattr(self.loss_cls, 'custom_cls_channels', False):
    scores = self.loss_cls.get_activation(cls_score)
elif self.use_sigmoid_cls:
    scores = cls_score.sigmoid()
else:
    # remind that we set FG labels to [0, num_class-1]
    # since mmdet v2.0
    # BG cat_id: num_class
    scores = cls_score.softmax(-1)[:, :-1]

After modification

if False: # getattr(self.loss_cls, 'custom_cls_channels', False):  # Change made here
    scores = self.loss_cls.get_activation(cls_score)
elif self.use_sigmoid_cls:
    scores = cls_score.sigmoid()
else:
    # remind that we set FG labels to [0, num_class-1]
    # since mmdet v2.0
    # BG cat_id: num_class
    scores = cls_score.softmax(-1)[:, :-1]
  1. By doing this, we force the 1st condition to be False, thus relying on the subsequent conditions. In earlier versions, this condition did not exist; it appears to be newly introduced. While I'm uncertain about the root cause of the malfunction, this adjustment seems to resolve the issue for now.
pigfishgogogo commented 11 months ago

Thank you very much for the detailed solution! -- It worked ! As a newbie, this problem has been bothering me for two days. To add: I just followed your method in the current mmdetection directory at first and it didn't work; but the bug was solved after I modified mmdet in the anaconda virtual environment!

leileilei2000 commented 10 months ago

非常感谢您的详细解决方案!--成功了!作为一个新手,这个问题已经困扰了我两天。补充:我一开始只是在当前的mmdetection目录中遵循了您的方法,但没有用;但是在我在 anaconda 虚拟环境中修改 mmdet 后,该错误得到了解决!

very cool!!!

SwjtuerFz commented 9 months ago

I encountered the same issue yesterday, and upon reviewing the code, I found a temporary solution (for the main branch).

TEMPORARY FIX

  1. Navigate to the code file mmdetection/mmdet/models/dense_heads/base_dense_head.py
  2. At line 376, within the if-statement, comment out getattr(self.loss_cls, 'custom_cls_channels', False): and replace it with False:

Before modification

if getattr(self.loss_cls, 'custom_cls_channels', False):
    scores = self.loss_cls.get_activation(cls_score)
elif self.use_sigmoid_cls:
    scores = cls_score.sigmoid()
else:
    # remind that we set FG labels to [0, num_class-1]
    # since mmdet v2.0
    # BG cat_id: num_class
    scores = cls_score.softmax(-1)[:, :-1]

After modification

if False: # getattr(self.loss_cls, 'custom_cls_channels', False):  # Change made here
    scores = self.loss_cls.get_activation(cls_score)
elif self.use_sigmoid_cls:
    scores = cls_score.sigmoid()
else:
    # remind that we set FG labels to [0, num_class-1]
    # since mmdet v2.0
    # BG cat_id: num_class
    scores = cls_score.softmax(-1)[:, :-1]
  1. By doing this, we force the 1st condition to be False, thus relying on the subsequent conditions. In earlier versions, this condition did not exist; it appears to be newly introduced. While I'm uncertain about the root cause of the malfunction, this adjustment seems to resolve the issue for now.

Thanks! It is works!

mookiechoi commented 7 months ago

Thank you!! I also solved this problem.