Spaces:
Sleeping
Sleeping
| import torch | |
| import torch.nn as nn | |
| from torchvision.models import convnext_tiny, ConvNeXt_Tiny_Weights | |
| from kan import KANLinear | |
| class ConvNeXtFeatureExtractor(nn.Module): | |
| def __init__( | |
| self, | |
| freeze_backbone: bool = True, | |
| unfreeze_last_stage: bool = False, | |
| ): | |
| super().__init__() | |
| weights = ConvNeXt_Tiny_Weights.DEFAULT | |
| self.backbone = convnext_tiny(weights=weights) | |
| if freeze_backbone: | |
| for p in self.backbone.parameters(): | |
| p.requires_grad = False | |
| if unfreeze_last_stage: | |
| for p in self.backbone.features[-1].parameters(): | |
| p.requires_grad = True | |
| self.output_dim = self.backbone.classifier[2].in_features | |
| self.backbone.classifier = nn.Identity() | |
| def forward(self, x): | |
| x = self.backbone(x) | |
| x = x.view(x.size(0), -1) | |
| return x | |
| class KANHead(nn.Module): | |
| def __init__( | |
| self, | |
| input_dim: int, | |
| num_classes: int, | |
| head_depth: int = 2, | |
| hidden_dim_1: int = 512, | |
| hidden_dim_2: int = 256, | |
| head_style: str = "standard", | |
| ): | |
| super().__init__() | |
| self.head_depth = head_depth | |
| self.head_style = head_style | |
| if head_style == "rakyan": | |
| if head_depth == 2: | |
| self.kan1 = KANLinear(input_dim, hidden_dim_1) | |
| self.bn1 = nn.BatchNorm1d(hidden_dim_1) | |
| self.act1 = nn.ReLU(inplace=True) | |
| self.kan2 = KANLinear(hidden_dim_1, num_classes) | |
| elif head_depth == 3: | |
| self.kan1 = KANLinear(input_dim, hidden_dim_1) | |
| self.bn1 = nn.BatchNorm1d(hidden_dim_1) | |
| self.act1 = nn.ReLU(inplace=True) | |
| self.drop1 = nn.Dropout(p=0.3) | |
| self.kan2 = KANLinear(hidden_dim_1, hidden_dim_2) | |
| self.bn2 = nn.BatchNorm1d(hidden_dim_2) | |
| self.act2 = nn.ReLU(inplace=True) | |
| self.drop2 = nn.Dropout(p=0.3) | |
| self.kan3 = KANLinear(hidden_dim_2, num_classes) | |
| else: | |
| raise ValueError("head_depth must be 2 or 3") | |
| elif head_style == "standard": | |
| if head_depth == 2: | |
| self.pre_norm = nn.LayerNorm(input_dim) | |
| self.kan1 = KANLinear(input_dim, hidden_dim_1) | |
| self.norm1 = nn.LayerNorm(hidden_dim_1) | |
| self.kan2 = KANLinear(hidden_dim_1, num_classes) | |
| elif head_depth == 3: | |
| self.pre_norm = nn.LayerNorm(input_dim) | |
| self.kan1 = KANLinear(input_dim, hidden_dim_1) | |
| self.norm1 = nn.LayerNorm(hidden_dim_1) | |
| self.kan2 = KANLinear(hidden_dim_1, hidden_dim_2) | |
| self.norm2 = nn.LayerNorm(hidden_dim_2) | |
| self.kan3 = KANLinear(hidden_dim_2, num_classes) | |
| else: | |
| raise ValueError("head_depth must be 2 or 3") | |
| else: | |
| raise ValueError("head_style must be 'standard' or 'rakyan'") | |
| def forward(self, x): | |
| if self.head_style == "rakyan": | |
| x = self.kan1(x); x = self.bn1(x); x = self.act1(x); x = self.drop1(x) | |
| if self.head_depth == 2: | |
| x = self.kan2(x) | |
| else: | |
| x = self.kan2(x); x = self.bn2(x); x = self.act2(x); x = self.drop2(x) | |
| x = self.kan3(x) | |
| return x | |
| x = self.pre_norm(x) | |
| x = self.kan1(x) | |
| x = self.norm1(x) | |
| if self.head_depth == 2: | |
| x = self.kan2(x) | |
| else: | |
| x = self.kan2(x) | |
| x = self.norm2(x) | |
| x = self.kan3(x) | |
| return x | |
| class ConvNextKAN(nn.Module): | |
| def __init__( | |
| self, | |
| num_classes: int = 10, | |
| head_depth: int = 2, | |
| hidden_dim_1: int = 512, | |
| hidden_dim_2: int = 256, | |
| freeze_backbone: bool = True, | |
| unfreeze_last_stage: bool = False, | |
| head_style: str = "standard" | |
| ): | |
| super().__init__() | |
| self.feature_extractor = ConvNeXtFeatureExtractor( | |
| freeze_backbone=freeze_backbone, | |
| unfreeze_last_stage=unfreeze_last_stage | |
| ) | |
| self.head = KANHead( | |
| input_dim=self.feature_extractor.output_dim, | |
| num_classes=num_classes, | |
| head_depth=head_depth, | |
| hidden_dim_1=hidden_dim_1, | |
| hidden_dim_2=hidden_dim_2, | |
| head_style=head_style | |
| ) | |
| def forward(self, x): | |
| features = self.feature_extractor(x) | |
| out = self.head(features) | |
| return out |