From 78ba0e84bad0cfa731c137f5504e6b360b7c832a Mon Sep 17 00:00:00 2001 From: VedantDalimkar <f20190209@goa.bits-pilani.ac.in> Date: Fri, 28 Feb 2025 18:03:21 +0530 Subject: [PATCH 01/44] Initial timm vit encoder commit --- .../encoders/__init__.py | 13 ++ .../encoders/timm_vit.py | 196 ++++++++++++++++++ 2 files changed, 209 insertions(+) create mode 100644 segmentation_models_pytorch/encoders/timm_vit.py diff --git a/segmentation_models_pytorch/encoders/__init__.py b/segmentation_models_pytorch/encoders/__init__.py index 7c74ec61..1f00c81d 100644 --- a/segmentation_models_pytorch/encoders/__init__.py +++ b/segmentation_models_pytorch/encoders/__init__.py @@ -24,6 +24,7 @@ from .mobileone import mobileone_encoders from .timm_universal import TimmUniversalEncoder +from .timm_vit import TimmViTEncoder from ._preprocessing import preprocess_input from ._legacy_pretrained_settings import pretrained_settings @@ -81,8 +82,20 @@ def get_encoder(name, in_channels=3, depth=5, weights=None, output_stride=32, ** if "mobilenetv3" in name: name = name.replace("tu-", "tu-tf_") + use_vit_encoder = kwargs.pop("use_vit_encoder",False) if name.startswith("tu-"): name = name[3:] + + if use_vit_encoder: + encoder = TimmViTEncoder( + name = name, + in_channels = in_channels, + depth = depth, + pretrained = weights is not None, + **kwargs + ) + return encoder + encoder = TimmUniversalEncoder( name=name, in_channels=in_channels, diff --git a/segmentation_models_pytorch/encoders/timm_vit.py b/segmentation_models_pytorch/encoders/timm_vit.py new file mode 100644 index 00000000..6fe00b79 --- /dev/null +++ b/segmentation_models_pytorch/encoders/timm_vit.py @@ -0,0 +1,196 @@ +""" +TimmUniversalEncoder provides a unified feature extraction interface built on the +`timm` library, supporting both traditional-style (e.g., ResNet) and transformer-style +models (e.g., Swin Transformer, ConvNeXt). + +This encoder produces consistent multi-level feature maps for semantic segmentation tasks. +It allows configuring the number of feature extraction stages (`depth`) and adjusting +`output_stride` when supported. + +Key Features: +- Flexible model selection using `timm.create_model`. +- Unified multi-level output across different model hierarchies. +- Automatic alignment for inconsistent feature scales: + - Transformer-style models (start at 1/4 scale): Insert dummy features for 1/2 scale. + - VGG-style models (include scale-1 features): Align outputs for compatibility. +- Easy access to feature scale information via the `reduction` property. + +Feature Scale Differences: +- Traditional-style models (e.g., ResNet): Scales at 1/2, 1/4, 1/8, 1/16, 1/32. +- Transformer-style models (e.g., Swin Transformer): Start at 1/4 scale, skip 1/2 scale. +- VGG-style models: Include scale-1 features (input resolution). + +Notes: +- `output_stride` is unsupported in some models, especially transformer-based architectures. +- Special handling for models like TResNet and DLA to ensure correct feature indexing. +- VGG-style models use `_is_vgg_style` to align scale-1 features with standard outputs. +""" + +from typing import Any, Optional + +import timm +import torch +import torch.nn as nn + + +class TimmViTEncoder(nn.Module): + """ + TODO + """ + + _is_torch_scriptable = True + _is_torch_exportable = True + _is_torch_compilable = True + + def __init__( + self, + name: str, + pretrained: bool = True, + in_channels: int = 3, + depth: int = 4, + out_indices : Optional[list[int]] = None, + **kwargs: dict[str, Any], + ): + """ + Initialize the encoder. + + Args: + name (str): Model name to load from `timm`. + pretrained (bool): Load pretrained weights (default: True). + in_channels (int): Number of input channels (default: 3 for RGB). + depth (int): Number of feature stages to extract (default: 5). + **kwargs: Additional arguments passed to `timm.create_model`. + """ + # At the moment we do not support models with more than 4 stages, + # but can be reconfigured in the future. + if depth > 4 or depth < 1: + raise ValueError( + f"{self.__class__.__name__} depth should be in range [1, 4], got {depth}" + ) + + super().__init__() + self.name = name + + # Default model configuration for feature extraction + common_kwargs = dict( + in_chans=in_channels, + features_only=True, + pretrained=pretrained, + out_indices=tuple(range(depth)), + ) + + # Load a temporary model to analyze its feature hierarchy + try: + with torch.device("meta"): + tmp_model = timm.create_model(name, features_only=True) + except Exception: + tmp_model = timm.create_model(name, features_only=True) + + # Check if model output is in channel-last format (NHWC) + self._is_channel_last = getattr(tmp_model, "output_fmt", None) == "NHWC" + + # Determine the model's downsampling pattern and set hierarchy flags + reduction_scales = list(tmp_model.feature_info.reduction()) + output_stride = reduction_scales[0] + + # Need model to output ViT style features with no downsampling + if len(set(reduction_scales)) != 1: + raise ValueError("Unsupported model downsampling pattern.") + + num_blocks = len(tmp_model.blocks) + if out_indices is None: + out_indices = [int(index * (num_blocks / 4)) - 1 for index in range(1,depth+1)] + + # Model with 24 blocks should use features from layers [5,12,18,24] + if num_blocks == 24: + out_indices[0] -= 1 + + + common_kwargs['out_indices'] = out_indices + self.model = timm.create_model( + name, **_merge_kwargs_no_duplicates(common_kwargs, kwargs) + ) + + self._out_channels = self.model.feature_info.channels() + self._in_channels = in_channels + self._depth = depth + self._output_stride = output_stride + + def forward(self, x: torch.Tensor) -> list[torch.Tensor]: + """ + Forward pass to extract multi-stage features. + + Args: + x (torch.Tensor): Input tensor of shape (B, C, H, W). + + Returns: + list[torch.Tensor]: List of feature maps at different scales. + """ + features = self.model(x) + + # Convert NHWC to NCHW if needed + if self._is_channel_last: + features = [ + feature.permute(0, 3, 1, 2).contiguous() for feature in features + ] + + return features + + @property + def out_channels(self) -> list[int]: + """ + Returns the number of output channels for each feature stage. + + Returns: + list[int]: A list of channel dimensions at each scale. + """ + return self._out_channels + + @property + def output_stride(self) -> int: + """ + Returns the effective output stride based on the model depth. + + Returns: + int: The effective output stride. + """ + return self._output_stride + + def load_state_dict(self, state_dict, **kwargs): + # for compatibility of weights for + # timm- ported encoders with TimmUniversalEncoder + patterns = ["regnet", "res2", "resnest", "mobilenetv3", "gernet"] + + is_deprecated_encoder = any( + self.name.startswith(pattern) for pattern in patterns + ) + + if is_deprecated_encoder: + keys = list(state_dict.keys()) + for key in keys: + new_key = key + if not key.startswith("model."): + new_key = "model." + key + if "gernet" in self.name: + new_key = new_key.replace(".stages.", ".stages_") + state_dict[new_key] = state_dict.pop(key) + + return super().load_state_dict(state_dict, **kwargs) + + +def _merge_kwargs_no_duplicates(a: dict[str, Any], b: dict[str, Any]) -> dict[str, Any]: + """ + Merge two dictionaries, ensuring no duplicate keys exist. + + Args: + a (dict): Base dictionary. + b (dict): Additional parameters to merge. + + Returns: + dict: A merged dictionary. + """ + duplicates = a.keys() & b.keys() + if duplicates: + raise ValueError(f"'{duplicates}' already specified internally") + + return a | b From 2c38de6026b3e8b6cf450413ec4657dbab6c4113 Mon Sep 17 00:00:00 2001 From: VedantDalimkar <f20190209@goa.bits-pilani.ac.in> Date: Sun, 2 Mar 2025 13:11:48 +0530 Subject: [PATCH 02/44] Add DPT model and update logic for TimmViTEncoder class --- encoders_table.md | 2 + .../decoders/dpt/__init__.py | 3 + .../decoders/dpt/decoder.py | 268 ++++++++++++++++++ .../decoders/dpt/model.py | 116 ++++++++ .../encoders/__init__.py | 12 +- .../encoders/timm_vit.py | 117 ++++++-- 6 files changed, 487 insertions(+), 31 deletions(-) create mode 100644 encoders_table.md create mode 100644 segmentation_models_pytorch/decoders/dpt/__init__.py create mode 100644 segmentation_models_pytorch/decoders/dpt/decoder.py create mode 100644 segmentation_models_pytorch/decoders/dpt/model.py diff --git a/encoders_table.md b/encoders_table.md new file mode 100644 index 00000000..c039b137 --- /dev/null +++ b/encoders_table.md @@ -0,0 +1,2 @@ +|Encoder |Pretrained weights |Params, M |Script |Compile |Export | +|--------------------------------|:------------------------------:|:------------------------------:|:------------------------------:|:------------------------------:|:------------------------------:| diff --git a/segmentation_models_pytorch/decoders/dpt/__init__.py b/segmentation_models_pytorch/decoders/dpt/__init__.py new file mode 100644 index 00000000..c729fe90 --- /dev/null +++ b/segmentation_models_pytorch/decoders/dpt/__init__.py @@ -0,0 +1,3 @@ +from .model import DPT + +__all__ = ["DPT"] diff --git a/segmentation_models_pytorch/decoders/dpt/decoder.py b/segmentation_models_pytorch/decoders/dpt/decoder.py new file mode 100644 index 00000000..2a0308a9 --- /dev/null +++ b/segmentation_models_pytorch/decoders/dpt/decoder.py @@ -0,0 +1,268 @@ +import torch +import torch.nn as nn + + +def _get_feature_processing_out_channels(encoder_name: str) -> list[int]: + """ + Get the output embedding dimensions for the features after decoder processing + """ + + encoder_name = encoder_name.lower() + # Output channels for hybrid ViT encoder after feature processing + if "vit" in encoder_name and "resnet" in encoder_name: + return [256, 512, 768, 768] + + # Output channels for ViT-large,ViT-huge,ViT-giant encoders after feature processing + if "vit" in encoder_name and any( + [variant in encoder_name for variant in ["huge", "large", "giant"]] + ): + return [256, 512, 1024, 1024] + + # Output channels for ViT-base and other encoders after feature processing + return [96, 192, 384, 768] + + +class Transpose(nn.Module): + def __init__(self, dim0: int, dim1: int): + super().__init__() + self.dim0 = dim0 + self.dim1 = dim1 + + def forward(self, x: torch.Tensor): + return torch.transpose(x, dim0=self.dim0, dim1=self.dim1) + + +class ProjectionReadout(nn.Module): + """ + Concatenates the cls tokens with the features to make use of the global information aggregated in the cls token. + Projects the combined feature map to the original embedding dimension using a MLP + """ + + def __init__(self, in_features: int, encoder_output_stride: int): + super().__init__() + self.project = nn.Sequential( + nn.Linear(in_features=2 * in_features, out_features=in_features), nn.GELU() + ) + + self.flatten = nn.Flatten(start_dim=2) + self.transpose = Transpose(dim0=1, dim1=2) + self.encoder_output_stride = encoder_output_stride + + def forward(self, feature: torch.Tensor, cls_token: torch.Tensor): + batch_size, _, height_dim, width_dim = feature.shape + feature = self.flatten(feature) + feature = self.transpose(feature) + + cls_token = cls_token.expand_as(feature) + + features = torch.cat([feature, cls_token], dim=2) + features = self.project(features) + features = self.transpose(features) + + features = features.view(batch_size, -1, height_dim, width_dim) + return features + + +class IgnoreReadout(nn.Module): + def __init__(self): + super().__init__() + + def forward(self, feature: torch.Tensor, cls_token: torch.Tensor): + return feature + + +class FeatureProcessBlock(nn.Module): + """ + Processes the features such that they have progressively increasing embedding size and progressively decreasing + spatial dimension + """ + + def __init__( + self, embed_dim: int, feature_dim: int, out_channel: int, upsample_factor: int + ): + super().__init__() + + self.project_to_out_channel = nn.Conv2d( + in_channels=embed_dim, out_channels=out_channel, kernel_size=1 + ) + + if upsample_factor > 1.0: + self.upsample = nn.ConvTranspose2d( + in_channels=out_channel, + out_channels=out_channel, + kernel_size=int(upsample_factor), + stride=int(upsample_factor), + ) + + elif upsample_factor == 1.0: + self.upsample = nn.Identity() + + else: + self.upsample = nn.Conv2d( + in_channels=out_channel, + out_channels=out_channel, + kernel_size=3, + stride=int(1 / upsample_factor), + padding=1, + ) + + self.project_to_feature_dim = nn.Conv2d( + in_channels=out_channel, out_channels=feature_dim, kernel_size=3, padding=1 + ) + + def forward(self, x: torch.Tensor): + x = self.project_to_out_channel(x) + x = self.upsample(x) + x = self.project_to_feature_dim(x) + + return x + + +class ResidualConvBlock(nn.Module): + def __init__(self, feature_dim: int): + super().__init__() + self.conv_block = nn.Sequential( + nn.ReLU(), + nn.Conv2d( + in_channels=feature_dim, + out_channels=feature_dim, + kernel_size=3, + padding=1, + bias=False, + ), + nn.BatchNorm2d(num_features=feature_dim), + nn.ReLU(), + nn.Conv2d( + in_channels=feature_dim, + out_channels=feature_dim, + kernel_size=3, + padding=1, + bias=False, + ), + nn.BatchNorm2d(num_features=feature_dim), + ) + + def forward(self, x: torch.Tensor): + return x + self.conv_block(x) + + +class FusionBlock(nn.Module): + """ + Fuses the processed encoder features in a residual manner and upsamples them + """ + + def __init__(self, feature_dim: int): + super().__init__() + self.residual_conv_block1 = ResidualConvBlock(feature_dim=feature_dim) + self.residual_conv_block2 = ResidualConvBlock(feature_dim=feature_dim) + self.project = nn.Conv2d( + in_channels=feature_dim, out_channels=feature_dim, kernel_size=1 + ) + self.activation = nn.ReLU() + + def forward(self, feature: torch.Tensor, preceding_layer_feature: torch.Tensor): + feature = self.residual_conv_block1(feature) + + if preceding_layer_feature is not None: + feature += preceding_layer_feature + + feature = self.residual_conv_block2(feature) + + feature = nn.functional.interpolate( + feature, scale_factor=2, align_corners=True, mode="bilinear" + ) + feature = self.project(feature) + feature = self.activation(feature) + + return feature + + +class DPTDecoder(nn.Module): + """ + Decoder part for DPT + + Processes the encoder features and class tokens (if encoder has class_tokens) to have spatial downsampling ratios of + [1/32,1/16,1/8,1/4] relative to the input image spatial dimension. + + The decoder then fuses these features in a residual manner and progressively upsamples them by a factor of 2 so that the + output has a downsampling ratio of 1/2 relative to the input image spatial dimension + + """ + + def __init__( + self, + encoder_name: str, + transformer_embed_dim: int, + encoder_output_stride: int, + feature_dim: int = 256, + encoder_depth: int = 4, + prefix_token_supported: bool = False, + ): + super().__init__() + + self.prefix_token_supported = prefix_token_supported + + # If encoder has cls token, then concatenate it with the features along the embedding dimension and project it + # back to the feature_dim dimension. Else, ignore the non-existent cls token + + if prefix_token_supported: + self.readout_blocks = nn.ModuleList( + [ + ProjectionReadout( + in_features=transformer_embed_dim, + encoder_output_stride=encoder_output_stride, + ) + for _ in range(encoder_depth) + ] + ) + else: + self.readout_blocks = [IgnoreReadout() for _ in range(encoder_depth)] + + upsample_factors = [ + (encoder_output_stride / 2 ** (index + 2)) + for index in range(0, encoder_depth) + ] + feature_processing_out_channels = _get_feature_processing_out_channels( + encoder_name + ) + if encoder_depth < len(feature_processing_out_channels): + feature_processing_out_channels = feature_processing_out_channels[ + :encoder_depth + ] + + self.feature_processing_blocks = nn.ModuleList( + [ + FeatureProcessBlock( + transformer_embed_dim, feature_dim, out_channel, upsample_factor + ) + for upsample_factor, out_channel in zip( + upsample_factors, feature_processing_out_channels + ) + ] + ) + + self.fusion_blocks = nn.ModuleList( + [FusionBlock(feature_dim=feature_dim) for _ in range(encoder_depth)] + ) + + def forward( + self, encoder_output: list[list[torch.Tensor], list[torch.Tensor]] + ) -> torch.Tensor: + features, cls_tokens = encoder_output + processed_features = [] + + # Process the encoder features to scale of [1/32,1/16,1/8,1/4] + for index, (feature, cls_token) in enumerate(zip(features, cls_tokens)): + readout_feature = self.readout_blocks[index](feature, cls_token) + processed_feature = self.feature_processing_blocks[index](readout_feature) + processed_features.append(processed_feature) + + preceding_layer_feature = None + + # Fusion and progressive upsampling starting from the last processed feature + processed_features = processed_features[::-1] + for fusion_block, feature in zip(self.fusion_blocks, processed_features): + out = fusion_block(feature, preceding_layer_feature) + preceding_layer_feature = out + + return out diff --git a/segmentation_models_pytorch/decoders/dpt/model.py b/segmentation_models_pytorch/decoders/dpt/model.py new file mode 100644 index 00000000..b5410188 --- /dev/null +++ b/segmentation_models_pytorch/decoders/dpt/model.py @@ -0,0 +1,116 @@ +from typing import Any, Optional, Union, Callable + +from segmentation_models_pytorch.base import ( + ClassificationHead, + SegmentationHead, + SegmentationModel, +) +from segmentation_models_pytorch.encoders import get_encoder +from segmentation_models_pytorch.base.hub_mixin import supports_config_loading +from .decoder import DPTDecoder + + +class DPT(SegmentationModel): + """ + DPT is a dense prediction architecture that leverages vision transformers in place of convolutional networks as + a backbone for dense prediction tasks + + It assembles tokens from various stages of the vision transformer into image-like representations at various resolutions + and progressively combines them into full-resolution predictions using a convolutional decoder. + + The transformer backbone processes representations at a constant and relatively high resolution and has a global receptive + field at every stage. These properties allow the dense vision transformer to provide finer-grained and more globally coherent + predictions when compared to fully-convolutional networks + + Args: + encoder_name: Name of the classification model that will be used as an encoder (a.k.a backbone) + to extract features of different spatial resolution + encoder_depth: A number of stages used in encoder in range [1,4]. Each stage generate features + smaller by a factor equal to the ViT model patch_size in spatial dimensions. + Default is 4 + encoder_weights: One of **None** (random initialization), or other pretrained weights (see table with + available weights for each encoder_name) + feature_dim : The latent dimension to which the encoder features will be projected to. + in_channels: Number of input channels for the model, default is 3 (RGB images) + classes: Number of classes for output mask (or you can think as a number of channels of output mask) + activation: An activation function to apply after the final convolution layer. + Available options are **"sigmoid"**, **"softmax"**, **"logsoftmax"**, **"tanh"**, **"identity"**, + **callable** and **None**. + Default is **None** + aux_params: Dictionary with parameters of the auxiliary output (classification head). Auxiliary output is build + on top of encoder if **aux_params** is not **None** (default). Supported params: + - classes (int): A number of classes + - pooling (str): One of "max", "avg". Default is "avg" + - dropout (float): Dropout factor in [0, 1) + - activation (str): An activation function to apply "sigmoid"/"softmax" + (could be **None** to return logits) + kwargs: Arguments passed to the encoder class ``__init__()`` function. Applies only to ``timm`` models. Keys with + ``None`` values are pruned before passing. + allow_downsampling : Allow ViT encoder to have progressive downsampling. Set to False for DPT as the architecture + requires all encoder feature outputs to have the same spatial shape. + allow_output_stride_not_power_of_two : Allow ViT encoders with output_stride not being a power of 2. This + is set False for DPT as the architecture requires the encoder output features to have an output stride of + [1/32,1/16,1/8,1/4] + + Returns: + ``torch.nn.Module``: DPT + + + """ + + @supports_config_loading + def __init__( + self, + encoder_name: str = "tu-vit_base_patch8_224", + encoder_depth: int = 4, + encoder_weights: Optional[str] = None, + feature_dim: int = 256, + in_channels: int = 3, + classes: int = 1, + activation: Optional[Union[str, Callable]] = None, + aux_params: Optional[dict] = None, + **kwargs: dict[str, Any], + ): + super().__init__() + + self.encoder = get_encoder( + encoder_name, + in_channels=in_channels, + depth=encoder_depth, + weights=encoder_weights, + use_vit_encoder=True, + allow_downsampling=False, + allow_output_stride_not_power_of_two=False, + **kwargs, + ) + + transformer_embed_dim = self.encoder.embed_dim + encoder_output_stride = self.encoder.output_stride + cls_token_supported = self.encoder.prefix_token_supported + + self.decoder = DPTDecoder( + encoder_name=encoder_name, + transformer_embed_dim=transformer_embed_dim, + feature_dim=feature_dim, + encoder_depth=encoder_depth, + encoder_output_stride=encoder_output_stride, + prefix_token_supported=cls_token_supported, + ) + + self.segmentation_head = SegmentationHead( + in_channels=feature_dim, + out_channels=classes, + activation=activation, + kernel_size=1, + upsampling=2, + ) + + if aux_params is not None: + self.classification_head = ClassificationHead( + in_channels=self.encoder.out_channels[-1], **aux_params + ) + else: + self.classification_head = None + + self.name = "dpt-{}".format(encoder_name) + self.initialize() diff --git a/segmentation_models_pytorch/encoders/__init__.py b/segmentation_models_pytorch/encoders/__init__.py index 1f00c81d..8ffb91f4 100644 --- a/segmentation_models_pytorch/encoders/__init__.py +++ b/segmentation_models_pytorch/encoders/__init__.py @@ -82,17 +82,17 @@ def get_encoder(name, in_channels=3, depth=5, weights=None, output_stride=32, ** if "mobilenetv3" in name: name = name.replace("tu-", "tu-tf_") - use_vit_encoder = kwargs.pop("use_vit_encoder",False) if name.startswith("tu-"): name = name[3:] + use_vit_encoder = kwargs.pop("use_vit_encoder", False) if use_vit_encoder: encoder = TimmViTEncoder( - name = name, - in_channels = in_channels, - depth = depth, - pretrained = weights is not None, - **kwargs + name=name, + in_channels=in_channels, + depth=depth, + pretrained=weights is not None, + **kwargs, ) return encoder diff --git a/segmentation_models_pytorch/encoders/timm_vit.py b/segmentation_models_pytorch/encoders/timm_vit.py index 6fe00b79..46903dde 100644 --- a/segmentation_models_pytorch/encoders/timm_vit.py +++ b/segmentation_models_pytorch/encoders/timm_vit.py @@ -35,7 +35,13 @@ class TimmViTEncoder(nn.Module): """ - TODO + A universal encoder leveraging the `timm` library for feature extraction from + ViT style models + + Features: + - Supports configurable depth and output stride. + - Ensures consistent multi-level feature extraction across diverse models. + - Compatible with convolutional and transformer-like backbones. """ _is_torch_scriptable = True @@ -48,17 +54,18 @@ def __init__( pretrained: bool = True, in_channels: int = 3, depth: int = 4, - out_indices : Optional[list[int]] = None, + output_indices: Optional[list[int] | int] = None, **kwargs: dict[str, Any], ): """ Initialize the encoder. Args: - name (str): Model name to load from `timm`. + name (str): ViT model name to load from `timm`. pretrained (bool): Load pretrained weights (default: True). in_channels (int): Number of input channels (default: 3 for RGB). - depth (int): Number of feature stages to extract (default: 5). + depth (int): Number of feature stages to extract (default: 4). + output_indices (Optional[list[int] | int]): Indices of blocks in the model to be used for feature extraction. **kwargs: Additional arguments passed to `timm.create_model`. """ # At the moment we do not support models with more than 4 stages, @@ -82,41 +89,69 @@ def __init__( # Load a temporary model to analyze its feature hierarchy try: with torch.device("meta"): - tmp_model = timm.create_model(name, features_only=True) + tmp_model = timm.create_model(name) except Exception: - tmp_model = timm.create_model(name, features_only=True) + tmp_model = timm.create_model(name) # Check if model output is in channel-last format (NHWC) self._is_channel_last = getattr(tmp_model, "output_fmt", None) == "NHWC" + feature_info = tmp_model.feature_info + model_num_blocks = len(feature_info) + + if depth > model_num_blocks: + raise ValueError( + f"Depth of the encoder cannot exceed the number of blocks in the model \ + got {depth} depth, model has {model_num_blocks} blocks" + ) + + if output_indices is None: + output_indices = [ + int((model_num_blocks / 4) * index) - 1 for index in range(1, depth + 1) + ] + + common_kwargs["out_indices"] = self.out_indices = output_indices + feature_info_obj = timm.models.FeatureInfo( + feature_info=feature_info, out_indices=output_indices + ) + # Determine the model's downsampling pattern and set hierarchy flags - reduction_scales = list(tmp_model.feature_info.reduction()) - output_stride = reduction_scales[0] + reduction_scales = list(feature_info_obj.reduction()) - # Need model to output ViT style features with no downsampling - if len(set(reduction_scales)) != 1: + allow_downsampling = kwargs.pop("allow_downsampling", True) + allow_output_stride_not_power_of_two = kwargs.pop( + "allow_output_stride_not_power_of_two", True + ) + # Raise an error if downsampling is not allowed and encoder outputs have progressive downsampling + if len(set(reduction_scales)) > 1 and not allow_downsampling: raise ValueError("Unsupported model downsampling pattern.") - - num_blocks = len(tmp_model.blocks) - if out_indices is None: - out_indices = [int(index * (num_blocks / 4)) - 1 for index in range(1,depth+1)] - # Model with 24 blocks should use features from layers [5,12,18,24] - if num_blocks == 24: - out_indices[0] -= 1 + self._output_stride = reduction_scales[0] + if ( + int(self._output_stride).bit_count() != 1 + and not allow_output_stride_not_power_of_two + ): + raise ValueError( + f"Models with stride which is not a power of 2 are not supported, \ + got output stride {self._output_stride}" + ) + + self.prefix_token_supported = getattr(tmp_model, "has_class_token", False) + self.num_prefix_tokens = getattr(tmp_model, "num_prefix_tokens", 0) + if self.prefix_token_supported: + common_kwargs["features_only"] = False - common_kwargs['out_indices'] = out_indices self.model = timm.create_model( - name, **_merge_kwargs_no_duplicates(common_kwargs, kwargs) - ) - - self._out_channels = self.model.feature_info.channels() + name, **_merge_kwargs_no_duplicates(common_kwargs, kwargs) + ) + + self._out_channels = feature_info_obj.channels() self._in_channels = in_channels self._depth = depth - self._output_stride = output_stride + self._embed_dim = tmp_model.embed_dim - def forward(self, x: torch.Tensor) -> list[torch.Tensor]: + def forward(self, x: torch.Tensor) -> list[list[torch.Tensor], list[torch.Tensor]]: """ Forward pass to extract multi-stage features. @@ -126,6 +161,26 @@ def forward(self, x: torch.Tensor) -> list[torch.Tensor]: Returns: list[torch.Tensor]: List of feature maps at different scales. """ + if self.prefix_token_supported: + intermediate_outputs = self.model.forward_intermediates( + x, + indices=self.out_indices, + return_prefix_tokens=True, + intermediates_only=True, + ) + features, cls_tokens = zip(*intermediate_outputs) + + # Convert NHWC to NCHW if needed + if self._is_channel_last: + features = [ + feature.permute(0, 3, 1, 2).contiguous() for feature in features + ] + + if self.num_prefix_tokens > 1: + cls_tokens = [cls_token[:, 0, :] for cls_token in cls_tokens] + + return [features, cls_tokens] + features = self.model(x) # Convert NHWC to NCHW if needed @@ -134,7 +189,19 @@ def forward(self, x: torch.Tensor) -> list[torch.Tensor]: feature.permute(0, 3, 1, 2).contiguous() for feature in features ] - return features + cls_tokens = [None] * len(features) + + return [features, cls_tokens] + + @property + def embed_dim(self) -> int: + """ + Returns the embedding dimension for the ViT encoder. + + Returns: + int: Embedding dimension. + """ + return self._embed_dim @property def out_channels(self) -> list[int]: From 5599409f35009434ec3389e60989852797cd4ab1 Mon Sep 17 00:00:00 2001 From: VedantDalimkar <f20190209@goa.bits-pilani.ac.in> Date: Sun, 2 Mar 2025 13:28:25 +0530 Subject: [PATCH 03/44] Removed redudant documentation --- .../encoders/timm_vit.py | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/segmentation_models_pytorch/encoders/timm_vit.py b/segmentation_models_pytorch/encoders/timm_vit.py index 46903dde..02b7f2e5 100644 --- a/segmentation_models_pytorch/encoders/timm_vit.py +++ b/segmentation_models_pytorch/encoders/timm_vit.py @@ -1,31 +1,3 @@ -""" -TimmUniversalEncoder provides a unified feature extraction interface built on the -`timm` library, supporting both traditional-style (e.g., ResNet) and transformer-style -models (e.g., Swin Transformer, ConvNeXt). - -This encoder produces consistent multi-level feature maps for semantic segmentation tasks. -It allows configuring the number of feature extraction stages (`depth`) and adjusting -`output_stride` when supported. - -Key Features: -- Flexible model selection using `timm.create_model`. -- Unified multi-level output across different model hierarchies. -- Automatic alignment for inconsistent feature scales: - - Transformer-style models (start at 1/4 scale): Insert dummy features for 1/2 scale. - - VGG-style models (include scale-1 features): Align outputs for compatibility. -- Easy access to feature scale information via the `reduction` property. - -Feature Scale Differences: -- Traditional-style models (e.g., ResNet): Scales at 1/2, 1/4, 1/8, 1/16, 1/32. -- Transformer-style models (e.g., Swin Transformer): Start at 1/4 scale, skip 1/2 scale. -- VGG-style models: Include scale-1 features (input resolution). - -Notes: -- `output_stride` is unsupported in some models, especially transformer-based architectures. -- Special handling for models like TResNet and DLA to ensure correct feature indexing. -- VGG-style models use `_is_vgg_style` to align scale-1 features with standard outputs. -""" - from typing import Any, Optional import timm From c47bdfb408625fb03fb62d1537f0f80975a9677e Mon Sep 17 00:00:00 2001 From: VedantDalimkar <f20190209@goa.bits-pilani.ac.in> Date: Wed, 5 Mar 2025 19:44:25 +0530 Subject: [PATCH 04/44] Added intitial test and some minor code modifications --- segmentation_models_pytorch/__init__.py | 3 + .../encoders/__init__.py | 1 + .../encoders/timm_vit.py | 14 +- tests/encoders/test_timm_vit_encoders.py | 296 ++++++++++++++++++ tests/models/test_dpt.py | 274 ++++++++++++++++ 5 files changed, 585 insertions(+), 3 deletions(-) create mode 100644 tests/encoders/test_timm_vit_encoders.py create mode 100644 tests/models/test_dpt.py diff --git a/segmentation_models_pytorch/__init__.py b/segmentation_models_pytorch/__init__.py index 8a1e17fe..7b6dbd65 100644 --- a/segmentation_models_pytorch/__init__.py +++ b/segmentation_models_pytorch/__init__.py @@ -14,6 +14,7 @@ from .decoders.pan import PAN from .decoders.upernet import UPerNet from .decoders.segformer import Segformer +from .decoders.dpt import DPT from .base.hub_mixin import from_pretrained from .__version__ import __version__ @@ -34,6 +35,7 @@ PAN, UPerNet, Segformer, + DPT ] MODEL_ARCHITECTURES_MAPPING = {a.__name__.lower(): a for a in _MODEL_ARCHITECTURES} @@ -84,6 +86,7 @@ def create_model( "PAN", "UPerNet", "Segformer", + "DPT", "from_pretrained", "create_model", "__version__", diff --git a/segmentation_models_pytorch/encoders/__init__.py b/segmentation_models_pytorch/encoders/__init__.py index 8ffb91f4..d1b68953 100644 --- a/segmentation_models_pytorch/encoders/__init__.py +++ b/segmentation_models_pytorch/encoders/__init__.py @@ -92,6 +92,7 @@ def get_encoder(name, in_channels=3, depth=5, weights=None, output_stride=32, ** in_channels=in_channels, depth=depth, pretrained=weights is not None, + output_stride = output_stride, **kwargs, ) return encoder diff --git a/segmentation_models_pytorch/encoders/timm_vit.py b/segmentation_models_pytorch/encoders/timm_vit.py index 02b7f2e5..e1d8fb0c 100644 --- a/segmentation_models_pytorch/encoders/timm_vit.py +++ b/segmentation_models_pytorch/encoders/timm_vit.py @@ -11,9 +11,8 @@ class TimmViTEncoder(nn.Module): ViT style models Features: - - Supports configurable depth and output stride. - - Ensures consistent multi-level feature extraction across diverse models. - - Compatible with convolutional and transformer-like backbones. + - Supports configurable depth. + - Ensures consistent multi-level feature extraction across all ViT models. """ _is_torch_scriptable = True @@ -50,6 +49,12 @@ def __init__( super().__init__() self.name = name + output_stride = kwargs.pop("output_stride",None) + if output_stride is not None: + raise ValueError( + "Dilated mode not supported, set output stride to None" + ) + # Default model configuration for feature extraction common_kwargs = dict( in_chans=in_channels, @@ -82,6 +87,9 @@ def __init__( int((model_num_blocks / 4) * index) - 1 for index in range(1, depth + 1) ] + if isinstance(output_indices,int): + output_indices = list(output_indices) + common_kwargs["out_indices"] = self.out_indices = output_indices feature_info_obj = timm.models.FeatureInfo( feature_info=feature_info, out_indices=output_indices diff --git a/tests/encoders/test_timm_vit_encoders.py b/tests/encoders/test_timm_vit_encoders.py new file mode 100644 index 00000000..6b7db8e5 --- /dev/null +++ b/tests/encoders/test_timm_vit_encoders.py @@ -0,0 +1,296 @@ +from tests.encoders import base +import timm +import torch +import segmentation_models_pytorch as smp +import pytest + +from tests.utils import ( + default_device, + check_run_test_on_diff_or_main, + requires_torch_greater_or_equal, +) + +timm_vit_encoders = ["tu-vit_tiny_patch16_224", + "tu-vit_small_patch32_224", + "tu-vit_base_patch32_384", + "tu-vit_base_patch32_siglip_256", + ] + +class TestTimmViTEncoders(base.BaseEncoderTester): + encoder_names = timm_vit_encoders + tiny_encoder_patch_size = 224 + + files_for_diff = ["encoders/dpt.py"] + + num_output_features = 4 + default_depth = 4 + output_strides = None + supports_dilated = False + + depth_to_test = [2,3,4] + + default_encoder_kwargs = {"use_vit_encoder" : True} + + def _get_model_expected_input_shape(self,encoder_name : str) -> int: + patch_size_str = encoder_name[ -3 : ] + return int(patch_size_str) + + def get_tiny_encoder(self): + return smp.encoders.get_encoder(self.encoder_names[0], encoder_weights=None,output_stride = None,**self.default_encoder_kwargs) + + def test_forward_backward(self): + for encoder_name in self.encoder_names: + patch_size = self._get_model_expected_input_shape(encoder_name) + sample = self._get_sample(height = patch_size, width = patch_size).to(default_device) + with self.subTest(encoder_name=encoder_name): + # init encoder + encoder = smp.encoders.get_encoder( + encoder_name, in_channels=3, encoder_weights=None,depth = self.default_depth,output_stride = None,**self.default_encoder_kwargs, + + ).to(default_device) + + # forward + features = encoder.forward(sample) + self.assertEqual( + len(features[0]), + self.num_output_features, + f"Encoder `{encoder_name}` should have {self.num_output_features} output feature maps, but has {len(features)}", + ) + + # backward + features[0][-1].mean().backward() + + def test_in_channels(self): + cases = [ + (encoder_name, in_channels) + for encoder_name in self.encoder_names + for in_channels in self.in_channels_to_test + ] + + for encoder_name, in_channels in cases: + patch_size = self._get_model_expected_input_shape(encoder_name) + sample = self._get_sample(height = patch_size, width = patch_size,num_channels=in_channels).to(default_device) + + with self.subTest(encoder_name=encoder_name, in_channels=in_channels): + encoder = smp.encoders.get_encoder( + encoder_name, in_channels=in_channels, encoder_weights=None,depth =4,output_stride = None,**self.default_encoder_kwargs + ).to(default_device) + encoder.eval() + + # forward + with torch.inference_mode(): + encoder.forward(sample) + + def test_depth(self): + cases = [ + (encoder_name, depth) + for encoder_name in self.encoder_names + for depth in self.depth_to_test + ] + + for encoder_name, depth in cases: + patch_size = self._get_model_expected_input_shape(encoder_name) + sample = self._get_sample(height = patch_size, width = patch_size).to(default_device) + with self.subTest(encoder_name=encoder_name, depth=depth): + encoder = smp.encoders.get_encoder( + encoder_name, + in_channels=self.default_num_channels, + encoder_weights=None, + depth=depth, + output_stride = None, + **self.default_encoder_kwargs + ).to(default_device) + encoder.eval() + + # forward + with torch.inference_mode(): + features = encoder.forward(sample) + + # check number of features + self.assertEqual( + len(features[0]), + depth, + f"Encoder `{encoder_name}` should have {depth} output feature maps, but has {len(features[0])}", + ) + + # check feature strides + height_strides, width_strides = self.get_features_output_strides( + sample, features[0] + ) + + timm_encoder_name = encoder_name[3 : ] + encoder_out_indices = encoder.out_indices + timm_model_feature_info = timm.create_model(model_name = timm_encoder_name).feature_info + feature_info_obj = timm.models.FeatureInfo(feature_info = timm_model_feature_info,out_indices = encoder_out_indices) + self.output_strides = feature_info_obj.reduction() + + self.assertEqual( + height_strides, + self.output_strides[: depth], + f"Encoder `{encoder_name}` should have output strides {self.output_strides[: depth]}, but has {height_strides}", + ) + self.assertEqual( + width_strides, + self.output_strides[: depth], + f"Encoder `{encoder_name}` should have output strides {self.output_strides[: depth]}, but has {width_strides}", + ) + + # check encoder output stride property + self.assertEqual( + encoder.output_stride, + self.output_strides[depth - 1], + f"Encoder `{encoder_name}` last feature map should have output stride {self.output_strides[depth - 1]}, but has {encoder.output_stride}", + ) + + # check out channels also have proper length + self.assertEqual( + len(encoder.out_channels), + depth, + f"Encoder `{encoder_name}` should have {depth} out_channels, but has {len(encoder.out_channels)}", + ) + + def test_invalid_depth(self): + with self.assertRaises(ValueError): + smp.encoders.get_encoder(self.encoder_names[0], depth=5,output_stride = None) + with self.assertRaises(ValueError): + smp.encoders.get_encoder(self.encoder_names[0], depth=0,output_stride = None) + + def test_dilated(self): + + + cases = [ + (encoder_name, stride) + for encoder_name in self.encoder_names + for stride in self.strides_to_test + ] + + # special case for encoders that do not support dilated model + # just check proper error is raised + if not self.supports_dilated: + with self.assertRaises(ValueError, msg="Dilated mode not supported, set output stride to None"): + encoder_name, stride = cases[0] + patch_size = self._get_model_expected_input_shape(encoder_name) + sample = self._get_sample(height = patch_size, width = patch_size).to(default_device) + encoder = smp.encoders.get_encoder( + encoder_name, + in_channels=self.default_num_channels, + encoder_weights=None, + output_stride=stride, + depth = self.default_depth, + **self.default_encoder_kwargs, + ).to(default_device) + return + + for encoder_name, stride in cases: + with self.subTest(encoder_name=encoder_name, stride=stride): + encoder = smp.encoders.get_encoder( + encoder_name, + in_channels=self.default_num_channels, + encoder_weights=None, + output_stride=stride, + depth = self.default_depth, + **self.default_encoder_kwargs, + ).to(default_device) + encoder.eval() + + # forward + with torch.inference_mode(): + features = encoder.forward(sample) + + height_strides, width_strides = self.get_features_output_strides( + sample, features[0] + ) + expected_height_strides = [min(stride, s) for s in height_strides] + expected_width_strides = [min(stride, s) for s in width_strides] + + self.assertEqual( + height_strides, + expected_height_strides, + f"Encoder `{encoder_name}` should have height output strides {expected_height_strides}, but has {height_strides}", + ) + self.assertEqual( + width_strides, + expected_width_strides, + f"Encoder `{encoder_name}` should have width output strides {expected_width_strides}, but has {width_strides}", + ) + + @pytest.mark.compile + def test_compile(self): + if not check_run_test_on_diff_or_main(self.files_for_diff): + self.skipTest("No diff and not on `main`.") + + encoder = self.get_tiny_encoder() + encoder = encoder.eval().to(default_device) + + sample = self._get_sample(height = self.tiny_encoder_patch_size, width = self.tiny_encoder_patch_size).to(default_device) + + torch.compiler.reset() + compiled_encoder = torch.compile( + encoder, fullgraph=True, dynamic=True, backend="eager" + ) + + if encoder._is_torch_compilable: + compiled_encoder(sample) + else: + with self.assertRaises(Exception): + compiled_encoder(sample) + + @pytest.mark.torch_export + @requires_torch_greater_or_equal("2.4.0") + def test_torch_export(self): + if not check_run_test_on_diff_or_main(self.files_for_diff): + self.skipTest("No diff and not on `main`.") + + sample = self._get_sample(height = self.tiny_encoder_patch_size, width = self.tiny_encoder_patch_size).to(default_device) + + encoder = self.get_tiny_encoder() + encoder = encoder.eval().to(default_device) + + if not encoder._is_torch_exportable: + with self.assertRaises(Exception): + exported_encoder = torch.export.export( + encoder, + args=(sample,), + strict=True, + ) + return + + exported_encoder = torch.export.export( + encoder, + args=(sample,), + strict=True, + ) + + with torch.inference_mode(): + eager_output = encoder(sample) + exported_output = exported_encoder.module().forward(sample) + + for eager_feature, exported_feature in zip(eager_output, exported_output): + torch.testing.assert_close(eager_feature, exported_feature) + + @pytest.mark.torch_script + def test_torch_script(self): + sample = self._get_sample(height = self.tiny_encoder_patch_size, width = self.tiny_encoder_patch_size).to(default_device) + + encoder = self.get_tiny_encoder() + encoder = encoder.eval().to(default_device) + + if not encoder._is_torch_scriptable: + with self.assertRaises(RuntimeError, msg="not torch scriptable"): + scripted_encoder = torch.jit.script(encoder) + return + + scripted_encoder = torch.jit.script(encoder) + + with torch.inference_mode(): + eager_output = encoder(sample) + scripted_output = scripted_encoder(sample) + + for eager_feature, scripted_feature in zip(eager_output, scripted_output): + torch.testing.assert_close(eager_feature, scripted_feature) + + + + + + \ No newline at end of file diff --git a/tests/models/test_dpt.py b/tests/models/test_dpt.py new file mode 100644 index 00000000..6fcd2891 --- /dev/null +++ b/tests/models/test_dpt.py @@ -0,0 +1,274 @@ +import os +import pytest +import inspect +import tempfile +import unittest +from functools import lru_cache +from huggingface_hub import hf_hub_download +import torch +import segmentation_models_pytorch as smp + +from tests.models import base +from tests.utils import ( + has_timm_test_models, + default_device, + slow_test, + requires_torch_greater_or_equal, + check_run_test_on_diff_or_main, +) + + +class TestDPTModel(base.BaseModelTester): + test_encoder_name = ( + "tu-vit_tiny_patch16_224" + ) + files_for_diff = [r"decoders/dpt/", r"base/"] + + default_height = 224 + default_width = 224 + + # should be overriden + test_model_type = "dpt" + + @property + def hub_checkpoint(self): + return f"smp-test-models/{self.model_type}-tu-resnet18" + + @property + def model_class(self): + return smp.MODEL_ARCHITECTURES_MAPPING[self.model_type] + + @property + def decoder_channels(self): + signature = inspect.signature(self.model_class) + # check if decoder_channels is in the signature + if "decoder_channels" in signature.parameters: + return signature.parameters["decoder_channels"].default + return None + + @lru_cache + def _get_sample(self, batch_size=None, num_channels=None, height=None, width=None): + batch_size = batch_size or self.default_batch_size + num_channels = num_channels or self.default_num_channels + height = height or self.default_height + width = width or self.default_width + return torch.rand(batch_size, num_channels, height, width) + + @lru_cache + def get_default_model(self): + model = smp.create_model(self.model_type, self.test_encoder_name, output_stride = None) + model = model.to(default_device) + return model + + def test_forward_backward(self): + sample = self._get_sample().to(default_device) + + model = self.get_default_model() + + # check default in_channels=3 + output = model(sample) + + # check default output number of classes = 1 + expected_number_of_classes = 1 + result_number_of_classes = output.shape[1] + self.assertEqual( + result_number_of_classes, + expected_number_of_classes, + f"Default output number of classes should be {expected_number_of_classes}, but got {result_number_of_classes}", + ) + + # check backward pass + output.mean().backward() + + def test_in_channels_and_depth_and_out_classes( + self, in_channels=1, depth=3, classes=7 + ): + kwargs = {"output_stride" : None, + } + + model = ( + smp.create_model( + arch=self.model_type, + encoder_name=self.test_encoder_name, + encoder_depth=depth, + in_channels=in_channels, + classes=classes, + **kwargs, + ) + .to(default_device) + .eval() + ) + + sample = self._get_sample(num_channels=in_channels).to(default_device) + + # check in channels correctly set + with torch.inference_mode(): + output = model(sample) + + self.assertEqual(output.shape[1], classes) + + def test_classification_head(self): + model = smp.create_model( + arch=self.model_type, + encoder_name=self.test_encoder_name, + aux_params={ + "pooling": "avg", + "classes": 10, + "dropout": 0.5, + "activation": "sigmoid", + }, + ) + model = model.to(default_device).eval() + + self.assertIsNotNone(model.classification_head) + self.assertIsInstance(model.classification_head[0], torch.nn.AdaptiveAvgPool2d) + self.assertIsInstance(model.classification_head[1], torch.nn.Flatten) + self.assertIsInstance(model.classification_head[2], torch.nn.Dropout) + self.assertEqual(model.classification_head[2].p, 0.5) + self.assertIsInstance(model.classification_head[3], torch.nn.Linear) + self.assertIsInstance(model.classification_head[4].activation, torch.nn.Sigmoid) + + sample = self._get_sample().to(default_device) + + with torch.inference_mode(): + _, cls_probs = model(sample) + + self.assertEqual(cls_probs.shape[1], 10) + + def test_any_resolution(self): + model = self.get_default_model() + + sample = self._get_sample( + height=self.default_height + 3, + width=self.default_width + 7, + ).to(default_device) + + if model.requires_divisible_input_shape: + with self.assertRaises(RuntimeError, msg="Wrong input shape"): + output = model(sample) + return + + with torch.inference_mode(): + output = model(sample) + + self.assertEqual(output.shape[2], self.default_height + 3) + self.assertEqual(output.shape[3], self.default_width + 7) + + @requires_torch_greater_or_equal("2.0.1") + def test_save_load_with_hub_mixin(self): + # instantiate model + model = self.get_default_model() + model.eval() + + # save model + with tempfile.TemporaryDirectory() as tmpdir: + model.save_pretrained( + tmpdir, dataset="test_dataset", metrics={"my_awesome_metric": 0.99} + ) + restored_model = smp.from_pretrained(tmpdir).to(default_device) + restored_model.eval() + + with open(os.path.join(tmpdir, "README.md"), "r") as f: + readme = f.read() + + # check inference is correct + sample = self._get_sample().to(default_device) + + with torch.inference_mode(): + output = model(sample) + restored_output = restored_model(sample) + + self.assertEqual(output.shape, restored_output.shape) + self.assertEqual(output.shape[1], 1) + + # check dataset and metrics are saved in readme + self.assertIn("test_dataset", readme) + self.assertIn("my_awesome_metric", readme) + + @slow_test + @requires_torch_greater_or_equal("2.0.1") + @pytest.mark.logits_match + def test_preserve_forward_output(self): + model = smp.from_pretrained(self.hub_checkpoint).eval().to(default_device) + + input_tensor_path = hf_hub_download( + repo_id=self.hub_checkpoint, filename="input-tensor.pth" + ) + output_tensor_path = hf_hub_download( + repo_id=self.hub_checkpoint, filename="output-tensor.pth" + ) + + input_tensor = torch.load(input_tensor_path, weights_only=True) + input_tensor = input_tensor.to(default_device) + output_tensor = torch.load(output_tensor_path, weights_only=True) + output_tensor = output_tensor.to(default_device) + + with torch.inference_mode(): + output = model(input_tensor) + + self.assertEqual(output.shape, output_tensor.shape) + is_close = torch.allclose(output, output_tensor, atol=5e-2) + max_diff = torch.max(torch.abs(output - output_tensor)) + self.assertTrue(is_close, f"Max diff: {max_diff}") + + @pytest.mark.compile + def test_compile(self): + if not check_run_test_on_diff_or_main(self.files_for_diff): + self.skipTest("No diff and not on `main`.") + + sample = self._get_sample().to(default_device) + model = self.get_default_model() + model = model.eval().to(default_device) + + torch.compiler.reset() + compiled_model = torch.compile( + model, fullgraph=True, dynamic=True, backend="eager" + ) + + with torch.inference_mode(): + compiled_model(sample) + + @pytest.mark.torch_export + def test_torch_export(self): + if not check_run_test_on_diff_or_main(self.files_for_diff): + self.skipTest("No diff and not on `main`.") + + sample = self._get_sample().to(default_device) + model = self.get_default_model() + model.eval() + + exported_model = torch.export.export( + model, + args=(sample,), + strict=True, + ) + + with torch.inference_mode(): + eager_output = model(sample) + exported_output = exported_model.module().forward(sample) + + self.assertEqual(eager_output.shape, exported_output.shape) + torch.testing.assert_close(eager_output, exported_output) + + @pytest.mark.torch_script + def test_torch_script(self): + if not check_run_test_on_diff_or_main(self.files_for_diff): + self.skipTest("No diff and not on `main`.") + + sample = self._get_sample().to(default_device) + model = self.get_default_model() + model.eval() + + if not model._is_torch_scriptable: + with self.assertRaises(RuntimeError): + scripted_model = torch.jit.script(model) + return + + scripted_model = torch.jit.script(model) + + with torch.inference_mode(): + scripted_output = scripted_model(sample) + eager_output = model(sample) + + self.assertEqual(scripted_output.shape, eager_output.shape) + torch.testing.assert_close(scripted_output, eager_output) From 71e2acb2809b8ebf00c807d29fc733947cfbdfc8 Mon Sep 17 00:00:00 2001 From: VedantDalimkar <f20190209@goa.bits-pilani.ac.in> Date: Sat, 8 Mar 2025 13:26:51 +0530 Subject: [PATCH 05/44] Code refactor --- segmentation_models_pytorch/__init__.py | 2 +- .../decoders/dpt/decoder.py | 9 +- .../decoders/dpt/model.py | 42 ++++- .../encoders/__init__.py | 2 +- .../encoders/timm_vit.py | 91 ++++----- tests/encoders/test_timm_vit_encoders.py | 173 ++++++++++++------ tests/models/test_dpt.py | 32 ++-- tests/utils.py | 9 + 8 files changed, 233 insertions(+), 127 deletions(-) diff --git a/segmentation_models_pytorch/__init__.py b/segmentation_models_pytorch/__init__.py index 7b6dbd65..37c64ef6 100644 --- a/segmentation_models_pytorch/__init__.py +++ b/segmentation_models_pytorch/__init__.py @@ -35,7 +35,7 @@ PAN, UPerNet, Segformer, - DPT + DPT, ] MODEL_ARCHITECTURES_MAPPING = {a.__name__.lower(): a for a in _MODEL_ARCHITECTURES} diff --git a/segmentation_models_pytorch/decoders/dpt/decoder.py b/segmentation_models_pytorch/decoders/dpt/decoder.py index 2a0308a9..61f436ca 100644 --- a/segmentation_models_pytorch/decoders/dpt/decoder.py +++ b/segmentation_models_pytorch/decoders/dpt/decoder.py @@ -196,16 +196,16 @@ def __init__( encoder_output_stride: int, feature_dim: int = 256, encoder_depth: int = 4, - prefix_token_supported: bool = False, + cls_token_supported: bool = False, ): super().__init__() - self.prefix_token_supported = prefix_token_supported + self.cls_token_supported = cls_token_supported # If encoder has cls token, then concatenate it with the features along the embedding dimension and project it # back to the feature_dim dimension. Else, ignore the non-existent cls token - if prefix_token_supported: + if cls_token_supported: self.readout_blocks = nn.ModuleList( [ ProjectionReadout( @@ -246,9 +246,8 @@ def __init__( ) def forward( - self, encoder_output: list[list[torch.Tensor], list[torch.Tensor]] + self, features: list[torch.Tensor], cls_tokens: list[torch.Tensor] ) -> torch.Tensor: - features, cls_tokens = encoder_output processed_features = [] # Process the encoder features to scale of [1/32,1/16,1/8,1/4] diff --git a/segmentation_models_pytorch/decoders/dpt/model.py b/segmentation_models_pytorch/decoders/dpt/model.py index b5410188..f4e23b53 100644 --- a/segmentation_models_pytorch/decoders/dpt/model.py +++ b/segmentation_models_pytorch/decoders/dpt/model.py @@ -1,4 +1,5 @@ from typing import Any, Optional, Union, Callable +import torch from segmentation_models_pytorch.base import ( ClassificationHead, @@ -6,6 +7,7 @@ SegmentationModel, ) from segmentation_models_pytorch.encoders import get_encoder +from segmentation_models_pytorch.base.utils import is_torch_compiling from segmentation_models_pytorch.base.hub_mixin import supports_config_loading from .decoder import DPTDecoder @@ -46,8 +48,8 @@ class DPT(SegmentationModel): (could be **None** to return logits) kwargs: Arguments passed to the encoder class ``__init__()`` function. Applies only to ``timm`` models. Keys with ``None`` values are pruned before passing. - allow_downsampling : Allow ViT encoder to have progressive downsampling. Set to False for DPT as the architecture - requires all encoder feature outputs to have the same spatial shape. + allow_downsampling : Allow ViT encoder to have progressive spatial downsampling for it's representations. + Set to False for DPT as the architecture requires all encoder feature outputs to have the same spatial shape. allow_output_stride_not_power_of_two : Allow ViT encoders with output_stride not being a power of 2. This is set False for DPT as the architecture requires the encoder output features to have an output stride of [1/32,1/16,1/8,1/4] @@ -58,6 +60,10 @@ class DPT(SegmentationModel): """ + _is_torch_scriptable = False + _is_torch_compilable = False + requires_divisible_input_shape = True + @supports_config_loading def __init__( self, @@ -84,17 +90,17 @@ def __init__( **kwargs, ) - transformer_embed_dim = self.encoder.embed_dim - encoder_output_stride = self.encoder.output_stride - cls_token_supported = self.encoder.prefix_token_supported + self.transformer_embed_dim = self.encoder.embed_dim + self.encoder_output_stride = self.encoder.output_stride + self.cls_token_supported = self.encoder.cls_token_supported self.decoder = DPTDecoder( encoder_name=encoder_name, - transformer_embed_dim=transformer_embed_dim, + transformer_embed_dim=self.transformer_embed_dim, feature_dim=feature_dim, encoder_depth=encoder_depth, - encoder_output_stride=encoder_output_stride, - prefix_token_supported=cls_token_supported, + encoder_output_stride=self.encoder_output_stride, + cls_token_supported=self.cls_token_supported, ) self.segmentation_head = SegmentationHead( @@ -114,3 +120,23 @@ def __init__( self.name = "dpt-{}".format(encoder_name) self.initialize() + + def forward(self, x): + """Sequentially pass `x` trough model`s encoder, decoder and heads""" + + if not ( + torch.jit.is_scripting() or torch.jit.is_tracing() or is_torch_compiling() + ): + self.check_input_shape(x) + + features, cls_tokens = self.encoder(x) + + decoder_output = self.decoder(features, cls_tokens) + + masks = self.segmentation_head(decoder_output) + + if self.classification_head is not None: + labels = self.classification_head(features[-1]) + return masks, labels + + return masks diff --git a/segmentation_models_pytorch/encoders/__init__.py b/segmentation_models_pytorch/encoders/__init__.py index d1b68953..3a912aa9 100644 --- a/segmentation_models_pytorch/encoders/__init__.py +++ b/segmentation_models_pytorch/encoders/__init__.py @@ -92,7 +92,7 @@ def get_encoder(name, in_channels=3, depth=5, weights=None, output_stride=32, ** in_channels=in_channels, depth=depth, pretrained=weights is not None, - output_stride = output_stride, + output_stride=output_stride, **kwargs, ) return encoder diff --git a/segmentation_models_pytorch/encoders/timm_vit.py b/segmentation_models_pytorch/encoders/timm_vit.py index e1d8fb0c..daeb235a 100644 --- a/segmentation_models_pytorch/encoders/timm_vit.py +++ b/segmentation_models_pytorch/encoders/timm_vit.py @@ -1,4 +1,4 @@ -from typing import Any, Optional +from typing import Any, Optional, Union import timm import torch @@ -15,9 +15,9 @@ class TimmViTEncoder(nn.Module): - Ensures consistent multi-level feature extraction across all ViT models. """ - _is_torch_scriptable = True + _is_torch_scriptable = False _is_torch_exportable = True - _is_torch_compilable = True + _is_torch_compilable = False def __init__( self, @@ -25,7 +25,7 @@ def __init__( pretrained: bool = True, in_channels: int = 3, depth: int = 4, - output_indices: Optional[list[int] | int] = None, + output_indices: Optional[Union[list[int], int]] = None, **kwargs: dict[str, Any], ): """ @@ -49,16 +49,14 @@ def __init__( super().__init__() self.name = name - output_stride = kwargs.pop("output_stride",None) + output_stride = kwargs.pop("output_stride", None) if output_stride is not None: - raise ValueError( - "Dilated mode not supported, set output stride to None" - ) + raise ValueError("Dilated mode not supported, set output stride to None") # Default model configuration for feature extraction common_kwargs = dict( in_chans=in_channels, - features_only=True, + features_only=False, pretrained=pretrained, out_indices=tuple(range(depth)), ) @@ -76,6 +74,23 @@ def __init__( feature_info = tmp_model.feature_info model_num_blocks = len(feature_info) + if output_indices is not None: + if isinstance(output_indices, int): + output_indices = list(output_indices) + + for output_index in output_indices: + if output_indices < 0 or output_indices > model_num_blocks: + raise ValueError( + f"Output indices for feature extraction should be greater than 0 and less \ + than the number of blocks in the model ({model_num_blocks}), got {output_index}" + ) + + if len(output_indices) != depth: + raise ValueError( + f"Length of output indices for feature extraction should be equal to the depth of the encoder\ + architecture, got output indices length - {len(output_indices)}, encoder depth - {depth}" + ) + if depth > model_num_blocks: raise ValueError( f"Depth of the encoder cannot exceed the number of blocks in the model \ @@ -87,9 +102,6 @@ def __init__( int((model_num_blocks / 4) * index) - 1 for index in range(1, depth + 1) ] - if isinstance(output_indices,int): - output_indices = list(output_indices) - common_kwargs["out_indices"] = self.out_indices = output_indices feature_info_obj = timm.models.FeatureInfo( feature_info=feature_info, out_indices=output_indices @@ -109,7 +121,7 @@ def __init__( self._output_stride = reduction_scales[0] if ( - int(self._output_stride).bit_count() != 1 + bin(self._output_stride).count("1") != 1 and not allow_output_stride_not_power_of_two ): raise ValueError( @@ -117,10 +129,8 @@ def __init__( got output stride {self._output_stride}" ) - self.prefix_token_supported = getattr(tmp_model, "has_class_token", False) + self.cls_token_supported = getattr(tmp_model, "has_class_token", False) self.num_prefix_tokens = getattr(tmp_model, "num_prefix_tokens", 0) - if self.prefix_token_supported: - common_kwargs["features_only"] = False self.model = timm.create_model( name, **_merge_kwargs_no_duplicates(common_kwargs, kwargs) @@ -131,7 +141,7 @@ def __init__( self._depth = depth self._embed_dim = tmp_model.embed_dim - def forward(self, x: torch.Tensor) -> list[list[torch.Tensor], list[torch.Tensor]]: + def forward(self, x: torch.Tensor) -> tuple[list[torch.Tensor], list[torch.Tensor]]: """ Forward pass to extract multi-stage features. @@ -139,39 +149,32 @@ def forward(self, x: torch.Tensor) -> list[list[torch.Tensor], list[torch.Tensor x (torch.Tensor): Input tensor of shape (B, C, H, W). Returns: - list[torch.Tensor]: List of feature maps at different scales. + tuple[list[torch.Tensor], list[torch.Tensor]]: Tuple of feature maps and cls tokens (if supported) at different scales. """ - if self.prefix_token_supported: - intermediate_outputs = self.model.forward_intermediates( - x, - indices=self.out_indices, - return_prefix_tokens=True, - intermediates_only=True, - ) - features, cls_tokens = zip(*intermediate_outputs) - - # Convert NHWC to NCHW if needed - if self._is_channel_last: - features = [ - feature.permute(0, 3, 1, 2).contiguous() for feature in features - ] - - if self.num_prefix_tokens > 1: - cls_tokens = [cls_token[:, 0, :] for cls_token in cls_tokens] + intermediate_outputs = self.model.forward_intermediates( + x, + indices=self.out_indices, + return_prefix_tokens=True, + intermediates_only=True, + ) - return [features, cls_tokens] + cls_tokens = [None] * len(self.out_indices) - features = self.model(x) + if self.num_prefix_tokens > 0: + features, prefix_tokens = zip(*intermediate_outputs) + if self.cls_token_supported: + if self.num_prefix_tokens == 1: + cls_tokens = prefix_tokens - # Convert NHWC to NCHW if needed - if self._is_channel_last: - features = [ - feature.permute(0, 3, 1, 2).contiguous() for feature in features - ] + elif self.num_prefix_tokens > 1: + cls_tokens = [ + prefix_token[:, 0, :] for prefix_token in prefix_tokens + ] - cls_tokens = [None] * len(features) + else: + features = intermediate_outputs - return [features, cls_tokens] + return features, cls_tokens @property def embed_dim(self) -> int: diff --git a/tests/encoders/test_timm_vit_encoders.py b/tests/encoders/test_timm_vit_encoders.py index 6b7db8e5..cc7ef200 100644 --- a/tests/encoders/test_timm_vit_encoders.py +++ b/tests/encoders/test_timm_vit_encoders.py @@ -8,13 +8,19 @@ default_device, check_run_test_on_diff_or_main, requires_torch_greater_or_equal, + requires_timm_greater_or_equal, ) -timm_vit_encoders = ["tu-vit_tiny_patch16_224", - "tu-vit_small_patch32_224", - "tu-vit_base_patch32_384", - "tu-vit_base_patch32_siglip_256", - ] +timm_vit_encoders = [ + "tu-vit_tiny_patch16_224", + "tu-vit_small_patch32_224", + "tu-vit_base_patch32_384", + "tu-vit_base_patch16_gap_224", + "tu-vit_medium_patch16_reg4_gap_256", + "tu-vit_so150m2_patch16_reg1_gap_256", + "tu-vit_medium_patch16_gap_240", +] + class TestTimmViTEncoders(base.BaseEncoderTester): encoder_names = timm_vit_encoders @@ -27,39 +33,53 @@ class TestTimmViTEncoders(base.BaseEncoderTester): output_strides = None supports_dilated = False - depth_to_test = [2,3,4] + depth_to_test = [2, 3, 4] - default_encoder_kwargs = {"use_vit_encoder" : True} + default_encoder_kwargs = {"use_vit_encoder": True} - def _get_model_expected_input_shape(self,encoder_name : str) -> int: - patch_size_str = encoder_name[ -3 : ] + def _get_model_expected_input_shape(self, encoder_name: str) -> int: + patch_size_str = encoder_name[-3:] return int(patch_size_str) - + def get_tiny_encoder(self): - return smp.encoders.get_encoder(self.encoder_names[0], encoder_weights=None,output_stride = None,**self.default_encoder_kwargs) - + return smp.encoders.get_encoder( + self.encoder_names[0], + encoder_weights=None, + output_stride=None, + depth=self.default_depth, + **self.default_encoder_kwargs, + ) + + @requires_timm_greater_or_equal("1.0.15") def test_forward_backward(self): for encoder_name in self.encoder_names: patch_size = self._get_model_expected_input_shape(encoder_name) - sample = self._get_sample(height = patch_size, width = patch_size).to(default_device) + sample = self._get_sample(height=patch_size, width=patch_size).to( + default_device + ) with self.subTest(encoder_name=encoder_name): # init encoder encoder = smp.encoders.get_encoder( - encoder_name, in_channels=3, encoder_weights=None,depth = self.default_depth,output_stride = None,**self.default_encoder_kwargs, - + encoder_name, + in_channels=3, + encoder_weights=None, + depth=self.default_depth, + output_stride=None, + **self.default_encoder_kwargs, ).to(default_device) # forward - features = encoder.forward(sample) + features, cls_tokens = encoder.forward(sample) self.assertEqual( - len(features[0]), + len(features), self.num_output_features, f"Encoder `{encoder_name}` should have {self.num_output_features} output feature maps, but has {len(features)}", ) # backward - features[0][-1].mean().backward() + features[-1].mean().backward() + @requires_timm_greater_or_equal("1.0.15") def test_in_channels(self): cases = [ (encoder_name, in_channels) @@ -69,11 +89,18 @@ def test_in_channels(self): for encoder_name, in_channels in cases: patch_size = self._get_model_expected_input_shape(encoder_name) - sample = self._get_sample(height = patch_size, width = patch_size,num_channels=in_channels).to(default_device) + sample = self._get_sample( + height=patch_size, width=patch_size, num_channels=in_channels + ).to(default_device) with self.subTest(encoder_name=encoder_name, in_channels=in_channels): encoder = smp.encoders.get_encoder( - encoder_name, in_channels=in_channels, encoder_weights=None,depth =4,output_stride = None,**self.default_encoder_kwargs + encoder_name, + in_channels=in_channels, + encoder_weights=None, + depth=4, + output_stride=None, + **self.default_encoder_kwargs, ).to(default_device) encoder.eval() @@ -81,6 +108,7 @@ def test_in_channels(self): with torch.inference_mode(): encoder.forward(sample) + @requires_timm_greater_or_equal("1.0.15") def test_depth(self): cases = [ (encoder_name, depth) @@ -90,49 +118,56 @@ def test_depth(self): for encoder_name, depth in cases: patch_size = self._get_model_expected_input_shape(encoder_name) - sample = self._get_sample(height = patch_size, width = patch_size).to(default_device) + sample = self._get_sample(height=patch_size, width=patch_size).to( + default_device + ) with self.subTest(encoder_name=encoder_name, depth=depth): encoder = smp.encoders.get_encoder( encoder_name, in_channels=self.default_num_channels, encoder_weights=None, depth=depth, - output_stride = None, - **self.default_encoder_kwargs + output_stride=None, + **self.default_encoder_kwargs, ).to(default_device) encoder.eval() # forward with torch.inference_mode(): - features = encoder.forward(sample) + features, cls_tokens = encoder.forward(sample) # check number of features self.assertEqual( - len(features[0]), + len(features), depth, - f"Encoder `{encoder_name}` should have {depth} output feature maps, but has {len(features[0])}", + f"Encoder `{encoder_name}` should have {depth} output feature maps, but has {len(features)}", ) # check feature strides height_strides, width_strides = self.get_features_output_strides( - sample, features[0] + sample, features ) - timm_encoder_name = encoder_name[3 : ] + timm_encoder_name = encoder_name[3:] encoder_out_indices = encoder.out_indices - timm_model_feature_info = timm.create_model(model_name = timm_encoder_name).feature_info - feature_info_obj = timm.models.FeatureInfo(feature_info = timm_model_feature_info,out_indices = encoder_out_indices) + timm_model_feature_info = timm.create_model( + model_name=timm_encoder_name + ).feature_info + feature_info_obj = timm.models.FeatureInfo( + feature_info=timm_model_feature_info, + out_indices=encoder_out_indices, + ) self.output_strides = feature_info_obj.reduction() self.assertEqual( height_strides, - self.output_strides[: depth], - f"Encoder `{encoder_name}` should have output strides {self.output_strides[: depth]}, but has {height_strides}", + self.output_strides[:depth], + f"Encoder `{encoder_name}` should have output strides {self.output_strides[:depth]}, but has {height_strides}", ) self.assertEqual( width_strides, - self.output_strides[: depth], - f"Encoder `{encoder_name}` should have output strides {self.output_strides[: depth]}, but has {width_strides}", + self.output_strides[:depth], + f"Encoder `{encoder_name}` should have output strides {self.output_strides[:depth]}, but has {width_strides}", ) # check encoder output stride property @@ -149,15 +184,40 @@ def test_depth(self): f"Encoder `{encoder_name}` should have {depth} out_channels, but has {len(encoder.out_channels)}", ) + @requires_timm_greater_or_equal("1.0.15") def test_invalid_depth(self): with self.assertRaises(ValueError): - smp.encoders.get_encoder(self.encoder_names[0], depth=5,output_stride = None) + smp.encoders.get_encoder(self.encoder_names[0], depth=5, output_stride=None) with self.assertRaises(ValueError): - smp.encoders.get_encoder(self.encoder_names[0], depth=0,output_stride = None) + smp.encoders.get_encoder(self.encoder_names[0], depth=0, output_stride=None) - def test_dilated(self): - + def test_invalid_out_indices(self): + with self.assertRaises(ValueError): + smp.encoders.get_encoder( + self.encoder_names[0], output_stride=None, out_indices=-1 + ) + with self.assertRaises(ValueError): + smp.encoders.get_encoder( + self.encoder_names[0], output_stride=None, out_indices=[1, 2, 25] + ) + + def test_invalid_out_indices_length(self): + with self.assertRaises(ValueError): + smp.encoders.get_encoder( + self.encoder_names[0], output_stride=None, out_indices=2, depth=2 + ) + + with self.assertRaises(ValueError): + smp.encoders.get_encoder( + self.encoder_names[0], + output_stride=None, + out_indices=[0, 1, 2, 3, 4], + depth=4, + ) + + @requires_timm_greater_or_equal("1.0.15") + def test_dilated(self): cases = [ (encoder_name, stride) for encoder_name in self.encoder_names @@ -167,16 +227,20 @@ def test_dilated(self): # special case for encoders that do not support dilated model # just check proper error is raised if not self.supports_dilated: - with self.assertRaises(ValueError, msg="Dilated mode not supported, set output stride to None"): + with self.assertRaises( + ValueError, msg="Dilated mode not supported, set output stride to None" + ): encoder_name, stride = cases[0] patch_size = self._get_model_expected_input_shape(encoder_name) - sample = self._get_sample(height = patch_size, width = patch_size).to(default_device) + sample = self._get_sample(height=patch_size, width=patch_size).to( + default_device + ) encoder = smp.encoders.get_encoder( encoder_name, in_channels=self.default_num_channels, encoder_weights=None, output_stride=stride, - depth = self.default_depth, + depth=self.default_depth, **self.default_encoder_kwargs, ).to(default_device) return @@ -188,17 +252,17 @@ def test_dilated(self): in_channels=self.default_num_channels, encoder_weights=None, output_stride=stride, - depth = self.default_depth, + depth=self.default_depth, **self.default_encoder_kwargs, ).to(default_device) encoder.eval() # forward with torch.inference_mode(): - features = encoder.forward(sample) + features, cls_tokens = encoder.forward(sample) height_strides, width_strides = self.get_features_output_strides( - sample, features[0] + encoder, sample, features ) expected_height_strides = [min(stride, s) for s in height_strides] expected_width_strides = [min(stride, s) for s in width_strides] @@ -214,6 +278,7 @@ def test_dilated(self): f"Encoder `{encoder_name}` should have width output strides {expected_width_strides}, but has {width_strides}", ) + @requires_timm_greater_or_equal("1.0.15") @pytest.mark.compile def test_compile(self): if not check_run_test_on_diff_or_main(self.files_for_diff): @@ -222,7 +287,9 @@ def test_compile(self): encoder = self.get_tiny_encoder() encoder = encoder.eval().to(default_device) - sample = self._get_sample(height = self.tiny_encoder_patch_size, width = self.tiny_encoder_patch_size).to(default_device) + sample = self._get_sample( + height=self.tiny_encoder_patch_size, width=self.tiny_encoder_patch_size + ).to(default_device) torch.compiler.reset() compiled_encoder = torch.compile( @@ -235,13 +302,16 @@ def test_compile(self): with self.assertRaises(Exception): compiled_encoder(sample) + @requires_timm_greater_or_equal("1.0.15") @pytest.mark.torch_export @requires_torch_greater_or_equal("2.4.0") def test_torch_export(self): if not check_run_test_on_diff_or_main(self.files_for_diff): self.skipTest("No diff and not on `main`.") - sample = self._get_sample(height = self.tiny_encoder_patch_size, width = self.tiny_encoder_patch_size).to(default_device) + sample = self._get_sample( + height=self.tiny_encoder_patch_size, width=self.tiny_encoder_patch_size + ).to(default_device) encoder = self.get_tiny_encoder() encoder = encoder.eval().to(default_device) @@ -268,9 +338,12 @@ def test_torch_export(self): for eager_feature, exported_feature in zip(eager_output, exported_output): torch.testing.assert_close(eager_feature, exported_feature) + @requires_timm_greater_or_equal("1.0.15") @pytest.mark.torch_script def test_torch_script(self): - sample = self._get_sample(height = self.tiny_encoder_patch_size, width = self.tiny_encoder_patch_size).to(default_device) + sample = self._get_sample( + height=self.tiny_encoder_patch_size, width=self.tiny_encoder_patch_size + ).to(default_device) encoder = self.get_tiny_encoder() encoder = encoder.eval().to(default_device) @@ -288,9 +361,3 @@ def test_torch_script(self): for eager_feature, scripted_feature in zip(eager_output, scripted_output): torch.testing.assert_close(eager_feature, scripted_feature) - - - - - - \ No newline at end of file diff --git a/tests/models/test_dpt.py b/tests/models/test_dpt.py index 6fcd2891..2c99cc80 100644 --- a/tests/models/test_dpt.py +++ b/tests/models/test_dpt.py @@ -2,7 +2,6 @@ import pytest import inspect import tempfile -import unittest from functools import lru_cache from huggingface_hub import hf_hub_download import torch @@ -10,18 +9,14 @@ from tests.models import base from tests.utils import ( - has_timm_test_models, default_device, - slow_test, requires_torch_greater_or_equal, check_run_test_on_diff_or_main, ) class TestDPTModel(base.BaseModelTester): - test_encoder_name = ( - "tu-vit_tiny_patch16_224" - ) + test_encoder_name = "tu-vit_tiny_patch16_224" files_for_diff = [r"decoders/dpt/", r"base/"] default_height = 224 @@ -32,7 +27,7 @@ class TestDPTModel(base.BaseModelTester): @property def hub_checkpoint(self): - return f"smp-test-models/{self.model_type}-tu-resnet18" + return f"smp-test-models/{self.model_type}-tu-vit_tiny_patch16_224" @property def model_class(self): @@ -56,7 +51,9 @@ def _get_sample(self, batch_size=None, num_channels=None, height=None, width=Non @lru_cache def get_default_model(self): - model = smp.create_model(self.model_type, self.test_encoder_name, output_stride = None) + model = smp.create_model( + self.model_type, self.test_encoder_name, output_stride=None + ) model = model.to(default_device) return model @@ -83,8 +80,9 @@ def test_forward_backward(self): def test_in_channels_and_depth_and_out_classes( self, in_channels=1, depth=3, classes=7 ): - kwargs = {"output_stride" : None, - } + kwargs = { + "output_stride": None, + } model = ( smp.create_model( @@ -111,6 +109,7 @@ def test_classification_head(self): model = smp.create_model( arch=self.model_type, encoder_name=self.test_encoder_name, + output_stride=None, aux_params={ "pooling": "avg", "classes": 10, @@ -185,7 +184,7 @@ def test_save_load_with_hub_mixin(self): self.assertIn("test_dataset", readme) self.assertIn("my_awesome_metric", readme) - @slow_test + # @slow_test @requires_torch_greater_or_equal("2.0.1") @pytest.mark.logits_match def test_preserve_forward_output(self): @@ -220,10 +219,13 @@ def test_compile(self): model = self.get_default_model() model = model.eval().to(default_device) - torch.compiler.reset() - compiled_model = torch.compile( - model, fullgraph=True, dynamic=True, backend="eager" - ) + if not model._is_torch_compilable: + with self.assertRaises(RuntimeError): + torch.compiler.reset() + compiled_model = torch.compile( + model, fullgraph=True, dynamic=True, backend="eager" + ) + return with torch.inference_mode(): compiled_model(sample) diff --git a/tests/utils.py b/tests/utils.py index 6e201f1d..02a7cada 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -28,6 +28,15 @@ def slow_test(test_case): return unittest.skipUnless(RUN_SLOW, "test is slow")(test_case) +def requires_timm_greater_or_equal(version: str): + timm_version = Version(timm.__version__) + provided_version = Version(version) + return unittest.skipUnless( + timm_version >= provided_version, + f"timm version {timm_version} is less than {provided_version}", + ) + + def requires_torch_greater_or_equal(version: str): torch_version = Version(torch.__version__) provided_version = Version(version) From e85836ddf211758819253b124fb27b95ec6cbf68 Mon Sep 17 00:00:00 2001 From: VedantDalimkar <f20190209@goa.bits-pilani.ac.in> Date: Sat, 22 Mar 2025 11:07:02 +0530 Subject: [PATCH 06/44] Added weight conversion script --- .gitignore | 6 +- .../decoders/dpt/decoder.py | 97 +++++-- .../decoders/dpt/model.py | 8 +- .../decoders/dpt/weight_conversion_script.py | 109 ++++++++ .../encoders/timm_vit.py | 45 +--- tests/models/test_dpt.py | 236 +++--------------- 6 files changed, 224 insertions(+), 277 deletions(-) create mode 100644 segmentation_models_pytorch/decoders/dpt/weight_conversion_script.py diff --git a/.gitignore b/.gitignore index 33db579f..0c53192b 100644 --- a/.gitignore +++ b/.gitignore @@ -75,6 +75,7 @@ target/ # Jupyter Notebook .ipynb_checkpoints +*ipynb* # pyenv .python-version @@ -109,4 +110,7 @@ venv.bak/ .mypy_cache/ # ruff -.ruff_cache/ \ No newline at end of file +.ruff_cache/ + +# model weight folder +dpt_large-ade20k-b12dca68 \ No newline at end of file diff --git a/segmentation_models_pytorch/decoders/dpt/decoder.py b/segmentation_models_pytorch/decoders/dpt/decoder.py index 61f436ca..821ce87f 100644 --- a/segmentation_models_pytorch/decoders/dpt/decoder.py +++ b/segmentation_models_pytorch/decoders/dpt/decoder.py @@ -1,5 +1,7 @@ import torch import torch.nn as nn +from segmentation_models_pytorch.base.modules import Activation +from typing import Optional def _get_feature_processing_out_channels(encoder_name: str) -> list[int]: @@ -71,7 +73,7 @@ def forward(self, feature: torch.Tensor, cls_token: torch.Tensor): return feature -class FeatureProcessBlock(nn.Module): +class ReassembleBlock(nn.Module): """ Processes the features such that they have progressively increasing embedding size and progressively decreasing spatial dimension @@ -107,7 +109,11 @@ def __init__( ) self.project_to_feature_dim = nn.Conv2d( - in_channels=out_channel, out_channels=feature_dim, kernel_size=3, padding=1 + in_channels=out_channel, + out_channels=feature_dim, + kernel_size=3, + padding=1, + bias=False, ) def forward(self, x: torch.Tensor): @@ -121,29 +127,34 @@ def forward(self, x: torch.Tensor): class ResidualConvBlock(nn.Module): def __init__(self, feature_dim: int): super().__init__() - self.conv_block = nn.Sequential( - nn.ReLU(), - nn.Conv2d( - in_channels=feature_dim, - out_channels=feature_dim, - kernel_size=3, - padding=1, - bias=False, - ), - nn.BatchNorm2d(num_features=feature_dim), - nn.ReLU(), - nn.Conv2d( - in_channels=feature_dim, - out_channels=feature_dim, - kernel_size=3, - padding=1, - bias=False, - ), - nn.BatchNorm2d(num_features=feature_dim), + + self.conv_1 = nn.Conv2d( + in_channels=feature_dim, + out_channels=feature_dim, + kernel_size=3, + padding=1, + bias=False, ) + self.batch_norm_1 = nn.BatchNorm2d(num_features=feature_dim) + self.conv_2 = nn.Conv2d( + in_channels=feature_dim, + out_channels=feature_dim, + kernel_size=3, + padding=1, + bias=False, + ) + self.batch_norm_2 = nn.BatchNorm2d(num_features=feature_dim) + self.activation = nn.ReLU() def forward(self, x: torch.Tensor): - return x + self.conv_block(x) + activated_x_1 = self.activation(x) + conv_1_out = self.conv_1(activated_x_1) + batch_norm_1_out = self.batch_norm_1(conv_1_out) + activated_x_2 = self.activation(batch_norm_1_out) + conv_2_out = self.conv_2(activated_x_2) + batch_norm_2_out = self.batch_norm_2(conv_2_out) + + return x + batch_norm_2_out class FusionBlock(nn.Module): @@ -172,7 +183,6 @@ def forward(self, feature: torch.Tensor, preceding_layer_feature: torch.Tensor): feature, scale_factor=2, align_corners=True, mode="bilinear" ) feature = self.project(feature) - feature = self.activation(feature) return feature @@ -230,9 +240,9 @@ def __init__( :encoder_depth ] - self.feature_processing_blocks = nn.ModuleList( + self.reassemble_blocks = nn.ModuleList( [ - FeatureProcessBlock( + ReassembleBlock( transformer_embed_dim, feature_dim, out_channel, upsample_factor ) for upsample_factor, out_channel in zip( @@ -253,7 +263,7 @@ def forward( # Process the encoder features to scale of [1/32,1/16,1/8,1/4] for index, (feature, cls_token) in enumerate(zip(features, cls_tokens)): readout_feature = self.readout_blocks[index](feature, cls_token) - processed_feature = self.feature_processing_blocks[index](readout_feature) + processed_feature = self.reassemble_blocks[index](readout_feature) processed_features.append(processed_feature) preceding_layer_feature = None @@ -265,3 +275,38 @@ def forward( preceding_layer_feature = out return out + + +class DPTSegmentationHead(nn.Module): + def __init__( + self, + in_channels: int, + out_channels: int, + activation: Optional[str] = None, + kernel_size: int = 3, + upsampling: float = 2.0, + ): + super().__init__() + + self.head = nn.Sequential( + nn.Conv2d( + in_channels, in_channels, kernel_size=kernel_size, padding=1, bias=False + ), + nn.BatchNorm2d(in_channels), + nn.ReLU(True), + nn.Dropout(0.1, False), + nn.Conv2d(in_channels, out_channels, kernel_size=1), + ) + self.activation = Activation(activation) + self.upsampling_factor = upsampling + + def forward(self, x): + head_output = self.head(x) + resized_output = nn.functional.interpolate( + head_output, + scale_factor=self.upsampling_factor, + mode="bilinear", + align_corners=True, + ) + activation_output = self.activation(resized_output) + return activation_output diff --git a/segmentation_models_pytorch/decoders/dpt/model.py b/segmentation_models_pytorch/decoders/dpt/model.py index f4e23b53..ba7693a2 100644 --- a/segmentation_models_pytorch/decoders/dpt/model.py +++ b/segmentation_models_pytorch/decoders/dpt/model.py @@ -9,7 +9,7 @@ from segmentation_models_pytorch.encoders import get_encoder from segmentation_models_pytorch.base.utils import is_torch_compiling from segmentation_models_pytorch.base.hub_mixin import supports_config_loading -from .decoder import DPTDecoder +from .decoder import DPTDecoder, DPTSegmentationHead class DPT(SegmentationModel): @@ -75,6 +75,7 @@ def __init__( classes: int = 1, activation: Optional[Union[str, Callable]] = None, aux_params: Optional[dict] = None, + output_stride: Optional[int] = None, **kwargs: dict[str, Any], ): super().__init__() @@ -86,6 +87,7 @@ def __init__( weights=encoder_weights, use_vit_encoder=True, allow_downsampling=False, + output_stride=output_stride, allow_output_stride_not_power_of_two=False, **kwargs, ) @@ -103,11 +105,11 @@ def __init__( cls_token_supported=self.cls_token_supported, ) - self.segmentation_head = SegmentationHead( + self.segmentation_head = DPTSegmentationHead( in_channels=feature_dim, out_channels=classes, activation=activation, - kernel_size=1, + kernel_size=3, upsampling=2, ) diff --git a/segmentation_models_pytorch/decoders/dpt/weight_conversion_script.py b/segmentation_models_pytorch/decoders/dpt/weight_conversion_script.py new file mode 100644 index 00000000..af63a9ae --- /dev/null +++ b/segmentation_models_pytorch/decoders/dpt/weight_conversion_script.py @@ -0,0 +1,109 @@ +import segmentation_models_pytorch as smp +import torch +import huggingface_hub + +MODEL_WEIGHTS_PATH = r"C:\Users\vedan\Downloads\dpt_large-ade20k-b12dca68.pt" +HF_HUB_PATH = "vedantdalimkar/DPT" + +if __name__ == "__main__": + smp_model = smp.DPT(encoder_name="tu-vit_large_patch16_384", classes=150) + dpt_model_dict = torch.load(MODEL_WEIGHTS_PATH) + + for layer_index in range(0, 4): + for param in [ + "running_mean", + "running_var", + "num_batches_tracked", + "weight", + "bias", + ]: + for block_index in [1, 2]: + for bn_index in [1, 2]: + # Assigning weights of 4th fusion layer of original model to 1st layer of SMP DPT model, + # Assigning weights of 3rd fusion layer of original model to 2nd layer of SMP DPT model ... + # and so on ... + + # This is because order of calling fusion layers is reversed in original DPT implementation + + dpt_model_dict[ + f"decoder.fusion_blocks.{layer_index}.residual_conv_block{block_index}.batch_norm_{bn_index}.{param}" + ] = dpt_model_dict.pop( + f"scratch.refinenet{4 - layer_index}.resConfUnit{block_index}.bn{bn_index}.{param}" + ) + + if param in ["weight", "bias"]: + if param == "weight": + for block_index in [1, 2]: + for conv_index in [1, 2]: + dpt_model_dict[ + f"decoder.fusion_blocks.{layer_index}.residual_conv_block{block_index}.conv_{conv_index}.{param}" + ] = dpt_model_dict.pop( + f"scratch.refinenet{4 - layer_index}.resConfUnit{block_index}.conv{conv_index}.{param}" + ) + + dpt_model_dict[ + f"decoder.reassemble_blocks.{layer_index}.project_to_feature_dim.{param}" + ] = dpt_model_dict.pop(f"scratch.layer{layer_index + 1}_rn.{param}") + + dpt_model_dict[ + f"decoder.fusion_blocks.{layer_index}.project.{param}" + ] = dpt_model_dict.pop( + f"scratch.refinenet{4 - layer_index}.out_conv.{param}" + ) + + dpt_model_dict[ + f"decoder.readout_blocks.{layer_index}.project.0.{param}" + ] = dpt_model_dict.pop( + f"pretrained.act_postprocess{layer_index + 1}.0.project.0.{param}" + ) + + dpt_model_dict[ + f"decoder.reassemble_blocks.{layer_index}.project_to_out_channel.{param}" + ] = dpt_model_dict.pop( + f"pretrained.act_postprocess{layer_index + 1}.3.{param}" + ) + + if layer_index != 2: + dpt_model_dict[ + f"decoder.reassemble_blocks.{layer_index}.upsample.{param}" + ] = dpt_model_dict.pop( + f"pretrained.act_postprocess{layer_index + 1}.4.{param}" + ) + + # Changing state dict keys for segmentation head + dpt_model_dict = { + ( + "segmentation_head.head" + name[len("scratch.output_conv") :] + if name.startswith("scratch.output_conv") + else name + ): parameter + for name, parameter in dpt_model_dict.items() + } + + # Changing state dict keys for encoder layers + dpt_model_dict = { + ( + "encoder.model" + name[len("pretrained.model") :] + if name.startswith("pretrained.model") + else name + ): parameter + for name, parameter in dpt_model_dict.items() + } + + # Removing keys,value pairs associated with auxiliary head + dpt_model_dict = { + name: parameter + for name, parameter in dpt_model_dict.items() + if not name.startswith("auxlayer") + } + + smp_model.load_state_dict(dpt_model_dict, strict=True) + + model_name = MODEL_WEIGHTS_PATH.split("\\")[-1].replace(".pt", "") + + smp_model.save_pretrained(model_name) + + repo_id = HF_HUB_PATH + api = huggingface_hub.HfApi() + api.create_repo(repo_id=repo_id, repo_type="model") + api.upload_folder(folder_path=model_name, repo_id=repo_id) diff --git a/segmentation_models_pytorch/encoders/timm_vit.py b/segmentation_models_pytorch/encoders/timm_vit.py index daeb235a..2dc16c01 100644 --- a/segmentation_models_pytorch/encoders/timm_vit.py +++ b/segmentation_models_pytorch/encoders/timm_vit.py @@ -4,6 +4,8 @@ import torch import torch.nn as nn +from .timm_universal import _merge_kwargs_no_duplicates + class TimmViTEncoder(nn.Module): """ @@ -26,6 +28,7 @@ def __init__( in_channels: int = 3, depth: int = 4, output_indices: Optional[Union[list[int], int]] = None, + output_stride: Optional[int] = None, **kwargs: dict[str, Any], ): """ @@ -49,7 +52,6 @@ def __init__( super().__init__() self.name = name - output_stride = kwargs.pop("output_stride", None) if output_stride is not None: raise ValueError("Dilated mode not supported, set output stride to None") @@ -160,6 +162,8 @@ def forward(self, x: torch.Tensor) -> tuple[list[torch.Tensor], list[torch.Tenso cls_tokens = [None] * len(self.out_indices) + # If there are multiple prefix tokens, discard the register tokens if they are present and + # return the CLS token, if it exists. Only patch features are retrieved if CLS token is not supported if self.num_prefix_tokens > 0: features, prefix_tokens = zip(*intermediate_outputs) if self.cls_token_supported: @@ -205,42 +209,3 @@ def output_stride(self) -> int: int: The effective output stride. """ return self._output_stride - - def load_state_dict(self, state_dict, **kwargs): - # for compatibility of weights for - # timm- ported encoders with TimmUniversalEncoder - patterns = ["regnet", "res2", "resnest", "mobilenetv3", "gernet"] - - is_deprecated_encoder = any( - self.name.startswith(pattern) for pattern in patterns - ) - - if is_deprecated_encoder: - keys = list(state_dict.keys()) - for key in keys: - new_key = key - if not key.startswith("model."): - new_key = "model." + key - if "gernet" in self.name: - new_key = new_key.replace(".stages.", ".stages_") - state_dict[new_key] = state_dict.pop(key) - - return super().load_state_dict(state_dict, **kwargs) - - -def _merge_kwargs_no_duplicates(a: dict[str, Any], b: dict[str, Any]) -> dict[str, Any]: - """ - Merge two dictionaries, ensuring no duplicate keys exist. - - Args: - a (dict): Base dictionary. - b (dict): Additional parameters to merge. - - Returns: - dict: A merged dictionary. - """ - duplicates = a.keys() & b.keys() - if duplicates: - raise ValueError(f"'{duplicates}' already specified internally") - - return a | b diff --git a/tests/models/test_dpt.py b/tests/models/test_dpt.py index 2c99cc80..33ad14f2 100644 --- a/tests/models/test_dpt.py +++ b/tests/models/test_dpt.py @@ -9,6 +9,7 @@ from tests.models import base from tests.utils import ( + slow_test, default_device, requires_torch_greater_or_equal, check_run_test_on_diff_or_main, @@ -16,199 +17,18 @@ class TestDPTModel(base.BaseModelTester): - test_encoder_name = "tu-vit_tiny_patch16_224" + test_encoder_name = "tu-vit_large_patch16_384" files_for_diff = [r"decoders/dpt/", r"base/"] - default_height = 224 - default_width = 224 + default_height = 384 + default_width = 384 # should be overriden test_model_type = "dpt" @property def hub_checkpoint(self): - return f"smp-test-models/{self.model_type}-tu-vit_tiny_patch16_224" - - @property - def model_class(self): - return smp.MODEL_ARCHITECTURES_MAPPING[self.model_type] - - @property - def decoder_channels(self): - signature = inspect.signature(self.model_class) - # check if decoder_channels is in the signature - if "decoder_channels" in signature.parameters: - return signature.parameters["decoder_channels"].default - return None - - @lru_cache - def _get_sample(self, batch_size=None, num_channels=None, height=None, width=None): - batch_size = batch_size or self.default_batch_size - num_channels = num_channels or self.default_num_channels - height = height or self.default_height - width = width or self.default_width - return torch.rand(batch_size, num_channels, height, width) - - @lru_cache - def get_default_model(self): - model = smp.create_model( - self.model_type, self.test_encoder_name, output_stride=None - ) - model = model.to(default_device) - return model - - def test_forward_backward(self): - sample = self._get_sample().to(default_device) - - model = self.get_default_model() - - # check default in_channels=3 - output = model(sample) - - # check default output number of classes = 1 - expected_number_of_classes = 1 - result_number_of_classes = output.shape[1] - self.assertEqual( - result_number_of_classes, - expected_number_of_classes, - f"Default output number of classes should be {expected_number_of_classes}, but got {result_number_of_classes}", - ) - - # check backward pass - output.mean().backward() - - def test_in_channels_and_depth_and_out_classes( - self, in_channels=1, depth=3, classes=7 - ): - kwargs = { - "output_stride": None, - } - - model = ( - smp.create_model( - arch=self.model_type, - encoder_name=self.test_encoder_name, - encoder_depth=depth, - in_channels=in_channels, - classes=classes, - **kwargs, - ) - .to(default_device) - .eval() - ) - - sample = self._get_sample(num_channels=in_channels).to(default_device) - - # check in channels correctly set - with torch.inference_mode(): - output = model(sample) - - self.assertEqual(output.shape[1], classes) - - def test_classification_head(self): - model = smp.create_model( - arch=self.model_type, - encoder_name=self.test_encoder_name, - output_stride=None, - aux_params={ - "pooling": "avg", - "classes": 10, - "dropout": 0.5, - "activation": "sigmoid", - }, - ) - model = model.to(default_device).eval() - - self.assertIsNotNone(model.classification_head) - self.assertIsInstance(model.classification_head[0], torch.nn.AdaptiveAvgPool2d) - self.assertIsInstance(model.classification_head[1], torch.nn.Flatten) - self.assertIsInstance(model.classification_head[2], torch.nn.Dropout) - self.assertEqual(model.classification_head[2].p, 0.5) - self.assertIsInstance(model.classification_head[3], torch.nn.Linear) - self.assertIsInstance(model.classification_head[4].activation, torch.nn.Sigmoid) - - sample = self._get_sample().to(default_device) - - with torch.inference_mode(): - _, cls_probs = model(sample) - - self.assertEqual(cls_probs.shape[1], 10) - - def test_any_resolution(self): - model = self.get_default_model() - - sample = self._get_sample( - height=self.default_height + 3, - width=self.default_width + 7, - ).to(default_device) - - if model.requires_divisible_input_shape: - with self.assertRaises(RuntimeError, msg="Wrong input shape"): - output = model(sample) - return - - with torch.inference_mode(): - output = model(sample) - - self.assertEqual(output.shape[2], self.default_height + 3) - self.assertEqual(output.shape[3], self.default_width + 7) - - @requires_torch_greater_or_equal("2.0.1") - def test_save_load_with_hub_mixin(self): - # instantiate model - model = self.get_default_model() - model.eval() - - # save model - with tempfile.TemporaryDirectory() as tmpdir: - model.save_pretrained( - tmpdir, dataset="test_dataset", metrics={"my_awesome_metric": 0.99} - ) - restored_model = smp.from_pretrained(tmpdir).to(default_device) - restored_model.eval() - - with open(os.path.join(tmpdir, "README.md"), "r") as f: - readme = f.read() - - # check inference is correct - sample = self._get_sample().to(default_device) - - with torch.inference_mode(): - output = model(sample) - restored_output = restored_model(sample) - - self.assertEqual(output.shape, restored_output.shape) - self.assertEqual(output.shape[1], 1) - - # check dataset and metrics are saved in readme - self.assertIn("test_dataset", readme) - self.assertIn("my_awesome_metric", readme) - - # @slow_test - @requires_torch_greater_or_equal("2.0.1") - @pytest.mark.logits_match - def test_preserve_forward_output(self): - model = smp.from_pretrained(self.hub_checkpoint).eval().to(default_device) - - input_tensor_path = hf_hub_download( - repo_id=self.hub_checkpoint, filename="input-tensor.pth" - ) - output_tensor_path = hf_hub_download( - repo_id=self.hub_checkpoint, filename="output-tensor.pth" - ) - - input_tensor = torch.load(input_tensor_path, weights_only=True) - input_tensor = input_tensor.to(default_device) - output_tensor = torch.load(output_tensor_path, weights_only=True) - output_tensor = output_tensor.to(default_device) - - with torch.inference_mode(): - output = model(input_tensor) - - self.assertEqual(output.shape, output_tensor.shape) - is_close = torch.allclose(output, output_tensor, atol=5e-2) - max_diff = torch.max(torch.abs(output - output_tensor)) - self.assertTrue(is_close, f"Max diff: {max_diff}") + return f"vedantdalimkar/DPT" @pytest.mark.compile def test_compile(self): @@ -230,28 +50,6 @@ def test_compile(self): with torch.inference_mode(): compiled_model(sample) - @pytest.mark.torch_export - def test_torch_export(self): - if not check_run_test_on_diff_or_main(self.files_for_diff): - self.skipTest("No diff and not on `main`.") - - sample = self._get_sample().to(default_device) - model = self.get_default_model() - model.eval() - - exported_model = torch.export.export( - model, - args=(sample,), - strict=True, - ) - - with torch.inference_mode(): - eager_output = model(sample) - exported_output = exported_model.module().forward(sample) - - self.assertEqual(eager_output.shape, exported_output.shape) - torch.testing.assert_close(eager_output, exported_output) - @pytest.mark.torch_script def test_torch_script(self): if not check_run_test_on_diff_or_main(self.files_for_diff): @@ -274,3 +72,27 @@ def test_torch_script(self): self.assertEqual(scripted_output.shape, eager_output.shape) torch.testing.assert_close(scripted_output, eager_output) + + @slow_test + @requires_torch_greater_or_equal("2.0.1") + @pytest.mark.logits_match + def test_preserve_forward_output(self): + model = smp.from_pretrained(self.hub_checkpoint).eval().to(default_device) + + input_tensor = torch.ones((1, 3, 384, 384)) + input_tensor = input_tensor.to(default_device) + + expected_logits_slice = torch.tensor( + [3.4166, 3.4422, 3.4677, 3.2784, 3.0880, 2.9497] + ) + with torch.inference_mode(): + output = model(input_tensor) + + resulted_logits_slice = output[0, 0, 0, 0:6].cpu() + + self.assertEqual(expected_logits_slice.shape, resulted_logits_slice.shape) + is_close = torch.allclose( + expected_logits_slice, resulted_logits_slice, atol=5e-2 + ) + max_diff = torch.max(torch.abs(expected_logits_slice - resulted_logits_slice)) + self.assertTrue(is_close, f"Max diff: {max_diff}") From 35cb060c05c66d6a9303e39f8b6ee0876369324d Mon Sep 17 00:00:00 2001 From: VedantDalimkar <f20190209@goa.bits-pilani.ac.in> Date: Sat, 22 Mar 2025 11:11:22 +0530 Subject: [PATCH 07/44] Moved conversion script to appropriate location --- .../models-conversions/dpt-original-to-smp.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename segmentation_models_pytorch/decoders/dpt/weight_conversion_script.py => scripts/models-conversions/dpt-original-to-smp.py (100%) diff --git a/segmentation_models_pytorch/decoders/dpt/weight_conversion_script.py b/scripts/models-conversions/dpt-original-to-smp.py similarity index 100% rename from segmentation_models_pytorch/decoders/dpt/weight_conversion_script.py rename to scripts/models-conversions/dpt-original-to-smp.py From aa84f4eb6035d80604a64f71a425d2d49d125c54 Mon Sep 17 00:00:00 2001 From: ved <vedant.dalimkar@airamatrix.com> Date: Sat, 22 Mar 2025 16:42:52 +0530 Subject: [PATCH 08/44] Added logic in timm table generation for adding ViT encoders for DPT --- misc/generate_table_timm.py | 55 +- timm_encoders.txt | 1474 +++++++++++++++++++++++++++++++++++ 2 files changed, 1520 insertions(+), 9 deletions(-) create mode 100644 timm_encoders.txt diff --git a/misc/generate_table_timm.py b/misc/generate_table_timm.py index 6c2a1b24..61bde150 100644 --- a/misc/generate_table_timm.py +++ b/misc/generate_table_timm.py @@ -15,32 +15,62 @@ def has_dilation_support(name): return True except Exception: return False + +def valid_vit_encoder_for_dpt(name): + if "vit" not in name: + return False + encoder = timm.create_model(name) + feature_info = encoder.feature_info + feature_info_obj = timm.models.FeatureInfo( + feature_info=feature_info, out_indices=[0,1,2,3] + ) + reduction_scales = list(feature_info_obj.reduction()) + + if len(set(reduction_scales)) > 1: + return False + + output_stride = reduction_scales[0] + if bin(output_stride).count("1") != 1: + return False + + return True def make_table(data): names = data.keys() max_len1 = max([len(x) for x in names]) + 2 max_len2 = len("support dilation") + 2 + max_len3 = len("Supported for DPT") + 2 - l1 = "+" + "-" * max_len1 + "+" + "-" * max_len2 + "+\n" - l2 = "+" + "=" * max_len1 + "+" + "=" * max_len2 + "+\n" + l1 = "+" + "-" * max_len1 + "+" + "-" * max_len2 + "+" + "-" * max_len3 + "+\n" + l2 = "+" + "=" * max_len1 + "+" + "=" * max_len2 + "+" + "-" * max_len3 + "+\n" top = ( "| " + "Encoder name".ljust(max_len1 - 2) + " | " + "Support dilation".center(max_len2 - 2) + + " | " + + "Supported for DPT".center(max_len3 - 2) + " |\n" ) table = l1 + top + l2 for k in sorted(data.keys()): - support = ( - "✅".center(max_len2 - 3) - if data[k]["has_dilation"] - else " ".center(max_len2 - 2) - ) - table += "| " + k.ljust(max_len1 - 2) + " | " + support + " |\n" + + if "has_dilation" in data[k] and data[k]["has_dilation"]: + support = ("✅".center(max_len2 - 3)) + + else: + support = (" ".center(max_len2 - 2)) + + if "supported_only_for_dpt" in data[k]: + supported_for_dpt = ("✅".center(max_len3 - 3)) + + else: + supported_for_dpt = (" ".center(max_len3 - 2)) + + table += "| " + k.ljust(max_len1 - 2) + " | " + support + " | " + supported_for_dpt + " |\n" table += l1 return table @@ -55,8 +85,15 @@ def make_table(data): check_features_and_reduction(name) has_dilation = has_dilation_support(name) supported_models[name] = dict(has_dilation=has_dilation) + except Exception: - continue + try: + if valid_vit_encoder_for_dpt(name): + supported_models[name] = dict(supported_only_for_dpt = True) + except: + continue + + table = make_table(supported_models) print(table) diff --git a/timm_encoders.txt b/timm_encoders.txt new file mode 100644 index 00000000..13cce112 --- /dev/null +++ b/timm_encoders.txt @@ -0,0 +1,1474 @@ ++---------------------------------------+------------------+-------------------+ +| Encoder name | Support dilation | Supported for DPT | ++=======================================+==================+-------------------+ +| bat_resnext26ts | ✅ | | ++---------------------------------------+------------------+-------------------+ +| botnet26t_256 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| botnet50ts_256 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| coatnet_0_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_0_rw_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_1_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_1_rw_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_2_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_2_rw_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_3_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_3_rw_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_4_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_5_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_bn_0_rw_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_nano_cc_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_nano_rw_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_pico_rw_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_rmlp_0_rw_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_rmlp_1_rw2_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_rmlp_1_rw_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_rmlp_2_rw_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_rmlp_2_rw_384 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_rmlp_3_rw_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnet_rmlp_nano_rw_224 | | | ++---------------------------------------+------------------+-------------------+ +| coatnext_nano_rw_224 | | | ++---------------------------------------+------------------+-------------------+ +| cs3darknet_focus_l | ✅ | | ++---------------------------------------+------------------+-------------------+ +| cs3darknet_focus_m | ✅ | | ++---------------------------------------+------------------+-------------------+ +| cs3darknet_focus_s | ✅ | | ++---------------------------------------+------------------+-------------------+ +| cs3darknet_focus_x | ✅ | | ++---------------------------------------+------------------+-------------------+ +| cs3darknet_l | ✅ | | ++---------------------------------------+------------------+-------------------+ +| cs3darknet_m | ✅ | | ++---------------------------------------+------------------+-------------------+ +| cs3darknet_s | ✅ | | ++---------------------------------------+------------------+-------------------+ +| cs3darknet_x | ✅ | | ++---------------------------------------+------------------+-------------------+ +| cs3edgenet_x | ✅ | | ++---------------------------------------+------------------+-------------------+ +| cs3se_edgenet_x | ✅ | | ++---------------------------------------+------------------+-------------------+ +| cs3sedarknet_l | ✅ | | ++---------------------------------------+------------------+-------------------+ +| cs3sedarknet_x | ✅ | | ++---------------------------------------+------------------+-------------------+ +| cs3sedarknet_xdw | ✅ | | ++---------------------------------------+------------------+-------------------+ +| cspresnet50 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| cspresnet50d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| cspresnet50w | ✅ | | ++---------------------------------------+------------------+-------------------+ +| cspresnext50 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| densenet121 | | | ++---------------------------------------+------------------+-------------------+ +| densenet161 | | | ++---------------------------------------+------------------+-------------------+ +| densenet169 | | | ++---------------------------------------+------------------+-------------------+ +| densenet201 | | | ++---------------------------------------+------------------+-------------------+ +| densenet264d | | | ++---------------------------------------+------------------+-------------------+ +| densenetblur121d | | | ++---------------------------------------+------------------+-------------------+ +| dla102 | | | ++---------------------------------------+------------------+-------------------+ +| dla102x | | | ++---------------------------------------+------------------+-------------------+ +| dla102x2 | | | ++---------------------------------------+------------------+-------------------+ +| dla169 | | | ++---------------------------------------+------------------+-------------------+ +| dla34 | | | ++---------------------------------------+------------------+-------------------+ +| dla46_c | | | ++---------------------------------------+------------------+-------------------+ +| dla46x_c | | | ++---------------------------------------+------------------+-------------------+ +| dla60 | | | ++---------------------------------------+------------------+-------------------+ +| dla60_res2net | | | ++---------------------------------------+------------------+-------------------+ +| dla60_res2next | | | ++---------------------------------------+------------------+-------------------+ +| dla60x | | | ++---------------------------------------+------------------+-------------------+ +| dla60x_c | | | ++---------------------------------------+------------------+-------------------+ +| dm_nfnet_f0 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| dm_nfnet_f1 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| dm_nfnet_f2 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| dm_nfnet_f3 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| dm_nfnet_f4 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| dm_nfnet_f5 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| dm_nfnet_f6 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| dpn107 | | | ++---------------------------------------+------------------+-------------------+ +| dpn131 | | | ++---------------------------------------+------------------+-------------------+ +| dpn48b | | | ++---------------------------------------+------------------+-------------------+ +| dpn68 | | | ++---------------------------------------+------------------+-------------------+ +| dpn68b | | | ++---------------------------------------+------------------+-------------------+ +| dpn92 | | | ++---------------------------------------+------------------+-------------------+ +| dpn98 | | | ++---------------------------------------+------------------+-------------------+ +| eca_botnext26ts_256 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| eca_halonext26ts | ✅ | | ++---------------------------------------+------------------+-------------------+ +| eca_nfnet_l0 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| eca_nfnet_l1 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| eca_nfnet_l2 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| eca_nfnet_l3 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| eca_resnet33ts | ✅ | | ++---------------------------------------+------------------+-------------------+ +| eca_resnext26ts | ✅ | | ++---------------------------------------+------------------+-------------------+ +| eca_vovnet39b | | | ++---------------------------------------+------------------+-------------------+ +| ecaresnet101d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| ecaresnet101d_pruned | ✅ | | ++---------------------------------------+------------------+-------------------+ +| ecaresnet200d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| ecaresnet269d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| ecaresnet26t | ✅ | | ++---------------------------------------+------------------+-------------------+ +| ecaresnet50d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| ecaresnet50d_pruned | ✅ | | ++---------------------------------------+------------------+-------------------+ +| ecaresnet50t | ✅ | | ++---------------------------------------+------------------+-------------------+ +| ecaresnetlight | ✅ | | ++---------------------------------------+------------------+-------------------+ +| ecaresnext26t_32x4d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| ecaresnext50t_32x4d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_b0 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_b0_g16_evos | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_b0_g8_gn | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_b0_gn | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_b1 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_b1_pruned | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_b2 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_b2_pruned | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_b3 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_b3_g8_gn | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_b3_gn | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_b3_pruned | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_b4 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_b5 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_b6 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_b7 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_b8 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_blur_b0 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_cc_b0_4e | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_cc_b0_8e | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_cc_b1_8e | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_el | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_el_pruned | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_em | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_es | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_es_pruned | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_l2 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_lite0 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_lite1 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_lite2 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_lite3 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnet_lite4 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnetv2_l | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnetv2_m | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnetv2_rw_m | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnetv2_rw_s | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnetv2_rw_t | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnetv2_s | ✅ | | ++---------------------------------------+------------------+-------------------+ +| efficientnetv2_xl | ✅ | | ++---------------------------------------+------------------+-------------------+ +| ese_vovnet19b_dw | | | ++---------------------------------------+------------------+-------------------+ +| ese_vovnet19b_slim | | | ++---------------------------------------+------------------+-------------------+ +| ese_vovnet19b_slim_dw | | | ++---------------------------------------+------------------+-------------------+ +| ese_vovnet39b | | | ++---------------------------------------+------------------+-------------------+ +| ese_vovnet39b_evos | | | ++---------------------------------------+------------------+-------------------+ +| ese_vovnet57b | | | ++---------------------------------------+------------------+-------------------+ +| ese_vovnet99b | | | ++---------------------------------------+------------------+-------------------+ +| fbnetc_100 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| fbnetv3_b | ✅ | | ++---------------------------------------+------------------+-------------------+ +| fbnetv3_d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| fbnetv3_g | ✅ | | ++---------------------------------------+------------------+-------------------+ +| flexivit_base | | ✅ | ++---------------------------------------+------------------+-------------------+ +| flexivit_large | | ✅ | ++---------------------------------------+------------------+-------------------+ +| flexivit_small | | ✅ | ++---------------------------------------+------------------+-------------------+ +| gc_efficientnetv2_rw_t | ✅ | | ++---------------------------------------+------------------+-------------------+ +| gcresnet33ts | ✅ | | ++---------------------------------------+------------------+-------------------+ +| gcresnet50t | ✅ | | ++---------------------------------------+------------------+-------------------+ +| gcresnext26ts | ✅ | | ++---------------------------------------+------------------+-------------------+ +| gcresnext50ts | ✅ | | ++---------------------------------------+------------------+-------------------+ +| gernet_l | ✅ | | ++---------------------------------------+------------------+-------------------+ +| gernet_m | ✅ | | ++---------------------------------------+------------------+-------------------+ +| gernet_s | ✅ | | ++---------------------------------------+------------------+-------------------+ +| ghostnet_050 | | | ++---------------------------------------+------------------+-------------------+ +| ghostnet_100 | | | ++---------------------------------------+------------------+-------------------+ +| ghostnet_130 | | | ++---------------------------------------+------------------+-------------------+ +| ghostnetv2_100 | | | ++---------------------------------------+------------------+-------------------+ +| ghostnetv2_130 | | | ++---------------------------------------+------------------+-------------------+ +| ghostnetv2_160 | | | ++---------------------------------------+------------------+-------------------+ +| halo2botnet50ts_256 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| halonet26t | ✅ | | ++---------------------------------------+------------------+-------------------+ +| halonet50ts | ✅ | | ++---------------------------------------+------------------+-------------------+ +| halonet_h1 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| haloregnetz_b | ✅ | | ++---------------------------------------+------------------+-------------------+ +| hardcorenas_a | ✅ | | ++---------------------------------------+------------------+-------------------+ +| hardcorenas_b | ✅ | | ++---------------------------------------+------------------+-------------------+ +| hardcorenas_c | ✅ | | ++---------------------------------------+------------------+-------------------+ +| hardcorenas_d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| hardcorenas_e | ✅ | | ++---------------------------------------+------------------+-------------------+ +| hardcorenas_f | ✅ | | ++---------------------------------------+------------------+-------------------+ +| hrnet_w18 | | | ++---------------------------------------+------------------+-------------------+ +| hrnet_w18_small | | | ++---------------------------------------+------------------+-------------------+ +| hrnet_w18_small_v2 | | | ++---------------------------------------+------------------+-------------------+ +| hrnet_w18_ssld | | | ++---------------------------------------+------------------+-------------------+ +| hrnet_w30 | | | ++---------------------------------------+------------------+-------------------+ +| hrnet_w32 | | | ++---------------------------------------+------------------+-------------------+ +| hrnet_w40 | | | ++---------------------------------------+------------------+-------------------+ +| hrnet_w44 | | | ++---------------------------------------+------------------+-------------------+ +| hrnet_w48 | | | ++---------------------------------------+------------------+-------------------+ +| hrnet_w48_ssld | | | ++---------------------------------------+------------------+-------------------+ +| hrnet_w64 | | | ++---------------------------------------+------------------+-------------------+ +| inception_resnet_v2 | | | ++---------------------------------------+------------------+-------------------+ +| inception_v3 | | | ++---------------------------------------+------------------+-------------------+ +| inception_v4 | | | ++---------------------------------------+------------------+-------------------+ +| lambda_resnet26rpt_256 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| lambda_resnet26t | ✅ | | ++---------------------------------------+------------------+-------------------+ +| lambda_resnet50ts | ✅ | | ++---------------------------------------+------------------+-------------------+ +| lamhalobotnet50ts_256 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| lcnet_035 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| lcnet_050 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| lcnet_075 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| lcnet_100 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| lcnet_150 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| legacy_senet154 | | | ++---------------------------------------+------------------+-------------------+ +| legacy_seresnet101 | | | ++---------------------------------------+------------------+-------------------+ +| legacy_seresnet152 | | | ++---------------------------------------+------------------+-------------------+ +| legacy_seresnet18 | | | ++---------------------------------------+------------------+-------------------+ +| legacy_seresnet34 | | | ++---------------------------------------+------------------+-------------------+ +| legacy_seresnet50 | | | ++---------------------------------------+------------------+-------------------+ +| legacy_seresnext101_32x4d | | | ++---------------------------------------+------------------+-------------------+ +| legacy_seresnext26_32x4d | | | ++---------------------------------------+------------------+-------------------+ +| legacy_seresnext50_32x4d | | | ++---------------------------------------+------------------+-------------------+ +| legacy_xception | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_base_tf_224 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_base_tf_384 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_base_tf_512 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_large_tf_224 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_large_tf_384 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_large_tf_512 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_nano_rw_256 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_pico_rw_256 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_rmlp_base_rw_224 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_rmlp_base_rw_384 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_rmlp_nano_rw_256 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_rmlp_pico_rw_256 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_rmlp_small_rw_224 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_rmlp_small_rw_256 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_rmlp_tiny_rw_256 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_small_tf_224 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_small_tf_384 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_small_tf_512 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_tiny_pm_256 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_tiny_rw_224 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_tiny_rw_256 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_tiny_tf_224 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_tiny_tf_384 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_tiny_tf_512 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_xlarge_tf_224 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_xlarge_tf_384 | | | ++---------------------------------------+------------------+-------------------+ +| maxvit_xlarge_tf_512 | | | ++---------------------------------------+------------------+-------------------+ +| maxxvit_rmlp_nano_rw_256 | | | ++---------------------------------------+------------------+-------------------+ +| maxxvit_rmlp_small_rw_256 | | | ++---------------------------------------+------------------+-------------------+ +| maxxvit_rmlp_tiny_rw_256 | | | ++---------------------------------------+------------------+-------------------+ +| maxxvitv2_nano_rw_256 | | | ++---------------------------------------+------------------+-------------------+ +| maxxvitv2_rmlp_base_rw_224 | | | ++---------------------------------------+------------------+-------------------+ +| maxxvitv2_rmlp_base_rw_384 | | | ++---------------------------------------+------------------+-------------------+ +| maxxvitv2_rmlp_large_rw_224 | | | ++---------------------------------------+------------------+-------------------+ +| mixnet_l | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mixnet_m | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mixnet_s | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mixnet_xl | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mixnet_xxl | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mnasnet_050 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mnasnet_075 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mnasnet_100 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mnasnet_140 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mnasnet_small | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenet_edgetpu_100 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenet_edgetpu_v2_l | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenet_edgetpu_v2_m | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenet_edgetpu_v2_s | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenet_edgetpu_v2_xs | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv1_100 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv1_100h | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv1_125 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv2_035 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv2_050 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv2_075 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv2_100 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv2_110d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv2_120d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv2_140 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv3_large_075 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv3_large_100 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv3_large_150d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv3_rw | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv3_small_050 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv3_small_075 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv3_small_100 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv4_conv_aa_large | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv4_conv_aa_medium | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv4_conv_blur_medium | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv4_conv_large | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv4_conv_medium | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv4_conv_small | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv4_conv_small_035 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv4_conv_small_050 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv4_hybrid_large | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv4_hybrid_large_075 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv4_hybrid_medium | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilenetv4_hybrid_medium_075 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobileone_s0 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobileone_s1 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobileone_s2 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobileone_s3 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobileone_s4 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilevit_s | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilevit_xs | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilevit_xxs | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilevitv2_050 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilevitv2_075 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilevitv2_100 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilevitv2_125 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilevitv2_150 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilevitv2_175 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| mobilevitv2_200 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nasnetalarge | | | ++---------------------------------------+------------------+-------------------+ +| nf_ecaresnet101 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nf_ecaresnet26 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nf_ecaresnet50 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nf_regnet_b0 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nf_regnet_b1 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nf_regnet_b2 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nf_regnet_b3 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nf_regnet_b4 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nf_regnet_b5 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nf_resnet101 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nf_resnet26 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nf_resnet50 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nf_seresnet101 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nf_seresnet26 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nf_seresnet50 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nfnet_f0 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nfnet_f1 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nfnet_f2 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nfnet_f3 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nfnet_f4 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nfnet_f5 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nfnet_f6 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nfnet_f7 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| nfnet_l0 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| pnasnet5large | | | ++---------------------------------------+------------------+-------------------+ +| regnetv_040 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetv_064 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetx_002 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetx_004 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetx_004_tv | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetx_006 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetx_008 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetx_016 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetx_032 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetx_040 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetx_064 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetx_080 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetx_120 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetx_160 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetx_320 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnety_002 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnety_004 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnety_006 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnety_008 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnety_008_tv | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnety_016 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnety_032 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnety_040 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnety_040_sgn | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnety_064 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnety_080 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnety_080_tv | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnety_120 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnety_1280 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnety_160 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnety_2560 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnety_320 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnety_640 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetz_005 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetz_040 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetz_040_h | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetz_b16 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetz_b16_evos | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetz_c16 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetz_c16_evos | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetz_d32 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetz_d8 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetz_d8_evos | ✅ | | ++---------------------------------------+------------------+-------------------+ +| regnetz_e8 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| repghostnet_050 | | | ++---------------------------------------+------------------+-------------------+ +| repghostnet_058 | | | ++---------------------------------------+------------------+-------------------+ +| repghostnet_080 | | | ++---------------------------------------+------------------+-------------------+ +| repghostnet_100 | | | ++---------------------------------------+------------------+-------------------+ +| repghostnet_111 | | | ++---------------------------------------+------------------+-------------------+ +| repghostnet_130 | | | ++---------------------------------------+------------------+-------------------+ +| repghostnet_150 | | | ++---------------------------------------+------------------+-------------------+ +| repghostnet_200 | | | ++---------------------------------------+------------------+-------------------+ +| repvgg_a0 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| repvgg_a1 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| repvgg_a2 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| repvgg_b0 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| repvgg_b1 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| repvgg_b1g4 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| repvgg_b2 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| repvgg_b2g4 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| repvgg_b3 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| repvgg_b3g4 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| repvgg_d2se | ✅ | | ++---------------------------------------+------------------+-------------------+ +| res2net101_26w_4s | ✅ | | ++---------------------------------------+------------------+-------------------+ +| res2net101d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| res2net50_14w_8s | ✅ | | ++---------------------------------------+------------------+-------------------+ +| res2net50_26w_4s | ✅ | | ++---------------------------------------+------------------+-------------------+ +| res2net50_26w_6s | ✅ | | ++---------------------------------------+------------------+-------------------+ +| res2net50_26w_8s | ✅ | | ++---------------------------------------+------------------+-------------------+ +| res2net50_48w_2s | ✅ | | ++---------------------------------------+------------------+-------------------+ +| res2net50d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| res2next50 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnest101e | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnest14d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnest200e | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnest269e | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnest26d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnest50d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnest50d_1s4x24d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnest50d_4s2x40d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet101 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet101_clip | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet101_clip_gap | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet101c | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet101d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet101s | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet10t | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet14t | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet152 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet152c | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet152d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet152s | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet18 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet18d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet200 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet200d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet26 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet26d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet26t | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet32ts | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet33ts | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet34 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet34d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet50 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet50_clip | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet50_clip_gap | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet50_gn | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet50_mlp | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet50c | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet50d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet50s | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet50t | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet50x16_clip | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet50x16_clip_gap | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet50x4_clip | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet50x4_clip_gap | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet50x64_clip | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet50x64_clip_gap | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet51q | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnet61q | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetaa101d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetaa34d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetaa50 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetaa50d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetblur101d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetblur18 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetblur50 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetblur50d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetrs101 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetrs152 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetrs200 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetrs270 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetrs350 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetrs420 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetrs50 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_101 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_101d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_101x1_bit | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_101x3_bit | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_152 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_152d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_152x2_bit | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_152x4_bit | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_18 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_18d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_34 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_34d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_50 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_50d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_50d_evos | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_50d_frn | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_50d_gn | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_50t | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_50x1_bit | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnetv2_50x3_bit | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnext101_32x16d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnext101_32x32d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnext101_32x4d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnext101_32x8d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnext101_64x4d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnext26ts | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnext50_32x4d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| resnext50d_32x4d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| rexnet_100 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| rexnet_130 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| rexnet_150 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| rexnet_200 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| rexnet_300 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| rexnetr_100 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| rexnetr_130 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| rexnetr_150 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| rexnetr_200 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| rexnetr_300 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| samvit_base_patch16 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| samvit_base_patch16_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| samvit_huge_patch16 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| samvit_large_patch16 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| sebotnet33ts_256 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| sehalonet33ts | ✅ | | ++---------------------------------------+------------------+-------------------+ +| selecsls42 | | | ++---------------------------------------+------------------+-------------------+ +| selecsls42b | | | ++---------------------------------------+------------------+-------------------+ +| selecsls60 | | | ++---------------------------------------+------------------+-------------------+ +| selecsls60b | | | ++---------------------------------------+------------------+-------------------+ +| selecsls84 | | | ++---------------------------------------+------------------+-------------------+ +| semnasnet_050 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| semnasnet_075 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| semnasnet_100 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| semnasnet_140 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| senet154 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnet101 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnet152 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnet152d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnet18 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnet200d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnet269d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnet33ts | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnet34 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnet50 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnet50t | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnetaa50d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnext101_32x4d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnext101_32x8d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnext101_64x4d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnext101d_32x8d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnext26d_32x4d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnext26t_32x4d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnext26ts | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnext50_32x4d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnextaa101d_32x8d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| seresnextaa201d_32x8d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| skresnet18 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| skresnet34 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| skresnet50 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| skresnet50d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| skresnext50_32x4d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| spnasnet_100 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| test_byobnet | ✅ | | ++---------------------------------------+------------------+-------------------+ +| test_efficientnet | ✅ | | ++---------------------------------------+------------------+-------------------+ +| test_efficientnet_evos | ✅ | | ++---------------------------------------+------------------+-------------------+ +| test_efficientnet_gn | ✅ | | ++---------------------------------------+------------------+-------------------+ +| test_efficientnet_ln | ✅ | | ++---------------------------------------+------------------+-------------------+ +| test_nfnet | ✅ | | ++---------------------------------------+------------------+-------------------+ +| test_resnet | ✅ | | ++---------------------------------------+------------------+-------------------+ +| test_vit | | ✅ | ++---------------------------------------+------------------+-------------------+ +| test_vit2 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| test_vit3 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| test_vit4 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_b0 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_b1 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_b2 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_b3 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_b4 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_b5 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_b6 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_b7 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_b8 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_cc_b0_4e | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_cc_b0_8e | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_cc_b1_8e | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_el | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_em | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_es | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_l2 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_lite0 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_lite1 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_lite2 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_lite3 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnet_lite4 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnetv2_b0 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnetv2_b1 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnetv2_b2 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnetv2_b3 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnetv2_l | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnetv2_m | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnetv2_s | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_efficientnetv2_xl | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_mixnet_l | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_mixnet_m | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_mixnet_s | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_mobilenetv3_large_075 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_mobilenetv3_large_100 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_mobilenetv3_large_minimal_100 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_mobilenetv3_small_075 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_mobilenetv3_small_100 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tf_mobilenetv3_small_minimal_100 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tinynet_a | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tinynet_b | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tinynet_c | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tinynet_d | ✅ | | ++---------------------------------------+------------------+-------------------+ +| tinynet_e | ✅ | | ++---------------------------------------+------------------+-------------------+ +| vit_base_mci_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_18x2_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_224_miil | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_clip_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_clip_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_clip_quickgelu_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_gap_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_plus_240 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_plus_clip_240 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_reg4_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_rope_reg1_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_rpn_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_siglip_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_siglip_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_siglip_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_siglip_512 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_siglip_gap_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_siglip_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_siglip_gap_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_siglip_gap_512 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch16_xp_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch32_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch32_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch32_clip_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch32_clip_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch32_clip_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch32_clip_448 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch32_clip_quickgelu_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch32_plus_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch32_siglip_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch32_siglip_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_patch8_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_r26_s32_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_r50_s16_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_r50_s16_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_resnet26d_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_base_resnet50d_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_betwixt_patch16_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_betwixt_patch16_reg1_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_betwixt_patch16_reg4_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_betwixt_patch16_reg4_gap_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_betwixt_patch16_rope_reg4_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_betwixt_patch32_clip_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_giant_patch16_gap_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_giantopt_patch16_siglip_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_giantopt_patch16_siglip_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_giantopt_patch16_siglip_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_giantopt_patch16_siglip_gap_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_huge_patch16_gap_448 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_large_patch16_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_large_patch16_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_large_patch16_siglip_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_large_patch16_siglip_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_large_patch16_siglip_512 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_large_patch16_siglip_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_large_patch16_siglip_gap_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_large_patch16_siglip_gap_512 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_large_patch32_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_large_patch32_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_large_r50_s32_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_large_r50_s32_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_little_patch16_reg1_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_little_patch16_reg4_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_medium_patch16_clip_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_medium_patch16_gap_240 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_medium_patch16_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_medium_patch16_gap_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_medium_patch16_reg1_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_medium_patch16_reg4_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_medium_patch16_rope_reg1_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_medium_patch32_clip_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_mediumd_patch16_reg4_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_mediumd_patch16_reg4_gap_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_mediumd_patch16_rope_reg1_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_pwee_patch16_reg1_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_relpos_base_patch16_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_relpos_base_patch16_cls_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_relpos_base_patch16_clsgap_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_relpos_base_patch16_plus_240 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_relpos_base_patch16_rpn_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_relpos_base_patch32_plus_rpn_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_relpos_medium_patch16_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_relpos_medium_patch16_cls_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_relpos_medium_patch16_rpn_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_relpos_small_patch16_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_relpos_small_patch16_rpn_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_small_patch16_18x2_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_small_patch16_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_small_patch16_36x1_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_small_patch16_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_small_patch32_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_small_patch32_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_small_patch8_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_small_r26_s32_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_small_r26_s32_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_small_resnet26d_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_small_resnet50d_s16_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_so150m2_patch16_reg1_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_so150m2_patch16_reg1_gap_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_so150m2_patch16_reg1_gap_448 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_so150m_patch16_reg4_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_so150m_patch16_reg4_gap_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_so150m_patch16_reg4_map_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_so400m_patch16_siglip_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_so400m_patch16_siglip_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_so400m_patch16_siglip_512 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_so400m_patch16_siglip_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_so400m_patch16_siglip_gap_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_so400m_patch16_siglip_gap_512 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_srelpos_medium_patch16_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_srelpos_small_patch16_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_tiny_patch16_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_tiny_patch16_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_tiny_r_s16_p8_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_tiny_r_s16_p8_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_wee_patch16_reg1_gap_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vit_xsmall_patch16_clip_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vitamin_base_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vitamin_large2_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vitamin_large2_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vitamin_large2_336 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vitamin_large2_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vitamin_large_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vitamin_large_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vitamin_large_336 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vitamin_large_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vitamin_small_224 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vitamin_xlarge_256 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vitamin_xlarge_336 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vitamin_xlarge_384 | | ✅ | ++---------------------------------------+------------------+-------------------+ +| vovnet39a | | | ++---------------------------------------+------------------+-------------------+ +| vovnet57a | | | ++---------------------------------------+------------------+-------------------+ +| wide_resnet101_2 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| wide_resnet50_2 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| xception41 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| xception41p | ✅ | | ++---------------------------------------+------------------+-------------------+ +| xception65 | ✅ | | ++---------------------------------------+------------------+-------------------+ +| xception65p | ✅ | | ++---------------------------------------+------------------+-------------------+ +| xception71 | ✅ | | ++---------------------------------------+------------------+-------------------+ + From 67c4a7539bd8d889c392b32304aef1dfb692a06c Mon Sep 17 00:00:00 2001 From: VedantDalimkar <f20190209@goa.bits-pilani.ac.in> Date: Sat, 22 Mar 2025 17:07:13 +0530 Subject: [PATCH 09/44] Ruff formatting --- misc/generate_table_timm.py | 38 +++++++++++++++++++++---------------- tests/models/test_dpt.py | 7 +------ 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/misc/generate_table_timm.py b/misc/generate_table_timm.py index 61bde150..8e875583 100644 --- a/misc/generate_table_timm.py +++ b/misc/generate_table_timm.py @@ -15,24 +15,25 @@ def has_dilation_support(name): return True except Exception: return False - + + def valid_vit_encoder_for_dpt(name): if "vit" not in name: return False encoder = timm.create_model(name) feature_info = encoder.feature_info feature_info_obj = timm.models.FeatureInfo( - feature_info=feature_info, out_indices=[0,1,2,3] - ) + feature_info=feature_info, out_indices=[0, 1, 2, 3] + ) reduction_scales = list(feature_info_obj.reduction()) if len(set(reduction_scales)) > 1: return False - + output_stride = reduction_scales[0] if bin(output_stride).count("1") != 1: return False - + return True @@ -57,20 +58,27 @@ def make_table(data): table = l1 + top + l2 for k in sorted(data.keys()): - if "has_dilation" in data[k] and data[k]["has_dilation"]: - support = ("✅".center(max_len2 - 3)) + support = "✅".center(max_len2 - 3) else: - support = (" ".center(max_len2 - 2)) + support = " ".center(max_len2 - 2) if "supported_only_for_dpt" in data[k]: - supported_for_dpt = ("✅".center(max_len3 - 3)) + supported_for_dpt = "✅".center(max_len3 - 3) else: - supported_for_dpt = (" ".center(max_len3 - 2)) - - table += "| " + k.ljust(max_len1 - 2) + " | " + support + " | " + supported_for_dpt + " |\n" + supported_for_dpt = " ".center(max_len3 - 2) + + table += ( + "| " + + k.ljust(max_len1 - 2) + + " | " + + support + + " | " + + supported_for_dpt + + " |\n" + ) table += l1 return table @@ -89,11 +97,9 @@ def make_table(data): except Exception: try: if valid_vit_encoder_for_dpt(name): - supported_models[name] = dict(supported_only_for_dpt = True) - except: + supported_models[name] = dict(supported_only_for_dpt=True) + except Exception: continue - - table = make_table(supported_models) print(table) diff --git a/tests/models/test_dpt.py b/tests/models/test_dpt.py index 33ad14f2..dc76c7a6 100644 --- a/tests/models/test_dpt.py +++ b/tests/models/test_dpt.py @@ -1,9 +1,4 @@ -import os import pytest -import inspect -import tempfile -from functools import lru_cache -from huggingface_hub import hf_hub_download import torch import segmentation_models_pytorch as smp @@ -28,7 +23,7 @@ class TestDPTModel(base.BaseModelTester): @property def hub_checkpoint(self): - return f"vedantdalimkar/DPT" + return "vedantdalimkar/DPT" @pytest.mark.compile def test_compile(self): From 85f22fb0363d510d7b03e5cc3a34c8354378b37c Mon Sep 17 00:00:00 2001 From: VedantDalimkar <f20190209@goa.bits-pilani.ac.in> Date: Thu, 27 Mar 2025 00:25:32 +0530 Subject: [PATCH 10/44] Code revision --- .gitignore | 5 +-- timm_encoders.txt => docs/timm_encoders.txt | 0 encoders_table.md | 2 - .../models-conversions/dpt-original-to-smp.py | 11 +---- .../decoders/dpt/model.py | 1 - tests/encoders/test_timm_vit_encoders.py | 6 +++ tests/models/base.py | 9 +++- tests/models/test_dpt.py | 44 ------------------- 8 files changed, 16 insertions(+), 62 deletions(-) rename timm_encoders.txt => docs/timm_encoders.txt (100%) delete mode 100644 encoders_table.md diff --git a/.gitignore b/.gitignore index 0c53192b..e0490fa5 100644 --- a/.gitignore +++ b/.gitignore @@ -110,7 +110,4 @@ venv.bak/ .mypy_cache/ # ruff -.ruff_cache/ - -# model weight folder -dpt_large-ade20k-b12dca68 \ No newline at end of file +.ruff_cache/ \ No newline at end of file diff --git a/timm_encoders.txt b/docs/timm_encoders.txt similarity index 100% rename from timm_encoders.txt rename to docs/timm_encoders.txt diff --git a/encoders_table.md b/encoders_table.md deleted file mode 100644 index c039b137..00000000 --- a/encoders_table.md +++ /dev/null @@ -1,2 +0,0 @@ -|Encoder |Pretrained weights |Params, M |Script |Compile |Export | -|--------------------------------|:------------------------------:|:------------------------------:|:------------------------------:|:------------------------------:|:------------------------------:| diff --git a/scripts/models-conversions/dpt-original-to-smp.py b/scripts/models-conversions/dpt-original-to-smp.py index af63a9ae..305bad79 100644 --- a/scripts/models-conversions/dpt-original-to-smp.py +++ b/scripts/models-conversions/dpt-original-to-smp.py @@ -1,6 +1,5 @@ import segmentation_models_pytorch as smp import torch -import huggingface_hub MODEL_WEIGHTS_PATH = r"C:\Users\vedan\Downloads\dpt_large-ade20k-b12dca68.pt" HF_HUB_PATH = "vedantdalimkar/DPT" @@ -98,12 +97,4 @@ } smp_model.load_state_dict(dpt_model_dict, strict=True) - - model_name = MODEL_WEIGHTS_PATH.split("\\")[-1].replace(".pt", "") - - smp_model.save_pretrained(model_name) - - repo_id = HF_HUB_PATH - api = huggingface_hub.HfApi() - api.create_repo(repo_id=repo_id, repo_type="model") - api.upload_folder(folder_path=model_name, repo_id=repo_id) + smp_model.save_pretrained(HF_HUB_PATH, push_to_hub=True) diff --git a/segmentation_models_pytorch/decoders/dpt/model.py b/segmentation_models_pytorch/decoders/dpt/model.py index ba7693a2..413eb067 100644 --- a/segmentation_models_pytorch/decoders/dpt/model.py +++ b/segmentation_models_pytorch/decoders/dpt/model.py @@ -3,7 +3,6 @@ from segmentation_models_pytorch.base import ( ClassificationHead, - SegmentationHead, SegmentationModel, ) from segmentation_models_pytorch.encoders import get_encoder diff --git a/tests/encoders/test_timm_vit_encoders.py b/tests/encoders/test_timm_vit_encoders.py index cc7ef200..eeb9e3c9 100644 --- a/tests/encoders/test_timm_vit_encoders.py +++ b/tests/encoders/test_timm_vit_encoders.py @@ -50,6 +50,8 @@ def get_tiny_encoder(self): **self.default_encoder_kwargs, ) + # Requires timm version greater than 1.0.15 as the required functionality of the timm VisionTransformer + # for SMP's TimmViTEncoder class were introduced in the latest version. @requires_timm_greater_or_equal("1.0.15") def test_forward_backward(self): for encoder_name in self.encoder_names: @@ -191,6 +193,7 @@ def test_invalid_depth(self): with self.assertRaises(ValueError): smp.encoders.get_encoder(self.encoder_names[0], depth=0, output_stride=None) + @requires_timm_greater_or_equal("1.0.15") def test_invalid_out_indices(self): with self.assertRaises(ValueError): smp.encoders.get_encoder( @@ -202,6 +205,7 @@ def test_invalid_out_indices(self): self.encoder_names[0], output_stride=None, out_indices=[1, 2, 25] ) + @requires_timm_greater_or_equal("1.0.15") def test_invalid_out_indices_length(self): with self.assertRaises(ValueError): smp.encoders.get_encoder( @@ -278,6 +282,8 @@ def test_dilated(self): f"Encoder `{encoder_name}` should have width output strides {expected_width_strides}, but has {width_strides}", ) + # Same test as in base class. However, this is not redundant as base class has a different + # ```get_tiny_encoder``` method @requires_timm_greater_or_equal("1.0.15") @pytest.mark.compile def test_compile(self): diff --git a/tests/models/base.py b/tests/models/base.py index f7492986..69d84617 100644 --- a/tests/models/base.py +++ b/tests/models/base.py @@ -231,11 +231,18 @@ def test_compile(self): model = self.get_default_model() model = model.eval().to(default_device) + if not model._is_torch_compilable: + with self.assertRaises(RuntimeError): + torch.compiler.reset() + compiled_model = torch.compile( + model, fullgraph=True, dynamic=True, backend="eager" + ) + return + torch.compiler.reset() compiled_model = torch.compile( model, fullgraph=True, dynamic=True, backend="eager" ) - with torch.inference_mode(): compiled_model(sample) diff --git a/tests/models/test_dpt.py b/tests/models/test_dpt.py index dc76c7a6..a394c227 100644 --- a/tests/models/test_dpt.py +++ b/tests/models/test_dpt.py @@ -7,7 +7,6 @@ slow_test, default_device, requires_torch_greater_or_equal, - check_run_test_on_diff_or_main, ) @@ -25,49 +24,6 @@ class TestDPTModel(base.BaseModelTester): def hub_checkpoint(self): return "vedantdalimkar/DPT" - @pytest.mark.compile - def test_compile(self): - if not check_run_test_on_diff_or_main(self.files_for_diff): - self.skipTest("No diff and not on `main`.") - - sample = self._get_sample().to(default_device) - model = self.get_default_model() - model = model.eval().to(default_device) - - if not model._is_torch_compilable: - with self.assertRaises(RuntimeError): - torch.compiler.reset() - compiled_model = torch.compile( - model, fullgraph=True, dynamic=True, backend="eager" - ) - return - - with torch.inference_mode(): - compiled_model(sample) - - @pytest.mark.torch_script - def test_torch_script(self): - if not check_run_test_on_diff_or_main(self.files_for_diff): - self.skipTest("No diff and not on `main`.") - - sample = self._get_sample().to(default_device) - model = self.get_default_model() - model.eval() - - if not model._is_torch_scriptable: - with self.assertRaises(RuntimeError): - scripted_model = torch.jit.script(model) - return - - scripted_model = torch.jit.script(model) - - with torch.inference_mode(): - scripted_output = scripted_model(sample) - eager_output = model(sample) - - self.assertEqual(scripted_output.shape, eager_output.shape) - torch.testing.assert_close(scripted_output, eager_output) - @slow_test @requires_torch_greater_or_equal("2.0.1") @pytest.mark.logits_match From ef48032ee283c20ccc1075df58951287495349c8 Mon Sep 17 00:00:00 2001 From: VedantDalimkar <f20190209@goa.bits-pilani.ac.in> Date: Thu, 27 Mar 2025 21:21:27 +0530 Subject: [PATCH 11/44] Remove unnecessary comment --- tests/encoders/test_timm_vit_encoders.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/encoders/test_timm_vit_encoders.py b/tests/encoders/test_timm_vit_encoders.py index eeb9e3c9..4063abb0 100644 --- a/tests/encoders/test_timm_vit_encoders.py +++ b/tests/encoders/test_timm_vit_encoders.py @@ -282,8 +282,6 @@ def test_dilated(self): f"Encoder `{encoder_name}` should have width output strides {expected_width_strides}, but has {width_strides}", ) - # Same test as in base class. However, this is not redundant as base class has a different - # ```get_tiny_encoder``` method @requires_timm_greater_or_equal("1.0.15") @pytest.mark.compile def test_compile(self): From 28204ad9e9e4fc346762364702fdf769f7d37331 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sat, 5 Apr 2025 22:27:23 +0000 Subject: [PATCH 12/44] Simplify ViT encoder --- .../decoders/dpt/model.py | 24 +- .../encoders/__init__.py | 15 +- .../encoders/timm_vit.py | 208 ++++++++---------- 3 files changed, 107 insertions(+), 140 deletions(-) diff --git a/segmentation_models_pytorch/decoders/dpt/model.py b/segmentation_models_pytorch/decoders/dpt/model.py index 413eb067..3d36844e 100644 --- a/segmentation_models_pytorch/decoders/dpt/model.py +++ b/segmentation_models_pytorch/decoders/dpt/model.py @@ -5,7 +5,7 @@ ClassificationHead, SegmentationModel, ) -from segmentation_models_pytorch.encoders import get_encoder +from segmentation_models_pytorch.encoders.timm_vit import TimmViTEncoder from segmentation_models_pytorch.base.utils import is_torch_compiling from segmentation_models_pytorch.base.hub_mixin import supports_config_loading from .decoder import DPTDecoder, DPTSegmentationHead @@ -69,31 +69,35 @@ def __init__( encoder_name: str = "tu-vit_base_patch8_224", encoder_depth: int = 4, encoder_weights: Optional[str] = None, + encoder_output_indices: Optional[list[int]] = None, feature_dim: int = 256, in_channels: int = 3, classes: int = 1, activation: Optional[Union[str, Callable]] = None, aux_params: Optional[dict] = None, - output_stride: Optional[int] = None, **kwargs: dict[str, Any], ): super().__init__() - self.encoder = get_encoder( - encoder_name, + if encoder_name.startswith("tu-"): + encoder_name = encoder_name[3:] + else: + raise ValueError( + f"Only Timm encoders are supported for DPT. Encoder name must start with 'tu-', got {encoder_name}" + ) + + self.encoder = TimmViTEncoder( + name=encoder_name, in_channels=in_channels, depth=encoder_depth, - weights=encoder_weights, - use_vit_encoder=True, - allow_downsampling=False, - output_stride=output_stride, - allow_output_stride_not_power_of_two=False, + pretrained=encoder_weights is not None, + output_indices=encoder_output_indices, **kwargs, ) self.transformer_embed_dim = self.encoder.embed_dim self.encoder_output_stride = self.encoder.output_stride - self.cls_token_supported = self.encoder.cls_token_supported + self.cls_token_supported = self.encoder.has_class_token self.decoder = DPTDecoder( encoder_name=encoder_name, diff --git a/segmentation_models_pytorch/encoders/__init__.py b/segmentation_models_pytorch/encoders/__init__.py index 3a912aa9..287a921a 100644 --- a/segmentation_models_pytorch/encoders/__init__.py +++ b/segmentation_models_pytorch/encoders/__init__.py @@ -24,7 +24,7 @@ from .mobileone import mobileone_encoders from .timm_universal import TimmUniversalEncoder -from .timm_vit import TimmViTEncoder +from .timm_vit import TimmViTEncoder # noqa F401 from ._preprocessing import preprocess_input from ._legacy_pretrained_settings import pretrained_settings @@ -84,19 +84,6 @@ def get_encoder(name, in_channels=3, depth=5, weights=None, output_stride=32, ** if name.startswith("tu-"): name = name[3:] - use_vit_encoder = kwargs.pop("use_vit_encoder", False) - - if use_vit_encoder: - encoder = TimmViTEncoder( - name=name, - in_channels=in_channels, - depth=depth, - pretrained=weights is not None, - output_stride=output_stride, - **kwargs, - ) - return encoder - encoder = TimmUniversalEncoder( name=name, in_channels=in_channels, diff --git a/segmentation_models_pytorch/encoders/timm_vit.py b/segmentation_models_pytorch/encoders/timm_vit.py index 2dc16c01..cbac97f3 100644 --- a/segmentation_models_pytorch/encoders/timm_vit.py +++ b/segmentation_models_pytorch/encoders/timm_vit.py @@ -1,4 +1,4 @@ -from typing import Any, Optional, Union +from typing import Any, Optional import timm import torch @@ -7,6 +7,56 @@ from .timm_universal import _merge_kwargs_no_duplicates +def sample_block_indices_uniformly(n: int, total_num_blocks: int) -> list[int]: + """ + Sample N block indices uniformly from the total number of blocks. + """ + return [ + int(total_num_blocks / n * block_depth) - 1 for block_depth in range(1, n + 1) + ] + + +def validate_output_indices( + output_indices: list[int], model_num_blocks: int, depth: int +): + """ + Validate the output indices are within the valid range of the model and the + length of the output indices is equal to the depth of the encoder. + """ + for output_index in output_indices: + if output_index < -model_num_blocks or output_index >= model_num_blocks: + raise ValueError( + f"Output indices for feature extraction should be in range " + f"[-{model_num_blocks}, {model_num_blocks}), because the model has {model_num_blocks} blocks, " + f"got index = {output_index}." + ) + + if len(output_indices) != depth: + raise ValueError( + f"Length of output indices for feature extraction should be equal to the depth of the encoder " + f"architecture, got output indices length - {len(output_indices)}, encoder depth - {depth}" + ) + + +def preprocess_output_indices( + output_indices: Optional[list[int]], model_num_blocks: int, depth: int +) -> list[int]: + """ + Preprocess the output indices for the encoder. + """ + + # Refine encoder output indices + if output_indices is None: + output_indices = sample_block_indices_uniformly(depth, model_num_blocks) + elif not isinstance(output_indices, (list, tuple)): + raise ValueError( + f"`output_indices` for encoder should be a list/tuple/None, got {type(output_indices)}" + ) + validate_output_indices(output_indices, model_num_blocks, depth) + + return output_indices + + class TimmViTEncoder(nn.Module): """ A universal encoder leveraging the `timm` library for feature extraction from @@ -27,8 +77,7 @@ def __init__( pretrained: bool = True, in_channels: int = 3, depth: int = 4, - output_indices: Optional[Union[list[int], int]] = None, - output_stride: Optional[int] = None, + output_indices: Optional[list[int]] = None, **kwargs: dict[str, Any], ): """ @@ -52,17 +101,6 @@ def __init__( super().__init__() self.name = name - if output_stride is not None: - raise ValueError("Dilated mode not supported, set output stride to None") - - # Default model configuration for feature extraction - common_kwargs = dict( - in_chans=in_channels, - features_only=False, - pretrained=pretrained, - out_indices=tuple(range(depth)), - ) - # Load a temporary model to analyze its feature hierarchy try: with torch.device("meta"): @@ -70,80 +108,50 @@ def __init__( except Exception: tmp_model = timm.create_model(name) - # Check if model output is in channel-last format (NHWC) + # Get all the necessary information about the model, and delete the temporary model self._is_channel_last = getattr(tmp_model, "output_fmt", None) == "NHWC" - feature_info = tmp_model.feature_info - model_num_blocks = len(feature_info) - - if output_indices is not None: - if isinstance(output_indices, int): - output_indices = list(output_indices) - - for output_index in output_indices: - if output_indices < 0 or output_indices > model_num_blocks: - raise ValueError( - f"Output indices for feature extraction should be greater than 0 and less \ - than the number of blocks in the model ({model_num_blocks}), got {output_index}" - ) - if len(output_indices) != depth: - raise ValueError( - f"Length of output indices for feature extraction should be equal to the depth of the encoder\ - architecture, got output indices length - {len(output_indices)}, encoder depth - {depth}" - ) + del tmp_model + # Additional checks + model_num_blocks = len(feature_info) if depth > model_num_blocks: raise ValueError( - f"Depth of the encoder cannot exceed the number of blocks in the model \ - got {depth} depth, model has {model_num_blocks} blocks" + f"Depth of the encoder cannot exceed the number of blocks in the model " + f"got {depth} depth, model has {model_num_blocks} blocks" ) - if output_indices is None: - output_indices = [ - int((model_num_blocks / 4) * index) - 1 for index in range(1, depth + 1) - ] - - common_kwargs["out_indices"] = self.out_indices = output_indices - feature_info_obj = timm.models.FeatureInfo( - feature_info=feature_info, out_indices=output_indices + # Preprocess the output indices, uniformly sample from model_num_blocks if None + output_indices = preprocess_output_indices( + output_indices, model_num_blocks, depth ) # Determine the model's downsampling pattern and set hierarchy flags - reduction_scales = list(feature_info_obj.reduction()) - - allow_downsampling = kwargs.pop("allow_downsampling", True) - allow_output_stride_not_power_of_two = kwargs.pop( - "allow_output_stride_not_power_of_two", True - ) - # Raise an error if downsampling is not allowed and encoder outputs have progressive downsampling - if len(set(reduction_scales)) > 1 and not allow_downsampling: - raise ValueError("Unsupported model downsampling pattern.") + reduction_scales = [feature_info[i]["reduction"] for i in output_indices] - self._output_stride = reduction_scales[0] - - if ( - bin(self._output_stride).count("1") != 1 - and not allow_output_stride_not_power_of_two - ): + # We only support the same reduction scales for ViT encoder, e.g. [16, 16, 16], and not [16, 8, 4] + if len(set(reduction_scales)) > 1: raise ValueError( - f"Models with stride which is not a power of 2 are not supported, \ - got output stride {self._output_stride}" + f"We only support the same reduction scales for ViT encoder, e.g. [16, 16, 16], and not {reduction_scales}" ) - self.cls_token_supported = getattr(tmp_model, "has_class_token", False) - self.num_prefix_tokens = getattr(tmp_model, "num_prefix_tokens", 0) + # Initiate timm model + model_kwargs = dict(in_chans=in_channels, pretrained=pretrained) + model_kwargs = _merge_kwargs_no_duplicates(model_kwargs, kwargs) + self.model = timm.create_model(name, **model_kwargs) - self.model = timm.create_model( - name, **_merge_kwargs_no_duplicates(common_kwargs, kwargs) - ) + # Private attributes for model forward + self._num_prefix_tokens = getattr(self.model, "num_prefix_tokens", 0) + self._output_indices = output_indices - self._out_channels = feature_info_obj.channels() - self._in_channels = in_channels - self._depth = depth - self._embed_dim = tmp_model.embed_dim + # Public attributes + self.output_stride = reduction_scales[-1] + self.out_channels = [feature_info[i]["num_chs"] for i in output_indices] + self.embed_dim = self.model.embed_dim + self.has_class_token = getattr(self.model, "has_class_token", False) - def forward(self, x: torch.Tensor) -> tuple[list[torch.Tensor], list[torch.Tensor]]: + def forward(self, x: torch.Tensor) -> tuple[list[torch.Tensor], list[Optional[torch.Tensor]]]: """ Forward pass to extract multi-stage features. @@ -155,57 +163,25 @@ def forward(self, x: torch.Tensor) -> tuple[list[torch.Tensor], list[torch.Tenso """ intermediate_outputs = self.model.forward_intermediates( x, - indices=self.out_indices, + indices=self._output_indices, return_prefix_tokens=True, intermediates_only=True, ) - cls_tokens = [None] * len(self.out_indices) - - # If there are multiple prefix tokens, discard the register tokens if they are present and - # return the CLS token, if it exists. Only patch features are retrieved if CLS token is not supported - if self.num_prefix_tokens > 0: - features, prefix_tokens = zip(*intermediate_outputs) - if self.cls_token_supported: - if self.num_prefix_tokens == 1: - cls_tokens = prefix_tokens - - elif self.num_prefix_tokens > 1: - cls_tokens = [ - prefix_token[:, 0, :] for prefix_token in prefix_tokens - ] - + # Split to features and prefix tokens + if self._num_prefix_tokens > 0: + features = [output[0] for output in intermediate_outputs] + prefix_tokens = [output[1] for output in intermediate_outputs] else: features = intermediate_outputs + prefix_tokens = None - return features, cls_tokens - - @property - def embed_dim(self) -> int: - """ - Returns the embedding dimension for the ViT encoder. - - Returns: - int: Embedding dimension. - """ - return self._embed_dim - - @property - def out_channels(self) -> list[int]: - """ - Returns the number of output channels for each feature stage. - - Returns: - list[int]: A list of channel dimensions at each scale. - """ - return self._out_channels - - @property - def output_stride(self) -> int: - """ - Returns the effective output stride based on the model depth. + # Get CLS token from prefix tokens + if self.has_class_token and self._num_prefix_tokens == 1: + cls_tokens = prefix_tokens + elif self.has_class_token and self._num_prefix_tokens > 1: + cls_tokens = [x[:, 0, :] for x in prefix_tokens] + else: + cls_tokens = [None] * len(self._output_indices) - Returns: - int: The effective output stride. - """ - return self._output_stride + return features, cls_tokens From 1b9a6f6a0d81b159a22658d790d29164a2d83735 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sat, 5 Apr 2025 22:55:32 +0000 Subject: [PATCH 13/44] Refactor ProjectionReadout --- .../decoders/dpt/decoder.py | 84 ++++++++----------- 1 file changed, 34 insertions(+), 50 deletions(-) diff --git a/segmentation_models_pytorch/decoders/dpt/decoder.py b/segmentation_models_pytorch/decoders/dpt/decoder.py index 821ce87f..4a346bcc 100644 --- a/segmentation_models_pytorch/decoders/dpt/decoder.py +++ b/segmentation_models_pytorch/decoders/dpt/decoder.py @@ -24,53 +24,42 @@ def _get_feature_processing_out_channels(encoder_name: str) -> list[int]: return [96, 192, 384, 768] -class Transpose(nn.Module): - def __init__(self, dim0: int, dim1: int): - super().__init__() - self.dim0 = dim0 - self.dim1 = dim1 - - def forward(self, x: torch.Tensor): - return torch.transpose(x, dim0=self.dim0, dim1=self.dim1) - - class ProjectionReadout(nn.Module): """ Concatenates the cls tokens with the features to make use of the global information aggregated in the cls token. Projects the combined feature map to the original embedding dimension using a MLP """ - def __init__(self, in_features: int, encoder_output_stride: int): + def __init__(self, embed_dim: int, has_cls_token: bool): super().__init__() + in_features = embed_dim * 2 if has_cls_token else embed_dim + out_features = embed_dim self.project = nn.Sequential( - nn.Linear(in_features=2 * in_features, out_features=in_features), nn.GELU() + nn.Linear(in_features, out_features), + nn.GELU(), ) + self.has_cls_token = has_cls_token - self.flatten = nn.Flatten(start_dim=2) - self.transpose = Transpose(dim0=1, dim1=2) - self.encoder_output_stride = encoder_output_stride + def forward(self, features: torch.Tensor, cls_token: Optional[torch.Tensor] = None): + batch_size, embed_dim, height, width = features.shape - def forward(self, feature: torch.Tensor, cls_token: torch.Tensor): - batch_size, _, height_dim, width_dim = feature.shape - feature = self.flatten(feature) - feature = self.transpose(feature) + # Rearrange to (batch_size, height * width, embed_dim) + features = features.view(batch_size, embed_dim, -1) + features = features.transpose(1, 2).contiguous() - cls_token = cls_token.expand_as(feature) + # Add CLS token + if cls_token is not None: + cls_token = cls_token.expand_as(features) + features = torch.cat([features, cls_token], dim=2) - features = torch.cat([feature, cls_token], dim=2) + # Project to embedding dimension features = self.project(features) - features = self.transpose(features) - - features = features.view(batch_size, -1, height_dim, width_dim) - return features - -class IgnoreReadout(nn.Module): - def __init__(self): - super().__init__() + # Rearrange back to (batch_size, embed_dim, height, width) + features = features.transpose(1, 2) + features = features.view(batch_size, -1, height, width) - def forward(self, feature: torch.Tensor, cls_token: torch.Tensor): - return feature + return features class ReassembleBlock(nn.Module): @@ -214,19 +203,13 @@ def __init__( # If encoder has cls token, then concatenate it with the features along the embedding dimension and project it # back to the feature_dim dimension. Else, ignore the non-existent cls token - - if cls_token_supported: - self.readout_blocks = nn.ModuleList( - [ - ProjectionReadout( - in_features=transformer_embed_dim, - encoder_output_stride=encoder_output_stride, - ) - for _ in range(encoder_depth) - ] + self.readout_blocks = nn.ModuleList() + for _ in range(encoder_depth): + block = ProjectionReadout( + embed_dim=transformer_embed_dim, + has_cls_token=cls_token_supported, ) - else: - self.readout_blocks = [IgnoreReadout() for _ in range(encoder_depth)] + self.readout_blocks.append(block) upsample_factors = [ (encoder_output_stride / 2 ** (index + 2)) @@ -235,10 +218,11 @@ def __init__( feature_processing_out_channels = _get_feature_processing_out_channels( encoder_name ) - if encoder_depth < len(feature_processing_out_channels): - feature_processing_out_channels = feature_processing_out_channels[ - :encoder_depth - ] + + # slice in case encoder_depth < len(feature_processing_out_channels) + feature_processing_out_channels = feature_processing_out_channels[ + :encoder_depth + ] self.reassemble_blocks = nn.ModuleList( [ @@ -293,14 +277,14 @@ def __init__( in_channels, in_channels, kernel_size=kernel_size, padding=1, bias=False ), nn.BatchNorm2d(in_channels), - nn.ReLU(True), - nn.Dropout(0.1, False), + nn.ReLU(inplace=True), + nn.Dropout(p=0.1, inplace=False), nn.Conv2d(in_channels, out_channels, kernel_size=1), ) self.activation = Activation(activation) self.upsampling_factor = upsampling - def forward(self, x): + def forward(self, x: torch.Tensor) -> torch.Tensor: head_output = self.head(x) resized_output = nn.functional.interpolate( head_output, From 334cfbbdf7dab3ade3fa5abb83c1df6ad66a367e Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 00:34:54 +0000 Subject: [PATCH 14/44] Refactor modeling DPT --- .../decoders/dpt/decoder.py | 186 ++++++++---------- .../decoders/dpt/model.py | 46 +++-- .../encoders/timm_vit.py | 55 ++---- 3 files changed, 128 insertions(+), 159 deletions(-) diff --git a/segmentation_models_pytorch/decoders/dpt/decoder.py b/segmentation_models_pytorch/decoders/dpt/decoder.py index 4a346bcc..d8faa5dd 100644 --- a/segmentation_models_pytorch/decoders/dpt/decoder.py +++ b/segmentation_models_pytorch/decoders/dpt/decoder.py @@ -1,30 +1,10 @@ import torch import torch.nn as nn from segmentation_models_pytorch.base.modules import Activation -from typing import Optional +from typing import Optional, Sequence -def _get_feature_processing_out_channels(encoder_name: str) -> list[int]: - """ - Get the output embedding dimensions for the features after decoder processing - """ - - encoder_name = encoder_name.lower() - # Output channels for hybrid ViT encoder after feature processing - if "vit" in encoder_name and "resnet" in encoder_name: - return [256, 512, 768, 768] - - # Output channels for ViT-large,ViT-huge,ViT-giant encoders after feature processing - if "vit" in encoder_name and any( - [variant in encoder_name for variant in ["huge", "large", "giant"]] - ): - return [256, 512, 1024, 1024] - - # Output channels for ViT-base and other encoders after feature processing - return [96, 192, 384, 768] - - -class ProjectionReadout(nn.Module): +class ProjectionBlock(nn.Module): """ Concatenates the cls tokens with the features to make use of the global information aggregated in the cls token. Projects the combined feature map to the original embedding dimension using a MLP @@ -38,9 +18,10 @@ def __init__(self, embed_dim: int, has_cls_token: bool): nn.Linear(in_features, out_features), nn.GELU(), ) - self.has_cls_token = has_cls_token - def forward(self, features: torch.Tensor, cls_token: Optional[torch.Tensor] = None): + def forward( + self, features: torch.Tensor, cls_token: Optional[torch.Tensor] = None + ) -> torch.Tensor: batch_size, embed_dim, height, width = features.shape # Rearrange to (batch_size, height * width, embed_dim) @@ -69,47 +50,50 @@ class ReassembleBlock(nn.Module): """ def __init__( - self, embed_dim: int, feature_dim: int, out_channel: int, upsample_factor: int + self, + in_channels: int, + mid_channels: int, + out_channels: int, + upsample_factor: int, ): super().__init__() self.project_to_out_channel = nn.Conv2d( - in_channels=embed_dim, out_channels=out_channel, kernel_size=1 + in_channels=in_channels, + out_channels=mid_channels, + kernel_size=1, ) if upsample_factor > 1.0: self.upsample = nn.ConvTranspose2d( - in_channels=out_channel, - out_channels=out_channel, + in_channels=mid_channels, + out_channels=mid_channels, kernel_size=int(upsample_factor), stride=int(upsample_factor), ) - elif upsample_factor == 1.0: self.upsample = nn.Identity() - else: self.upsample = nn.Conv2d( - in_channels=out_channel, - out_channels=out_channel, + in_channels=mid_channels, + out_channels=mid_channels, kernel_size=3, stride=int(1 / upsample_factor), padding=1, ) self.project_to_feature_dim = nn.Conv2d( - in_channels=out_channel, - out_channels=feature_dim, + in_channels=mid_channels, + out_channels=out_channels, kernel_size=3, padding=1, bias=False, ) - def forward(self, x: torch.Tensor): + def forward(self, x: torch.Tensor) -> torch.Tensor: x = self.project_to_out_channel(x) x = self.upsample(x) x = self.project_to_feature_dim(x) - return x @@ -135,15 +119,23 @@ def __init__(self, feature_dim: int): self.batch_norm_2 = nn.BatchNorm2d(num_features=feature_dim) self.activation = nn.ReLU() - def forward(self, x: torch.Tensor): - activated_x_1 = self.activation(x) - conv_1_out = self.conv_1(activated_x_1) - batch_norm_1_out = self.batch_norm_1(conv_1_out) - activated_x_2 = self.activation(batch_norm_1_out) - conv_2_out = self.conv_2(activated_x_2) - batch_norm_2_out = self.batch_norm_2(conv_2_out) + def forward(self, x: torch.Tensor) -> torch.Tensor: + residual = x - return x + batch_norm_2_out + # Block 1 + x = self.activation(x) + x = self.conv_1(x) + x = self.batch_norm_1(x) + + # Block 2 + x = self.activation(x) + x = self.conv_2(x) + x = self.batch_norm_2(x) + + # Add residual + x = x + residual + + return x class FusionBlock(nn.Module): @@ -153,26 +145,24 @@ class FusionBlock(nn.Module): def __init__(self, feature_dim: int): super().__init__() - self.residual_conv_block1 = ResidualConvBlock(feature_dim=feature_dim) - self.residual_conv_block2 = ResidualConvBlock(feature_dim=feature_dim) - self.project = nn.Conv2d( - in_channels=feature_dim, out_channels=feature_dim, kernel_size=1 - ) + self.residual_conv_block1 = ResidualConvBlock(feature_dim) + self.residual_conv_block2 = ResidualConvBlock(feature_dim) + self.project = nn.Conv2d(feature_dim, feature_dim, kernel_size=1) self.activation = nn.ReLU() - def forward(self, feature: torch.Tensor, preceding_layer_feature: torch.Tensor): + def forward( + self, + feature: torch.Tensor, + previous_feature: Optional[torch.Tensor] = None, + ) -> torch.Tensor: feature = self.residual_conv_block1(feature) - - if preceding_layer_feature is not None: - feature += preceding_layer_feature - + if previous_feature is not None: + feature = feature + previous_feature feature = self.residual_conv_block2(feature) - feature = nn.functional.interpolate( feature, scale_factor=2, align_corners=True, mode="bilinear" ) feature = self.project(feature) - return feature @@ -181,7 +171,7 @@ class DPTDecoder(nn.Module): Decoder part for DPT Processes the encoder features and class tokens (if encoder has class_tokens) to have spatial downsampling ratios of - [1/32,1/16,1/8,1/4] relative to the input image spatial dimension. + [1/4, 1/8, 1/16, 1/32, ...] relative to the input image spatial dimension. The decoder then fuses these features in a residual manner and progressively upsamples them by a factor of 2 so that the output has a downsampling ratio of 1/2 relative to the input image spatial dimension @@ -190,75 +180,57 @@ class DPTDecoder(nn.Module): def __init__( self, - encoder_name: str, - transformer_embed_dim: int, - encoder_output_stride: int, - feature_dim: int = 256, - encoder_depth: int = 4, - cls_token_supported: bool = False, + embed_dim: int, + encoder_output_strides: Sequence[int] = (16, 16, 16, 16), + intermediate_channels: Sequence[int] = (256, 512, 1024, 1024), + fusion_channels: int = 256, + has_cls_token: bool = False, ): super().__init__() - self.cls_token_supported = cls_token_supported + num_blocks = len(encoder_output_strides) # If encoder has cls token, then concatenate it with the features along the embedding dimension and project it # back to the feature_dim dimension. Else, ignore the non-existent cls token - self.readout_blocks = nn.ModuleList() - for _ in range(encoder_depth): - block = ProjectionReadout( - embed_dim=transformer_embed_dim, - has_cls_token=cls_token_supported, - ) - self.readout_blocks.append(block) + blocks = [ProjectionBlock(embed_dim, has_cls_token) for _ in range(num_blocks)] + self.readout_blocks = nn.ModuleList(blocks) - upsample_factors = [ - (encoder_output_stride / 2 ** (index + 2)) - for index in range(0, encoder_depth) + # Upsample factors to resize features to [1/4, 1/8, 1/16, 1/32, ...] scales + scale_factors = [ + stride / 2 ** (i + 2) for i, stride in enumerate(encoder_output_strides) ] - feature_processing_out_channels = _get_feature_processing_out_channels( - encoder_name - ) - - # slice in case encoder_depth < len(feature_processing_out_channels) - feature_processing_out_channels = feature_processing_out_channels[ - :encoder_depth - ] - - self.reassemble_blocks = nn.ModuleList( - [ - ReassembleBlock( - transformer_embed_dim, feature_dim, out_channel, upsample_factor - ) - for upsample_factor, out_channel in zip( - upsample_factors, feature_processing_out_channels - ) - ] - ) + self.reassemble_blocks = nn.ModuleList() + for factor, mid_channels in zip(scale_factors, intermediate_channels): + block = ReassembleBlock( + in_channels=embed_dim, + mid_channels=mid_channels, + out_channels=fusion_channels, + upsample_factor=factor, + ) + self.reassemble_blocks.append(block) - self.fusion_blocks = nn.ModuleList( - [FusionBlock(feature_dim=feature_dim) for _ in range(encoder_depth)] - ) + # Fusion blocks to fuse the processed features in a sequential manner + fusion_blocks = [FusionBlock(fusion_channels) for _ in range(num_blocks)] + self.fusion_blocks = nn.ModuleList(fusion_blocks) def forward( - self, features: list[torch.Tensor], cls_tokens: list[torch.Tensor] + self, features: list[torch.Tensor], cls_tokens: list[Optional[torch.Tensor]] ) -> torch.Tensor: + # Process the encoder features to scale of [1/4, 1/8, 1/16, 1/32, ...] processed_features = [] - - # Process the encoder features to scale of [1/32,1/16,1/8,1/4] - for index, (feature, cls_token) in enumerate(zip(features, cls_tokens)): - readout_feature = self.readout_blocks[index](feature, cls_token) - processed_feature = self.reassemble_blocks[index](readout_feature) + for i, (feature, cls_token) in enumerate(zip(features, cls_tokens)): + readout_feature = self.readout_blocks[i](feature, cls_token) + processed_feature = self.reassemble_blocks[i](readout_feature) processed_features.append(processed_feature) - preceding_layer_feature = None - # Fusion and progressive upsampling starting from the last processed feature + previous_feature = None processed_features = processed_features[::-1] for fusion_block, feature in zip(self.fusion_blocks, processed_features): - out = fusion_block(feature, preceding_layer_feature) - preceding_layer_feature = out + fused_feature = fusion_block(feature, previous_feature) + previous_feature = fused_feature - return out + return fused_feature class DPTSegmentationHead(nn.Module): diff --git a/segmentation_models_pytorch/decoders/dpt/model.py b/segmentation_models_pytorch/decoders/dpt/model.py index 3d36844e..5dcd8ce8 100644 --- a/segmentation_models_pytorch/decoders/dpt/model.py +++ b/segmentation_models_pytorch/decoders/dpt/model.py @@ -1,4 +1,4 @@ -from typing import Any, Optional, Union, Callable +from typing import Any, Optional, Union, Callable, Sequence import torch from segmentation_models_pytorch.base import ( @@ -70,7 +70,9 @@ def __init__( encoder_depth: int = 4, encoder_weights: Optional[str] = None, encoder_output_indices: Optional[list[int]] = None, - feature_dim: int = 256, + decoder_intermediate_channels: Sequence[int] = (256, 512, 1024, 1024), + decoder_fusion_channels: int = 256, + feature_dim: int = 256, # TODO: remove this in_channels: int = 3, classes: int = 1, activation: Optional[Union[str, Callable]] = None, @@ -78,7 +80,6 @@ def __init__( **kwargs: dict[str, Any], ): super().__init__() - if encoder_name.startswith("tu-"): encoder_name = encoder_name[3:] else: @@ -95,21 +96,16 @@ def __init__( **kwargs, ) - self.transformer_embed_dim = self.encoder.embed_dim - self.encoder_output_stride = self.encoder.output_stride - self.cls_token_supported = self.encoder.has_class_token - self.decoder = DPTDecoder( - encoder_name=encoder_name, - transformer_embed_dim=self.transformer_embed_dim, - feature_dim=feature_dim, - encoder_depth=encoder_depth, - encoder_output_stride=self.encoder_output_stride, - cls_token_supported=self.cls_token_supported, + embed_dim=self.encoder.embed_dim, + intermediate_channels=decoder_intermediate_channels, + fusion_channels=decoder_fusion_channels, + encoder_output_strides=self.encoder.output_strides, + has_cls_token=self.encoder.has_class_token, ) self.segmentation_head = DPTSegmentationHead( - in_channels=feature_dim, + in_channels=decoder_fusion_channels, out_channels=classes, activation=activation, kernel_size=3, @@ -135,9 +131,7 @@ def forward(self, x): self.check_input_shape(x) features, cls_tokens = self.encoder(x) - decoder_output = self.decoder(features, cls_tokens) - masks = self.segmentation_head(decoder_output) if self.classification_head is not None: @@ -145,3 +139,23 @@ def forward(self, x): return masks, labels return masks + + +def _get_feature_processing_out_channels(encoder_name: str) -> list[int]: + """ + Get the output embedding dimensions for the features after decoder processing + """ + + encoder_name = encoder_name.lower() + # Output channels for hybrid ViT encoder after feature processing + if "vit" in encoder_name and "resnet" in encoder_name: + return [256, 512, 768, 768] + + # Output channels for ViT-large,ViT-huge,ViT-giant encoders after feature processing + if "vit" in encoder_name and any( + [variant in encoder_name for variant in ["huge", "large", "giant"]] + ): + return [256, 512, 1024, 1024] + + # Output channels for ViT-base and other encoders after feature processing + return [96, 192, 384, 768] diff --git a/segmentation_models_pytorch/encoders/timm_vit.py b/segmentation_models_pytorch/encoders/timm_vit.py index cbac97f3..efad1161 100644 --- a/segmentation_models_pytorch/encoders/timm_vit.py +++ b/segmentation_models_pytorch/encoders/timm_vit.py @@ -31,12 +31,6 @@ def validate_output_indices( f"got index = {output_index}." ) - if len(output_indices) != depth: - raise ValueError( - f"Length of output indices for feature extraction should be equal to the depth of the encoder " - f"architecture, got output indices length - {len(output_indices)}, encoder depth - {depth}" - ) - def preprocess_output_indices( output_indices: Optional[list[int]], model_num_blocks: int, depth: int @@ -91,28 +85,28 @@ def __init__( output_indices (Optional[list[int] | int]): Indices of blocks in the model to be used for feature extraction. **kwargs: Additional arguments passed to `timm.create_model`. """ - # At the moment we do not support models with more than 4 stages, - # but can be reconfigured in the future. + super().__init__() + if depth > 4 or depth < 1: raise ValueError( f"{self.__class__.__name__} depth should be in range [1, 4], got {depth}" ) - super().__init__() - self.name = name + if isinstance(output_indices, (list, tuple)) and len(output_indices) != depth: + raise ValueError( + f"Length of output indices for feature extraction should be equal to the depth of the encoder " + f"architecture, got output indices length - {len(output_indices)}, encoder depth - {depth}" + ) - # Load a temporary model to analyze its feature hierarchy - try: - with torch.device("meta"): - tmp_model = timm.create_model(name) - except Exception: - tmp_model = timm.create_model(name) + self.name = name - # Get all the necessary information about the model, and delete the temporary model - self._is_channel_last = getattr(tmp_model, "output_fmt", None) == "NHWC" - feature_info = tmp_model.feature_info + # Load a timm model + encoder_kwargs = dict(in_chans=in_channels, pretrained=pretrained) + encoder_kwargs = _merge_kwargs_no_duplicates(encoder_kwargs, kwargs) + self.model = timm.create_model(name, **encoder_kwargs) - del tmp_model + # Get all the necessary information about the model + feature_info = self.model.feature_info # Additional checks model_num_blocks = len(feature_info) @@ -127,31 +121,20 @@ def __init__( output_indices, model_num_blocks, depth ) - # Determine the model's downsampling pattern and set hierarchy flags - reduction_scales = [feature_info[i]["reduction"] for i in output_indices] - - # We only support the same reduction scales for ViT encoder, e.g. [16, 16, 16], and not [16, 8, 4] - if len(set(reduction_scales)) > 1: - raise ValueError( - f"We only support the same reduction scales for ViT encoder, e.g. [16, 16, 16], and not {reduction_scales}" - ) - - # Initiate timm model - model_kwargs = dict(in_chans=in_channels, pretrained=pretrained) - model_kwargs = _merge_kwargs_no_duplicates(model_kwargs, kwargs) - self.model = timm.create_model(name, **model_kwargs) - # Private attributes for model forward self._num_prefix_tokens = getattr(self.model, "num_prefix_tokens", 0) self._output_indices = output_indices # Public attributes - self.output_stride = reduction_scales[-1] + self.output_strides = [feature_info[i]["reduction"] for i in output_indices] + self.output_stride = self.output_strides[-1] self.out_channels = [feature_info[i]["num_chs"] for i in output_indices] self.embed_dim = self.model.embed_dim self.has_class_token = getattr(self.model, "has_class_token", False) - def forward(self, x: torch.Tensor) -> tuple[list[torch.Tensor], list[Optional[torch.Tensor]]]: + def forward( + self, x: torch.Tensor + ) -> tuple[list[torch.Tensor], list[Optional[torch.Tensor]]]: """ Forward pass to extract multi-stage features. From 7e1ef3b6c4a6405ff6c85cae127da62e7bb1e7be Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 01:11:13 +0000 Subject: [PATCH 15/44] Support more encoders --- .../decoders/dpt/decoder.py | 12 ++-- .../decoders/dpt/model.py | 2 +- .../encoders/timm_vit.py | 55 +++++++++++-------- 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/segmentation_models_pytorch/decoders/dpt/decoder.py b/segmentation_models_pytorch/decoders/dpt/decoder.py index d8faa5dd..568a28a4 100644 --- a/segmentation_models_pytorch/decoders/dpt/decoder.py +++ b/segmentation_models_pytorch/decoders/dpt/decoder.py @@ -180,7 +180,7 @@ class DPTDecoder(nn.Module): def __init__( self, - embed_dim: int, + encoder_out_channels: Sequence[int] = (756, 756, 756, 756), encoder_output_strides: Sequence[int] = (16, 16, 16, 16), intermediate_channels: Sequence[int] = (256, 512, 1024, 1024), fusion_channels: int = 256, @@ -192,7 +192,7 @@ def __init__( # If encoder has cls token, then concatenate it with the features along the embedding dimension and project it # back to the feature_dim dimension. Else, ignore the non-existent cls token - blocks = [ProjectionBlock(embed_dim, has_cls_token) for _ in range(num_blocks)] + blocks = [ProjectionBlock(in_channels, has_cls_token) for in_channels in encoder_out_channels] self.readout_blocks = nn.ModuleList(blocks) # Upsample factors to resize features to [1/4, 1/8, 1/16, 1/32, ...] scales @@ -200,12 +200,12 @@ def __init__( stride / 2 ** (i + 2) for i, stride in enumerate(encoder_output_strides) ] self.reassemble_blocks = nn.ModuleList() - for factor, mid_channels in zip(scale_factors, intermediate_channels): + for i in range(num_blocks): block = ReassembleBlock( - in_channels=embed_dim, - mid_channels=mid_channels, + in_channels=encoder_out_channels[i], + mid_channels=intermediate_channels[i], out_channels=fusion_channels, - upsample_factor=factor, + upsample_factor=scale_factors[i], ) self.reassemble_blocks.append(block) diff --git a/segmentation_models_pytorch/decoders/dpt/model.py b/segmentation_models_pytorch/decoders/dpt/model.py index 5dcd8ce8..d0e8795e 100644 --- a/segmentation_models_pytorch/decoders/dpt/model.py +++ b/segmentation_models_pytorch/decoders/dpt/model.py @@ -97,7 +97,7 @@ def __init__( ) self.decoder = DPTDecoder( - embed_dim=self.encoder.embed_dim, + encoder_out_channels=self.encoder.out_channels, intermediate_channels=decoder_intermediate_channels, fusion_channels=decoder_fusion_channels, encoder_output_strides=self.encoder.output_strides, diff --git a/segmentation_models_pytorch/encoders/timm_vit.py b/segmentation_models_pytorch/encoders/timm_vit.py index efad1161..f161ad0d 100644 --- a/segmentation_models_pytorch/encoders/timm_vit.py +++ b/segmentation_models_pytorch/encoders/timm_vit.py @@ -129,9 +129,37 @@ def __init__( self.output_strides = [feature_info[i]["reduction"] for i in output_indices] self.output_stride = self.output_strides[-1] self.out_channels = [feature_info[i]["num_chs"] for i in output_indices] - self.embed_dim = self.model.embed_dim self.has_class_token = getattr(self.model, "has_class_token", False) + def _forward_with_prefix_tokens(self, x: torch.Tensor) -> tuple[list[torch.Tensor], list[Optional[torch.Tensor]]]: + + intermediate_outputs = self.model.forward_intermediates( + x, + indices=self._output_indices, + return_prefix_tokens=True, + intermediates_only=True, + ) + + features = [output[0] for output in intermediate_outputs] + prefix_tokens = [output[1] for output in intermediate_outputs] + + if self.has_class_token and self._num_prefix_tokens > 1: + cls_tokens = [x[:, 0, :] for x in prefix_tokens] + else: + cls_tokens = [None] * len(intermediate_outputs) + + return features, cls_tokens + + def _forward_without_prefix_tokens(self, x: torch.Tensor) -> tuple[list[torch.Tensor], list[Optional[torch.Tensor]]]: + features = self.model.forward_intermediates( + x, + indices=self._output_indices, + intermediates_only=True, + ) + cls_tokens = [None] * len(features) + + return features, cls_tokens + def forward( self, x: torch.Tensor ) -> tuple[list[torch.Tensor], list[Optional[torch.Tensor]]]: @@ -144,27 +172,8 @@ def forward( Returns: tuple[list[torch.Tensor], list[torch.Tensor]]: Tuple of feature maps and cls tokens (if supported) at different scales. """ - intermediate_outputs = self.model.forward_intermediates( - x, - indices=self._output_indices, - return_prefix_tokens=True, - intermediates_only=True, - ) - - # Split to features and prefix tokens + if self._num_prefix_tokens > 0: - features = [output[0] for output in intermediate_outputs] - prefix_tokens = [output[1] for output in intermediate_outputs] + return self._forward_with_prefix_tokens(x) else: - features = intermediate_outputs - prefix_tokens = None - - # Get CLS token from prefix tokens - if self.has_class_token and self._num_prefix_tokens == 1: - cls_tokens = prefix_tokens - elif self.has_class_token and self._num_prefix_tokens > 1: - cls_tokens = [x[:, 0, :] for x in prefix_tokens] - else: - cls_tokens = [None] * len(self._output_indices) - - return features, cls_tokens + return self._forward_without_prefix_tokens(x) From d65c0f7df65d07847b2022a745d287a38fa70a30 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 10:44:42 +0000 Subject: [PATCH 16/44] Refactor a bit conversion, added validation --- .../models-conversions/dpt-original-to-smp.py | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/scripts/models-conversions/dpt-original-to-smp.py b/scripts/models-conversions/dpt-original-to-smp.py index 305bad79..4c9cfb53 100644 --- a/scripts/models-conversions/dpt-original-to-smp.py +++ b/scripts/models-conversions/dpt-original-to-smp.py @@ -1,12 +1,12 @@ import segmentation_models_pytorch as smp import torch -MODEL_WEIGHTS_PATH = r"C:\Users\vedan\Downloads\dpt_large-ade20k-b12dca68.pt" -HF_HUB_PATH = "vedantdalimkar/DPT" +MODEL_WEIGHTS_PATH = r"dpt_large-ade20k-b12dca68.pt" +HF_HUB_PATH = "qubvel-hf/dpt-large-ade20k" if __name__ == "__main__": smp_model = smp.DPT(encoder_name="tu-vit_large_patch16_384", classes=150) - dpt_model_dict = torch.load(MODEL_WEIGHTS_PATH) + dpt_model_dict = torch.load(MODEL_WEIGHTS_PATH, weights_only=True) for layer_index in range(0, 4): for param in [ @@ -96,5 +96,25 @@ if not name.startswith("auxlayer") } + # ------- DO NOT touch this section ------- smp_model.load_state_dict(dpt_model_dict, strict=True) - smp_model.save_pretrained(HF_HUB_PATH, push_to_hub=True) + smp_model.save_pretrained(HF_HUB_PATH, push_to_hub=False) + + smp_model = smp.from_pretrained(HF_HUB_PATH) + smp_model.eval() + + input_tensor = torch.ones((1, 3, 384, 384)) + output = smp_model(input_tensor) + + print(output.shape) + print(output[0, 0, :3, :3]) + + expected_slice = torch.tensor( + [ + [3.4243, 3.4553, 3.4863], + [3.3332, 3.2876, 3.2419], + [3.2422, 3.1199, 2.9975], + ] + ) + + torch.testing.assert_close(output[0, 0, :3, :3], expected_slice, atol=1e-4, rtol=1e-4) From 0a62fe05a87bab3c153ee37574696b4bc96a39fd Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 10:44:55 +0000 Subject: [PATCH 17/44] Fixup --- segmentation_models_pytorch/decoders/dpt/decoder.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/segmentation_models_pytorch/decoders/dpt/decoder.py b/segmentation_models_pytorch/decoders/dpt/decoder.py index 568a28a4..98e80c14 100644 --- a/segmentation_models_pytorch/decoders/dpt/decoder.py +++ b/segmentation_models_pytorch/decoders/dpt/decoder.py @@ -192,7 +192,10 @@ def __init__( # If encoder has cls token, then concatenate it with the features along the embedding dimension and project it # back to the feature_dim dimension. Else, ignore the non-existent cls token - blocks = [ProjectionBlock(in_channels, has_cls_token) for in_channels in encoder_out_channels] + blocks = [ + ProjectionBlock(in_channels, has_cls_token) + for in_channels in encoder_out_channels + ] self.readout_blocks = nn.ModuleList(blocks) # Upsample factors to resize features to [1/4, 1/8, 1/16, 1/32, ...] scales From e3238ae9875bcda40f8f6ece1c3cdd7855e9c643 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 10:45:16 +0000 Subject: [PATCH 18/44] Split forward for timm_vit --- .../encoders/timm_vit.py | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/segmentation_models_pytorch/encoders/timm_vit.py b/segmentation_models_pytorch/encoders/timm_vit.py index f161ad0d..1595c41f 100644 --- a/segmentation_models_pytorch/encoders/timm_vit.py +++ b/segmentation_models_pytorch/encoders/timm_vit.py @@ -131,8 +131,9 @@ def __init__( self.out_channels = [feature_info[i]["num_chs"] for i in output_indices] self.has_class_token = getattr(self.model, "has_class_token", False) - def _forward_with_prefix_tokens(self, x: torch.Tensor) -> tuple[list[torch.Tensor], list[Optional[torch.Tensor]]]: - + def _forward_with_cls_token( + self, x: torch.Tensor + ) -> tuple[list[torch.Tensor], list[torch.Tensor]]: intermediate_outputs = self.model.forward_intermediates( x, indices=self._output_indices, @@ -141,24 +142,20 @@ def _forward_with_prefix_tokens(self, x: torch.Tensor) -> tuple[list[torch.Tenso ) features = [output[0] for output in intermediate_outputs] - prefix_tokens = [output[1] for output in intermediate_outputs] + cls_tokens = [output[1] for output in intermediate_outputs] if self.has_class_token and self._num_prefix_tokens > 1: - cls_tokens = [x[:, 0, :] for x in prefix_tokens] - else: - cls_tokens = [None] * len(intermediate_outputs) + cls_tokens = [x[:, 0, :] for x in cls_tokens] return features, cls_tokens - - def _forward_without_prefix_tokens(self, x: torch.Tensor) -> tuple[list[torch.Tensor], list[Optional[torch.Tensor]]]: + + def _forward_without_cls_token(self, x: torch.Tensor) -> list[torch.Tensor]: features = self.model.forward_intermediates( x, indices=self._output_indices, intermediates_only=True, ) - cls_tokens = [None] * len(features) - - return features, cls_tokens + return features def forward( self, x: torch.Tensor @@ -172,8 +169,11 @@ def forward( Returns: tuple[list[torch.Tensor], list[torch.Tensor]]: Tuple of feature maps and cls tokens (if supported) at different scales. """ - - if self._num_prefix_tokens > 0: - return self._forward_with_prefix_tokens(x) + + if self.has_class_token: + features, cls_tokens = self._forward_with_cls_token(x) else: - return self._forward_without_prefix_tokens(x) + features = self._forward_without_cls_token(x) + cls_tokens = [None] * len(features) + + return features, cls_tokens From df4d087e90974886454f64354b1343c5d6940906 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 11:00:52 +0000 Subject: [PATCH 19/44] Rename readout, remove feature_dim --- scripts/models-conversions/dpt-original-to-smp.py | 4 ++-- segmentation_models_pytorch/decoders/dpt/decoder.py | 6 +++--- segmentation_models_pytorch/decoders/dpt/model.py | 1 - 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/scripts/models-conversions/dpt-original-to-smp.py b/scripts/models-conversions/dpt-original-to-smp.py index 4c9cfb53..3d46aa83 100644 --- a/scripts/models-conversions/dpt-original-to-smp.py +++ b/scripts/models-conversions/dpt-original-to-smp.py @@ -5,7 +5,7 @@ HF_HUB_PATH = "qubvel-hf/dpt-large-ade20k" if __name__ == "__main__": - smp_model = smp.DPT(encoder_name="tu-vit_large_patch16_384", classes=150) + smp_model = smp.DPT(encoder_name="tu-vit_large_patch16_384", classes=150, dynamic_img_size=True) dpt_model_dict = torch.load(MODEL_WEIGHTS_PATH, weights_only=True) for layer_index in range(0, 4): @@ -51,7 +51,7 @@ ) dpt_model_dict[ - f"decoder.readout_blocks.{layer_index}.project.0.{param}" + f"decoder.projection_blocks.{layer_index}.project.0.{param}" ] = dpt_model_dict.pop( f"pretrained.act_postprocess{layer_index + 1}.0.project.0.{param}" ) diff --git a/segmentation_models_pytorch/decoders/dpt/decoder.py b/segmentation_models_pytorch/decoders/dpt/decoder.py index 98e80c14..33743a59 100644 --- a/segmentation_models_pytorch/decoders/dpt/decoder.py +++ b/segmentation_models_pytorch/decoders/dpt/decoder.py @@ -196,7 +196,7 @@ def __init__( ProjectionBlock(in_channels, has_cls_token) for in_channels in encoder_out_channels ] - self.readout_blocks = nn.ModuleList(blocks) + self.projection_blocks = nn.ModuleList(blocks) # Upsample factors to resize features to [1/4, 1/8, 1/16, 1/32, ...] scales scale_factors = [ @@ -222,8 +222,8 @@ def forward( # Process the encoder features to scale of [1/4, 1/8, 1/16, 1/32, ...] processed_features = [] for i, (feature, cls_token) in enumerate(zip(features, cls_tokens)): - readout_feature = self.readout_blocks[i](feature, cls_token) - processed_feature = self.reassemble_blocks[i](readout_feature) + projected_feature = self.projection_blocks[i](feature, cls_token) + processed_feature = self.reassemble_blocks[i](projected_feature) processed_features.append(processed_feature) # Fusion and progressive upsampling starting from the last processed feature diff --git a/segmentation_models_pytorch/decoders/dpt/model.py b/segmentation_models_pytorch/decoders/dpt/model.py index d0e8795e..bf98255a 100644 --- a/segmentation_models_pytorch/decoders/dpt/model.py +++ b/segmentation_models_pytorch/decoders/dpt/model.py @@ -72,7 +72,6 @@ def __init__( encoder_output_indices: Optional[list[int]] = None, decoder_intermediate_channels: Sequence[int] = (256, 512, 1024, 1024), decoder_fusion_channels: int = 256, - feature_dim: int = 256, # TODO: remove this in_channels: int = 3, classes: int = 1, activation: Optional[Union[str, Callable]] = None, From 8bcb0ed2b85a9b915e2c5fed75f49b104d6cd2f2 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 11:39:01 +0000 Subject: [PATCH 20/44] refactor + add transform --- .../models-conversions/dpt-original-to-smp.py | 125 +++++++++--------- 1 file changed, 63 insertions(+), 62 deletions(-) diff --git a/scripts/models-conversions/dpt-original-to-smp.py b/scripts/models-conversions/dpt-original-to-smp.py index 3d46aa83..277b04b6 100644 --- a/scripts/models-conversions/dpt-original-to-smp.py +++ b/scripts/models-conversions/dpt-original-to-smp.py @@ -1,106 +1,96 @@ -import segmentation_models_pytorch as smp +import cv2 import torch +import albumentations as A +import segmentation_models_pytorch as smp MODEL_WEIGHTS_PATH = r"dpt_large-ade20k-b12dca68.pt" HF_HUB_PATH = "qubvel-hf/dpt-large-ade20k" + +def get_transform(): + return A.Compose( + [ + A.LongestMaxSize(max_size=480, interpolation=cv2.INTER_CUBIC), + A.Normalize( + mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), max_pixel_value=255.0 + ), + # This is not correct transform, ideally image should resized without padding to multiple of 32, + # but we take there is no such transform in albumentations, here is closest one + A.PadIfNeeded( + min_height=None, + min_width=None, + pad_height_divisor=32, + pad_width_divisor=32, + border_mode=cv2.BORDER_CONSTANT, + value=0, + p=1, + ), + ] + ) + + if __name__ == "__main__": + # fmt: off smp_model = smp.DPT(encoder_name="tu-vit_large_patch16_384", classes=150, dynamic_img_size=True) dpt_model_dict = torch.load(MODEL_WEIGHTS_PATH, weights_only=True) for layer_index in range(0, 4): - for param in [ - "running_mean", - "running_var", - "num_batches_tracked", - "weight", - "bias", - ]: + for param in ["running_mean", "running_var", "num_batches_tracked", "weight", "bias"]: for block_index in [1, 2]: for bn_index in [1, 2]: # Assigning weights of 4th fusion layer of original model to 1st layer of SMP DPT model, # Assigning weights of 3rd fusion layer of original model to 2nd layer of SMP DPT model ... # and so on ... - # This is because order of calling fusion layers is reversed in original DPT implementation - - dpt_model_dict[ - f"decoder.fusion_blocks.{layer_index}.residual_conv_block{block_index}.batch_norm_{bn_index}.{param}" - ] = dpt_model_dict.pop( - f"scratch.refinenet{4 - layer_index}.resConfUnit{block_index}.bn{bn_index}.{param}" - ) + dpt_model_dict[f"decoder.fusion_blocks.{layer_index}.residual_conv_block{block_index}.batch_norm_{bn_index}.{param}"] = \ + dpt_model_dict.pop(f"scratch.refinenet{4 - layer_index}.resConfUnit{block_index}.bn{bn_index}.{param}") if param in ["weight", "bias"]: if param == "weight": for block_index in [1, 2]: for conv_index in [1, 2]: - dpt_model_dict[ - f"decoder.fusion_blocks.{layer_index}.residual_conv_block{block_index}.conv_{conv_index}.{param}" - ] = dpt_model_dict.pop( - f"scratch.refinenet{4 - layer_index}.resConfUnit{block_index}.conv{conv_index}.{param}" - ) - - dpt_model_dict[ - f"decoder.reassemble_blocks.{layer_index}.project_to_feature_dim.{param}" - ] = dpt_model_dict.pop(f"scratch.layer{layer_index + 1}_rn.{param}") - - dpt_model_dict[ - f"decoder.fusion_blocks.{layer_index}.project.{param}" - ] = dpt_model_dict.pop( - f"scratch.refinenet{4 - layer_index}.out_conv.{param}" - ) - - dpt_model_dict[ - f"decoder.projection_blocks.{layer_index}.project.0.{param}" - ] = dpt_model_dict.pop( - f"pretrained.act_postprocess{layer_index + 1}.0.project.0.{param}" - ) - - dpt_model_dict[ - f"decoder.reassemble_blocks.{layer_index}.project_to_out_channel.{param}" - ] = dpt_model_dict.pop( - f"pretrained.act_postprocess{layer_index + 1}.3.{param}" - ) + dpt_model_dict[f"decoder.fusion_blocks.{layer_index}.residual_conv_block{block_index}.conv_{conv_index}.{param}"] = \ + dpt_model_dict.pop(f"scratch.refinenet{4 - layer_index}.resConfUnit{block_index}.conv{conv_index}.{param}") + + dpt_model_dict[f"decoder.reassemble_blocks.{layer_index}.project_to_feature_dim.{param}"] = \ + dpt_model_dict.pop(f"scratch.layer{layer_index + 1}_rn.{param}") + + dpt_model_dict[f"decoder.fusion_blocks.{layer_index}.project.{param}"] = \ + dpt_model_dict.pop(f"scratch.refinenet{4 - layer_index}.out_conv.{param}") + + dpt_model_dict[f"decoder.projection_blocks.{layer_index}.project.0.{param}"] = \ + dpt_model_dict.pop(f"pretrained.act_postprocess{layer_index + 1}.0.project.0.{param}") + + dpt_model_dict[f"decoder.reassemble_blocks.{layer_index}.project_to_out_channel.{param}"] = \ + dpt_model_dict.pop(f"pretrained.act_postprocess{layer_index + 1}.3.{param}") if layer_index != 2: - dpt_model_dict[ - f"decoder.reassemble_blocks.{layer_index}.upsample.{param}" - ] = dpt_model_dict.pop( - f"pretrained.act_postprocess{layer_index + 1}.4.{param}" - ) + dpt_model_dict[f"decoder.reassemble_blocks.{layer_index}.upsample.{param}"] = \ + dpt_model_dict.pop(f"pretrained.act_postprocess{layer_index + 1}.4.{param}") # Changing state dict keys for segmentation head dpt_model_dict = { - ( - "segmentation_head.head" + name[len("scratch.output_conv") :] - if name.startswith("scratch.output_conv") - else name - ): parameter + name.replace("scratch.output_conv", "segmentation_head.head"): parameter for name, parameter in dpt_model_dict.items() } # Changing state dict keys for encoder layers dpt_model_dict = { - ( - "encoder.model" + name[len("pretrained.model") :] - if name.startswith("pretrained.model") - else name - ): parameter + name.replace("pretrained.model", "encoder.model"): parameter for name, parameter in dpt_model_dict.items() } - # Removing keys,value pairs associated with auxiliary head + # Removing keys, value pairs associated with auxiliary head dpt_model_dict = { name: parameter for name, parameter in dpt_model_dict.items() if not name.startswith("auxlayer") } + # fmt: on - # ------- DO NOT touch this section ------- smp_model.load_state_dict(dpt_model_dict, strict=True) - smp_model.save_pretrained(HF_HUB_PATH, push_to_hub=False) - smp_model = smp.from_pretrained(HF_HUB_PATH) + # ------- DO NOT touch this section ------- smp_model.eval() input_tensor = torch.ones((1, 3, 384, 384)) @@ -117,4 +107,15 @@ ] ) - torch.testing.assert_close(output[0, 0, :3, :3], expected_slice, atol=1e-4, rtol=1e-4) + torch.testing.assert_close( + output[0, 0, :3, :3], expected_slice, atol=1e-4, rtol=1e-4 + ) + + # Saving + transform = get_transform() + + transform.save_pretrained(HF_HUB_PATH) + smp_model.save_pretrained(HF_HUB_PATH, push_to_hub=False) + + # Re-loading to make sure everything is saved correctly + smp_model = smp.from_pretrained(HF_HUB_PATH) From 6ba67461f462189a2aa66f3d041c918d8f0ebd41 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 11:39:40 +0000 Subject: [PATCH 21/44] Fixup --- scripts/models-conversions/dpt-original-to-smp.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/models-conversions/dpt-original-to-smp.py b/scripts/models-conversions/dpt-original-to-smp.py index 277b04b6..fab1705d 100644 --- a/scripts/models-conversions/dpt-original-to-smp.py +++ b/scripts/models-conversions/dpt-original-to-smp.py @@ -5,6 +5,7 @@ MODEL_WEIGHTS_PATH = r"dpt_large-ade20k-b12dca68.pt" HF_HUB_PATH = "qubvel-hf/dpt-large-ade20k" +PUSH_TO_HUB = False def get_transform(): @@ -115,7 +116,7 @@ def get_transform(): transform = get_transform() transform.save_pretrained(HF_HUB_PATH) - smp_model.save_pretrained(HF_HUB_PATH, push_to_hub=False) + smp_model.save_pretrained(HF_HUB_PATH, push_to_hub=PUSH_TO_HUB) # Re-loading to make sure everything is saved correctly smp_model = smp.from_pretrained(HF_HUB_PATH) From 8fd8c77f7a1db8fa7ac87138f11140baa453a61c Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 11:45:26 +0000 Subject: [PATCH 22/44] Refine docs a bit --- .../decoders/dpt/model.py | 29 +++++-------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/segmentation_models_pytorch/decoders/dpt/model.py b/segmentation_models_pytorch/decoders/dpt/model.py index bf98255a..b39adc58 100644 --- a/segmentation_models_pytorch/decoders/dpt/model.py +++ b/segmentation_models_pytorch/decoders/dpt/model.py @@ -31,7 +31,14 @@ class DPT(SegmentationModel): Default is 4 encoder_weights: One of **None** (random initialization), or other pretrained weights (see table with available weights for each encoder_name) - feature_dim : The latent dimension to which the encoder features will be projected to. + encoder_output_indices: The indices of the encoder output features to use. If **None** will be sampled uniformly + across the number of blocks in encoder, e.g. if number of blocks is 4 and encoder has 20 blocks, then + encoder_output_indices will be (4, 9, 14, 19). If specified the number of indices should be equal to + encoder_depth. Default is **None**. + decoder_intermediate_channels: The number of channels for the intermediate decoder layers. Reduce if you + want to reduce the number of parameters in the decoder. Default is (256, 512, 1024, 1024). + decoder_fusion_channels: The latent dimension to which the encoder features will be projected to before fusion. + Default is 256. in_channels: Number of input channels for the model, default is 3 (RGB images) classes: Number of classes for output mask (or you can think as a number of channels of output mask) activation: An activation function to apply after the final convolution layer. @@ -138,23 +145,3 @@ def forward(self, x): return masks, labels return masks - - -def _get_feature_processing_out_channels(encoder_name: str) -> list[int]: - """ - Get the output embedding dimensions for the features after decoder processing - """ - - encoder_name = encoder_name.lower() - # Output channels for hybrid ViT encoder after feature processing - if "vit" in encoder_name and "resnet" in encoder_name: - return [256, 512, 768, 768] - - # Output channels for ViT-large,ViT-huge,ViT-giant encoders after feature processing - if "vit" in encoder_name and any( - [variant in encoder_name for variant in ["huge", "large", "giant"]] - ): - return [256, 512, 1024, 1024] - - # Output channels for ViT-base and other encoders after feature processing - return [96, 192, 384, 768] From 9bf1fd2e6f07c61c2c99f5e0e9fdb817987ab218 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 11:46:52 +0000 Subject: [PATCH 23/44] Refine docs --- segmentation_models_pytorch/decoders/dpt/model.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/segmentation_models_pytorch/decoders/dpt/model.py b/segmentation_models_pytorch/decoders/dpt/model.py index b39adc58..69a39097 100644 --- a/segmentation_models_pytorch/decoders/dpt/model.py +++ b/segmentation_models_pytorch/decoders/dpt/model.py @@ -53,17 +53,11 @@ class DPT(SegmentationModel): - activation (str): An activation function to apply "sigmoid"/"softmax" (could be **None** to return logits) kwargs: Arguments passed to the encoder class ``__init__()`` function. Applies only to ``timm`` models. Keys with - ``None`` values are pruned before passing. - allow_downsampling : Allow ViT encoder to have progressive spatial downsampling for it's representations. - Set to False for DPT as the architecture requires all encoder feature outputs to have the same spatial shape. - allow_output_stride_not_power_of_two : Allow ViT encoders with output_stride not being a power of 2. This - is set False for DPT as the architecture requires the encoder output features to have an output stride of - [1/32,1/16,1/8,1/4] + ``None`` values are pruned before passing. Specify ``dynamic_img_size=True`` to allow the model to handle images of different sizes. Returns: ``torch.nn.Module``: DPT - """ _is_torch_scriptable = False From 0e9170f14f63237ad049682742834b3a4ec290b4 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 12:25:53 +0000 Subject: [PATCH 24/44] Refine model size a bit and docs --- segmentation_models_pytorch/decoders/dpt/model.py | 7 +++++++ segmentation_models_pytorch/encoders/timm_vit.py | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/segmentation_models_pytorch/decoders/dpt/model.py b/segmentation_models_pytorch/decoders/dpt/model.py index 69a39097..94bd4048 100644 --- a/segmentation_models_pytorch/decoders/dpt/model.py +++ b/segmentation_models_pytorch/decoders/dpt/model.py @@ -23,6 +23,13 @@ class DPT(SegmentationModel): field at every stage. These properties allow the dense vision transformer to provide finer-grained and more globally coherent predictions when compared to fully-convolutional networks + Note: + Since this model uses a Vision Transformer backbone, it typically requires a fixed input image size. + To handle variable input sizes, you can set `dynamic_img_size=True` in the model initialization + (if supported by the specific `timm` encoder). You can check if an encoder requires fixed size + using `model.encoder.is_fixed_input_size`, and get the required input dimensions from + `model.encoder.input_size`, however it's no guarantee that information is available. + Args: encoder_name: Name of the classification model that will be used as an encoder (a.k.a backbone) to extract features of different spatial resolution diff --git a/segmentation_models_pytorch/encoders/timm_vit.py b/segmentation_models_pytorch/encoders/timm_vit.py index 1595c41f..f52b4b10 100644 --- a/segmentation_models_pytorch/encoders/timm_vit.py +++ b/segmentation_models_pytorch/encoders/timm_vit.py @@ -105,6 +105,12 @@ def __init__( encoder_kwargs = _merge_kwargs_no_duplicates(encoder_kwargs, kwargs) self.model = timm.create_model(name, **encoder_kwargs) + if not hasattr(self.model, "forward_intermediates"): + raise ValueError( + f"Encoder `{name}` does not support `forward_intermediates` for feature extraction. " + f"Please update `timm` or use another encoder." + ) + # Get all the necessary information about the model feature_info = self.model.feature_info @@ -131,6 +137,14 @@ def __init__( self.out_channels = [feature_info[i]["num_chs"] for i in output_indices] self.has_class_token = getattr(self.model, "has_class_token", False) + @property + def is_fixed_input_size(self) -> bool: + return self.model.pretrained_cfg.get("fixed_input_size", False) + + @property + def input_size(self) -> int: + return self.model.pretrained_cfg.get("input_size", None) + def _forward_with_cls_token( self, x: torch.Tensor ) -> tuple[list[torch.Tensor], list[torch.Tensor]]: From a0aa5a8c762353dad45895eb7c8a745eaa8216ff Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 21:47:12 +0000 Subject: [PATCH 25/44] Add to docs --- docs/encoders_dpt.rst | 462 ++++++++++++++++++++++++++++++++++++++++++ docs/models.rst | 11 + 2 files changed, 473 insertions(+) create mode 100644 docs/encoders_dpt.rst diff --git a/docs/encoders_dpt.rst b/docs/encoders_dpt.rst new file mode 100644 index 00000000..31b16d0f --- /dev/null +++ b/docs/encoders_dpt.rst @@ -0,0 +1,462 @@ +.. _dpt-encoders: + +DPT Encoders +============ + +This is a list of Vision Transformer encoders that are compatible with the DPT architecture +These encoders have been tested and verified to work with DPT models. +While other Vision Transformer encoders from timm may also be compatible, the ones listed below are tested to work properly. + +.. list-table:: Encoder Name + :widths: 100 + :header-rows: 0 + + * - tu-fastvit_ma36.apple_dist_in1k + * - tu-fastvit_ma36.apple_in1k + * - tu-fastvit_mci0.apple_mclip + * - tu-fastvit_mci1.apple_mclip + * - tu-fastvit_mci2.apple_mclip + * - tu-fastvit_s12.apple_dist_in1k + * - tu-fastvit_s12.apple_in1k + * - tu-fastvit_sa12.apple_dist_in1k + * - tu-fastvit_sa12.apple_in1k + * - tu-fastvit_sa24.apple_dist_in1k + * - tu-fastvit_sa24.apple_in1k + * - tu-fastvit_sa36.apple_dist_in1k + * - tu-fastvit_sa36.apple_in1k + * - tu-fastvit_t8.apple_dist_in1k + * - tu-fastvit_t8.apple_in1k + * - tu-fastvit_t12.apple_dist_in1k + * - tu-fastvit_t12.apple_in1k + * - tu-flexivit_base.300ep_in1k + * - tu-flexivit_base.300ep_in21k + * - tu-flexivit_base.600ep_in1k + * - tu-flexivit_base.1000ep_in21k + * - tu-flexivit_base.1200ep_in1k + * - tu-flexivit_base.patch16_in21k + * - tu-flexivit_base.patch30_in21k + * - tu-flexivit_large.300ep_in1k + * - tu-flexivit_large.600ep_in1k + * - tu-flexivit_large.1200ep_in1k + * - tu-flexivit_small.300ep_in1k + * - tu-flexivit_small.600ep_in1k + * - tu-flexivit_small.1200ep_in1k + * - tu-maxvit_base_tf_224.in1k + * - tu-maxvit_base_tf_224.in21k + * - tu-maxvit_base_tf_384.in1k + * - tu-maxvit_base_tf_384.in21k_ft_in1k + * - tu-maxvit_base_tf_512.in1k + * - tu-maxvit_base_tf_512.in21k_ft_in1k + * - tu-maxvit_large_tf_224.in1k + * - tu-maxvit_large_tf_224.in21k + * - tu-maxvit_large_tf_384.in1k + * - tu-maxvit_large_tf_384.in21k_ft_in1k + * - tu-maxvit_large_tf_512.in1k + * - tu-maxvit_large_tf_512.in21k_ft_in1k + * - tu-maxvit_nano_rw_256.sw_in1k + * - tu-maxvit_rmlp_base_rw_224.sw_in12k + * - tu-maxvit_rmlp_base_rw_224.sw_in12k_ft_in1k + * - tu-maxvit_rmlp_base_rw_384.sw_in12k_ft_in1k + * - tu-maxvit_rmlp_nano_rw_256.sw_in1k + * - tu-maxvit_rmlp_pico_rw_256.sw_in1k + * - tu-maxvit_rmlp_small_rw_224.sw_in1k + * - tu-maxvit_rmlp_tiny_rw_256.sw_in1k + * - tu-maxvit_small_tf_224.in1k + * - tu-maxvit_small_tf_384.in1k + * - tu-maxvit_small_tf_512.in1k + * - tu-maxvit_tiny_rw_224.sw_in1k + * - tu-maxvit_tiny_tf_224.in1k + * - tu-maxvit_tiny_tf_384.in1k + * - tu-maxvit_tiny_tf_512.in1k + * - tu-maxvit_xlarge_tf_224.in21k + * - tu-maxvit_xlarge_tf_384.in21k_ft_in1k + * - tu-maxvit_xlarge_tf_512.in21k_ft_in1k + * - tu-maxxvit_rmlp_nano_rw_256.sw_in1k + * - tu-maxxvit_rmlp_small_rw_256.sw_in1k + * - tu-maxxvitv2_nano_rw_256.sw_in1k + * - tu-maxxvitv2_rmlp_base_rw_224.sw_in12k + * - tu-maxxvitv2_rmlp_base_rw_224.sw_in12k_ft_in1k + * - tu-maxxvitv2_rmlp_base_rw_384.sw_in12k_ft_in1k + * - tu-mobilevit_s.cvnets_in1k + * - tu-mobilevit_xs.cvnets_in1k + * - tu-mobilevit_xxs.cvnets_in1k + * - tu-mobilevitv2_050.cvnets_in1k + * - tu-mobilevitv2_075.cvnets_in1k + * - tu-mobilevitv2_100.cvnets_in1k + * - tu-mobilevitv2_125.cvnets_in1k + * - tu-mobilevitv2_150.cvnets_in1k + * - tu-mobilevitv2_150.cvnets_in22k_ft_in1k + * - tu-mobilevitv2_150.cvnets_in22k_ft_in1k_384 + * - tu-mobilevitv2_175.cvnets_in1k + * - tu-mobilevitv2_175.cvnets_in22k_ft_in1k + * - tu-mobilevitv2_175.cvnets_in22k_ft_in1k_384 + * - tu-mobilevitv2_200.cvnets_in1k + * - tu-mobilevitv2_200.cvnets_in22k_ft_in1k + * - tu-mobilevitv2_200.cvnets_in22k_ft_in1k_384 + * - tu-mvitv2_base.fb_in1k + * - tu-mvitv2_base_cls.fb_inw21k + * - tu-mvitv2_huge_cls.fb_inw21k + * - tu-mvitv2_large.fb_in1k + * - tu-mvitv2_large_cls.fb_inw21k + * - tu-mvitv2_small.fb_in1k + * - tu-mvitv2_tiny.fb_in1k + * - tu-samvit_base_patch16.sa1b + * - tu-samvit_huge_patch16.sa1b + * - tu-samvit_large_patch16.sa1b + * - tu-test_vit2.r160_in1k + * - tu-test_vit3.r160_in1k + * - tu-test_vit.r160_in1k + * - tu-vit_base_mci_224.apple_mclip + * - tu-vit_base_mci_224.apple_mclip_lt + * - tu-vit_base_patch8_224.augreg2_in21k_ft_in1k + * - tu-vit_base_patch8_224.augreg_in21k + * - tu-vit_base_patch8_224.augreg_in21k_ft_in1k + * - tu-vit_base_patch8_224.dino + * - tu-vit_base_patch16_224.augreg2_in21k_ft_in1k + * - tu-vit_base_patch16_224.augreg_in1k + * - tu-vit_base_patch16_224.augreg_in21k + * - tu-vit_base_patch16_224.augreg_in21k_ft_in1k + * - tu-vit_base_patch16_224.dino + * - tu-vit_base_patch16_224.mae + * - tu-vit_base_patch16_224.orig_in21k + * - tu-vit_base_patch16_224.orig_in21k_ft_in1k + * - tu-vit_base_patch16_224.sam_in1k + * - tu-vit_base_patch16_224_miil.in21k + * - tu-vit_base_patch16_224_miil.in21k_ft_in1k + * - tu-vit_base_patch16_384.augreg_in1k + * - tu-vit_base_patch16_384.augreg_in21k_ft_in1k + * - tu-vit_base_patch16_384.orig_in21k_ft_in1k + * - tu-vit_base_patch16_clip_224.datacompxl + * - tu-vit_base_patch16_clip_224.dfn2b + * - tu-vit_base_patch16_clip_224.laion2b + * - tu-vit_base_patch16_clip_224.laion2b_ft_in1k + * - tu-vit_base_patch16_clip_224.laion2b_ft_in12k + * - tu-vit_base_patch16_clip_224.laion2b_ft_in12k_in1k + * - tu-vit_base_patch16_clip_224.laion400m_e32 + * - tu-vit_base_patch16_clip_224.metaclip_2pt5b + * - tu-vit_base_patch16_clip_224.metaclip_400m + * - tu-vit_base_patch16_clip_224.openai + * - tu-vit_base_patch16_clip_224.openai_ft_in1k + * - tu-vit_base_patch16_clip_224.openai_ft_in12k + * - tu-vit_base_patch16_clip_224.openai_ft_in12k_in1k + * - tu-vit_base_patch16_clip_384.laion2b_ft_in1k + * - tu-vit_base_patch16_clip_384.laion2b_ft_in12k_in1k + * - tu-vit_base_patch16_clip_384.openai_ft_in1k + * - tu-vit_base_patch16_clip_384.openai_ft_in12k_in1k + * - tu-vit_base_patch16_clip_quickgelu_224.metaclip_2pt5b + * - tu-vit_base_patch16_clip_quickgelu_224.metaclip_400m + * - tu-vit_base_patch16_clip_quickgelu_224.openai + * - tu-vit_base_patch16_plus_clip_240.laion400m_e32 + * - tu-vit_base_patch16_rope_reg1_gap_256.sbb_in1k + * - tu-vit_base_patch16_rpn_224.sw_in1k + * - tu-vit_base_patch16_siglip_224.v2_webli + * - tu-vit_base_patch16_siglip_224.webli + * - tu-vit_base_patch16_siglip_256.v2_webli + * - tu-vit_base_patch16_siglip_256.webli + * - tu-vit_base_patch16_siglip_256.webli_i18n + * - tu-vit_base_patch16_siglip_384.v2_webli + * - tu-vit_base_patch16_siglip_384.webli + * - tu-vit_base_patch16_siglip_512.v2_webli + * - tu-vit_base_patch16_siglip_512.webli + * - tu-vit_base_patch16_siglip_gap_224.v2_webli + * - tu-vit_base_patch16_siglip_gap_224.webli + * - tu-vit_base_patch16_siglip_gap_256.v2_webli + * - tu-vit_base_patch16_siglip_gap_256.webli + * - tu-vit_base_patch16_siglip_gap_256.webli_i18n + * - tu-vit_base_patch16_siglip_gap_384.v2_webli + * - tu-vit_base_patch16_siglip_gap_384.webli + * - tu-vit_base_patch16_siglip_gap_512.v2_webli + * - tu-vit_base_patch16_siglip_gap_512.webli + * - tu-vit_base_patch32_224.augreg_in1k + * - tu-vit_base_patch32_224.augreg_in21k + * - tu-vit_base_patch32_224.augreg_in21k_ft_in1k + * - tu-vit_base_patch32_224.orig_in21k + * - tu-vit_base_patch32_224.sam_in1k + * - tu-vit_base_patch32_384.augreg_in1k + * - tu-vit_base_patch32_384.augreg_in21k_ft_in1k + * - tu-vit_base_patch32_clip_224.datacompxl + * - tu-vit_base_patch32_clip_224.laion2b + * - tu-vit_base_patch32_clip_224.laion2b_ft_in1k + * - tu-vit_base_patch32_clip_224.laion2b_ft_in12k_in1k + * - tu-vit_base_patch32_clip_224.laion400m_e32 + * - tu-vit_base_patch32_clip_224.metaclip_2pt5b + * - tu-vit_base_patch32_clip_224.metaclip_400m + * - tu-vit_base_patch32_clip_224.openai + * - tu-vit_base_patch32_clip_224.openai_ft_in1k + * - tu-vit_base_patch32_clip_256.datacompxl + * - tu-vit_base_patch32_clip_384.laion2b_ft_in12k_in1k + * - tu-vit_base_patch32_clip_384.openai_ft_in12k_in1k + * - tu-vit_base_patch32_clip_448.laion2b_ft_in12k_in1k + * - tu-vit_base_patch32_clip_quickgelu_224.laion400m_e32 + * - tu-vit_base_patch32_clip_quickgelu_224.metaclip_2pt5b + * - tu-vit_base_patch32_clip_quickgelu_224.metaclip_400m + * - tu-vit_base_patch32_clip_quickgelu_224.openai + * - tu-vit_base_patch32_siglip_256.v2_webli + * - tu-vit_base_patch32_siglip_gap_256.v2_webli + * - tu-vit_base_r50_s16_224.orig_in21k + * - tu-vit_base_r50_s16_384.orig_in21k_ft_in1k + * - tu-vit_betwixt_patch16_reg1_gap_256.sbb_in1k + * - tu-vit_betwixt_patch16_reg4_gap_256.sbb2_e200_in12k + * - tu-vit_betwixt_patch16_reg4_gap_256.sbb2_e200_in12k_ft_in1k + * - tu-vit_betwixt_patch16_reg4_gap_256.sbb_in1k + * - tu-vit_betwixt_patch16_reg4_gap_256.sbb_in12k + * - tu-vit_betwixt_patch16_reg4_gap_256.sbb_in12k_ft_in1k + * - tu-vit_betwixt_patch16_reg4_gap_384.sbb2_e200_in12k_ft_in1k + * - tu-vit_betwixt_patch16_rope_reg4_gap_256.sbb_in1k + * - tu-vit_betwixt_patch32_clip_224.tinyclip_laion400m + * - tu-vit_giant_patch16_gap_224.in22k_ijepa + * - tu-vit_giantopt_patch16_siglip_256.v2_webli + * - tu-vit_giantopt_patch16_siglip_384.v2_webli + * - tu-vit_giantopt_patch16_siglip_gap_256.v2_webli + * - tu-vit_giantopt_patch16_siglip_gap_384.v2_webli + * - tu-vit_huge_patch16_gap_448.in1k_ijepa + * - tu-vit_large_patch16_224.augreg_in21k + * - tu-vit_large_patch16_224.augreg_in21k_ft_in1k + * - tu-vit_large_patch16_224.mae + * - tu-vit_large_patch16_224.orig_in21k + * - tu-vit_large_patch16_384.augreg_in21k_ft_in1k + * - tu-vit_large_patch16_siglip_256.v2_webli + * - tu-vit_large_patch16_siglip_256.webli + * - tu-vit_large_patch16_siglip_384.v2_webli + * - tu-vit_large_patch16_siglip_384.webli + * - tu-vit_large_patch16_siglip_512.v2_webli + * - tu-vit_large_patch16_siglip_gap_256.v2_webli + * - tu-vit_large_patch16_siglip_gap_256.webli + * - tu-vit_large_patch16_siglip_gap_384.v2_webli + * - tu-vit_large_patch16_siglip_gap_384.webli + * - tu-vit_large_patch16_siglip_gap_512.v2_webli + * - tu-vit_large_patch32_224.orig_in21k + * - tu-vit_large_patch32_384.orig_in21k_ft_in1k + * - tu-vit_large_r50_s32_224.augreg_in21k + * - tu-vit_large_r50_s32_224.augreg_in21k_ft_in1k + * - tu-vit_large_r50_s32_384.augreg_in21k_ft_in1k + * - tu-vit_little_patch16_reg1_gap_256.sbb_in12k + * - tu-vit_little_patch16_reg1_gap_256.sbb_in12k_ft_in1k + * - tu-vit_little_patch16_reg4_gap_256.sbb_in1k + * - tu-vit_medium_patch16_clip_224.tinyclip_yfcc15m + * - tu-vit_medium_patch16_gap_240.sw_in12k + * - tu-vit_medium_patch16_gap_256.sw_in12k_ft_in1k + * - tu-vit_medium_patch16_gap_384.sw_in12k_ft_in1k + * - tu-vit_medium_patch16_reg1_gap_256.sbb_in1k + * - tu-vit_medium_patch16_reg4_gap_256.sbb_in1k + * - tu-vit_medium_patch16_reg4_gap_256.sbb_in12k + * - tu-vit_medium_patch16_reg4_gap_256.sbb_in12k_ft_in1k + * - tu-vit_medium_patch16_rope_reg1_gap_256.sbb_in1k + * - tu-vit_medium_patch32_clip_224.tinyclip_laion400m + * - tu-vit_mediumd_patch16_reg4_gap_256.sbb2_e200_in12k + * - tu-vit_mediumd_patch16_reg4_gap_256.sbb2_e200_in12k_ft_in1k + * - tu-vit_mediumd_patch16_reg4_gap_256.sbb_in12k + * - tu-vit_mediumd_patch16_reg4_gap_256.sbb_in12k_ft_in1k + * - tu-vit_mediumd_patch16_reg4_gap_384.sbb2_e200_in12k_ft_in1k + * - tu-vit_mediumd_patch16_rope_reg1_gap_256.sbb_in1k + * - tu-vit_pwee_patch16_reg1_gap_256.sbb_in1k + * - tu-vit_relpos_base_patch16_224.sw_in1k + * - tu-vit_relpos_base_patch16_clsgap_224.sw_in1k + * - tu-vit_relpos_base_patch32_plus_rpn_256.sw_in1k + * - tu-vit_relpos_medium_patch16_224.sw_in1k + * - tu-vit_relpos_medium_patch16_cls_224.sw_in1k + * - tu-vit_relpos_medium_patch16_rpn_224.sw_in1k + * - tu-vit_relpos_small_patch16_224.sw_in1k + * - tu-vit_small_patch8_224.dino + * - tu-vit_small_patch16_224.augreg_in1k + * - tu-vit_small_patch16_224.augreg_in21k + * - tu-vit_small_patch16_224.augreg_in21k_ft_in1k + * - tu-vit_small_patch16_224.dino + * - tu-vit_small_patch16_384.augreg_in1k + * - tu-vit_small_patch16_384.augreg_in21k_ft_in1k + * - tu-vit_small_patch32_224.augreg_in21k + * - tu-vit_small_patch32_224.augreg_in21k_ft_in1k + * - tu-vit_small_patch32_384.augreg_in21k_ft_in1k + * - tu-vit_small_r26_s32_224.augreg_in21k + * - tu-vit_small_r26_s32_224.augreg_in21k_ft_in1k + * - tu-vit_small_r26_s32_384.augreg_in21k_ft_in1k + * - tu-vit_so150m2_patch16_reg1_gap_256.sbb_e200_in12k + * - tu-vit_so150m2_patch16_reg1_gap_256.sbb_e200_in12k_ft_in1k + * - tu-vit_so150m2_patch16_reg1_gap_384.sbb_e200_in12k_ft_in1k + * - tu-vit_so150m2_patch16_reg1_gap_448.sbb_e200_in12k_ft_in1k + * - tu-vit_so150m_patch16_reg4_gap_256.sbb_e250_in12k + * - tu-vit_so150m_patch16_reg4_gap_256.sbb_e250_in12k_ft_in1k + * - tu-vit_so150m_patch16_reg4_gap_384.sbb_e250_in12k_ft_in1k + * - tu-vit_so400m_patch16_siglip_256.v2_webli + * - tu-vit_so400m_patch16_siglip_256.webli_i18n + * - tu-vit_so400m_patch16_siglip_384.v2_webli + * - tu-vit_so400m_patch16_siglip_512.v2_webli + * - tu-vit_so400m_patch16_siglip_gap_256.v2_webli + * - tu-vit_so400m_patch16_siglip_gap_256.webli_i18n + * - tu-vit_so400m_patch16_siglip_gap_384.v2_webli + * - tu-vit_so400m_patch16_siglip_gap_512.v2_webli + * - tu-vit_srelpos_medium_patch16_224.sw_in1k + * - tu-vit_srelpos_small_patch16_224.sw_in1k + * - tu-vit_tiny_patch16_224.augreg_in21k + * - tu-vit_tiny_patch16_224.augreg_in21k_ft_in1k + * - tu-vit_tiny_patch16_384.augreg_in21k_ft_in1k + * - tu-vit_tiny_r_s16_p8_224.augreg_in21k + * - tu-vit_tiny_r_s16_p8_224.augreg_in21k_ft_in1k + * - tu-vit_tiny_r_s16_p8_384.augreg_in21k_ft_in1k + * - tu-vit_wee_patch16_reg1_gap_256.sbb_in1k + * - tu-vit_xsmall_patch16_clip_224.tinyclip_yfcc15m + * - tu-vitamin_base_224.datacomp1b_clip + * - tu-vitamin_base_224.datacomp1b_clip_ltt + * - tu-vitamin_large2_224.datacomp1b_clip + * - tu-vitamin_large2_256.datacomp1b_clip + * - tu-vitamin_large2_336.datacomp1b_clip + * - tu-vitamin_large2_384.datacomp1b_clip + * - tu-vitamin_large_224.datacomp1b_clip + * - tu-vitamin_large_256.datacomp1b_clip + * - tu-vitamin_large_336.datacomp1b_clip + * - tu-vitamin_large_384.datacomp1b_clip + * - tu-vitamin_small_224.datacomp1b_clip + * - tu-vitamin_small_224.datacomp1b_clip_ltt + * - tu-vitamin_xlarge_256.datacomp1b_clip + * - tu-vitamin_xlarge_336.datacomp1b_clip + * - tu-vitamin_xlarge_384.datacomp1b_clip + * - tu-hiera_small_abswin_256.sbb2_e200_in12k + * - tu-hiera_small_abswin_256.sbb2_e200_in12k_ft_in1k + * - tu-hiera_small_abswin_256.sbb2_pd_e200_in12k + * - tu-hiera_small_abswin_256.sbb2_pd_e200_in12k_ft_in1k + * - tu-swin_base_patch4_window7_224.ms_in1k + * - tu-swin_base_patch4_window7_224.ms_in22k + * - tu-swin_base_patch4_window7_224.ms_in22k_ft_in1k + * - tu-swin_base_patch4_window12_384.ms_in1k + * - tu-swin_base_patch4_window12_384.ms_in22k + * - tu-swin_base_patch4_window12_384.ms_in22k_ft_in1k + * - tu-swin_large_patch4_window7_224.ms_in22k + * - tu-swin_large_patch4_window7_224.ms_in22k_ft_in1k + * - tu-swin_large_patch4_window12_384.ms_in22k + * - tu-swin_large_patch4_window12_384.ms_in22k_ft_in1k + * - tu-swin_s3_base_224.ms_in1k + * - tu-swin_s3_small_224.ms_in1k + * - tu-swin_s3_tiny_224.ms_in1k + * - tu-swin_small_patch4_window7_224.ms_in1k + * - tu-swin_small_patch4_window7_224.ms_in22k + * - tu-swin_small_patch4_window7_224.ms_in22k_ft_in1k + * - tu-swin_tiny_patch4_window7_224.ms_in1k + * - tu-swin_tiny_patch4_window7_224.ms_in22k + * - tu-swin_tiny_patch4_window7_224.ms_in22k_ft_in1k + * - tu-swinv2_base_window8_256.ms_in1k + * - tu-swinv2_base_window12_192.ms_in22k + * - tu-swinv2_base_window12to16_192to256.ms_in22k_ft_in1k + * - tu-swinv2_base_window12to24_192to384.ms_in22k_ft_in1k + * - tu-swinv2_base_window16_256.ms_in1k + * - tu-swinv2_cr_small_224.sw_in1k + * - tu-swinv2_cr_small_ns_224.sw_in1k + * - tu-swinv2_cr_tiny_ns_224.sw_in1k + * - tu-swinv2_large_window12_192.ms_in22k + * - tu-swinv2_large_window12to16_192to256.ms_in22k_ft_in1k + * - tu-swinv2_large_window12to24_192to384.ms_in22k_ft_in1k + * - tu-swinv2_small_window8_256.ms_in1k + * - tu-swinv2_small_window16_256.ms_in1k + * - tu-swinv2_tiny_window8_256.ms_in1k + * - tu-swinv2_tiny_window16_256.ms_in1k + * - tu-efficientformer_l1.snap_dist_in1k + * - tu-efficientformer_l3.snap_dist_in1k + * - tu-efficientformer_l7.snap_dist_in1k + * - tu-beit_base_patch16_224.in22k_ft_in22k + * - tu-beit_base_patch16_224.in22k_ft_in22k_in1k + * - tu-beit_base_patch16_384.in22k_ft_in22k_in1k + * - tu-beit_large_patch16_224.in22k_ft_in22k + * - tu-beit_large_patch16_224.in22k_ft_in22k_in1k + * - tu-beit_large_patch16_384.in22k_ft_in22k_in1k + * - tu-beit_large_patch16_512.in22k_ft_in22k_in1k + * - tu-beitv2_base_patch16_224.in1k_ft_in1k + * - tu-beitv2_base_patch16_224.in1k_ft_in22k + * - tu-beitv2_base_patch16_224.in1k_ft_in22k_in1k + * - tu-beitv2_large_patch16_224.in1k_ft_in1k + * - tu-beitv2_large_patch16_224.in1k_ft_in22k + * - tu-beitv2_large_patch16_224.in1k_ft_in22k_in1k + * - tu-cait_m36_384.fb_dist_in1k + * - tu-cait_m48_448.fb_dist_in1k + * - tu-cait_s24_224.fb_dist_in1k + * - tu-cait_s24_384.fb_dist_in1k + * - tu-cait_s36_384.fb_dist_in1k + * - tu-cait_xs24_384.fb_dist_in1k + * - tu-cait_xxs24_224.fb_dist_in1k + * - tu-cait_xxs24_384.fb_dist_in1k + * - tu-cait_xxs36_224.fb_dist_in1k + * - tu-cait_xxs36_384.fb_dist_in1k + * - tu-coatnet_0_rw_224.sw_in1k + * - tu-coatnet_1_rw_224.sw_in1k + * - tu-coatnet_2_rw_224.sw_in12k + * - tu-coatnet_2_rw_224.sw_in12k_ft_in1k + * - tu-coatnet_3_rw_224.sw_in12k + * - tu-coatnet_bn_0_rw_224.sw_in1k + * - tu-coatnet_nano_rw_224.sw_in1k + * - tu-coatnet_rmlp_1_rw2_224.sw_in12k + * - tu-coatnet_rmlp_1_rw2_224.sw_in12k_ft_in1k + * - tu-coatnet_rmlp_1_rw_224.sw_in1k + * - tu-coatnet_rmlp_2_rw_224.sw_in1k + * - tu-coatnet_rmlp_2_rw_224.sw_in12k + * - tu-coatnet_rmlp_2_rw_224.sw_in12k_ft_in1k + * - tu-coatnet_rmlp_2_rw_384.sw_in12k_ft_in1k + * - tu-coatnet_rmlp_nano_rw_224.sw_in1k + * - tu-deit3_base_patch16_224.fb_in1k + * - tu-deit3_base_patch16_224.fb_in22k_ft_in1k + * - tu-deit3_base_patch16_384.fb_in1k + * - tu-deit3_base_patch16_384.fb_in22k_ft_in1k + * - tu-deit3_large_patch16_224.fb_in1k + * - tu-deit3_large_patch16_224.fb_in22k_ft_in1k + * - tu-deit3_large_patch16_384.fb_in1k + * - tu-deit3_large_patch16_384.fb_in22k_ft_in1k + * - tu-deit3_medium_patch16_224.fb_in1k + * - tu-deit3_medium_patch16_224.fb_in22k_ft_in1k + * - tu-deit3_small_patch16_224.fb_in1k + * - tu-deit3_small_patch16_224.fb_in22k_ft_in1k + * - tu-deit3_small_patch16_384.fb_in1k + * - tu-deit3_small_patch16_384.fb_in22k_ft_in1k + * - tu-deit_base_distilled_patch16_224.fb_in1k + * - tu-deit_base_distilled_patch16_384.fb_in1k + * - tu-deit_base_patch16_224.fb_in1k + * - tu-deit_base_patch16_384.fb_in1k + * - tu-deit_small_distilled_patch16_224.fb_in1k + * - tu-deit_small_patch16_224.fb_in1k + * - tu-deit_tiny_distilled_patch16_224.fb_in1k + * - tu-deit_tiny_patch16_224.fb_in1k + * - tu-regnety_160.deit_in1k + * - tu-twins_pcpvt_base.in1k + * - tu-twins_pcpvt_large.in1k + * - tu-twins_pcpvt_small.in1k + * - tu-twins_svt_base.in1k + * - tu-twins_svt_large.in1k + * - tu-twins_svt_small.in1k + * - tu-xcit_large_24_p8_224.fb_dist_in1k + * - tu-xcit_large_24_p8_224.fb_in1k + * - tu-xcit_large_24_p8_384.fb_dist_in1k + * - tu-xcit_large_24_p16_224.fb_dist_in1k + * - tu-xcit_large_24_p16_224.fb_in1k + * - tu-xcit_large_24_p16_384.fb_dist_in1k + * - tu-xcit_medium_24_p8_224.fb_dist_in1k + * - tu-xcit_medium_24_p8_224.fb_in1k + * - tu-xcit_medium_24_p8_384.fb_dist_in1k + * - tu-xcit_medium_24_p16_224.fb_dist_in1k + * - tu-xcit_medium_24_p16_224.fb_in1k + * - tu-xcit_medium_24_p16_384.fb_dist_in1k + * - tu-xcit_nano_12_p8_224.fb_dist_in1k + * - tu-xcit_nano_12_p8_224.fb_in1k + * - tu-xcit_nano_12_p8_384.fb_dist_in1k + * - tu-xcit_nano_12_p16_224.fb_dist_in1k + * - tu-xcit_nano_12_p16_224.fb_in1k + * - tu-xcit_nano_12_p16_384.fb_dist_in1k + * - tu-xcit_small_12_p8_224.fb_dist_in1k + * - tu-xcit_small_12_p8_224.fb_in1k + * - tu-xcit_small_12_p8_384.fb_dist_in1k + * - tu-xcit_small_12_p16_224.fb_dist_in1k + * - tu-xcit_small_12_p16_224.fb_in1k + * - tu-xcit_small_12_p16_384.fb_dist_in1k + * - tu-xcit_small_24_p8_224.fb_dist_in1k + * - tu-xcit_small_24_p8_224.fb_in1k + * - tu-xcit_small_24_p8_384.fb_dist_in1k + * - tu-xcit_small_24_p16_224.fb_dist_in1k + * - tu-xcit_small_24_p16_224.fb_in1k + * - tu-xcit_small_24_p16_384.fb_dist_in1k + * - tu-xcit_tiny_12_p8_224.fb_dist_in1k + * - tu-xcit_tiny_12_p8_224.fb_in1k + * - tu-xcit_tiny_12_p8_384.fb_dist_in1k + * - tu-xcit_tiny_12_p16_224.fb_dist_in1k + * - tu-xcit_tiny_12_p16_224.fb_in1k + * - tu-xcit_tiny_12_p16_384.fb_dist_in1k + * - tu-xcit_tiny_24_p8_224.fb_dist_in1k + * - tu-xcit_tiny_24_p8_224.fb_in1k + * - tu-xcit_tiny_24_p8_384.fb_dist_in1k + * - tu-xcit_tiny_24_p16_224.fb_dist_in1k + * - tu-xcit_tiny_24_p16_224.fb_in1k + * - tu-xcit_tiny_24_p16_384.fb_dist_in1k \ No newline at end of file diff --git a/docs/models.rst b/docs/models.rst index c2037afb..f1a970ce 100644 --- a/docs/models.rst +++ b/docs/models.rst @@ -81,3 +81,14 @@ Segformer ~~~~~~~~~ .. autoclass:: segmentation_models_pytorch.Segformer + +.. _dpt: + +DPT +~~~ + +.. note:: + + See full list of DPT-compatible timm encoders in :ref:`dpt-encoders`. + +.. autoclass:: segmentation_models_pytorch.DPT From 6cfd3be403fc8d367920bc1671581fa1d62f9314 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 22:04:09 +0000 Subject: [PATCH 26/44] Add note --- docs/models.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/models.rst b/docs/models.rst index f1a970ce..ab04bb5e 100644 --- a/docs/models.rst +++ b/docs/models.rst @@ -91,4 +91,8 @@ DPT See full list of DPT-compatible timm encoders in :ref:`dpt-encoders`. +.. note:: + + For some encoders, the model requires ``dynamic_img_size=True`` to be passed in order to work with resolutions different from what the encoder was trained for. + .. autoclass:: segmentation_models_pytorch.DPT From d4b162d7939bf4aa96c88725e6dca5519eecce8b Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 22:05:50 +0000 Subject: [PATCH 27/44] Remove txt --- docs/timm_encoders.txt | 1474 ---------------------------------------- 1 file changed, 1474 deletions(-) delete mode 100644 docs/timm_encoders.txt diff --git a/docs/timm_encoders.txt b/docs/timm_encoders.txt deleted file mode 100644 index 13cce112..00000000 --- a/docs/timm_encoders.txt +++ /dev/null @@ -1,1474 +0,0 @@ -+---------------------------------------+------------------+-------------------+ -| Encoder name | Support dilation | Supported for DPT | -+=======================================+==================+-------------------+ -| bat_resnext26ts | ✅ | | -+---------------------------------------+------------------+-------------------+ -| botnet26t_256 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| botnet50ts_256 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| coatnet_0_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_0_rw_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_1_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_1_rw_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_2_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_2_rw_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_3_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_3_rw_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_4_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_5_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_bn_0_rw_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_nano_cc_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_nano_rw_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_pico_rw_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_rmlp_0_rw_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_rmlp_1_rw2_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_rmlp_1_rw_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_rmlp_2_rw_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_rmlp_2_rw_384 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_rmlp_3_rw_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnet_rmlp_nano_rw_224 | | | -+---------------------------------------+------------------+-------------------+ -| coatnext_nano_rw_224 | | | -+---------------------------------------+------------------+-------------------+ -| cs3darknet_focus_l | ✅ | | -+---------------------------------------+------------------+-------------------+ -| cs3darknet_focus_m | ✅ | | -+---------------------------------------+------------------+-------------------+ -| cs3darknet_focus_s | ✅ | | -+---------------------------------------+------------------+-------------------+ -| cs3darknet_focus_x | ✅ | | -+---------------------------------------+------------------+-------------------+ -| cs3darknet_l | ✅ | | -+---------------------------------------+------------------+-------------------+ -| cs3darknet_m | ✅ | | -+---------------------------------------+------------------+-------------------+ -| cs3darknet_s | ✅ | | -+---------------------------------------+------------------+-------------------+ -| cs3darknet_x | ✅ | | -+---------------------------------------+------------------+-------------------+ -| cs3edgenet_x | ✅ | | -+---------------------------------------+------------------+-------------------+ -| cs3se_edgenet_x | ✅ | | -+---------------------------------------+------------------+-------------------+ -| cs3sedarknet_l | ✅ | | -+---------------------------------------+------------------+-------------------+ -| cs3sedarknet_x | ✅ | | -+---------------------------------------+------------------+-------------------+ -| cs3sedarknet_xdw | ✅ | | -+---------------------------------------+------------------+-------------------+ -| cspresnet50 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| cspresnet50d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| cspresnet50w | ✅ | | -+---------------------------------------+------------------+-------------------+ -| cspresnext50 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| densenet121 | | | -+---------------------------------------+------------------+-------------------+ -| densenet161 | | | -+---------------------------------------+------------------+-------------------+ -| densenet169 | | | -+---------------------------------------+------------------+-------------------+ -| densenet201 | | | -+---------------------------------------+------------------+-------------------+ -| densenet264d | | | -+---------------------------------------+------------------+-------------------+ -| densenetblur121d | | | -+---------------------------------------+------------------+-------------------+ -| dla102 | | | -+---------------------------------------+------------------+-------------------+ -| dla102x | | | -+---------------------------------------+------------------+-------------------+ -| dla102x2 | | | -+---------------------------------------+------------------+-------------------+ -| dla169 | | | -+---------------------------------------+------------------+-------------------+ -| dla34 | | | -+---------------------------------------+------------------+-------------------+ -| dla46_c | | | -+---------------------------------------+------------------+-------------------+ -| dla46x_c | | | -+---------------------------------------+------------------+-------------------+ -| dla60 | | | -+---------------------------------------+------------------+-------------------+ -| dla60_res2net | | | -+---------------------------------------+------------------+-------------------+ -| dla60_res2next | | | -+---------------------------------------+------------------+-------------------+ -| dla60x | | | -+---------------------------------------+------------------+-------------------+ -| dla60x_c | | | -+---------------------------------------+------------------+-------------------+ -| dm_nfnet_f0 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| dm_nfnet_f1 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| dm_nfnet_f2 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| dm_nfnet_f3 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| dm_nfnet_f4 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| dm_nfnet_f5 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| dm_nfnet_f6 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| dpn107 | | | -+---------------------------------------+------------------+-------------------+ -| dpn131 | | | -+---------------------------------------+------------------+-------------------+ -| dpn48b | | | -+---------------------------------------+------------------+-------------------+ -| dpn68 | | | -+---------------------------------------+------------------+-------------------+ -| dpn68b | | | -+---------------------------------------+------------------+-------------------+ -| dpn92 | | | -+---------------------------------------+------------------+-------------------+ -| dpn98 | | | -+---------------------------------------+------------------+-------------------+ -| eca_botnext26ts_256 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| eca_halonext26ts | ✅ | | -+---------------------------------------+------------------+-------------------+ -| eca_nfnet_l0 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| eca_nfnet_l1 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| eca_nfnet_l2 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| eca_nfnet_l3 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| eca_resnet33ts | ✅ | | -+---------------------------------------+------------------+-------------------+ -| eca_resnext26ts | ✅ | | -+---------------------------------------+------------------+-------------------+ -| eca_vovnet39b | | | -+---------------------------------------+------------------+-------------------+ -| ecaresnet101d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| ecaresnet101d_pruned | ✅ | | -+---------------------------------------+------------------+-------------------+ -| ecaresnet200d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| ecaresnet269d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| ecaresnet26t | ✅ | | -+---------------------------------------+------------------+-------------------+ -| ecaresnet50d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| ecaresnet50d_pruned | ✅ | | -+---------------------------------------+------------------+-------------------+ -| ecaresnet50t | ✅ | | -+---------------------------------------+------------------+-------------------+ -| ecaresnetlight | ✅ | | -+---------------------------------------+------------------+-------------------+ -| ecaresnext26t_32x4d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| ecaresnext50t_32x4d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_b0 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_b0_g16_evos | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_b0_g8_gn | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_b0_gn | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_b1 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_b1_pruned | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_b2 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_b2_pruned | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_b3 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_b3_g8_gn | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_b3_gn | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_b3_pruned | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_b4 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_b5 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_b6 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_b7 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_b8 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_blur_b0 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_cc_b0_4e | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_cc_b0_8e | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_cc_b1_8e | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_el | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_el_pruned | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_em | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_es | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_es_pruned | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_l2 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_lite0 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_lite1 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_lite2 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_lite3 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnet_lite4 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnetv2_l | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnetv2_m | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnetv2_rw_m | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnetv2_rw_s | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnetv2_rw_t | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnetv2_s | ✅ | | -+---------------------------------------+------------------+-------------------+ -| efficientnetv2_xl | ✅ | | -+---------------------------------------+------------------+-------------------+ -| ese_vovnet19b_dw | | | -+---------------------------------------+------------------+-------------------+ -| ese_vovnet19b_slim | | | -+---------------------------------------+------------------+-------------------+ -| ese_vovnet19b_slim_dw | | | -+---------------------------------------+------------------+-------------------+ -| ese_vovnet39b | | | -+---------------------------------------+------------------+-------------------+ -| ese_vovnet39b_evos | | | -+---------------------------------------+------------------+-------------------+ -| ese_vovnet57b | | | -+---------------------------------------+------------------+-------------------+ -| ese_vovnet99b | | | -+---------------------------------------+------------------+-------------------+ -| fbnetc_100 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| fbnetv3_b | ✅ | | -+---------------------------------------+------------------+-------------------+ -| fbnetv3_d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| fbnetv3_g | ✅ | | -+---------------------------------------+------------------+-------------------+ -| flexivit_base | | ✅ | -+---------------------------------------+------------------+-------------------+ -| flexivit_large | | ✅ | -+---------------------------------------+------------------+-------------------+ -| flexivit_small | | ✅ | -+---------------------------------------+------------------+-------------------+ -| gc_efficientnetv2_rw_t | ✅ | | -+---------------------------------------+------------------+-------------------+ -| gcresnet33ts | ✅ | | -+---------------------------------------+------------------+-------------------+ -| gcresnet50t | ✅ | | -+---------------------------------------+------------------+-------------------+ -| gcresnext26ts | ✅ | | -+---------------------------------------+------------------+-------------------+ -| gcresnext50ts | ✅ | | -+---------------------------------------+------------------+-------------------+ -| gernet_l | ✅ | | -+---------------------------------------+------------------+-------------------+ -| gernet_m | ✅ | | -+---------------------------------------+------------------+-------------------+ -| gernet_s | ✅ | | -+---------------------------------------+------------------+-------------------+ -| ghostnet_050 | | | -+---------------------------------------+------------------+-------------------+ -| ghostnet_100 | | | -+---------------------------------------+------------------+-------------------+ -| ghostnet_130 | | | -+---------------------------------------+------------------+-------------------+ -| ghostnetv2_100 | | | -+---------------------------------------+------------------+-------------------+ -| ghostnetv2_130 | | | -+---------------------------------------+------------------+-------------------+ -| ghostnetv2_160 | | | -+---------------------------------------+------------------+-------------------+ -| halo2botnet50ts_256 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| halonet26t | ✅ | | -+---------------------------------------+------------------+-------------------+ -| halonet50ts | ✅ | | -+---------------------------------------+------------------+-------------------+ -| halonet_h1 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| haloregnetz_b | ✅ | | -+---------------------------------------+------------------+-------------------+ -| hardcorenas_a | ✅ | | -+---------------------------------------+------------------+-------------------+ -| hardcorenas_b | ✅ | | -+---------------------------------------+------------------+-------------------+ -| hardcorenas_c | ✅ | | -+---------------------------------------+------------------+-------------------+ -| hardcorenas_d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| hardcorenas_e | ✅ | | -+---------------------------------------+------------------+-------------------+ -| hardcorenas_f | ✅ | | -+---------------------------------------+------------------+-------------------+ -| hrnet_w18 | | | -+---------------------------------------+------------------+-------------------+ -| hrnet_w18_small | | | -+---------------------------------------+------------------+-------------------+ -| hrnet_w18_small_v2 | | | -+---------------------------------------+------------------+-------------------+ -| hrnet_w18_ssld | | | -+---------------------------------------+------------------+-------------------+ -| hrnet_w30 | | | -+---------------------------------------+------------------+-------------------+ -| hrnet_w32 | | | -+---------------------------------------+------------------+-------------------+ -| hrnet_w40 | | | -+---------------------------------------+------------------+-------------------+ -| hrnet_w44 | | | -+---------------------------------------+------------------+-------------------+ -| hrnet_w48 | | | -+---------------------------------------+------------------+-------------------+ -| hrnet_w48_ssld | | | -+---------------------------------------+------------------+-------------------+ -| hrnet_w64 | | | -+---------------------------------------+------------------+-------------------+ -| inception_resnet_v2 | | | -+---------------------------------------+------------------+-------------------+ -| inception_v3 | | | -+---------------------------------------+------------------+-------------------+ -| inception_v4 | | | -+---------------------------------------+------------------+-------------------+ -| lambda_resnet26rpt_256 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| lambda_resnet26t | ✅ | | -+---------------------------------------+------------------+-------------------+ -| lambda_resnet50ts | ✅ | | -+---------------------------------------+------------------+-------------------+ -| lamhalobotnet50ts_256 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| lcnet_035 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| lcnet_050 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| lcnet_075 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| lcnet_100 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| lcnet_150 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| legacy_senet154 | | | -+---------------------------------------+------------------+-------------------+ -| legacy_seresnet101 | | | -+---------------------------------------+------------------+-------------------+ -| legacy_seresnet152 | | | -+---------------------------------------+------------------+-------------------+ -| legacy_seresnet18 | | | -+---------------------------------------+------------------+-------------------+ -| legacy_seresnet34 | | | -+---------------------------------------+------------------+-------------------+ -| legacy_seresnet50 | | | -+---------------------------------------+------------------+-------------------+ -| legacy_seresnext101_32x4d | | | -+---------------------------------------+------------------+-------------------+ -| legacy_seresnext26_32x4d | | | -+---------------------------------------+------------------+-------------------+ -| legacy_seresnext50_32x4d | | | -+---------------------------------------+------------------+-------------------+ -| legacy_xception | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_base_tf_224 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_base_tf_384 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_base_tf_512 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_large_tf_224 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_large_tf_384 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_large_tf_512 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_nano_rw_256 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_pico_rw_256 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_rmlp_base_rw_224 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_rmlp_base_rw_384 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_rmlp_nano_rw_256 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_rmlp_pico_rw_256 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_rmlp_small_rw_224 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_rmlp_small_rw_256 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_rmlp_tiny_rw_256 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_small_tf_224 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_small_tf_384 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_small_tf_512 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_tiny_pm_256 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_tiny_rw_224 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_tiny_rw_256 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_tiny_tf_224 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_tiny_tf_384 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_tiny_tf_512 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_xlarge_tf_224 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_xlarge_tf_384 | | | -+---------------------------------------+------------------+-------------------+ -| maxvit_xlarge_tf_512 | | | -+---------------------------------------+------------------+-------------------+ -| maxxvit_rmlp_nano_rw_256 | | | -+---------------------------------------+------------------+-------------------+ -| maxxvit_rmlp_small_rw_256 | | | -+---------------------------------------+------------------+-------------------+ -| maxxvit_rmlp_tiny_rw_256 | | | -+---------------------------------------+------------------+-------------------+ -| maxxvitv2_nano_rw_256 | | | -+---------------------------------------+------------------+-------------------+ -| maxxvitv2_rmlp_base_rw_224 | | | -+---------------------------------------+------------------+-------------------+ -| maxxvitv2_rmlp_base_rw_384 | | | -+---------------------------------------+------------------+-------------------+ -| maxxvitv2_rmlp_large_rw_224 | | | -+---------------------------------------+------------------+-------------------+ -| mixnet_l | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mixnet_m | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mixnet_s | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mixnet_xl | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mixnet_xxl | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mnasnet_050 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mnasnet_075 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mnasnet_100 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mnasnet_140 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mnasnet_small | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenet_edgetpu_100 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenet_edgetpu_v2_l | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenet_edgetpu_v2_m | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenet_edgetpu_v2_s | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenet_edgetpu_v2_xs | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv1_100 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv1_100h | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv1_125 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv2_035 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv2_050 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv2_075 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv2_100 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv2_110d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv2_120d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv2_140 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv3_large_075 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv3_large_100 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv3_large_150d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv3_rw | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv3_small_050 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv3_small_075 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv3_small_100 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv4_conv_aa_large | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv4_conv_aa_medium | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv4_conv_blur_medium | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv4_conv_large | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv4_conv_medium | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv4_conv_small | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv4_conv_small_035 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv4_conv_small_050 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv4_hybrid_large | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv4_hybrid_large_075 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv4_hybrid_medium | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilenetv4_hybrid_medium_075 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobileone_s0 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobileone_s1 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobileone_s2 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobileone_s3 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobileone_s4 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilevit_s | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilevit_xs | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilevit_xxs | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilevitv2_050 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilevitv2_075 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilevitv2_100 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilevitv2_125 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilevitv2_150 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilevitv2_175 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| mobilevitv2_200 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nasnetalarge | | | -+---------------------------------------+------------------+-------------------+ -| nf_ecaresnet101 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nf_ecaresnet26 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nf_ecaresnet50 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nf_regnet_b0 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nf_regnet_b1 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nf_regnet_b2 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nf_regnet_b3 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nf_regnet_b4 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nf_regnet_b5 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nf_resnet101 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nf_resnet26 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nf_resnet50 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nf_seresnet101 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nf_seresnet26 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nf_seresnet50 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nfnet_f0 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nfnet_f1 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nfnet_f2 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nfnet_f3 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nfnet_f4 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nfnet_f5 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nfnet_f6 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nfnet_f7 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| nfnet_l0 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| pnasnet5large | | | -+---------------------------------------+------------------+-------------------+ -| regnetv_040 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetv_064 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetx_002 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetx_004 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetx_004_tv | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetx_006 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetx_008 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetx_016 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetx_032 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetx_040 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetx_064 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetx_080 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetx_120 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetx_160 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetx_320 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnety_002 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnety_004 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnety_006 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnety_008 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnety_008_tv | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnety_016 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnety_032 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnety_040 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnety_040_sgn | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnety_064 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnety_080 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnety_080_tv | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnety_120 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnety_1280 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnety_160 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnety_2560 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnety_320 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnety_640 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetz_005 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetz_040 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetz_040_h | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetz_b16 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetz_b16_evos | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetz_c16 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetz_c16_evos | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetz_d32 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetz_d8 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetz_d8_evos | ✅ | | -+---------------------------------------+------------------+-------------------+ -| regnetz_e8 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| repghostnet_050 | | | -+---------------------------------------+------------------+-------------------+ -| repghostnet_058 | | | -+---------------------------------------+------------------+-------------------+ -| repghostnet_080 | | | -+---------------------------------------+------------------+-------------------+ -| repghostnet_100 | | | -+---------------------------------------+------------------+-------------------+ -| repghostnet_111 | | | -+---------------------------------------+------------------+-------------------+ -| repghostnet_130 | | | -+---------------------------------------+------------------+-------------------+ -| repghostnet_150 | | | -+---------------------------------------+------------------+-------------------+ -| repghostnet_200 | | | -+---------------------------------------+------------------+-------------------+ -| repvgg_a0 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| repvgg_a1 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| repvgg_a2 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| repvgg_b0 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| repvgg_b1 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| repvgg_b1g4 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| repvgg_b2 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| repvgg_b2g4 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| repvgg_b3 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| repvgg_b3g4 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| repvgg_d2se | ✅ | | -+---------------------------------------+------------------+-------------------+ -| res2net101_26w_4s | ✅ | | -+---------------------------------------+------------------+-------------------+ -| res2net101d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| res2net50_14w_8s | ✅ | | -+---------------------------------------+------------------+-------------------+ -| res2net50_26w_4s | ✅ | | -+---------------------------------------+------------------+-------------------+ -| res2net50_26w_6s | ✅ | | -+---------------------------------------+------------------+-------------------+ -| res2net50_26w_8s | ✅ | | -+---------------------------------------+------------------+-------------------+ -| res2net50_48w_2s | ✅ | | -+---------------------------------------+------------------+-------------------+ -| res2net50d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| res2next50 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnest101e | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnest14d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnest200e | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnest269e | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnest26d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnest50d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnest50d_1s4x24d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnest50d_4s2x40d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet101 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet101_clip | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet101_clip_gap | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet101c | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet101d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet101s | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet10t | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet14t | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet152 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet152c | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet152d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet152s | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet18 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet18d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet200 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet200d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet26 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet26d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet26t | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet32ts | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet33ts | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet34 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet34d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet50 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet50_clip | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet50_clip_gap | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet50_gn | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet50_mlp | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet50c | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet50d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet50s | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet50t | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet50x16_clip | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet50x16_clip_gap | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet50x4_clip | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet50x4_clip_gap | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet50x64_clip | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet50x64_clip_gap | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet51q | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnet61q | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetaa101d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetaa34d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetaa50 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetaa50d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetblur101d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetblur18 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetblur50 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetblur50d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetrs101 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetrs152 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetrs200 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetrs270 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetrs350 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetrs420 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetrs50 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_101 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_101d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_101x1_bit | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_101x3_bit | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_152 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_152d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_152x2_bit | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_152x4_bit | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_18 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_18d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_34 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_34d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_50 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_50d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_50d_evos | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_50d_frn | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_50d_gn | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_50t | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_50x1_bit | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnetv2_50x3_bit | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnext101_32x16d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnext101_32x32d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnext101_32x4d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnext101_32x8d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnext101_64x4d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnext26ts | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnext50_32x4d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| resnext50d_32x4d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| rexnet_100 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| rexnet_130 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| rexnet_150 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| rexnet_200 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| rexnet_300 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| rexnetr_100 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| rexnetr_130 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| rexnetr_150 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| rexnetr_200 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| rexnetr_300 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| samvit_base_patch16 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| samvit_base_patch16_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| samvit_huge_patch16 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| samvit_large_patch16 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| sebotnet33ts_256 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| sehalonet33ts | ✅ | | -+---------------------------------------+------------------+-------------------+ -| selecsls42 | | | -+---------------------------------------+------------------+-------------------+ -| selecsls42b | | | -+---------------------------------------+------------------+-------------------+ -| selecsls60 | | | -+---------------------------------------+------------------+-------------------+ -| selecsls60b | | | -+---------------------------------------+------------------+-------------------+ -| selecsls84 | | | -+---------------------------------------+------------------+-------------------+ -| semnasnet_050 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| semnasnet_075 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| semnasnet_100 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| semnasnet_140 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| senet154 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnet101 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnet152 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnet152d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnet18 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnet200d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnet269d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnet33ts | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnet34 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnet50 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnet50t | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnetaa50d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnext101_32x4d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnext101_32x8d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnext101_64x4d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnext101d_32x8d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnext26d_32x4d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnext26t_32x4d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnext26ts | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnext50_32x4d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnextaa101d_32x8d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| seresnextaa201d_32x8d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| skresnet18 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| skresnet34 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| skresnet50 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| skresnet50d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| skresnext50_32x4d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| spnasnet_100 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| test_byobnet | ✅ | | -+---------------------------------------+------------------+-------------------+ -| test_efficientnet | ✅ | | -+---------------------------------------+------------------+-------------------+ -| test_efficientnet_evos | ✅ | | -+---------------------------------------+------------------+-------------------+ -| test_efficientnet_gn | ✅ | | -+---------------------------------------+------------------+-------------------+ -| test_efficientnet_ln | ✅ | | -+---------------------------------------+------------------+-------------------+ -| test_nfnet | ✅ | | -+---------------------------------------+------------------+-------------------+ -| test_resnet | ✅ | | -+---------------------------------------+------------------+-------------------+ -| test_vit | | ✅ | -+---------------------------------------+------------------+-------------------+ -| test_vit2 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| test_vit3 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| test_vit4 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_b0 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_b1 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_b2 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_b3 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_b4 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_b5 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_b6 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_b7 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_b8 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_cc_b0_4e | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_cc_b0_8e | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_cc_b1_8e | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_el | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_em | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_es | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_l2 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_lite0 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_lite1 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_lite2 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_lite3 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnet_lite4 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnetv2_b0 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnetv2_b1 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnetv2_b2 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnetv2_b3 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnetv2_l | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnetv2_m | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnetv2_s | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_efficientnetv2_xl | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_mixnet_l | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_mixnet_m | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_mixnet_s | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_mobilenetv3_large_075 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_mobilenetv3_large_100 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_mobilenetv3_large_minimal_100 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_mobilenetv3_small_075 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_mobilenetv3_small_100 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tf_mobilenetv3_small_minimal_100 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tinynet_a | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tinynet_b | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tinynet_c | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tinynet_d | ✅ | | -+---------------------------------------+------------------+-------------------+ -| tinynet_e | ✅ | | -+---------------------------------------+------------------+-------------------+ -| vit_base_mci_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_18x2_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_224_miil | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_clip_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_clip_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_clip_quickgelu_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_gap_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_plus_240 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_plus_clip_240 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_reg4_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_rope_reg1_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_rpn_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_siglip_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_siglip_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_siglip_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_siglip_512 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_siglip_gap_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_siglip_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_siglip_gap_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_siglip_gap_512 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch16_xp_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch32_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch32_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch32_clip_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch32_clip_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch32_clip_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch32_clip_448 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch32_clip_quickgelu_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch32_plus_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch32_siglip_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch32_siglip_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_patch8_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_r26_s32_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_r50_s16_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_r50_s16_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_resnet26d_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_base_resnet50d_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_betwixt_patch16_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_betwixt_patch16_reg1_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_betwixt_patch16_reg4_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_betwixt_patch16_reg4_gap_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_betwixt_patch16_rope_reg4_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_betwixt_patch32_clip_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_giant_patch16_gap_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_giantopt_patch16_siglip_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_giantopt_patch16_siglip_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_giantopt_patch16_siglip_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_giantopt_patch16_siglip_gap_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_huge_patch16_gap_448 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_large_patch16_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_large_patch16_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_large_patch16_siglip_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_large_patch16_siglip_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_large_patch16_siglip_512 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_large_patch16_siglip_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_large_patch16_siglip_gap_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_large_patch16_siglip_gap_512 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_large_patch32_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_large_patch32_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_large_r50_s32_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_large_r50_s32_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_little_patch16_reg1_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_little_patch16_reg4_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_medium_patch16_clip_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_medium_patch16_gap_240 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_medium_patch16_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_medium_patch16_gap_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_medium_patch16_reg1_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_medium_patch16_reg4_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_medium_patch16_rope_reg1_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_medium_patch32_clip_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_mediumd_patch16_reg4_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_mediumd_patch16_reg4_gap_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_mediumd_patch16_rope_reg1_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_pwee_patch16_reg1_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_relpos_base_patch16_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_relpos_base_patch16_cls_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_relpos_base_patch16_clsgap_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_relpos_base_patch16_plus_240 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_relpos_base_patch16_rpn_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_relpos_base_patch32_plus_rpn_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_relpos_medium_patch16_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_relpos_medium_patch16_cls_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_relpos_medium_patch16_rpn_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_relpos_small_patch16_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_relpos_small_patch16_rpn_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_small_patch16_18x2_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_small_patch16_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_small_patch16_36x1_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_small_patch16_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_small_patch32_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_small_patch32_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_small_patch8_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_small_r26_s32_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_small_r26_s32_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_small_resnet26d_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_small_resnet50d_s16_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_so150m2_patch16_reg1_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_so150m2_patch16_reg1_gap_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_so150m2_patch16_reg1_gap_448 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_so150m_patch16_reg4_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_so150m_patch16_reg4_gap_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_so150m_patch16_reg4_map_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_so400m_patch16_siglip_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_so400m_patch16_siglip_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_so400m_patch16_siglip_512 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_so400m_patch16_siglip_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_so400m_patch16_siglip_gap_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_so400m_patch16_siglip_gap_512 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_srelpos_medium_patch16_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_srelpos_small_patch16_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_tiny_patch16_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_tiny_patch16_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_tiny_r_s16_p8_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_tiny_r_s16_p8_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_wee_patch16_reg1_gap_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vit_xsmall_patch16_clip_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vitamin_base_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vitamin_large2_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vitamin_large2_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vitamin_large2_336 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vitamin_large2_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vitamin_large_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vitamin_large_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vitamin_large_336 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vitamin_large_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vitamin_small_224 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vitamin_xlarge_256 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vitamin_xlarge_336 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vitamin_xlarge_384 | | ✅ | -+---------------------------------------+------------------+-------------------+ -| vovnet39a | | | -+---------------------------------------+------------------+-------------------+ -| vovnet57a | | | -+---------------------------------------+------------------+-------------------+ -| wide_resnet101_2 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| wide_resnet50_2 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| xception41 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| xception41p | ✅ | | -+---------------------------------------+------------------+-------------------+ -| xception65 | ✅ | | -+---------------------------------------+------------------+-------------------+ -| xception65p | ✅ | | -+---------------------------------------+------------------+-------------------+ -| xception71 | ✅ | | -+---------------------------------------+------------------+-------------------+ - From 5fe80a5aca026bc49743d758bf389e7ea96d1060 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 22:05:59 +0000 Subject: [PATCH 28/44] Fix doc --- docs/encoders_dpt.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/encoders_dpt.rst b/docs/encoders_dpt.rst index 31b16d0f..9ce3af31 100644 --- a/docs/encoders_dpt.rst +++ b/docs/encoders_dpt.rst @@ -3,8 +3,7 @@ DPT Encoders ============ -This is a list of Vision Transformer encoders that are compatible with the DPT architecture -These encoders have been tested and verified to work with DPT models. +This is a list of Vision Transformer encoders that are compatible with the DPT architecture. While other Vision Transformer encoders from timm may also be compatible, the ones listed below are tested to work properly. .. list-table:: Encoder Name From 0a1497233357ed095fa230341be9fc549c07b711 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 22:06:09 +0000 Subject: [PATCH 29/44] Fix docstring --- .../decoders/deeplabv3/model.py | 6 ++---- .../decoders/dpt/model.py | 16 ++++++++-------- .../decoders/fpn/model.py | 3 +-- .../decoders/linknet/model.py | 3 +-- .../decoders/manet/model.py | 3 +-- .../decoders/pan/model.py | 3 +-- .../decoders/pspnet/model.py | 3 +-- .../decoders/segformer/model.py | 3 +-- .../decoders/unet/model.py | 3 +-- .../decoders/unetplusplus/model.py | 3 +-- .../decoders/upernet/model.py | 3 +-- 11 files changed, 19 insertions(+), 30 deletions(-) diff --git a/segmentation_models_pytorch/decoders/deeplabv3/model.py b/segmentation_models_pytorch/decoders/deeplabv3/model.py index c14776f3..38ca9e04 100644 --- a/segmentation_models_pytorch/decoders/deeplabv3/model.py +++ b/segmentation_models_pytorch/decoders/deeplabv3/model.py @@ -34,8 +34,7 @@ class DeepLabV3(SegmentationModel): classes: A number of classes for output mask (or you can think as a number of channels of output mask) activation: An activation function to apply after the final convolution layer. Available options are **"sigmoid"**, **"softmax"**, **"logsoftmax"**, **"tanh"**, **"identity"**, - **callable** and **None**. - Default is **None** + **callable** and **None**. Default is **None**. upsampling: Final upsampling factor. Default is **None** to preserve input-output spatial shape identity aux_params: Dictionary with parameters of the auxiliary output (classification head). Auxiliary output is build on top of encoder if **aux_params** is not **None** (default). Supported params: @@ -159,8 +158,7 @@ class DeepLabV3Plus(SegmentationModel): classes: A number of classes for output mask (or you can think as a number of channels of output mask) activation: An activation function to apply after the final convolution layer. Available options are **"sigmoid"**, **"softmax"**, **"logsoftmax"**, **"tanh"**, **"identity"**, - **callable** and **None**. - Default is **None** + **callable** and **None**. Default is **None**. upsampling: Final upsampling factor. Default is 4 to preserve input-output spatial shape identity. aux_params: Dictionary with parameters of the auxiliary output (classification head). Auxiliary output is build on top of encoder if **aux_params** is not **None** (default). Supported params: diff --git a/segmentation_models_pytorch/decoders/dpt/model.py b/segmentation_models_pytorch/decoders/dpt/model.py index 94bd4048..24e2616d 100644 --- a/segmentation_models_pytorch/decoders/dpt/model.py +++ b/segmentation_models_pytorch/decoders/dpt/model.py @@ -32,12 +32,13 @@ class DPT(SegmentationModel): Args: encoder_name: Name of the classification model that will be used as an encoder (a.k.a backbone) - to extract features of different spatial resolution + to extract features of different spatial resolution. encoder_depth: A number of stages used in encoder in range [1,4]. Each stage generate features smaller by a factor equal to the ViT model patch_size in spatial dimensions. - Default is 4 - encoder_weights: One of **None** (random initialization), or other pretrained weights (see table with - available weights for each encoder_name) + Default is 4. + encoder_weights: One of **None** (random initialization), or not **None** (pretrained weights would be loaded + with respect to the encoder_name, e.g. for ``"tu-vit_base_patch16_224.augreg_in21k"`` - ``"augreg_in21k"`` + weights would be loaded). encoder_output_indices: The indices of the encoder output features to use. If **None** will be sampled uniformly across the number of blocks in encoder, e.g. if number of blocks is 4 and encoder has 20 blocks, then encoder_output_indices will be (4, 9, 14, 19). If specified the number of indices should be equal to @@ -50,8 +51,7 @@ class DPT(SegmentationModel): classes: Number of classes for output mask (or you can think as a number of channels of output mask) activation: An activation function to apply after the final convolution layer. Available options are **"sigmoid"**, **"softmax"**, **"logsoftmax"**, **"tanh"**, **"identity"**, - **callable** and **None**. - Default is **None** + **callable** and **None**. Default is **None**. aux_params: Dictionary with parameters of the auxiliary output (classification head). Auxiliary output is build on top of encoder if **aux_params** is not **None** (default). Supported params: - classes (int): A number of classes @@ -74,9 +74,9 @@ class DPT(SegmentationModel): @supports_config_loading def __init__( self, - encoder_name: str = "tu-vit_base_patch8_224", + encoder_name: str = "tu-vit_base_patch16_224.augreg_in21k", encoder_depth: int = 4, - encoder_weights: Optional[str] = None, + encoder_weights: Optional[str] = "imagenet", encoder_output_indices: Optional[list[int]] = None, decoder_intermediate_channels: Sequence[int] = (256, 512, 1024, 1024), decoder_fusion_channels: int = 256, diff --git a/segmentation_models_pytorch/decoders/fpn/model.py b/segmentation_models_pytorch/decoders/fpn/model.py index 7420b289..939128f1 100644 --- a/segmentation_models_pytorch/decoders/fpn/model.py +++ b/segmentation_models_pytorch/decoders/fpn/model.py @@ -32,8 +32,7 @@ class FPN(SegmentationModel): classes: A number of classes for output mask (or you can think as a number of channels of output mask) activation: An activation function to apply after the final convolution layer. Available options are **"sigmoid"**, **"softmax"**, **"logsoftmax"**, **"tanh"**, **"identity"**, - **callable** and **None**. - Default is **None** + **callable** and **None**. Default is **None**. upsampling: Final upsampling factor. Default is 4 to preserve input-output spatial shape identity aux_params: Dictionary with parameters of the auxiliary output (classification head). Auxiliary output is build on top of encoder if **aux_params** is not **None** (default). Supported params: diff --git a/segmentation_models_pytorch/decoders/linknet/model.py b/segmentation_models_pytorch/decoders/linknet/model.py index 356468ed..1772db6e 100644 --- a/segmentation_models_pytorch/decoders/linknet/model.py +++ b/segmentation_models_pytorch/decoders/linknet/model.py @@ -36,8 +36,7 @@ class Linknet(SegmentationModel): classes: A number of classes for output mask (or you can think as a number of channels of output mask) activation: An activation function to apply after the final convolution layer. Available options are **"sigmoid"**, **"softmax"**, **"logsoftmax"**, **"tanh"**, **"identity"**, - **callable** and **None**. - Default is **None** + **callable** and **None**. Default is **None**. aux_params: Dictionary with parameters of the auxiliary output (classification head). Auxiliary output is build on top of encoder if **aux_params** is not **None** (default). Supported params: - classes (int): A number of classes diff --git a/segmentation_models_pytorch/decoders/manet/model.py b/segmentation_models_pytorch/decoders/manet/model.py index 6ed59207..d4ae2fee 100644 --- a/segmentation_models_pytorch/decoders/manet/model.py +++ b/segmentation_models_pytorch/decoders/manet/model.py @@ -38,8 +38,7 @@ class MAnet(SegmentationModel): classes: A number of classes for output mask (or you can think as a number of channels of output mask) activation: An activation function to apply after the final convolution layer. Available options are **"sigmoid"**, **"softmax"**, **"logsoftmax"**, **"tanh"**, **"identity"**, - **callable** and **None**. - Default is **None** + **callable** and **None**. Default is **None**. aux_params: Dictionary with parameters of the auxiliary output (classification head). Auxiliary output is build on top of encoder if **aux_params** is not **None** (default). Supported params: - classes (int): A number of classes diff --git a/segmentation_models_pytorch/decoders/pan/model.py b/segmentation_models_pytorch/decoders/pan/model.py index 6d5e78c2..76399f45 100644 --- a/segmentation_models_pytorch/decoders/pan/model.py +++ b/segmentation_models_pytorch/decoders/pan/model.py @@ -34,8 +34,7 @@ class PAN(SegmentationModel): classes: A number of classes for output mask (or you can think as a number of channels of output mask) activation: An activation function to apply after the final convolution layer. Available options are **"sigmoid"**, **"softmax"**, **"logsoftmax"**, **"tanh"**, **"identity"**, - **callable** and **None**. - Default is **None** + **callable** and **None**. Default is **None**. upsampling: Final upsampling factor. Default is 4 to preserve input-output spatial shape identity aux_params: Dictionary with parameters of the auxiliary output (classification head). Auxiliary output is build on top of encoder if **aux_params** is not **None** (default). Supported params: diff --git a/segmentation_models_pytorch/decoders/pspnet/model.py b/segmentation_models_pytorch/decoders/pspnet/model.py index 8b99b3da..164f5da6 100644 --- a/segmentation_models_pytorch/decoders/pspnet/model.py +++ b/segmentation_models_pytorch/decoders/pspnet/model.py @@ -36,8 +36,7 @@ class PSPNet(SegmentationModel): classes: A number of classes for output mask (or you can think as a number of channels of output mask) activation: An activation function to apply after the final convolution layer. Available options are **"sigmoid"**, **"softmax"**, **"logsoftmax"**, **"tanh"**, **"identity"**, - **callable** and **None**. - Default is **None** + **callable** and **None**. Default is **None**. upsampling: Final upsampling factor. Default is 8 to preserve input-output spatial shape identity aux_params: Dictionary with parameters of the auxiliary output (classification head). Auxiliary output is build on top of encoder if **aux_params** is not **None** (default). Supported params: diff --git a/segmentation_models_pytorch/decoders/segformer/model.py b/segmentation_models_pytorch/decoders/segformer/model.py index 45805de7..65d7e8fa 100644 --- a/segmentation_models_pytorch/decoders/segformer/model.py +++ b/segmentation_models_pytorch/decoders/segformer/model.py @@ -28,8 +28,7 @@ class Segformer(SegmentationModel): classes: A number of classes for output mask (or you can think as a number of channels of output mask) activation: An activation function to apply after the final convolution layer. Available options are **"sigmoid"**, **"softmax"**, **"logsoftmax"**, **"tanh"**, **"identity"**, - **callable** and **None**. - Default is **None** + **callable** and **None**. Default is **None**. aux_params: Dictionary with parameters of the auxiliary output (classification head). Auxiliary output is build on top of encoder if **aux_params** is not **None** (default). Supported params: - classes (int): A number of classes diff --git a/segmentation_models_pytorch/decoders/unet/model.py b/segmentation_models_pytorch/decoders/unet/model.py index 4b30527d..7d92318a 100644 --- a/segmentation_models_pytorch/decoders/unet/model.py +++ b/segmentation_models_pytorch/decoders/unet/model.py @@ -50,8 +50,7 @@ class Unet(SegmentationModel): classes: A number of classes for output mask (or you can think as a number of channels of output mask) activation: An activation function to apply after the final convolution layer. Available options are **"sigmoid"**, **"softmax"**, **"logsoftmax"**, **"tanh"**, **"identity"**, - **callable** and **None**. - Default is **None** + **callable** and **None**. Default is **None**. aux_params: Dictionary with parameters of the auxiliary output (classification head). Auxiliary output is build on top of encoder if **aux_params** is not **None** (default). Supported params: - classes (int): A number of classes diff --git a/segmentation_models_pytorch/decoders/unetplusplus/model.py b/segmentation_models_pytorch/decoders/unetplusplus/model.py index 5c3d3a91..96538d8f 100644 --- a/segmentation_models_pytorch/decoders/unetplusplus/model.py +++ b/segmentation_models_pytorch/decoders/unetplusplus/model.py @@ -37,8 +37,7 @@ class UnetPlusPlus(SegmentationModel): classes: A number of classes for output mask (or you can think as a number of channels of output mask) activation: An activation function to apply after the final convolution layer. Available options are **"sigmoid"**, **"softmax"**, **"logsoftmax"**, **"tanh"**, **"identity"**, - **callable** and **None**. - Default is **None** + **callable** and **None**. Default is **None**. aux_params: Dictionary with parameters of the auxiliary output (classification head). Auxiliary output is build on top of encoder if **aux_params** is not **None** (default). Supported params: - classes (int): A number of classes diff --git a/segmentation_models_pytorch/decoders/upernet/model.py b/segmentation_models_pytorch/decoders/upernet/model.py index 7ffeee5b..7b599aaa 100644 --- a/segmentation_models_pytorch/decoders/upernet/model.py +++ b/segmentation_models_pytorch/decoders/upernet/model.py @@ -29,8 +29,7 @@ class UPerNet(SegmentationModel): classes: A number of classes for output mask (or you can think as a number of channels of output mask) activation: An activation function to apply after the final convolution layer. Available options are **"sigmoid"**, **"softmax"**, **"logsoftmax"**, **"tanh"**, **"identity"**, - **callable** and **None**. - Default is **None** + **callable** and **None**. Default is **None**. aux_params: Dictionary with parameters of the auxiliary output (classification head). Auxiliary output is build on top of encoder if **aux_params** is not **None** (default). Supported params: - classes (int): A number of classes From 5b28978695d610d72dff5d85d7778670c02d1039 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 22:07:51 +0000 Subject: [PATCH 30/44] Fixing list in activation --- segmentation_models_pytorch/decoders/dpt/model.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/segmentation_models_pytorch/decoders/dpt/model.py b/segmentation_models_pytorch/decoders/dpt/model.py index 24e2616d..88dd8357 100644 --- a/segmentation_models_pytorch/decoders/dpt/model.py +++ b/segmentation_models_pytorch/decoders/dpt/model.py @@ -54,11 +54,10 @@ class DPT(SegmentationModel): **callable** and **None**. Default is **None**. aux_params: Dictionary with parameters of the auxiliary output (classification head). Auxiliary output is build on top of encoder if **aux_params** is not **None** (default). Supported params: - - classes (int): A number of classes - - pooling (str): One of "max", "avg". Default is "avg" - - dropout (float): Dropout factor in [0, 1) - - activation (str): An activation function to apply "sigmoid"/"softmax" - (could be **None** to return logits) + * classes (int): A number of classes; + * pooling (str): One of "max", "avg". Default is "avg"; + * dropout (float): Dropout factor in [0, 1); + * activation (str): An activation function to apply "sigmoid"/"softmax" (could be **None** to return logits). kwargs: Arguments passed to the encoder class ``__init__()`` function. Applies only to ``timm`` models. Keys with ``None`` values are pruned before passing. Specify ``dynamic_img_size=True`` to allow the model to handle images of different sizes. From 0ed621c395672716731906292d88fff397baaed3 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 22:12:53 +0000 Subject: [PATCH 31/44] Fixing list --- segmentation_models_pytorch/decoders/dpt/model.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/segmentation_models_pytorch/decoders/dpt/model.py b/segmentation_models_pytorch/decoders/dpt/model.py index 88dd8357..1e33e4a5 100644 --- a/segmentation_models_pytorch/decoders/dpt/model.py +++ b/segmentation_models_pytorch/decoders/dpt/model.py @@ -54,10 +54,10 @@ class DPT(SegmentationModel): **callable** and **None**. Default is **None**. aux_params: Dictionary with parameters of the auxiliary output (classification head). Auxiliary output is build on top of encoder if **aux_params** is not **None** (default). Supported params: - * classes (int): A number of classes; - * pooling (str): One of "max", "avg". Default is "avg"; - * dropout (float): Dropout factor in [0, 1); - * activation (str): An activation function to apply "sigmoid"/"softmax" (could be **None** to return logits). + - **classes** (*int*): A number of classes; + - **pooling** (*str*): One of "max", "avg". Default is "avg"; + - **dropout** (*float*): Dropout factor in [0, 1); + - **activation** (*str*): An activation function to apply "sigmoid"/"softmax" (could be **None** to return logits). kwargs: Arguments passed to the encoder class ``__init__()`` function. Applies only to ``timm`` models. Keys with ``None`` values are pruned before passing. Specify ``dynamic_img_size=True`` to allow the model to handle images of different sizes. From 620731048562a885852e216de9b94b196d299aa9 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 22:15:28 +0000 Subject: [PATCH 32/44] Fixing list --- segmentation_models_pytorch/decoders/dpt/model.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/segmentation_models_pytorch/decoders/dpt/model.py b/segmentation_models_pytorch/decoders/dpt/model.py index 1e33e4a5..fd6cb0ea 100644 --- a/segmentation_models_pytorch/decoders/dpt/model.py +++ b/segmentation_models_pytorch/decoders/dpt/model.py @@ -54,10 +54,11 @@ class DPT(SegmentationModel): **callable** and **None**. Default is **None**. aux_params: Dictionary with parameters of the auxiliary output (classification head). Auxiliary output is build on top of encoder if **aux_params** is not **None** (default). Supported params: - - **classes** (*int*): A number of classes; - - **pooling** (*str*): One of "max", "avg". Default is "avg"; - - **dropout** (*float*): Dropout factor in [0, 1); - - **activation** (*str*): An activation function to apply "sigmoid"/"softmax" (could be **None** to return logits). + + - **classes** (*int*): A number of classes; + - **pooling** (*str*): One of "max", "avg". Default is "avg"; + - **dropout** (*float*): Dropout factor in [0, 1); + - **activation** (*str*): An activation function to apply "sigmoid"/"softmax" (could be **None** to return logits). kwargs: Arguments passed to the encoder class ``__init__()`` function. Applies only to ``timm`` models. Keys with ``None`` values are pruned before passing. Specify ``dynamic_img_size=True`` to allow the model to handle images of different sizes. From 19eeebe3aab938bad2401e6e9060ec942eca33f8 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 22:21:09 +0000 Subject: [PATCH 33/44] Fixup, fix type hint --- segmentation_models_pytorch/decoders/dpt/decoder.py | 4 ++-- segmentation_models_pytorch/decoders/dpt/model.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/segmentation_models_pytorch/decoders/dpt/decoder.py b/segmentation_models_pytorch/decoders/dpt/decoder.py index 33743a59..96d10c49 100644 --- a/segmentation_models_pytorch/decoders/dpt/decoder.py +++ b/segmentation_models_pytorch/decoders/dpt/decoder.py @@ -1,7 +1,7 @@ import torch import torch.nn as nn from segmentation_models_pytorch.base.modules import Activation -from typing import Optional, Sequence +from typing import Optional, Sequence, Union, Callable class ProjectionBlock(nn.Module): @@ -241,7 +241,7 @@ def __init__( self, in_channels: int, out_channels: int, - activation: Optional[str] = None, + activation: Optional[Union[str, Callable]] = None, kernel_size: int = 3, upsampling: float = 2.0, ): diff --git a/segmentation_models_pytorch/decoders/dpt/model.py b/segmentation_models_pytorch/decoders/dpt/model.py index fd6cb0ea..1dc7ee07 100644 --- a/segmentation_models_pytorch/decoders/dpt/model.py +++ b/segmentation_models_pytorch/decoders/dpt/model.py @@ -25,7 +25,7 @@ class DPT(SegmentationModel): Note: Since this model uses a Vision Transformer backbone, it typically requires a fixed input image size. - To handle variable input sizes, you can set `dynamic_img_size=True` in the model initialization + To handle variable input sizes, you can set `dynamic_img_size=True` in the model initialization (if supported by the specific `timm` encoder). You can check if an encoder requires fixed size using `model.encoder.is_fixed_input_size`, and get the required input dimensions from `model.encoder.input_size`, however it's no guarantee that information is available. From 1257c4b9ca43f8a4e288cb8881b62f229f95229e Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 22:25:27 +0000 Subject: [PATCH 34/44] Add to README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 91833975..68f2392c 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Segmentation based on [PyTorch](https://pytorch.org/).** The main features of the library are: - Super simple high-level API (just two lines to create a neural network) - - 11 encoder-decoder model architectures (Unet, Unet++, Segformer, ...) + - 12 encoder-decoder model architectures (Unet, Unet++, Segformer, DPT, ...) - 800+ **pretrained** convolution- and transform-based encoders, including [timm](https://github.com/huggingface/pytorch-image-models) support - Popular metrics and losses for training routines (Dice, Jaccard, Tversky, ...) - ONNX export and torch script/trace/compile friendly @@ -123,6 +123,7 @@ Congratulations! You are done! Now you can train your model with your favorite f - DeepLabV3+ [[paper](https://arxiv.org/abs/1802.02611)] [[docs](https://smp.readthedocs.io/en/latest/models.html#id9)] - UPerNet [[paper](https://arxiv.org/abs/1807.10221)] [[docs](https://smp.readthedocs.io/en/latest/models.html#upernet)] - Segformer [[paper](https://arxiv.org/abs/2105.15203)] [[docs](https://smp.readthedocs.io/en/latest/models.html#segformer)] + - DPT [[paper](https://arxiv.org/abs/2103.13413)] [[docs](https://smp.readthedocs.io/en/latest/models.html#dpt)] ### Encoders <a name="encoders"></a> From 21a164a39ab435505bf8040f578d69cb75688743 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Sun, 6 Apr 2025 22:32:46 +0000 Subject: [PATCH 35/44] Add example --- README.md | 1 + examples/dpt_inference_pretrained.ipynb | 138 ++++++++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 examples/dpt_inference_pretrained.ipynb diff --git a/README.md b/README.md index 68f2392c..0670eb18 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,7 @@ Congratulations! You are done! Now you can train your model with your favorite f | **Train** multiclass segmentation on CamVid | [Notebook](https://github.com/qubvel-org/segmentation_models.pytorch/blob/main/examples/camvid_segmentation_multiclass.ipynb) | [](https://colab.research.google.com/github/qubvel-org/segmentation_models.pytorch/blob/main/examples/camvid_segmentation_multiclass.ipynb) | | **Train** clothes binary segmentation by @ternaus | [Repo](https://github.com/ternaus/cloths_segmentation) | | | **Load and inference** pretrained Segformer | [Notebook](https://github.com/qubvel-org/segmentation_models.pytorch/blob/main/examples/segformer_inference_pretrained.ipynb) | [](https://colab.research.google.com/github/qubvel/segmentation_models.pytorch/blob/main/examples/segformer_inference_pretrained.ipynb) | +| **Load and inference** pretrained DPT | [Notebook](https://github.com/qubvel-org/segmentation_models.pytorch/blob/main/examples/dpt_inference_pretrained.ipynb) | [](https://colab.research.google.com/github/qubvel/segmentation_models.pytorch/blob/main/examples/dpt_inference_pretrained.ipynb) | | **Save and load** models locally / to HuggingFace Hub |[Notebook](https://github.com/qubvel-org/segmentation_models.pytorch/blob/main/examples/save_load_model_and_share_with_hf_hub.ipynb) | [](https://colab.research.google.com/github/qubvel/segmentation_models.pytorch/blob/main/examples/save_load_model_and_share_with_hf_hub.ipynb) | **Export** trained model to ONNX | [Notebook](https://github.com/qubvel/segmentation_models.pytorch/blob/main/examples/convert_to_onnx.ipynb) | [](https://colab.research.google.com/github/qubvel/segmentation_models.pytorch/blob/main/examples/convert_to_onnx.ipynb) | diff --git a/examples/dpt_inference_pretrained.ipynb b/examples/dpt_inference_pretrained.ipynb new file mode 100644 index 00000000..adfb5a15 --- /dev/null +++ b/examples/dpt_inference_pretrained.ipynb @@ -0,0 +1,138 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[](https://colab.research.google.com/github/qubvel/segmentation_models.pytorch/blob/main/examples/dpt_inference_pretrained.ipynb)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# make sure you have the latest version of the libraries\n", + "!pip install -U segmentation-models-pytorch\n", + "!pip install albumentations matplotlib requests pillow" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "import numpy as np\n", + "import albumentations as A\n", + "import matplotlib.pyplot as plt\n", + "\n", + "import torch\n", + "import segmentation_models_pytorch as smp\n", + "\n", + "from PIL import Image" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Loading weights from local directory\n" + ] + } + ], + "source": [ + "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", + "\n", + "# More checkpoints can be found here:\n", + "checkpoint = \"smp-hub/dpt-large-ade20k\"\n", + "\n", + "# Load pretrained model and preprocessing function\n", + "model = smp.from_pretrained(checkpoint).eval().to(device)\n", + "preprocessing = A.Compose.from_pretrained(checkpoint)\n", + "\n", + "# Load image\n", + "url = \"https://huggingface.co/datasets/hf-internal-testing/fixtures_ade20k/resolve/main/ADE_val_00000001.jpg\"\n", + "image = Image.open(requests.get(url, stream=True).raw)\n", + "\n", + "# Preprocess image\n", + "image = np.array(image)\n", + "normalized_image = preprocessing(image=image)[\"image\"]\n", + "input_tensor = torch.as_tensor(normalized_image)\n", + "input_tensor = input_tensor.permute(2, 0, 1).unsqueeze(0) # HWC -> BCHW\n", + "input_tensor = input_tensor.to(device)\n", + "\n", + "# Perform inference\n", + "with torch.no_grad():\n", + " output_mask = model(input_tensor)\n", + "\n", + "# Postprocess mask\n", + "mask = torch.nn.functional.interpolate(\n", + " output_mask, size=image.shape[:2], mode=\"bilinear\", align_corners=False\n", + ")\n", + "mask = mask[0].argmax(0).cpu().numpy()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "<Figure size 1200x600 with 2 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Plot results\n", + "plt.figure(figsize=(12, 6))\n", + "\n", + "plt.subplot(121)\n", + "plt.axis(\"off\")\n", + "plt.imshow(image)\n", + "plt.title(\"Input Image\")\n", + "\n", + "plt.subplot(122)\n", + "plt.axis(\"off\")\n", + "plt.imshow(mask)\n", + "plt.title(\"Output Mask\")\n", + "\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 8d3ed4fd26677fdf1da5e02bf8c6e9db7cdafb15 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Mon, 7 Apr 2025 12:33:55 +0000 Subject: [PATCH 36/44] Add decoder_readout according to initial impl --- .../decoders/dpt/decoder.py | 77 ++++++++++++++----- .../decoders/dpt/model.py | 24 +++++- .../encoders/timm_vit.py | 24 +++--- 3 files changed, 91 insertions(+), 34 deletions(-) diff --git a/segmentation_models_pytorch/decoders/dpt/decoder.py b/segmentation_models_pytorch/decoders/dpt/decoder.py index 96d10c49..6f402630 100644 --- a/segmentation_models_pytorch/decoders/dpt/decoder.py +++ b/segmentation_models_pytorch/decoders/dpt/decoder.py @@ -1,18 +1,21 @@ import torch import torch.nn as nn from segmentation_models_pytorch.base.modules import Activation -from typing import Optional, Sequence, Union, Callable +from typing import Optional, Sequence, Union, Callable, Literal -class ProjectionBlock(nn.Module): +class ReadoutConcatBlock(nn.Module): """ - Concatenates the cls tokens with the features to make use of the global information aggregated in the cls token. - Projects the combined feature map to the original embedding dimension using a MLP + Concatenates the cls tokens with the features to make use of the global information aggregated in the prefix (cls) tokens. + Projects the combined feature map to the original embedding dimension using a MLP. + + According to: + https://github.com/isl-org/DPT/blob/cd3fe90bb4c48577535cc4d51b602acca688a2ee/dpt/vit.py#L79-L90 """ - def __init__(self, embed_dim: int, has_cls_token: bool): + def __init__(self, embed_dim: int, has_prefix_tokens: bool): super().__init__() - in_features = embed_dim * 2 if has_cls_token else embed_dim + in_features = embed_dim * 2 if has_prefix_tokens else embed_dim out_features = embed_dim self.project = nn.Sequential( nn.Linear(in_features, out_features), @@ -20,7 +23,7 @@ def __init__(self, embed_dim: int, has_cls_token: bool): ) def forward( - self, features: torch.Tensor, cls_token: Optional[torch.Tensor] = None + self, features: torch.Tensor, prefix_tokens: Optional[torch.Tensor] = None ) -> torch.Tensor: batch_size, embed_dim, height, width = features.shape @@ -28,10 +31,10 @@ def forward( features = features.view(batch_size, embed_dim, -1) features = features.transpose(1, 2).contiguous() - # Add CLS token - if cls_token is not None: - cls_token = cls_token.expand_as(features) - features = torch.cat([features, cls_token], dim=2) + if prefix_tokens is not None: + # (batch_size, num_tokens, embed_dim) -> (batch_size, embed_dim) + prefix_tokens = prefix_tokens[:, 0].expand_as(features) + features = torch.cat([features, prefix_tokens], dim=2) # Project to embedding dimension features = self.project(features) @@ -43,6 +46,34 @@ def forward( return features +class ReadoutAddBlock(nn.Module): + """ + Adds the prefix tokens to the features to make use of the global information aggregated in the prefix (cls) tokens. + + According to: + https://github.com/isl-org/DPT/blob/cd3fe90bb4c48577535cc4d51b602acca688a2ee/dpt/vit.py#L71-L76 + """ + + def forward( + self, features: torch.Tensor, prefix_tokens: Optional[torch.Tensor] = None + ) -> torch.Tensor: + if prefix_tokens is not None: + batch_size, embed_dim, height, width = features.shape + prefix_tokens = prefix_tokens.mean(dim=1) + prefix_tokens = prefix_tokens.view(batch_size, embed_dim, 1, 1) + features = features + prefix_tokens + return features + + +class ReadoutIgnoreBlock(nn.Module): + """ + Ignores the prefix tokens and returns the features as is. + """ + + def forward(self, features: torch.Tensor, *args, **kwargs) -> torch.Tensor: + return features + + class ReassembleBlock(nn.Module): """ Processes the features such that they have progressively increasing embedding size and progressively decreasing @@ -182,20 +213,30 @@ def __init__( self, encoder_out_channels: Sequence[int] = (756, 756, 756, 756), encoder_output_strides: Sequence[int] = (16, 16, 16, 16), + encoder_has_prefix_tokens: bool = True, + readout: Literal["cat", "add", "ignore"] = "cat", intermediate_channels: Sequence[int] = (256, 512, 1024, 1024), fusion_channels: int = 256, - has_cls_token: bool = False, ): super().__init__() num_blocks = len(encoder_output_strides) - # If encoder has cls token, then concatenate it with the features along the embedding dimension and project it - # back to the feature_dim dimension. Else, ignore the non-existent cls token - blocks = [ - ProjectionBlock(in_channels, has_cls_token) - for in_channels in encoder_out_channels - ] + # If encoder has prefix tokens (e.g. cls_token), then we can concat/add/ignore them + # according to the readout mode + if readout == "cat": + blocks = [ + ReadoutConcatBlock(in_channels, encoder_has_prefix_tokens) + for in_channels in encoder_out_channels + ] + elif readout == "add": + blocks = [ReadoutAddBlock() for _ in encoder_out_channels] + elif readout == "ignore": + blocks = [ReadoutIgnoreBlock() for _ in encoder_out_channels] + else: + raise ValueError( + f"Invalid readout mode: {readout}, should be one of: 'cat', 'add', 'ignore'" + ) self.projection_blocks = nn.ModuleList(blocks) # Upsample factors to resize features to [1/4, 1/8, 1/16, 1/32, ...] scales diff --git a/segmentation_models_pytorch/decoders/dpt/model.py b/segmentation_models_pytorch/decoders/dpt/model.py index 1dc7ee07..a04a268d 100644 --- a/segmentation_models_pytorch/decoders/dpt/model.py +++ b/segmentation_models_pytorch/decoders/dpt/model.py @@ -1,4 +1,6 @@ -from typing import Any, Optional, Union, Callable, Sequence +import warnings +from typing import Any, Optional, Union, Callable, Sequence, Literal + import torch from segmentation_models_pytorch.base import ( @@ -43,6 +45,8 @@ class DPT(SegmentationModel): across the number of blocks in encoder, e.g. if number of blocks is 4 and encoder has 20 blocks, then encoder_output_indices will be (4, 9, 14, 19). If specified the number of indices should be equal to encoder_depth. Default is **None**. + decoder_readout: The strategy to utilize the prefix tokens (e.g. cls_token) from the encoder. + Can be one of **"cat"**, **"add"**, or **"ignore"**. Default is **"cat"**. decoder_intermediate_channels: The number of channels for the intermediate decoder layers. Reduce if you want to reduce the number of parameters in the decoder. Default is (256, 512, 1024, 1024). decoder_fusion_channels: The latent dimension to which the encoder features will be projected to before fusion. @@ -78,6 +82,7 @@ def __init__( encoder_depth: int = 4, encoder_weights: Optional[str] = "imagenet", encoder_output_indices: Optional[list[int]] = None, + decoder_readout: Literal["ignore", "add", "cat"] = "cat", decoder_intermediate_channels: Sequence[int] = (256, 512, 1024, 1024), decoder_fusion_channels: int = 256, in_channels: int = 3, @@ -94,6 +99,11 @@ def __init__( f"Only Timm encoders are supported for DPT. Encoder name must start with 'tu-', got {encoder_name}" ) + if decoder_readout not in ["ignore", "add", "cat"]: + raise ValueError( + f"Invalid decoder readout mode. Must be one of: 'ignore', 'add', 'cat'. Got: {decoder_readout}" + ) + self.encoder = TimmViTEncoder( name=encoder_name, in_channels=in_channels, @@ -103,12 +113,20 @@ def __init__( **kwargs, ) + if not self.encoder.has_prefix_tokens and decoder_readout != "ignore": + warnings.warn( + f"Encoder does not have prefix tokens (e.g. cls_token), but `decoder_readout` is set to '{decoder_readout}'. " + f"It's recommended to set `decoder_readout='ignore'` when using a encoder without prefix tokens.", + UserWarning, + ) + self.decoder = DPTDecoder( encoder_out_channels=self.encoder.out_channels, + encoder_output_strides=self.encoder.output_strides, + encoder_has_prefix_tokens=self.encoder.has_prefix_tokens, + readout=decoder_readout, intermediate_channels=decoder_intermediate_channels, fusion_channels=decoder_fusion_channels, - encoder_output_strides=self.encoder.output_strides, - has_cls_token=self.encoder.has_class_token, ) self.segmentation_head = DPTSegmentationHead( diff --git a/segmentation_models_pytorch/encoders/timm_vit.py b/segmentation_models_pytorch/encoders/timm_vit.py index f52b4b10..1df0ab41 100644 --- a/segmentation_models_pytorch/encoders/timm_vit.py +++ b/segmentation_models_pytorch/encoders/timm_vit.py @@ -129,13 +129,14 @@ def __init__( # Private attributes for model forward self._num_prefix_tokens = getattr(self.model, "num_prefix_tokens", 0) + self._has_cls_token = getattr(self.model, "has_cls_token", False) self._output_indices = output_indices # Public attributes self.output_strides = [feature_info[i]["reduction"] for i in output_indices] self.output_stride = self.output_strides[-1] self.out_channels = [feature_info[i]["num_chs"] for i in output_indices] - self.has_class_token = getattr(self.model, "has_class_token", False) + self.has_prefix_tokens = self._num_prefix_tokens > 0 @property def is_fixed_input_size(self) -> bool: @@ -145,25 +146,22 @@ def is_fixed_input_size(self) -> bool: def input_size(self) -> int: return self.model.pretrained_cfg.get("input_size", None) - def _forward_with_cls_token( + def _forward_with_prefix_tokens( self, x: torch.Tensor ) -> tuple[list[torch.Tensor], list[torch.Tensor]]: intermediate_outputs = self.model.forward_intermediates( x, indices=self._output_indices, - return_prefix_tokens=True, intermediates_only=True, + return_prefix_tokens=True, ) features = [output[0] for output in intermediate_outputs] - cls_tokens = [output[1] for output in intermediate_outputs] - - if self.has_class_token and self._num_prefix_tokens > 1: - cls_tokens = [x[:, 0, :] for x in cls_tokens] + prefix_tokens = [output[1] for output in intermediate_outputs] - return features, cls_tokens + return features, prefix_tokens - def _forward_without_cls_token(self, x: torch.Tensor) -> list[torch.Tensor]: + def _forward_without_prefix_tokens(self, x: torch.Tensor) -> list[torch.Tensor]: features = self.model.forward_intermediates( x, indices=self._output_indices, @@ -184,10 +182,10 @@ def forward( tuple[list[torch.Tensor], list[torch.Tensor]]: Tuple of feature maps and cls tokens (if supported) at different scales. """ - if self.has_class_token: - features, cls_tokens = self._forward_with_cls_token(x) + if self.has_prefix_tokens: + features, prefix_tokens = self._forward_with_prefix_tokens(x) else: features = self._forward_without_cls_token(x) - cls_tokens = [None] * len(features) + prefix_tokens = [None] * len(features) - return features, cls_tokens + return features, prefix_tokens From 4eb6ec301d4298d1ea40dd34068bf4405d125c34 Mon Sep 17 00:00:00 2001 From: VedantDalimkar <f20190209@goa.bits-pilani.ac.in> Date: Mon, 7 Apr 2025 21:06:33 +0530 Subject: [PATCH 37/44] Tests update --- .../decoders/dpt/model.py | 4 +- .../encoders/timm_vit.py | 7 +- tests/encoders/test_timm_vit_encoders.py | 100 +++++++++--------- tests/models/test_dpt.py | 6 +- 4 files changed, 60 insertions(+), 57 deletions(-) diff --git a/segmentation_models_pytorch/decoders/dpt/model.py b/segmentation_models_pytorch/decoders/dpt/model.py index a04a268d..857c4b92 100644 --- a/segmentation_models_pytorch/decoders/dpt/model.py +++ b/segmentation_models_pytorch/decoders/dpt/model.py @@ -71,8 +71,8 @@ class DPT(SegmentationModel): """ - _is_torch_scriptable = False - _is_torch_compilable = False + _is_torch_scriptable = True + _is_torch_compilable = True requires_divisible_input_shape = True @supports_config_loading diff --git a/segmentation_models_pytorch/encoders/timm_vit.py b/segmentation_models_pytorch/encoders/timm_vit.py index 1df0ab41..56e7cabd 100644 --- a/segmentation_models_pytorch/encoders/timm_vit.py +++ b/segmentation_models_pytorch/encoders/timm_vit.py @@ -92,6 +92,11 @@ def __init__( f"{self.__class__.__name__} depth should be in range [1, 4], got {depth}" ) + # Output stride validation needed for smp encoder test consistency + output_stride = kwargs.pop("output_stride", None) + if output_stride is not None: + raise ValueError("Dilated mode not supported, set output stride to None") + if isinstance(output_indices, (list, tuple)) and len(output_indices) != depth: raise ValueError( f"Length of output indices for feature extraction should be equal to the depth of the encoder " @@ -185,7 +190,7 @@ def forward( if self.has_prefix_tokens: features, prefix_tokens = self._forward_with_prefix_tokens(x) else: - features = self._forward_without_cls_token(x) + features = self._forward_without_prefix_tokens(x) prefix_tokens = [None] * len(features) return features, prefix_tokens diff --git a/tests/encoders/test_timm_vit_encoders.py b/tests/encoders/test_timm_vit_encoders.py index 4063abb0..9f742e1d 100644 --- a/tests/encoders/test_timm_vit_encoders.py +++ b/tests/encoders/test_timm_vit_encoders.py @@ -1,8 +1,9 @@ from tests.encoders import base import timm import torch -import segmentation_models_pytorch as smp import pytest +from segmentation_models_pytorch.encoders import TimmViTEncoder +from segmentation_models_pytorch.encoders.timm_vit import sample_block_indices_uniformly from tests.utils import ( default_device, @@ -11,20 +12,14 @@ requires_timm_greater_or_equal, ) -timm_vit_encoders = [ - "tu-vit_tiny_patch16_224", - "tu-vit_small_patch32_224", - "tu-vit_base_patch32_384", - "tu-vit_base_patch16_gap_224", - "tu-vit_medium_patch16_reg4_gap_256", - "tu-vit_so150m2_patch16_reg1_gap_256", - "tu-vit_medium_patch16_gap_240", -] +timm_vit_encoders = ["vit_tiny_patch16_224"] class TestTimmViTEncoders(base.BaseEncoderTester): encoder_names = timm_vit_encoders tiny_encoder_patch_size = 224 + default_height = 224 + default_width = 224 files_for_diff = ["encoders/dpt.py"] @@ -35,14 +30,10 @@ class TestTimmViTEncoders(base.BaseEncoderTester): depth_to_test = [2, 3, 4] - default_encoder_kwargs = {"use_vit_encoder": True} - - def _get_model_expected_input_shape(self, encoder_name: str) -> int: - patch_size_str = encoder_name[-3:] - return int(patch_size_str) + default_encoder_kwargs = {"pretrained": False} def get_tiny_encoder(self): - return smp.encoders.get_encoder( + return TimmViTEncoder( self.encoder_names[0], encoder_weights=None, output_stride=None, @@ -55,13 +46,10 @@ def get_tiny_encoder(self): @requires_timm_greater_or_equal("1.0.15") def test_forward_backward(self): for encoder_name in self.encoder_names: - patch_size = self._get_model_expected_input_shape(encoder_name) - sample = self._get_sample(height=patch_size, width=patch_size).to( - default_device - ) + sample = self._get_sample().to(default_device) with self.subTest(encoder_name=encoder_name): # init encoder - encoder = smp.encoders.get_encoder( + encoder = TimmViTEncoder( encoder_name, in_channels=3, encoder_weights=None, @@ -90,13 +78,10 @@ def test_in_channels(self): ] for encoder_name, in_channels in cases: - patch_size = self._get_model_expected_input_shape(encoder_name) - sample = self._get_sample( - height=patch_size, width=patch_size, num_channels=in_channels - ).to(default_device) + sample = self._get_sample(num_channels=in_channels).to(default_device) with self.subTest(encoder_name=encoder_name, in_channels=in_channels): - encoder = smp.encoders.get_encoder( + encoder = TimmViTEncoder( encoder_name, in_channels=in_channels, encoder_weights=None, @@ -119,12 +104,9 @@ def test_depth(self): ] for encoder_name, depth in cases: - patch_size = self._get_model_expected_input_shape(encoder_name) - sample = self._get_sample(height=patch_size, width=patch_size).to( - default_device - ) + sample = self._get_sample().to(default_device) with self.subTest(encoder_name=encoder_name, depth=depth): - encoder = smp.encoders.get_encoder( + encoder = TimmViTEncoder( encoder_name, in_channels=self.default_num_channels, encoder_weights=None, @@ -150,10 +132,9 @@ def test_depth(self): sample, features ) - timm_encoder_name = encoder_name[3:] - encoder_out_indices = encoder.out_indices + encoder_out_indices = sample_block_indices_uniformly(depth, 12) timm_model_feature_info = timm.create_model( - model_name=timm_encoder_name + model_name=encoder_name ).feature_info feature_info_obj = timm.models.FeatureInfo( feature_info=timm_model_feature_info, @@ -189,35 +170,56 @@ def test_depth(self): @requires_timm_greater_or_equal("1.0.15") def test_invalid_depth(self): with self.assertRaises(ValueError): - smp.encoders.get_encoder(self.encoder_names[0], depth=5, output_stride=None) + TimmViTEncoder( + self.encoder_names[0], + depth=5, + output_stride=None, + **self.default_encoder_kwargs, + ) with self.assertRaises(ValueError): - smp.encoders.get_encoder(self.encoder_names[0], depth=0, output_stride=None) + TimmViTEncoder( + self.encoder_names[0], + depth=0, + output_stride=None, + **self.default_encoder_kwargs, + ) @requires_timm_greater_or_equal("1.0.15") def test_invalid_out_indices(self): with self.assertRaises(ValueError): - smp.encoders.get_encoder( - self.encoder_names[0], output_stride=None, out_indices=-1 + TimmViTEncoder( + self.encoder_names[0], + output_stride=None, + output_indices=-25, + **self.default_encoder_kwargs, ) with self.assertRaises(ValueError): - smp.encoders.get_encoder( - self.encoder_names[0], output_stride=None, out_indices=[1, 2, 25] + TimmViTEncoder( + self.encoder_names[0], + output_stride=None, + output_indices=[1, 2, 25], + **self.default_encoder_kwargs, ) @requires_timm_greater_or_equal("1.0.15") def test_invalid_out_indices_length(self): with self.assertRaises(ValueError): - smp.encoders.get_encoder( - self.encoder_names[0], output_stride=None, out_indices=2, depth=2 + TimmViTEncoder( + self.encoder_names[0], + output_stride=None, + output_indices=2, + depth=2, + **self.default_encoder_kwargs, ) with self.assertRaises(ValueError): - smp.encoders.get_encoder( + TimmViTEncoder( self.encoder_names[0], output_stride=None, - out_indices=[0, 1, 2, 3, 4], + output_indices=[0, 1, 2, 3, 4], depth=4, + **self.default_encoder_kwargs, ) @requires_timm_greater_or_equal("1.0.15") @@ -235,23 +237,19 @@ def test_dilated(self): ValueError, msg="Dilated mode not supported, set output stride to None" ): encoder_name, stride = cases[0] - patch_size = self._get_model_expected_input_shape(encoder_name) - sample = self._get_sample(height=patch_size, width=patch_size).to( - default_device - ) - encoder = smp.encoders.get_encoder( + sample = self._get_sample().to(default_device) + encoder = TimmViTEncoder( encoder_name, in_channels=self.default_num_channels, encoder_weights=None, output_stride=stride, depth=self.default_depth, - **self.default_encoder_kwargs, ).to(default_device) return for encoder_name, stride in cases: with self.subTest(encoder_name=encoder_name, stride=stride): - encoder = smp.encoders.get_encoder( + encoder = TimmViTEncoder( encoder_name, in_channels=self.default_num_channels, encoder_weights=None, diff --git a/tests/models/test_dpt.py b/tests/models/test_dpt.py index a394c227..1630d0d2 100644 --- a/tests/models/test_dpt.py +++ b/tests/models/test_dpt.py @@ -11,11 +11,11 @@ class TestDPTModel(base.BaseModelTester): - test_encoder_name = "tu-vit_large_patch16_384" + test_encoder_name = "tu-vit_tiny_patch16_224" files_for_diff = [r"decoders/dpt/", r"base/"] - default_height = 384 - default_width = 384 + default_height = 224 + default_width = 224 # should be overriden test_model_type = "dpt" From 165b9c0f2a1d11259267b608cdb3f313b2a4a3fe Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Mon, 7 Apr 2025 18:47:20 +0000 Subject: [PATCH 38/44] Fix encoder tests --- .../encoders/timm_vit.py | 21 +- tests/encoders/test_timm_vit_encoders.py | 239 ++++-------------- 2 files changed, 63 insertions(+), 197 deletions(-) diff --git a/segmentation_models_pytorch/encoders/timm_vit.py b/segmentation_models_pytorch/encoders/timm_vit.py index 56e7cabd..5519d897 100644 --- a/segmentation_models_pytorch/encoders/timm_vit.py +++ b/segmentation_models_pytorch/encoders/timm_vit.py @@ -61,9 +61,10 @@ class TimmViTEncoder(nn.Module): - Ensures consistent multi-level feature extraction across all ViT models. """ + # prefix tokens are not supported for scripting _is_torch_scriptable = False _is_torch_exportable = True - _is_torch_compilable = False + _is_torch_compilable = True def __init__( self, @@ -87,10 +88,8 @@ def __init__( """ super().__init__() - if depth > 4 or depth < 1: - raise ValueError( - f"{self.__class__.__name__} depth should be in range [1, 4], got {depth}" - ) + if depth < 1: + raise ValueError(f"`encoder_depth` should be greater than 1, got {depth}.") # Output stride validation needed for smp encoder test consistency output_stride = kwargs.pop("output_stride", None) @@ -142,14 +141,10 @@ def __init__( self.output_stride = self.output_strides[-1] self.out_channels = [feature_info[i]["num_chs"] for i in output_indices] self.has_prefix_tokens = self._num_prefix_tokens > 0 - - @property - def is_fixed_input_size(self) -> bool: - return self.model.pretrained_cfg.get("fixed_input_size", False) - - @property - def input_size(self) -> int: - return self.model.pretrained_cfg.get("input_size", None) + self.input_size = self.model.pretrained_cfg.get("input_size", None) + self.is_fixed_input_size = self.model.pretrained_cfg.get( + "fixed_input_size", False + ) def _forward_with_prefix_tokens( self, x: torch.Tensor diff --git a/tests/encoders/test_timm_vit_encoders.py b/tests/encoders/test_timm_vit_encoders.py index 9f742e1d..260d926f 100644 --- a/tests/encoders/test_timm_vit_encoders.py +++ b/tests/encoders/test_timm_vit_encoders.py @@ -1,10 +1,11 @@ -from tests.encoders import base import timm import torch import pytest + from segmentation_models_pytorch.encoders import TimmViTEncoder from segmentation_models_pytorch.encoders.timm_vit import sample_block_indices_uniformly +from tests.encoders import base from tests.utils import ( default_device, check_run_test_on_diff_or_main, @@ -15,6 +16,7 @@ timm_vit_encoders = ["vit_tiny_patch16_224"] +@requires_timm_greater_or_equal("1.0.0") class TestTimmViTEncoders(base.BaseEncoderTester): encoder_names = timm_vit_encoders tiny_encoder_patch_size = 224 @@ -30,46 +32,48 @@ class TestTimmViTEncoders(base.BaseEncoderTester): depth_to_test = [2, 3, 4] - default_encoder_kwargs = {"pretrained": False} - - def get_tiny_encoder(self): + def get_tiny_encoder(self) -> TimmViTEncoder: return TimmViTEncoder( - self.encoder_names[0], - encoder_weights=None, - output_stride=None, + name=self.encoder_names[0], + pretrained=False, depth=self.default_depth, - **self.default_encoder_kwargs, + in_channels=3, ) - # Requires timm version greater than 1.0.15 as the required functionality of the timm VisionTransformer - # for SMP's TimmViTEncoder class were introduced in the latest version. - @requires_timm_greater_or_equal("1.0.15") + def get_encoder(self, encoder_name: str, **kwargs) -> TimmViTEncoder: + default_kwargs = { + "name": encoder_name, + "pretrained": False, + "depth": self.default_depth, + "in_channels": 3, + } + default_kwargs.update(kwargs) + return TimmViTEncoder(**default_kwargs) + def test_forward_backward(self): for encoder_name in self.encoder_names: sample = self._get_sample().to(default_device) with self.subTest(encoder_name=encoder_name): # init encoder - encoder = TimmViTEncoder( - encoder_name, - in_channels=3, - encoder_weights=None, - depth=self.default_depth, - output_stride=None, - **self.default_encoder_kwargs, - ).to(default_device) + encoder = self.get_encoder(encoder_name).to(default_device) # forward - features, cls_tokens = encoder.forward(sample) + features, prefix_tokens = encoder.forward(sample) self.assertEqual( len(features), self.num_output_features, f"Encoder `{encoder_name}` should have {self.num_output_features} output feature maps, but has {len(features)}", ) + if encoder.has_prefix_tokens: + self.assertEqual( + len(prefix_tokens), + self.num_output_features, + f"Encoder `{encoder_name}` should have {self.num_output_features} prefix tokens, but has {len(prefix_tokens)}", + ) # backward features[-1].mean().backward() - @requires_timm_greater_or_equal("1.0.15") def test_in_channels(self): cases = [ (encoder_name, in_channels) @@ -81,21 +85,15 @@ def test_in_channels(self): sample = self._get_sample(num_channels=in_channels).to(default_device) with self.subTest(encoder_name=encoder_name, in_channels=in_channels): - encoder = TimmViTEncoder( - encoder_name, - in_channels=in_channels, - encoder_weights=None, - depth=4, - output_stride=None, - **self.default_encoder_kwargs, - ).to(default_device) + encoder = self.get_encoder(encoder_name, in_channels=in_channels).to( + default_device + ) encoder.eval() # forward with torch.inference_mode(): encoder.forward(sample) - @requires_timm_greater_or_equal("1.0.15") def test_depth(self): cases = [ (encoder_name, depth) @@ -106,19 +104,12 @@ def test_depth(self): for encoder_name, depth in cases: sample = self._get_sample().to(default_device) with self.subTest(encoder_name=encoder_name, depth=depth): - encoder = TimmViTEncoder( - encoder_name, - in_channels=self.default_num_channels, - encoder_weights=None, - depth=depth, - output_stride=None, - **self.default_encoder_kwargs, - ).to(default_device) + encoder = self.get_encoder(encoder_name, depth=depth).to(default_device) encoder.eval() # forward with torch.inference_mode(): - features, cls_tokens = encoder.forward(sample) + features, _ = encoder.forward(sample) # check number of features self.assertEqual( @@ -133,31 +124,27 @@ def test_depth(self): ) encoder_out_indices = sample_block_indices_uniformly(depth, 12) - timm_model_feature_info = timm.create_model( - model_name=encoder_name - ).feature_info - feature_info_obj = timm.models.FeatureInfo( - feature_info=timm_model_feature_info, - out_indices=encoder_out_indices, - ) - self.output_strides = feature_info_obj.reduction() + feature_info = timm.create_model(model_name=encoder_name).feature_info + output_strides = [ + feature_info[i]["reduction"] for i in encoder_out_indices + ] self.assertEqual( height_strides, - self.output_strides[:depth], - f"Encoder `{encoder_name}` should have output strides {self.output_strides[:depth]}, but has {height_strides}", + output_strides, + f"Encoder `{encoder_name}` should have output strides {output_strides}, but has {height_strides}", ) self.assertEqual( width_strides, - self.output_strides[:depth], - f"Encoder `{encoder_name}` should have output strides {self.output_strides[:depth]}, but has {width_strides}", + output_strides, + f"Encoder `{encoder_name}` should have output strides {output_strides}, but has {width_strides}", ) # check encoder output stride property self.assertEqual( - encoder.output_stride, - self.output_strides[depth - 1], - f"Encoder `{encoder_name}` last feature map should have output stride {self.output_strides[depth - 1]}, but has {encoder.output_stride}", + encoder.output_strides, + output_strides, + f"Encoder `{encoder_name}` last feature map should have output stride {output_strides[depth - 1]}, but has {encoder.output_stride}", ) # check out channels also have proper length @@ -167,120 +154,32 @@ def test_depth(self): f"Encoder `{encoder_name}` should have {depth} out_channels, but has {len(encoder.out_channels)}", ) - @requires_timm_greater_or_equal("1.0.15") def test_invalid_depth(self): with self.assertRaises(ValueError): - TimmViTEncoder( - self.encoder_names[0], - depth=5, - output_stride=None, - **self.default_encoder_kwargs, - ) + self.get_encoder(self.encoder_names[0], depth=0) with self.assertRaises(ValueError): - TimmViTEncoder( - self.encoder_names[0], - depth=0, - output_stride=None, - **self.default_encoder_kwargs, - ) + self.get_encoder(self.encoder_names[0], depth=25) - @requires_timm_greater_or_equal("1.0.15") def test_invalid_out_indices(self): + # out of range with self.assertRaises(ValueError): - TimmViTEncoder( - self.encoder_names[0], - output_stride=None, - output_indices=-25, - **self.default_encoder_kwargs, - ) - + self.get_encoder(self.encoder_names[0], depth=1, output_indices=-25) with self.assertRaises(ValueError): - TimmViTEncoder( - self.encoder_names[0], - output_stride=None, - output_indices=[1, 2, 25], - **self.default_encoder_kwargs, - ) + self.get_encoder(self.encoder_names[0], depth=3, output_indices=[1, 2, 25]) - @requires_timm_greater_or_equal("1.0.15") - def test_invalid_out_indices_length(self): + # invalid length with self.assertRaises(ValueError): - TimmViTEncoder( + self.get_encoder( self.encoder_names[0], - output_stride=None, - output_indices=2, depth=2, - **self.default_encoder_kwargs, + output_indices=[ + 2, + ], ) - with self.assertRaises(ValueError): - TimmViTEncoder( - self.encoder_names[0], - output_stride=None, - output_indices=[0, 1, 2, 3, 4], - depth=4, - **self.default_encoder_kwargs, - ) - - @requires_timm_greater_or_equal("1.0.15") def test_dilated(self): - cases = [ - (encoder_name, stride) - for encoder_name in self.encoder_names - for stride in self.strides_to_test - ] - - # special case for encoders that do not support dilated model - # just check proper error is raised - if not self.supports_dilated: - with self.assertRaises( - ValueError, msg="Dilated mode not supported, set output stride to None" - ): - encoder_name, stride = cases[0] - sample = self._get_sample().to(default_device) - encoder = TimmViTEncoder( - encoder_name, - in_channels=self.default_num_channels, - encoder_weights=None, - output_stride=stride, - depth=self.default_depth, - ).to(default_device) - return - - for encoder_name, stride in cases: - with self.subTest(encoder_name=encoder_name, stride=stride): - encoder = TimmViTEncoder( - encoder_name, - in_channels=self.default_num_channels, - encoder_weights=None, - output_stride=stride, - depth=self.default_depth, - **self.default_encoder_kwargs, - ).to(default_device) - encoder.eval() - - # forward - with torch.inference_mode(): - features, cls_tokens = encoder.forward(sample) - - height_strides, width_strides = self.get_features_output_strides( - encoder, sample, features - ) - expected_height_strides = [min(stride, s) for s in height_strides] - expected_width_strides = [min(stride, s) for s in width_strides] - - self.assertEqual( - height_strides, - expected_height_strides, - f"Encoder `{encoder_name}` should have height output strides {expected_height_strides}, but has {height_strides}", - ) - self.assertEqual( - width_strides, - expected_width_strides, - f"Encoder `{encoder_name}` should have width output strides {expected_width_strides}, but has {width_strides}", - ) + pytest.skip("Dilation is not supported for ViT encoders") - @requires_timm_greater_or_equal("1.0.15") @pytest.mark.compile def test_compile(self): if not check_run_test_on_diff_or_main(self.files_for_diff): @@ -304,7 +203,6 @@ def test_compile(self): with self.assertRaises(Exception): compiled_encoder(sample) - @requires_timm_greater_or_equal("1.0.15") @pytest.mark.torch_export @requires_torch_greater_or_equal("2.4.0") def test_torch_export(self): @@ -318,15 +216,6 @@ def test_torch_export(self): encoder = self.get_tiny_encoder() encoder = encoder.eval().to(default_device) - if not encoder._is_torch_exportable: - with self.assertRaises(Exception): - exported_encoder = torch.export.export( - encoder, - args=(sample,), - strict=True, - ) - return - exported_encoder = torch.export.export( encoder, args=(sample,), @@ -340,26 +229,8 @@ def test_torch_export(self): for eager_feature, exported_feature in zip(eager_output, exported_output): torch.testing.assert_close(eager_feature, exported_feature) - @requires_timm_greater_or_equal("1.0.15") @pytest.mark.torch_script def test_torch_script(self): - sample = self._get_sample( - height=self.tiny_encoder_patch_size, width=self.tiny_encoder_patch_size - ).to(default_device) - - encoder = self.get_tiny_encoder() - encoder = encoder.eval().to(default_device) - - if not encoder._is_torch_scriptable: - with self.assertRaises(RuntimeError, msg="not torch scriptable"): - scripted_encoder = torch.jit.script(encoder) - return - - scripted_encoder = torch.jit.script(encoder) - - with torch.inference_mode(): - eager_output = encoder(sample) - scripted_output = scripted_encoder(sample) - - for eager_feature, scripted_feature in zip(eager_output, scripted_output): - torch.testing.assert_close(eager_feature, scripted_feature) + pytest.skip( + "Encoder with prefix tokens are not supported for scripting, due to poor type handling" + ) From 5603707d6a3b2474e96a8201e119b9ab372b34b7 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Mon, 7 Apr 2025 19:02:17 +0000 Subject: [PATCH 39/44] Fix DPT tests --- .../decoders/dpt/decoder.py | 16 +++++++++------- .../decoders/dpt/model.py | 7 ++++--- tests/models/test_dpt.py | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/segmentation_models_pytorch/decoders/dpt/decoder.py b/segmentation_models_pytorch/decoders/dpt/decoder.py index 6f402630..3a8d837b 100644 --- a/segmentation_models_pytorch/decoders/dpt/decoder.py +++ b/segmentation_models_pytorch/decoders/dpt/decoder.py @@ -258,21 +258,23 @@ def __init__( self.fusion_blocks = nn.ModuleList(fusion_blocks) def forward( - self, features: list[torch.Tensor], cls_tokens: list[Optional[torch.Tensor]] + self, features: list[torch.Tensor], prefix_tokens: list[Optional[torch.Tensor]] ) -> torch.Tensor: # Process the encoder features to scale of [1/4, 1/8, 1/16, 1/32, ...] processed_features = [] - for i, (feature, cls_token) in enumerate(zip(features, cls_tokens)): - projected_feature = self.projection_blocks[i](feature, cls_token) + for i, (feature, prefix_tokens_i) in enumerate(zip(features, prefix_tokens)): + projected_feature = self.projection_blocks[i](feature, prefix_tokens_i) processed_feature = self.reassemble_blocks[i](projected_feature) processed_features.append(processed_feature) # Fusion and progressive upsampling starting from the last processed feature - previous_feature = None processed_features = processed_features[::-1] - for fusion_block, feature in zip(self.fusion_blocks, processed_features): - fused_feature = fusion_block(feature, previous_feature) - previous_feature = fused_feature + for i, fusion_block in enumerate(self.fusion_blocks): + processed_feature = processed_features[i] + if i == 0: + fused_feature = fusion_block(processed_feature) + else: + fused_feature = fusion_block(processed_feature, fused_feature) return fused_feature diff --git a/segmentation_models_pytorch/decoders/dpt/model.py b/segmentation_models_pytorch/decoders/dpt/model.py index 857c4b92..1294dd4f 100644 --- a/segmentation_models_pytorch/decoders/dpt/model.py +++ b/segmentation_models_pytorch/decoders/dpt/model.py @@ -71,7 +71,8 @@ class DPT(SegmentationModel): """ - _is_torch_scriptable = True + # fails for encoders with prefix tokens + _is_torch_scriptable = False _is_torch_compilable = True requires_divisible_input_shape = True @@ -155,8 +156,8 @@ def forward(self, x): ): self.check_input_shape(x) - features, cls_tokens = self.encoder(x) - decoder_output = self.decoder(features, cls_tokens) + features, prefix_tokens = self.encoder(x) + decoder_output = self.decoder(features, prefix_tokens) masks = self.segmentation_head(decoder_output) if self.classification_head is not None: diff --git a/tests/models/test_dpt.py b/tests/models/test_dpt.py index 1630d0d2..bd6574ca 100644 --- a/tests/models/test_dpt.py +++ b/tests/models/test_dpt.py @@ -22,7 +22,7 @@ class TestDPTModel(base.BaseModelTester): @property def hub_checkpoint(self): - return "vedantdalimkar/DPT" + return "smp-hub/dpt-large-ade20k" @slow_test @requires_torch_greater_or_equal("2.0.1") From 95189646254df2b3d70e6a5c2f6b2fb96c031f23 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Mon, 7 Apr 2025 19:40:41 +0000 Subject: [PATCH 40/44] Refactor a bit --- .../decoders/dpt/decoder.py | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/segmentation_models_pytorch/decoders/dpt/decoder.py b/segmentation_models_pytorch/decoders/dpt/decoder.py index 3a8d837b..c0b4634b 100644 --- a/segmentation_models_pytorch/decoders/dpt/decoder.py +++ b/segmentation_models_pytorch/decoders/dpt/decoder.py @@ -220,7 +220,16 @@ def __init__( ): super().__init__() - num_blocks = len(encoder_output_strides) + if not ( + len(encoder_out_channels) + == len(encoder_output_strides) + == len(intermediate_channels) + ): + raise ValueError( + "encoder_out_channels, encoder_output_strides and intermediate_channels must have the same length" + ) + + num_blocks = len(encoder_out_channels) # If encoder has prefix tokens (e.g. cls_token), then we can concat/add/ignore them # according to the readout mode @@ -269,12 +278,9 @@ def forward( # Fusion and progressive upsampling starting from the last processed feature processed_features = processed_features[::-1] - for i, fusion_block in enumerate(self.fusion_blocks): - processed_feature = processed_features[i] - if i == 0: - fused_feature = fusion_block(processed_feature) - else: - fused_feature = fusion_block(processed_feature, fused_feature) + fused_feature = None + for fusion_block, feature in zip(self.fusion_blocks, processed_features): + fused_feature = fusion_block(feature, fused_feature) return fused_feature From 38cb94491a14f59d2313d26e9984280972d5218f Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Mon, 7 Apr 2025 19:40:58 +0000 Subject: [PATCH 41/44] Tests --- tests/models/base.py | 8 +++++--- tests/models/test_dpt.py | 11 ++++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/tests/models/base.py b/tests/models/base.py index 19bd71da..a6320955 100644 --- a/tests/models/base.py +++ b/tests/models/base.py @@ -33,6 +33,8 @@ class BaseModelTester(unittest.TestCase): default_height = 64 default_width = 64 + compile_dynamic = True + @property def model_type(self): if self.test_model_type is None: @@ -232,16 +234,16 @@ def test_compile(self): model = model.eval().to(default_device) if not model._is_torch_compilable: - with self.assertRaises(RuntimeError): + with self.assertRaises((RuntimeError)): torch.compiler.reset() compiled_model = torch.compile( - model, fullgraph=True, dynamic=True, backend="eager" + model, fullgraph=True, dynamic=self.compile_dynamic, backend="eager" ) return torch.compiler.reset() compiled_model = torch.compile( - model, fullgraph=True, dynamic=True, backend="eager" + model, fullgraph=True, dynamic=self.compile_dynamic, backend="eager" ) with torch.inference_mode(): compiled_model(sample) diff --git a/tests/models/test_dpt.py b/tests/models/test_dpt.py index bd6574ca..057ed224 100644 --- a/tests/models/test_dpt.py +++ b/tests/models/test_dpt.py @@ -20,15 +20,20 @@ class TestDPTModel(base.BaseModelTester): # should be overriden test_model_type = "dpt" + compile_dynamic = False + @property def hub_checkpoint(self): - return "smp-hub/dpt-large-ade20k" + return "smp-test-models/dpt-tu-test_vit" @slow_test @requires_torch_greater_or_equal("2.0.1") @pytest.mark.logits_match - def test_preserve_forward_output(self): - model = smp.from_pretrained(self.hub_checkpoint).eval().to(default_device) + def test_load_pretrained(self): + hub_checkpoint = "smp-hub/dpt-large-ade20k" + + model = smp.from_pretrained(hub_checkpoint) + model = model.eval().to(default_device) input_tensor = torch.ones((1, 3, 384, 384)) input_tensor = input_tensor.to(default_device) From 17d33289459aef148618e96df6aee22bd78b2fc2 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Mon, 7 Apr 2025 19:41:18 +0000 Subject: [PATCH 42/44] Update gen test models --- misc/generate_test_models.py | 45 +++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/misc/generate_test_models.py b/misc/generate_test_models.py index 61d6bfd0..a26cbc66 100644 --- a/misc/generate_test_models.py +++ b/misc/generate_test_models.py @@ -9,33 +9,50 @@ api = huggingface_hub.HfApi(token=os.getenv("HF_TOKEN")) -for model_name, model_class in smp.MODEL_ARCHITECTURES_MAPPING.items(): - model = model_class(encoder_name=ENCODER_NAME) - model = model.eval() - - # generate test sample - torch.manual_seed(423553) - sample = torch.rand(1, 3, 256, 256) - - with torch.no_grad(): - output = model(sample) +def save_and_push(model, inputs, outputs, model_name, encoder_name): with tempfile.TemporaryDirectory() as tmpdir: # save model model.save_pretrained(f"{tmpdir}") # save input and output - torch.save(sample, f"{tmpdir}/input-tensor.pth") - torch.save(output, f"{tmpdir}/output-tensor.pth") + torch.save(inputs, f"{tmpdir}/input-tensor.pth") + torch.save(outputs, f"{tmpdir}/output-tensor.pth") # create repo - repo_id = f"{HUB_REPO}/{model_name}-{ENCODER_NAME}" + repo_id = f"{HUB_REPO}/{model_name}-{encoder_name}" if not api.repo_exists(repo_id=repo_id): api.create_repo(repo_id=repo_id, repo_type="model") # upload to hub api.upload_folder( folder_path=tmpdir, - repo_id=f"{HUB_REPO}/{model_name}-{ENCODER_NAME}", + repo_id=f"{HUB_REPO}/{model_name}-{encoder_name}", repo_type="model", ) + + +for model_name, model_class in smp.MODEL_ARCHITECTURES_MAPPING.items(): + if model_name == "dpt": + encoder_name = "tu-test_vit" + model = smp.DPT( + encoder_name=encoder_name, + decoder_readout="cat", + decoder_intermediate_channels=(16, 32, 64, 64), + decoder_fusion_channels=16, + dynamic_img_size=True, + ) + else: + encoder_name = ENCODER_NAME + model = model_class(encoder_name=encoder_name) + + model = model.eval() + + # generate test sample + torch.manual_seed(423553) + sample = torch.rand(1, 3, 256, 256) + + with torch.no_grad(): + output = model(sample) + + save_and_push(model, sample, output, model_name, encoder_name) From 83b9655e312840dda810af5940124be1ce1b6dc6 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Mon, 7 Apr 2025 19:43:57 +0000 Subject: [PATCH 43/44] Revert gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index e0490fa5..33db579f 100644 --- a/.gitignore +++ b/.gitignore @@ -75,7 +75,6 @@ target/ # Jupyter Notebook .ipynb_checkpoints -*ipynb* # pyenv .python-version From 343fbe0891efd9d37243b67d7fb4a6869ba898b1 Mon Sep 17 00:00:00 2001 From: qubvel <qubvel@gmail.com> Date: Mon, 7 Apr 2025 19:56:04 +0000 Subject: [PATCH 44/44] Fix test --- tests/models/base.py | 3 +++ tests/models/test_dpt.py | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/tests/models/base.py b/tests/models/base.py index a6320955..717bc801 100644 --- a/tests/models/base.py +++ b/tests/models/base.py @@ -99,6 +99,9 @@ def test_in_channels_and_depth_and_out_classes( if self.model_type in ["unet", "unetplusplus", "manet"]: kwargs = {"decoder_channels": self.decoder_channels[:depth]} + if self.model_type == "dpt": + kwargs = {"decoder_intermediate_channels": self.decoder_channels[:depth]} + model = ( smp.create_model( arch=self.model_type, diff --git a/tests/models/test_dpt.py b/tests/models/test_dpt.py index 057ed224..40df1e38 100644 --- a/tests/models/test_dpt.py +++ b/tests/models/test_dpt.py @@ -1,4 +1,5 @@ import pytest +import inspect import torch import segmentation_models_pytorch as smp @@ -22,6 +23,11 @@ class TestDPTModel(base.BaseModelTester): compile_dynamic = False + @property + def decoder_channels(self): + signature = inspect.signature(self.model_class) + return signature.parameters["decoder_intermediate_channels"].default + @property def hub_checkpoint(self): return "smp-test-models/dpt-tu-test_vit"