| from torch import nn, Tensor |
| import torch.nn.functional as F |
| import timm |
| from typing import Union, Optional |
|
|
| from ..utils import BasicBlock, Bottleneck, make_resnet_layers |
| from ..utils import _init_weights |
|
|
|
|
| model_configs = { |
| "resnet18.tv_in1k": { |
| "decoder_channels": [512, 256, 128], |
| }, |
| "resnet34.tv_in1k": { |
| "decoder_channels": [512, 256, 128], |
| }, |
| "resnet50.tv_in1k": { |
| "decoder_channels": [512, 256, 256, 128], |
| }, |
| "resnet101.tv_in1k": { |
| "decoder_channels": [512, 512, 256, 256, 128], |
| }, |
| "resnet152.tv_in1k": { |
| "decoder_channels": [512, 512, 512, 256, 256, 128], |
| }, |
| } |
|
|
|
|
| class ResNet(nn.Module): |
| def __init__( |
| self, |
| decoder_block: Union[BasicBlock, Bottleneck], |
| backbone: str = "resnet34.tv_in1k", |
| reduction: Optional[int] = None, |
| ) -> None: |
| super().__init__() |
| assert backbone in model_configs.keys(), f"Backbone should be in {model_configs.keys()}" |
| config = model_configs[backbone] |
| encoder = timm.create_model(backbone, pretrained=True, features_only=True, out_indices=(-1,)) |
| encoder_reduction = encoder.feature_info.reduction()[-1] |
|
|
| if reduction <= 16: |
| if "resnet18" in backbone or "resnet34" in backbone: |
| encoder.layer4[0].conv1.stride = (1, 1) |
| encoder.layer4[0].downsample[0].stride = (1, 1) |
| else: |
| encoder.layer4[0].conv2.stride = (1, 1) |
| encoder.layer4[0].downsample[0].stride = (1, 1) |
| encoder_reduction = encoder_reduction // 2 |
|
|
| self.encoder = encoder |
| self.encoder_reduction = encoder_reduction |
|
|
| encoder_out_channels = self.encoder.feature_info.channels()[-1] |
|
|
| decoder_channels = config["decoder_channels"] |
| self.decoder = make_resnet_layers( |
| block=decoder_block, |
| cfg=decoder_channels, |
| in_channels=encoder_out_channels, |
| dilation=1, |
| expansion=1, |
| ) |
| self.decoder.apply(_init_weights) |
|
|
| self.reduction = self.encoder_reduction if reduction is None else reduction |
| self.channels = decoder_channels[-1] |
|
|
| def forward(self, x: Tensor) -> Tensor: |
| x = self.encoder(x)[-1] |
| if self.encoder_reduction != self.reduction: |
| x = F.interpolate(x, scale_factor=self.encoder_reduction / self.reduction, mode="bilinear") |
| x = self.decoder(x) |
|
|
| return x |
|
|
|
|
| def resnet18(reduction: int = 32) -> ResNet: |
| return ResNet(decoder_block=BasicBlock, backbone="resnet18.tv_in1k", reduction=reduction) |
|
|
|
|
| def resnet34(reduction: int = 32) -> ResNet: |
| return ResNet(decoder_block=BasicBlock, backbone="resnet34.tv_in1k", reduction=reduction) |
|
|
|
|
| def resnet50(reduction: int = 32) -> ResNet: |
| return ResNet(decoder_block=Bottleneck, backbone="resnet50.tv_in1k", reduction=reduction) |
|
|
|
|
| def resnet101(reduction: int = 32) -> ResNet: |
| return ResNet(decoder_block=Bottleneck, backbone="resnet101.tv_in1k", reduction=reduction) |
|
|
|
|
| def resnet152(reduction: int = 32) -> ResNet: |
| return ResNet(decoder_block=Bottleneck, backbone="resnet152.tv_in1k", reduction=reduction) |
|
|