import torch import torch.nn as nn import torch.nn.functional as F from typing import List, Optional class ResNetBlock(nn.Module): def __init__(self, in_channels, out_channels, stride=1, downsample=None): super().__init__() self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False) self.bn1 = nn.BatchNorm2d(out_channels) self.relu = nn.ReLU(inplace=True) self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False) self.bn2 = nn.BatchNorm2d(out_channels) self.downsample = downsample def forward(self, x): identity = x out = self.conv1(x) out = self.bn1(out) out = self.relu(out) out = self.conv2(out) out = self.bn2(out) if self.downsample is not None: identity = self.downsample(x) out += identity out = self.relu(out) return out class ResNet(nn.Module): def __init__(self, block, layers, num_classes=1000, in_channels=3): super().__init__() self.in_channels = 64 self.conv1 = nn.Conv2d(in_channels, 64, kernel_size=7, stride=2, padding=3, bias=False) self.bn1 = nn.BatchNorm2d(64) self.relu = nn.ReLU(inplace=True) self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) self.layer1 = self._make_layer(block, 64, layers[0]) self.layer2 = self._make_layer(block, 128, layers[1], stride=2) self.layer3 = self._make_layer(block, 256, layers[2], stride=2) self.layer4 = self._make_layer(block, 512, layers[3], stride=2) self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) self.fc = nn.Linear(512, num_classes) def _make_layer(self, block, out_channels, blocks, stride=1): downsample = None if stride != 1 or self.in_channels != out_channels: downsample = nn.Sequential( nn.Conv2d(self.in_channels, out_channels, kernel_size=1, stride=stride, bias=False), nn.BatchNorm2d(out_channels) ) layers = [] layers.append(block(self.in_channels, out_channels, stride, downsample)) self.in_channels = out_channels for _ in range(1, blocks): layers.append(block(out_channels, out_channels)) return nn.Sequential(*layers) def forward(self, x): x = self.conv1(x) x = self.bn1(x) x = self.relu(x) x = self.maxpool(x) x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x) x = self.avgpool(x) x = torch.flatten(x, 1) x = self.fc(x) return x class EfficientNetBlock(nn.Module): def __init__(self, in_channels, out_channels, kernel_size, stride, expand_ratio, se_ratio=0.25): super().__init__() self.stride = stride self.use_residual = (stride == 1 and in_channels == out_channels) hidden_dim = in_channels * expand_ratio self.use_expansion = expand_ratio != 1 if self.use_expansion: self.expand_conv = nn.Sequential( nn.Conv2d(in_channels, hidden_dim, 1, bias=False), nn.BatchNorm2d(hidden_dim), nn.SiLU(inplace=True) ) self.depthwise_conv = nn.Sequential( nn.Conv2d(hidden_dim, hidden_dim, kernel_size, stride, kernel_size // 2, groups=hidden_dim, bias=False), nn.BatchNorm2d(hidden_dim), nn.SiLU(inplace=True) ) se_channels = max(1, int(in_channels * se_ratio)) self.se = nn.Sequential( nn.AdaptiveAvgPool2d(1), nn.Conv2d(hidden_dim, se_channels, 1), nn.SiLU(inplace=True), nn.Conv2d(se_channels, hidden_dim, 1), nn.Sigmoid() ) self.project_conv = nn.Sequential( nn.Conv2d(hidden_dim, out_channels, 1, bias=False), nn.BatchNorm2d(out_channels) ) def forward(self, x): identity = x if self.use_expansion: x = self.expand_conv(x) x = self.depthwise_conv(x) se_weight = self.se(x) x = x * se_weight x = self.project_conv(x) if self.use_residual: x = x + identity return x class UNetBlock(nn.Module): def __init__(self, in_channels, out_channels, down=True): super().__init__() self.down = down if down: self.conv = nn.Sequential( nn.Conv2d(in_channels, out_channels, 3, padding=1), nn.BatchNorm2d(out_channels), nn.ReLU(inplace=True), nn.Conv2d(out_channels, out_channels, 3, padding=1), nn.BatchNorm2d(out_channels), nn.ReLU(inplace=True) ) self.pool = nn.MaxPool2d(2) else: self.conv = nn.Sequential( nn.Conv2d(in_channels, out_channels, 3, padding=1), nn.BatchNorm2d(out_channels), nn.ReLU(inplace=True), nn.Conv2d(out_channels, out_channels, 3, padding=1), nn.BatchNorm2d(out_channels), nn.ReLU(inplace=True) ) self.up = nn.ConvTranspose2d(in_channels, in_channels // 2, 2, stride=2) def forward(self, x, skip=None): if self.down: x = self.conv(x) pool = self.pool(x) return x, pool else: x = self.up(x) if skip is not None: x = torch.cat([x, skip], dim=1) x = self.conv(x) return x class ConvNeXtBlock(nn.Module): def __init__(self, dim, drop_path=0.0, layer_scale_init_value=1e-6): super().__init__() self.dwconv = nn.Conv2d(dim, dim, kernel_size=7, padding=3, groups=dim) self.norm = nn.LayerNorm(dim, eps=1e-6) self.pwconv1 = nn.Linear(dim, 4 * dim) self.act = nn.GELU() self.pwconv2 = nn.Linear(4 * dim, dim) self.gamma = nn.Parameter(layer_scale_init_value * torch.ones(dim)) if layer_scale_init_value > 0 else None from .modules import DropPath self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity() def forward(self, x): identity = x x = self.dwconv(x) x = x.permute(0, 2, 3, 1) x = self.norm(x) x = self.pwconv1(x) x = self.act(x) x = self.pwconv2(x) if self.gamma is not None: x = self.gamma * x x = x.permute(0, 3, 1, 2) x = identity + self.drop_path(x) return x class DilatedConvBlock(nn.Module): def __init__(self, in_channels, out_channels, dilation_rates=[1, 2, 4, 8]): super().__init__() self.convs = nn.ModuleList([ nn.Sequential( nn.Conv2d(in_channels, out_channels // len(dilation_rates), 3, padding=d, dilation=d), nn.BatchNorm2d(out_channels // len(dilation_rates)), nn.ReLU(inplace=True) ) for d in dilation_rates ]) def forward(self, x): return torch.cat([conv(x) for conv in self.convs], dim=1) class PyramidPoolingModule(nn.Module): def __init__(self, in_channels, out_channels, pool_sizes=[1, 2, 3, 6]): super().__init__() self.stages = nn.ModuleList([ nn.Sequential( nn.AdaptiveAvgPool2d(size), nn.Conv2d(in_channels, out_channels // len(pool_sizes), 1), nn.BatchNorm2d(out_channels // len(pool_sizes)), nn.ReLU(inplace=True) ) for size in pool_sizes ]) def forward(self, x): h, w = x.size(2), x.size(3) features = [x] for stage in self.stages: pooled = stage(x) features.append(F.interpolate(pooled, size=(h, w), mode='bilinear', align_corners=False)) return torch.cat(features, dim=1)