Files
2026-07-13 13:24:13 +08:00

120 lines
4.2 KiB
Python

import torch
from torch import nn
from timm.models.layers import trunc_normal_ as __call_trunc_normal_
from .modeling_utils import VisionTransformer
from .modeling_beit3_vision import beit3_base_vision
from functools import partial
def trunc_normal_(tensor, mean=0., std=1.):
__call_trunc_normal_(tensor, mean=mean, std=std, a=-std, b=std)
class EncoderDecoderArchForImageReconstrction(nn.Module):
# This is the main class for the encoder-decoder architecture
# It is used for image reconstruction
# contains encoer backbone, decoder backbone
def __init__(
self,
encoder_config: dict,
encoder_post_processor: nn.Module,
decoder_pre_processor: nn.Module,
decoder_config: dict,
decoder_post_processor: nn.Module,
):
super().__init__()
self.img_size = encoder_config['img_size']
self.encoder = self.build_encoder(encoder_config)
self.encoder_post_processor = encoder_post_processor
self.decoder_pre_processor = decoder_pre_processor
self.decoder = self.build_decoder(decoder_config)
self.decoder_post_processor = decoder_post_processor
def init_weights(self):
if self.encoder_post_processor is not None:
self.encoder_post_processor.apply(self._init_weights)
if self.decoder_pre_processor is not None:
self.decoder_pre_processor.apply(self._init_weights)
if self.decoder_post_processor is not None:
self.decoder_post_processor.apply(self._init_weights)
def _init_weights(self, m):
if isinstance(m, nn.Linear) or isinstance(m, nn.Embedding):
trunc_normal_(m.weight, std=.02)
if isinstance(m, nn.Linear) and m.bias is not None:
nn.init.constant_(m.bias, 0)
elif isinstance(m, nn.LayerNorm):
nn.init.constant_(m.bias, 0)
nn.init.constant_(m.weight, 1.0)
@staticmethod
def build_encoder(config):
backbone = config.pop('arch')
if backbone.startswith('vit'):
module = VisionTransformer(**config)
elif backbone == 'beit3-base':
module = beit3_base_vision(image_size=config["img_size"])
return module
@staticmethod
def build_decoder(config):
backbone = config.pop('arch')
return VisionTransformer(**config)
def encode(self, img):
encoder_features = self.encoder(img, return_patch_tokens=True)
return self.encoder_post_processor(encoder_features)
def decode(self, quantize, **decoder_kwargs):
quantize = self.decoder_pre_processor(quantize)
decoder_features = self.decoder(quantize, return_patch_tokens=True, **decoder_kwargs)
return self.decoder_post_processor(decoder_features)
def get_model_default_params(
embed_dim=768, depth=12, img_size=256,
patch_size=16, in_chans=3, num_heads=12,
):
return dict(
img_size=img_size, patch_size=patch_size, in_chans=in_chans,
embed_dim=embed_dim, depth=depth, num_heads=num_heads, mlp_ratio=4.,
qkv_bias=True, drop_rate=0., attn_drop_rate=0.,
drop_path_rate=0., norm_layer=partial(nn.LayerNorm, eps=1e-6),
)
def get_basic_config(
img_size=256, patch_size=16,
encoder_arch='beit3-base', decoder_arch='vit-base',
**kwargs,
):
if encoder_arch in ('vit-base', 'beit3-base'):
encoder_config = get_model_default_params(
embed_dim=768, depth=12, num_heads=12,
)
else:
raise ValueError(f"Unknown encoder arch: {encoder_arch}")
encoder_config['patch_size'] = patch_size
encoder_config['img_size'] = img_size
encoder_config['arch'] = encoder_arch
if decoder_arch == 'vit-base':
decoder_config = get_model_default_params(
embed_dim=768, depth=12, num_heads=12,
)
else:
raise ValueError(f"Unknown decoder arch: {decoder_arch}")
decoder_config['arch'] = decoder_arch
return {
'encoder_config': encoder_config,
'decoder_config': decoder_config,
'patch_size': patch_size,
}, kwargs