| import torch |
| import torch.nn as nn |
| import torch_scatter |
| import torch_cluster |
|
|
| from pointcept.models.losses import build_criteria |
| from pointcept.models.utils.structure import Point |
| from pointcept.models.utils import offset2batch |
| from .builder import MODELS, build_model |
|
|
|
|
| @MODELS.register_module() |
| class DefaultSegmentor(nn.Module): |
| def __init__(self, backbone=None, criteria=None): |
| super().__init__() |
| self.backbone = build_model(backbone) |
| self.criteria = build_criteria(criteria) |
|
|
| def forward(self, input_dict): |
| if "condition" in input_dict.keys(): |
| |
| |
| input_dict["condition"] = input_dict["condition"][0] |
| seg_logits = self.backbone(input_dict) |
| |
| if self.training: |
| loss = self.criteria(seg_logits, input_dict["segment"]) |
| return dict(loss=loss) |
| |
| elif "segment" in input_dict.keys(): |
| loss = self.criteria(seg_logits, input_dict["segment"]) |
| return dict(loss=loss, seg_logits=seg_logits) |
| |
| else: |
| return dict(seg_logits=seg_logits) |
|
|
|
|
| @MODELS.register_module() |
| class DefaultSegmentorV2(nn.Module): |
| def __init__( |
| self, |
| num_classes, |
| backbone_out_channels, |
| backbone=None, |
| criteria=None, |
| freeze_backbone=False, |
| ): |
| super().__init__() |
| self.seg_head = ( |
| nn.Linear(backbone_out_channels, num_classes) |
| if num_classes > 0 |
| else nn.Identity() |
| ) |
| self.backbone = build_model(backbone) |
| self.criteria = build_criteria(criteria) |
| self.freeze_backbone = freeze_backbone |
| if self.freeze_backbone: |
| for p in self.backbone.parameters(): |
| p.requires_grad = False |
|
|
| def forward(self, input_dict, return_point=False): |
| point = Point(input_dict) |
| point = self.backbone(point) |
| |
| |
| if isinstance(point, Point): |
| while "pooling_parent" in point.keys(): |
| assert "pooling_inverse" in point.keys() |
| parent = point.pop("pooling_parent") |
| inverse = point.pop("pooling_inverse") |
| parent.feat = torch.cat([parent.feat, point.feat[inverse]], dim=-1) |
| point = parent |
| feat = point.feat |
| else: |
| feat = point |
| seg_logits = self.seg_head(feat) |
| return_dict = dict() |
| if return_point: |
| |
| return_dict["point"] = point |
| |
| if self.training: |
| loss = self.criteria(seg_logits, input_dict["segment"]) |
| return_dict["loss"] = loss |
| |
| elif "segment" in input_dict.keys(): |
| loss = self.criteria(seg_logits, input_dict["segment"]) |
| return_dict["loss"] = loss |
| return_dict["seg_logits"] = seg_logits |
| |
| else: |
| return_dict["seg_logits"] = seg_logits |
| return return_dict |
|
|
|
|
| @MODELS.register_module() |
| class DINOEnhancedSegmentor(nn.Module): |
| def __init__( |
| self, |
| num_classes, |
| backbone_out_channels, |
| backbone=None, |
| criteria=None, |
| freeze_backbone=False, |
| ): |
| super().__init__() |
| self.seg_head = ( |
| nn.Linear(backbone_out_channels, num_classes) |
| if num_classes > 0 |
| else nn.Identity() |
| ) |
| self.backbone = build_model(backbone) if backbone is not None else None |
| self.criteria = build_criteria(criteria) |
| self.freeze_backbone = freeze_backbone |
| if self.backbone is not None and self.freeze_backbone: |
| for p in self.backbone.parameters(): |
| p.requires_grad = False |
|
|
| def forward(self, input_dict, return_point=False): |
| point = Point(input_dict) |
| if self.backbone is not None: |
| if self.freeze_backbone: |
| with torch.no_grad(): |
| point = self.backbone(point) |
| else: |
| point = self.backbone(point) |
| point_list = [point] |
| while "unpooling_parent" in point_list[-1].keys(): |
| point_list.append(point_list[-1].pop("unpooling_parent")) |
| for i in reversed(range(1, len(point_list))): |
| point = point_list[i] |
| parent = point_list[i - 1] |
| assert "pooling_inverse" in point.keys() |
| inverse = point.pooling_inverse |
| parent.feat = torch.cat([parent.feat, point.feat[inverse]], dim=-1) |
| point = point_list[0] |
| while "pooling_parent" in point.keys(): |
| assert "pooling_inverse" in point.keys() |
| parent = point.pop("pooling_parent") |
| inverse = point.pooling_inverse |
| parent.feat = torch.cat([parent.feat, point.feat[inverse]], dim=-1) |
| point = parent |
| feat = [point.feat] |
| else: |
| feat = [] |
| dino_coord = input_dict["dino_coord"] |
| dino_feat = input_dict["dino_feat"] |
| dino_offset = input_dict["dino_offset"] |
| idx = torch_cluster.knn( |
| x=dino_coord, |
| y=point.origin_coord, |
| batch_x=offset2batch(dino_offset), |
| batch_y=offset2batch(point.origin_offset), |
| k=1, |
| )[1] |
|
|
| feat.append(dino_feat[idx]) |
| feat = torch.concatenate(feat, dim=-1) |
| seg_logits = self.seg_head(feat) |
| return_dict = dict() |
| if return_point: |
| |
| return_dict["point"] = point |
| |
| if self.training: |
| loss = self.criteria(seg_logits, input_dict["segment"]) |
| return_dict["loss"] = loss |
| |
| elif "segment" in input_dict.keys(): |
| loss = self.criteria(seg_logits, input_dict["segment"]) |
| return_dict["loss"] = loss |
| return_dict["seg_logits"] = seg_logits |
| |
| else: |
| return_dict["seg_logits"] = seg_logits |
| return return_dict |
|
|
|
|
| @MODELS.register_module() |
| class DefaultClassifier(nn.Module): |
| def __init__( |
| self, |
| backbone=None, |
| criteria=None, |
| num_classes=40, |
| backbone_embed_dim=256, |
| ): |
| super().__init__() |
| self.backbone = build_model(backbone) |
| self.criteria = build_criteria(criteria) |
| self.num_classes = num_classes |
| self.backbone_embed_dim = backbone_embed_dim |
| self.cls_head = nn.Sequential( |
| nn.Linear(backbone_embed_dim, 256), |
| nn.BatchNorm1d(256), |
| nn.ReLU(inplace=True), |
| nn.Dropout(p=0.5), |
| nn.Linear(256, 128), |
| nn.BatchNorm1d(128), |
| nn.ReLU(inplace=True), |
| nn.Dropout(p=0.5), |
| nn.Linear(128, num_classes), |
| ) |
|
|
| def forward(self, input_dict): |
| point = Point(input_dict) |
| point = self.backbone(point) |
| |
| |
| |
| if isinstance(point, Point): |
| point.feat = torch_scatter.segment_csr( |
| src=point.feat, |
| indptr=nn.functional.pad(point.offset, (1, 0)), |
| reduce="mean", |
| ) |
| feat = point.feat |
| else: |
| feat = point |
| cls_logits = self.cls_head(feat) |
| if self.training: |
| loss = self.criteria(cls_logits, input_dict["category"]) |
| return dict(loss=loss) |
| elif "category" in input_dict.keys(): |
| loss = self.criteria(cls_logits, input_dict["category"]) |
| return dict(loss=loss, cls_logits=cls_logits) |
| else: |
| return dict(cls_logits=cls_logits) |
|
|