{"record":{"id":"c34b544eaeff4242","repo":"WZMIAOMIAO/deep-learning-for-image-processing","slug":"the-backbone-not-has-attribute-out-channel","errorCode":null,"errorMessage":"the backbone not has attribute: out_channel","messagePattern":"the backbone not has attribute: out_channel","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"pytorch_object_detection/ssd/src/ssd_model.py","lineNumber":38,"sourceCode":"        conv4_block1 = self.feature_extractor[-1][0]\n\n        # 修改conv4_block1的步距，从2->1\n        conv4_block1.conv1.stride = (1, 1)\n        conv4_block1.conv2.stride = (1, 1)\n        conv4_block1.downsample[0].stride = (1, 1)\n\n    def forward(self, x):\n        x = self.feature_extractor(x)\n        return x\n\n\nclass SSD300(nn.Module):\n    def __init__(self, backbone=None, num_classes=21):\n        super(SSD300, self).__init__()\n        if backbone is None:\n            raise Exception(\"backbone is None\")\n        if not hasattr(backbone, \"out_channels\"):\n            raise Exception(\"the backbone not has attribute: out_channel\")\n        self.feature_extractor = backbone\n\n        self.num_classes = num_classes\n        # out_channels = [1024, 512, 512, 256, 256, 256] for resnet50\n        self._build_additional_features(self.feature_extractor.out_channels)\n        self.num_defaults = [4, 6, 6, 6, 4, 4]\n        location_extractors = []\n        confidence_extractors = []\n\n        # out_channels = [1024, 512, 512, 256, 256, 256] for resnet50\n        for nd, oc in zip(self.num_defaults, self.feature_extractor.out_channels):\n            # nd is number_default_boxes, oc is output_channel\n            location_extractors.append(nn.Conv2d(oc, nd * 4, kernel_size=3, padding=1))\n            confidence_extractors.append(nn.Conv2d(oc, nd * self.num_classes, kernel_size=3, padding=1))\n\n        self.loc = nn.ModuleList(location_extractors)\n        self.conf = nn.ModuleList(confidence_extractors)\n        self._init_weights()","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/WZMIAOMIAO/deep-learning-for-image-processing/blob/1ec3fe6f374fc9969973a61f819de25658595afa/pytorch_object_detection/ssd/src/ssd_model.py#L20-L56","documentation":"After the None check, SSD300 verifies the backbone exposes out_channels, needed by _build_additional_features to size extra conv layers. A backbone without this attribute (e.g. a raw resnet50 module without FPN wrapping) raises this Exception. Message says 'out_channel' but the attribute checked is 'out_channels'.","triggerScenarios":"Passing a plain torchvision resnet50 model directly (it lacks out_channels) instead of a wrapped FPN backbone; using a custom backbone whose only_out attribute is named differently; passing None-adjacent objects like a ModuleList of layers.","commonSituations":"Building SSD from torchvision models without the resnet50_fpn_backbone wrapper; custom feature extractors forgetting to set self.out_channels; mixing code from tutorial versions where the wrapper was implicit.","solutions":["Wrap the CNN with resnet50_fpn_backbone() which adds an FPN exposing out_channels","Set self.out_channels on your custom backbone (list of per-feature-map channel widths) and ensure hasattr passes","Verify the object you pass is the wrapped backbone, not the raw torchvision model"],"exampleFix":"// before\nbackbone = resnet50(pretrained=True)\nmodel = SSD300(backbone=backbone, num_classes=21)\n// after\nfrom torchvision.models.detection.backbone_utils import resnet_fpn_backbone\nbackbone = resnet_fpn_backbone('resnet50', pretrained=True)  # has out_channels\nmodel = SSD300(backbone=backbone, num_classes=21)","handlingStrategy":"type-guard","validationCode":"assert hasattr(backbone, 'out_channels'), 'backbone must expose out_channels (use an FPN-wrapped backbone)'","typeGuard":"def has_out_channels(obj) -> bool:\n    return hasattr(obj, 'out_channels')","tryCatchPattern":"try:\n    model = SSD300(backbone=backbone, num_classes=21)\nexcept Exception as e:\n    print(f'Backbone interface mismatch: {e}; wrap with resnet_fpn_backbone')","preventionTips":["Use resnet50_fpn_backbone-style wrappers that define out_channels","Add out_channels to any custom feature extractor","Write a unit test constructing SSD300 with your backbone"],"tags":["pytorch","ssd","backbone","interface","duck-typing"],"backgroundTag":"backbone-missing-out-channels","analyzedSha":"1ec3fe6f374fc9969973a61f819de25658595afa","analyzedAt":"2026-08-30T09:19:11.901Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}