Image Feature Extraction
Transformers
ONNX
Safetensors
English
Japanese
egara_net
feature-extraction
embeddings
illustration
vision-transformer
dino
custom-architecture
custom_code
Instructions to use Columba1198/EgaraNet with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Columba1198/EgaraNet with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-feature-extraction", model="Columba1198/EgaraNet", trust_remote_code=True)# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("Columba1198/EgaraNet", trust_remote_code=True, dtype="auto") - Notebooks
- Google Colab
- Kaggle
Upload folder using huggingface_hub
Browse files- config.json +89 -0
- configuration_egara_net.py +307 -0
- model.safetensors +3 -0
- modeling_egara_net.py +259 -0
config.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_comment": "EgaraNet: DINOv3 ViT-L backbone + StyleNet (Transposed Transformer Block) composite model config.",
|
| 3 |
+
|
| 4 |
+
"model_type": "egara_net",
|
| 5 |
+
"architectures": ["EgaraNetModel"],
|
| 6 |
+
"torch_dtype": "float32",
|
| 7 |
+
"transformers_version": "4.56.0.dev0",
|
| 8 |
+
|
| 9 |
+
"auto_map": {
|
| 10 |
+
"AutoConfig": "configuration_egara_net.EgaraNetConfig",
|
| 11 |
+
"AutoModel": "modeling_egara_net.EgaraNetModel"
|
| 12 |
+
},
|
| 13 |
+
|
| 14 |
+
"_section_backbone": "--- DINOv3 ViT Backbone (nested sub-config) ---",
|
| 15 |
+
"backbone_config": {
|
| 16 |
+
"model_type": "dinov3_vit",
|
| 17 |
+
"architectures": ["DINOv3ViTModel"],
|
| 18 |
+
|
| 19 |
+
"hidden_size": 1024,
|
| 20 |
+
"num_hidden_layers": 24,
|
| 21 |
+
"num_attention_heads": 16,
|
| 22 |
+
"intermediate_size": 4096,
|
| 23 |
+
"hidden_act": "gelu",
|
| 24 |
+
|
| 25 |
+
"image_size": 224,
|
| 26 |
+
"patch_size": 16,
|
| 27 |
+
"num_channels": 3,
|
| 28 |
+
"num_register_tokens": 4,
|
| 29 |
+
|
| 30 |
+
"attention_dropout": 0.0,
|
| 31 |
+
"drop_path_rate": 0.0,
|
| 32 |
+
"layer_norm_eps": 1e-05,
|
| 33 |
+
"layerscale_value": 1.0,
|
| 34 |
+
|
| 35 |
+
"pos_embed_rescale": 2.0,
|
| 36 |
+
"pos_embed_jitter": null,
|
| 37 |
+
"pos_embed_shift": null,
|
| 38 |
+
"rope_theta": 100.0,
|
| 39 |
+
|
| 40 |
+
"key_bias": false,
|
| 41 |
+
"query_bias": true,
|
| 42 |
+
"value_bias": true,
|
| 43 |
+
"proj_bias": true,
|
| 44 |
+
"mlp_bias": true,
|
| 45 |
+
"use_gated_mlp": false,
|
| 46 |
+
|
| 47 |
+
"initializer_range": 0.02,
|
| 48 |
+
"torch_dtype": "float32",
|
| 49 |
+
"transformers_version": "4.56.0.dev0"
|
| 50 |
+
},
|
| 51 |
+
|
| 52 |
+
"_section_stylenet": "--- StyleNet: Transposed Transformer Block (TTB) head ---",
|
| 53 |
+
|
| 54 |
+
"ttb_input_dim": null,
|
| 55 |
+
"_ttb_input_dim_note": "null = auto-inferred from backbone_config.hidden_size at model init",
|
| 56 |
+
|
| 57 |
+
"ttb_hidden_dim": 1024,
|
| 58 |
+
"_ttb_hidden_dim_note": "Internal channel dimension of TTB layers. Matches backbone hidden_size for ViT-L.",
|
| 59 |
+
|
| 60 |
+
"ttb_output_dim": 1024,
|
| 61 |
+
"_ttb_output_dim_note": "Final L2-normalised style vector dimension.",
|
| 62 |
+
|
| 63 |
+
"ttb_num_layers": 3,
|
| 64 |
+
"_ttb_num_layers_note": "Number of stacked TransposedTransformerBlock layers.",
|
| 65 |
+
|
| 66 |
+
"ttb_num_heads": 16,
|
| 67 |
+
"_ttb_num_heads_note": "Number of attention heads in TTB. Must divide ttb_hidden_dim evenly. (1024 / 16 = 64)",
|
| 68 |
+
|
| 69 |
+
"_section_ttb_internals": "--- TTB internals (derived / documented for reference) ---",
|
| 70 |
+
"ttb_rms_norm_eps": 1e-05,
|
| 71 |
+
"ttb_swiglu_multiple": 64,
|
| 72 |
+
"_ttb_swiglu_note": "SwiGLU hidden = round_up(floor(hidden_dim * 8/3), multiple). E.g. 768->2048, 1024->2752.",
|
| 73 |
+
|
| 74 |
+
"_section_attnpool": "--- Attention Pooling ---",
|
| 75 |
+
"attn_pool_num_heads": 8,
|
| 76 |
+
"_attn_pool_note": "nn.MultiheadAttention heads used in AttentionPooling. Must divide ttb_hidden_dim.",
|
| 77 |
+
|
| 78 |
+
"_section_head": "--- Projection Head (hidden -> output) ---",
|
| 79 |
+
"head_act": "silu",
|
| 80 |
+
"_head_note": "Linear(hidden) -> SiLU -> Linear(output). Output is L2-normalised.",
|
| 81 |
+
|
| 82 |
+
"_section_preprocessing": "--- Default inference preprocessing ---",
|
| 83 |
+
"image_size": 512,
|
| 84 |
+
"keep_aspect_ratio": true,
|
| 85 |
+
"_keep_aspect_ratio_note": "true = MaxResizeMod16(image_size); false = square resize.",
|
| 86 |
+
"image_mean": [0.485, 0.456, 0.406],
|
| 87 |
+
"image_std": [0.229, 0.224, 0.225],
|
| 88 |
+
"_image_stats_note": "ImageNet stats; must match backbone preprocessor_config.json."
|
| 89 |
+
}
|
configuration_egara_net.py
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
configuration_egara_net.py
|
| 3 |
+
βββββββββββββββββββββββββ
|
| 4 |
+
Hugging Face PretrainedConfig for the EgaraNet composite model.
|
| 5 |
+
|
| 6 |
+
Model structure
|
| 7 |
+
βββββββββββββββ
|
| 8 |
+
EgaraNetModel
|
| 9 |
+
βbackbone : DINOv3 ViT (frozen or fine-tuned)
|
| 10 |
+
β config stored under `backbone_config`
|
| 11 |
+
βstyle_net : StyleNet
|
| 12 |
+
βinput_proj : Identity or Linear (input_dim β hidden_dim)
|
| 13 |
+
βttb_layers [ΓN] : TransposedTransformerBlock
|
| 14 |
+
β βRMSNorm + TTB attention (cross-covariance / transposed)
|
| 15 |
+
β βRMSNorm + SwiGLU FFN
|
| 16 |
+
βattn_pool : AttentionPooling (learned query β MHA)
|
| 17 |
+
βhead : Linear β SiLU β Linear (L2-normalised output)
|
| 18 |
+
|
| 19 |
+
Usage
|
| 20 |
+
βββββ
|
| 21 |
+
from configuration_egara_net import EgaraNetConfig
|
| 22 |
+
|
| 23 |
+
# Build from scratch
|
| 24 |
+
cfg = EgaraNetConfig(
|
| 25 |
+
ttb_hidden_dim=1024,
|
| 26 |
+
ttb_output_dim=1024,
|
| 27 |
+
ttb_num_layers=3,
|
| 28 |
+
ttb_num_heads=16,
|
| 29 |
+
)
|
| 30 |
+
cfg.save_pretrained("./my_egara_net/")
|
| 31 |
+
|
| 32 |
+
# Load from directory
|
| 33 |
+
cfg = EgaraNetConfig.from_pretrained("./my_egara_net/")
|
| 34 |
+
|
| 35 |
+
# Load backbone config separately
|
| 36 |
+
backbone_cfg = cfg.backbone_config # PretrainedConfig instance
|
| 37 |
+
"""
|
| 38 |
+
|
| 39 |
+
from __future__ import annotations
|
| 40 |
+
|
| 41 |
+
import math
|
| 42 |
+
from typing import Any
|
| 43 |
+
|
| 44 |
+
from transformers import AutoConfig, PretrainedConfig
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 48 |
+
# Helpers
|
| 49 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 50 |
+
|
| 51 |
+
def _swiglu_hidden_dim(dim: int, multiple: int = 64) -> int:
|
| 52 |
+
"""Compute SwiGLU hidden dimension: round_up(floor(dim * 8/3), multiple)."""
|
| 53 |
+
raw = int(dim * 8 / 3)
|
| 54 |
+
return ((raw + multiple - 1) // multiple) * multiple
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 58 |
+
# Config
|
| 59 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 60 |
+
|
| 61 |
+
class EgaraNetConfig(PretrainedConfig):
|
| 62 |
+
r"""
|
| 63 |
+
Configuration for the EgaraNet style extractor.
|
| 64 |
+
|
| 65 |
+
Args
|
| 66 |
+
ββββ
|
| 67 |
+
backbone_config (dict | PretrainedConfig | None):
|
| 68 |
+
Config for the DINOv3 ViT backbone. A dict is automatically
|
| 69 |
+
converted to the appropriate ``PretrainedConfig`` subclass via
|
| 70 |
+
``AutoConfig``. If ``None``, a default ``dinov3_vit`` config is
|
| 71 |
+
loaded from ``backbone_model_id``.
|
| 72 |
+
|
| 73 |
+
backbone_model_id (str):
|
| 74 |
+
HF hub ID used when ``backbone_config`` is ``None``, e.g.
|
| 75 |
+
``"facebook/dinov3-vitl16-pretrain-lvd1689m"``. Ignored when
|
| 76 |
+
``backbone_config`` is provided explicitly.
|
| 77 |
+
|
| 78 |
+
ttb_input_dim (int | None):
|
| 79 |
+
Input channel dimension fed into StyleNet. ``None`` (default)
|
| 80 |
+
means it is inferred automatically from
|
| 81 |
+
``backbone_config.hidden_size`` at model initialisation.
|
| 82 |
+
|
| 83 |
+
ttb_hidden_dim (int):
|
| 84 |
+
Internal channel width of every TTB layer and the AttentionPooling
|
| 85 |
+
query. Should match ``backbone_config.hidden_size`` (1024 for ViT-L).
|
| 86 |
+
|
| 87 |
+
ttb_output_dim (int):
|
| 88 |
+
Dimension of the final L2-normalised style vector.
|
| 89 |
+
|
| 90 |
+
ttb_num_layers (int):
|
| 91 |
+
Number of stacked ``TransposedTransformerBlock`` layers.
|
| 92 |
+
|
| 93 |
+
ttb_num_heads (int):
|
| 94 |
+
Number of attention heads inside each TTB.
|
| 95 |
+
Must satisfy ``ttb_hidden_dim % ttb_num_heads == 0``.
|
| 96 |
+
|
| 97 |
+
ttb_rms_norm_eps (float):
|
| 98 |
+
Ξ΅ used in all ``RMSNorm`` layers.
|
| 99 |
+
|
| 100 |
+
ttb_swiglu_multiple (int):
|
| 101 |
+
SwiGLU hidden dim is rounded up to the nearest multiple of this
|
| 102 |
+
value. ``hidden = round_up(floor(ttb_hidden_dim * 8/3), multiple)``.
|
| 103 |
+
|
| 104 |
+
attn_pool_num_heads (int):
|
| 105 |
+
Number of heads for ``nn.MultiheadAttention`` inside
|
| 106 |
+
``AttentionPooling``. Must divide ``ttb_hidden_dim``.
|
| 107 |
+
|
| 108 |
+
head_act (str):
|
| 109 |
+
Activation between the two linear layers in the projection head.
|
| 110 |
+
Currently only ``"silu"`` is supported.
|
| 111 |
+
|
| 112 |
+
image_size (int):
|
| 113 |
+
Default long-edge size used at inference time.
|
| 114 |
+
|
| 115 |
+
keep_aspect_ratio (bool):
|
| 116 |
+
``True`` β ``MaxResizeMod16(image_size)`` (preserves aspect ratio,
|
| 117 |
+
snaps to multiples of 16).
|
| 118 |
+
``False`` β square ``Resize((image_size, image_size))``.
|
| 119 |
+
|
| 120 |
+
image_mean / image_std (list[float]):
|
| 121 |
+
Per-channel normalisation statistics. Must match the backbone's
|
| 122 |
+
``preprocessor_config.json``. Defaults to ImageNet statistics.
|
| 123 |
+
"""
|
| 124 |
+
|
| 125 |
+
model_type = "egara_net"
|
| 126 |
+
is_composition = True # tells HF this is a composite config
|
| 127 |
+
|
| 128 |
+
def __init__(
|
| 129 |
+
self,
|
| 130 |
+
# Backbone
|
| 131 |
+
backbone_config: dict | PretrainedConfig | None = None,
|
| 132 |
+
backbone_model_id: str = "facebook/dinov3-vitl16-pretrain-lvd1689m",
|
| 133 |
+
# StyleNet / TTB
|
| 134 |
+
ttb_input_dim: int | None = None,
|
| 135 |
+
ttb_hidden_dim: int = 1024,
|
| 136 |
+
ttb_output_dim: int = 1024,
|
| 137 |
+
ttb_num_layers: int = 3,
|
| 138 |
+
ttb_num_heads: int = 16,
|
| 139 |
+
ttb_rms_norm_eps: float = 1e-5,
|
| 140 |
+
ttb_swiglu_multiple: int = 64,
|
| 141 |
+
# Attention Pooling
|
| 142 |
+
attn_pool_num_heads: int = 8,
|
| 143 |
+
# Projection Head
|
| 144 |
+
head_act: str = "silu",
|
| 145 |
+
# Default Inference Preprocessing
|
| 146 |
+
image_size: int = 512,
|
| 147 |
+
keep_aspect_ratio: bool = True,
|
| 148 |
+
image_mean: list[float] | None = None,
|
| 149 |
+
image_std: list[float] | None = None,
|
| 150 |
+
**kwargs: Any,
|
| 151 |
+
) -> None:
|
| 152 |
+
# Validate constraints
|
| 153 |
+
if ttb_hidden_dim % ttb_num_heads != 0:
|
| 154 |
+
raise ValueError(
|
| 155 |
+
f"ttb_hidden_dim ({ttb_hidden_dim}) must be divisible by "
|
| 156 |
+
f"ttb_num_heads ({ttb_num_heads})."
|
| 157 |
+
)
|
| 158 |
+
if ttb_hidden_dim % attn_pool_num_heads != 0:
|
| 159 |
+
raise ValueError(
|
| 160 |
+
f"ttb_hidden_dim ({ttb_hidden_dim}) must be divisible by "
|
| 161 |
+
f"attn_pool_num_heads ({attn_pool_num_heads})."
|
| 162 |
+
)
|
| 163 |
+
if ttb_num_layers < 1:
|
| 164 |
+
raise ValueError(f"ttb_num_layers must be >= 1, got {ttb_num_layers}.")
|
| 165 |
+
|
| 166 |
+
# Backbone config
|
| 167 |
+
if isinstance(backbone_config, dict):
|
| 168 |
+
# AutoConfig dispatches on "model_type" key
|
| 169 |
+
backbone_config = AutoConfig.for_model(**backbone_config)
|
| 170 |
+
self.backbone_config: PretrainedConfig | None = backbone_config
|
| 171 |
+
self.backbone_model_id: str = backbone_model_id
|
| 172 |
+
|
| 173 |
+
# StyleNet params
|
| 174 |
+
self.ttb_input_dim: int | None = ttb_input_dim
|
| 175 |
+
self.ttb_hidden_dim: int = ttb_hidden_dim
|
| 176 |
+
self.ttb_output_dim: int = ttb_output_dim
|
| 177 |
+
self.ttb_num_layers: int = ttb_num_layers
|
| 178 |
+
self.ttb_num_heads: int = ttb_num_heads
|
| 179 |
+
self.ttb_rms_norm_eps: float = ttb_rms_norm_eps
|
| 180 |
+
self.ttb_swiglu_multiple: int = ttb_swiglu_multiple
|
| 181 |
+
|
| 182 |
+
# Attention Pooling
|
| 183 |
+
self.attn_pool_num_heads: int = attn_pool_num_heads
|
| 184 |
+
|
| 185 |
+
# Projection Head
|
| 186 |
+
self.head_act: str = head_act
|
| 187 |
+
|
| 188 |
+
# Preprocessing defaults
|
| 189 |
+
self.image_size: int = image_size
|
| 190 |
+
self.keep_aspect_ratio: bool = keep_aspect_ratio
|
| 191 |
+
self.image_mean: list[float] = image_mean or [0.485, 0.456, 0.406]
|
| 192 |
+
self.image_std: list[float] = image_std or [0.229, 0.224, 0.225]
|
| 193 |
+
|
| 194 |
+
super().__init__(**kwargs)
|
| 195 |
+
|
| 196 |
+
# Derived / read-only properties
|
| 197 |
+
|
| 198 |
+
@property
|
| 199 |
+
def backbone_hidden_size(self) -> int:
|
| 200 |
+
"""Backbone output channel width (inferred from backbone_config)."""
|
| 201 |
+
if self.backbone_config is not None:
|
| 202 |
+
return self.backbone_config.hidden_size
|
| 203 |
+
raise AttributeError(
|
| 204 |
+
"backbone_config is not set; cannot infer backbone_hidden_size."
|
| 205 |
+
)
|
| 206 |
+
|
| 207 |
+
@property
|
| 208 |
+
def effective_ttb_input_dim(self) -> int:
|
| 209 |
+
"""Actual input_dim used by StyleNet input_proj."""
|
| 210 |
+
return self.ttb_input_dim if self.ttb_input_dim is not None \
|
| 211 |
+
else self.backbone_hidden_size
|
| 212 |
+
|
| 213 |
+
@property
|
| 214 |
+
def ttb_swiglu_hidden_dim(self) -> int:
|
| 215 |
+
"""Derived SwiGLU intermediate dimension (not stored in JSON)."""
|
| 216 |
+
return _swiglu_hidden_dim(self.ttb_hidden_dim, self.ttb_swiglu_multiple)
|
| 217 |
+
|
| 218 |
+
@property
|
| 219 |
+
def ttb_head_dim(self) -> int:
|
| 220 |
+
"""Per-head dimension inside TTB attention."""
|
| 221 |
+
return self.ttb_hidden_dim // self.ttb_num_heads
|
| 222 |
+
|
| 223 |
+
# Serialisation
|
| 224 |
+
|
| 225 |
+
def to_dict(self) -> dict[str, Any]:
|
| 226 |
+
output = super().to_dict()
|
| 227 |
+
# Serialise nested backbone config as a plain dict
|
| 228 |
+
if self.backbone_config is not None:
|
| 229 |
+
output["backbone_config"] = self.backbone_config.to_dict()
|
| 230 |
+
return output
|
| 231 |
+
|
| 232 |
+
@classmethod
|
| 233 |
+
def from_dict(cls, config_dict: dict[str, Any], **kwargs) -> "EgaraNetConfig":
|
| 234 |
+
# AutoConfig.for_model is invoked inside __init__ for backbone_config
|
| 235 |
+
return super().from_dict(config_dict, **kwargs)
|
| 236 |
+
|
| 237 |
+
# Pretty repr
|
| 238 |
+
|
| 239 |
+
def __repr__(self) -> str:
|
| 240 |
+
backbone_name = (
|
| 241 |
+
getattr(self.backbone_config, "model_type", "?")
|
| 242 |
+
if self.backbone_config else self.backbone_model_id
|
| 243 |
+
)
|
| 244 |
+
return (
|
| 245 |
+
f"EgaraNetConfig(\n"
|
| 246 |
+
f" backbone : {backbone_name}"
|
| 247 |
+
f" (hidden={getattr(self.backbone_config, 'hidden_size', '?')})\n"
|
| 248 |
+
f" ttb_input_dim : {self.effective_ttb_input_dim} "
|
| 249 |
+
f"({'auto' if self.ttb_input_dim is None else 'explicit'})\n"
|
| 250 |
+
f" ttb_hidden_dim : {self.ttb_hidden_dim}\n"
|
| 251 |
+
f" ttb_output_dim : {self.ttb_output_dim}\n"
|
| 252 |
+
f" ttb_num_layers : {self.ttb_num_layers}\n"
|
| 253 |
+
f" ttb_num_heads : {self.ttb_num_heads} "
|
| 254 |
+
f"(head_dim={self.ttb_head_dim})\n"
|
| 255 |
+
f" ttb_swiglu_hidden : {self.ttb_swiglu_hidden_dim}\n"
|
| 256 |
+
f" attn_pool_heads : {self.attn_pool_num_heads}\n"
|
| 257 |
+
f" head_act : {self.head_act}\n"
|
| 258 |
+
f" image_size : {self.image_size} "
|
| 259 |
+
f"keep_ratio={self.keep_aspect_ratio}\n"
|
| 260 |
+
f")"
|
| 261 |
+
)
|
| 262 |
+
|
| 263 |
+
|
| 264 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 265 |
+
# Auto-registration (call once at import time, safe to repeat)
|
| 266 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 267 |
+
try:
|
| 268 |
+
AutoConfig.register("egara_net", EgaraNetConfig)
|
| 269 |
+
except ValueError:
|
| 270 |
+
pass # already registered (e.g. module reimported in notebook)
|
| 271 |
+
|
| 272 |
+
|
| 273 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 274 |
+
# Quick self-test
|
| 275 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 276 |
+
if __name__ == "__main__":
|
| 277 |
+
import json, pathlib
|
| 278 |
+
|
| 279 |
+
here = pathlib.Path(__file__).parent
|
| 280 |
+
|
| 281 |
+
# Build from the JSON files supplied with the model
|
| 282 |
+
backbone_dict = json.loads((here / "config.json").read_text())
|
| 283 |
+
backbone_cfg = backbone_dict.get("backbone_config", backbone_dict)
|
| 284 |
+
|
| 285 |
+
cfg = EgaraNetConfig(
|
| 286 |
+
backbone_config=backbone_cfg,
|
| 287 |
+
ttb_hidden_dim=backbone_cfg.get("hidden_size", 1024),
|
| 288 |
+
ttb_output_dim=backbone_cfg.get("hidden_size", 1024),
|
| 289 |
+
ttb_num_layers=3,
|
| 290 |
+
ttb_num_heads=16,
|
| 291 |
+
attn_pool_num_heads=8,
|
| 292 |
+
)
|
| 293 |
+
print(cfg)
|
| 294 |
+
|
| 295 |
+
# Round-trip JSON serialisation
|
| 296 |
+
tmp = pathlib.Path("/tmp/egara_net_test")
|
| 297 |
+
cfg.save_pretrained(tmp)
|
| 298 |
+
cfg2 = EgaraNetConfig.from_pretrained(tmp)
|
| 299 |
+
assert cfg.ttb_hidden_dim == cfg2.ttb_hidden_dim
|
| 300 |
+
assert cfg.ttb_output_dim == cfg2.ttb_output_dim
|
| 301 |
+
assert cfg.ttb_num_layers == cfg2.ttb_num_layers
|
| 302 |
+
print("Round-trip OK β")
|
| 303 |
+
|
| 304 |
+
# Derived properties
|
| 305 |
+
print(f"SwiGLU hidden dim : {cfg.ttb_swiglu_hidden_dim}")
|
| 306 |
+
print(f"TTB head dim : {cfg.ttb_head_dim}")
|
| 307 |
+
print(f"Effective input : {cfg.effective_ttb_input_dim}")
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b9b0d29d8f3bca26aa2429d3a14684e90b4298aafb8f039dc078d16518f8c073
|
| 3 |
+
size 1389584856
|
modeling_egara_net.py
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
modeling_egara_net.py
|
| 3 |
+
ββββββββββββββββββββ
|
| 4 |
+
Hugging Face PreTrainedModel implementation for EgaraNet.
|
| 5 |
+
|
| 6 |
+
EgaraNet is a composite model:
|
| 7 |
+
backbone : DINOv3 ViT (frozen feature extractor)
|
| 8 |
+
style_net : StyleNet (Transposed Transformer Block head)
|
| 9 |
+
|
| 10 |
+
Usage:
|
| 11 |
+
from modeling_egara_net import EgaraNetModel
|
| 12 |
+
model = EgaraNetModel.from_pretrained("path/to/model_dir", trust_remote_code=True)
|
| 13 |
+
# or after uploading to Hub:
|
| 14 |
+
model = EgaraNetModel.from_pretrained("user/egara-net", trust_remote_code=True)
|
| 15 |
+
"""
|
| 16 |
+
|
| 17 |
+
from __future__ import annotations
|
| 18 |
+
|
| 19 |
+
import math
|
| 20 |
+
from dataclasses import dataclass
|
| 21 |
+
from typing import Optional
|
| 22 |
+
|
| 23 |
+
import torch
|
| 24 |
+
import torch.nn as nn
|
| 25 |
+
import torch.nn.functional as F
|
| 26 |
+
from transformers import AutoModel, PreTrainedModel
|
| 27 |
+
from transformers.modeling_outputs import ModelOutput
|
| 28 |
+
|
| 29 |
+
from .configuration_egara_net import EgaraNetConfig
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 33 |
+
# Output dataclass
|
| 34 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 35 |
+
|
| 36 |
+
@dataclass
|
| 37 |
+
class EgaraNetOutput(ModelOutput):
|
| 38 |
+
"""
|
| 39 |
+
Output of EgaraNetModel.
|
| 40 |
+
|
| 41 |
+
Attributes:
|
| 42 |
+
style_embedding: L2-normalised style vector [B, output_dim]
|
| 43 |
+
backbone_features: raw backbone output [B, N, hidden_size] (optional)
|
| 44 |
+
"""
|
| 45 |
+
style_embedding: torch.FloatTensor = None
|
| 46 |
+
backbone_features: Optional[torch.FloatTensor] = None
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 50 |
+
# Building blocks
|
| 51 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 52 |
+
|
| 53 |
+
class RMSNorm(nn.Module):
|
| 54 |
+
"""Root Mean Square Layer Normalization."""
|
| 55 |
+
|
| 56 |
+
def __init__(self, dim: int, eps: float = 1e-5):
|
| 57 |
+
super().__init__()
|
| 58 |
+
self.weight = nn.Parameter(torch.ones(dim))
|
| 59 |
+
self.eps = eps
|
| 60 |
+
|
| 61 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 62 |
+
orig_dtype = x.dtype
|
| 63 |
+
x_fp32 = x.to(torch.float32)
|
| 64 |
+
rms = torch.sqrt(x_fp32.pow(2).mean(-1, keepdim=True) + self.eps)
|
| 65 |
+
out = (x_fp32 / rms) * self.weight.to(torch.float32)
|
| 66 |
+
return out.to(orig_dtype)
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
class SwiGLU(nn.Module):
|
| 70 |
+
"""SwiGLU Feed-Forward Network."""
|
| 71 |
+
|
| 72 |
+
def __init__(self, dim: int, multiple: int = 64):
|
| 73 |
+
super().__init__()
|
| 74 |
+
hidden_dim = int(dim * 8 / 3)
|
| 75 |
+
hidden_dim = ((hidden_dim + multiple - 1) // multiple) * multiple
|
| 76 |
+
self.w_gate = nn.Linear(dim, hidden_dim, bias=False)
|
| 77 |
+
self.w_up = nn.Linear(dim, hidden_dim, bias=False)
|
| 78 |
+
self.w_down = nn.Linear(hidden_dim, dim, bias=False)
|
| 79 |
+
|
| 80 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 81 |
+
return self.w_down(F.silu(self.w_gate(x)) * self.w_up(x))
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
class TransposedTransformerBlock(nn.Module):
|
| 85 |
+
"""
|
| 86 |
+
TTB β Transposed Transformer Block.
|
| 87 |
+
Cross-covariance attention in (HeadDim Γ HeadDim) space.
|
| 88 |
+
"""
|
| 89 |
+
|
| 90 |
+
def __init__(self, dim: int, num_heads: int, eps: float = 1e-5,
|
| 91 |
+
swiglu_multiple: int = 64):
|
| 92 |
+
super().__init__()
|
| 93 |
+
self.num_heads = num_heads
|
| 94 |
+
self.head_dim = dim // num_heads
|
| 95 |
+
self.scale = self.head_dim ** -0.5
|
| 96 |
+
|
| 97 |
+
self.norm = RMSNorm(dim, eps=eps)
|
| 98 |
+
self.qkv = nn.Linear(dim, dim * 3, bias=False)
|
| 99 |
+
self.q_norm = RMSNorm(self.head_dim, eps=eps)
|
| 100 |
+
self.k_norm = RMSNorm(self.head_dim, eps=eps)
|
| 101 |
+
self.proj = nn.Linear(dim, dim)
|
| 102 |
+
|
| 103 |
+
self.norm_ffn = RMSNorm(dim, eps=eps)
|
| 104 |
+
self.ffn = SwiGLU(dim, multiple=swiglu_multiple)
|
| 105 |
+
|
| 106 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 107 |
+
B, N, C = x.shape
|
| 108 |
+
shortcut = x
|
| 109 |
+
x = self.norm(x)
|
| 110 |
+
|
| 111 |
+
qkv = (self.qkv(x)
|
| 112 |
+
.reshape(B, N, 3, self.num_heads, self.head_dim)
|
| 113 |
+
.permute(2, 0, 3, 1, 4))
|
| 114 |
+
q, k, v = qkv.unbind(0)
|
| 115 |
+
|
| 116 |
+
q = self.q_norm(q)
|
| 117 |
+
k = self.k_norm(k)
|
| 118 |
+
|
| 119 |
+
# Transposed attention: (HeadDim, N) @ (N, HeadDim) β (HeadDim, HeadDim)
|
| 120 |
+
q = q.transpose(-2, -1)
|
| 121 |
+
attn = (q @ k) * self.scale
|
| 122 |
+
attn = attn.softmax(dim=-1)
|
| 123 |
+
|
| 124 |
+
v = v.transpose(-2, -1)
|
| 125 |
+
x = attn @ v # (HeadDim, HeadDim) @ (HeadDim, N) β (HeadDim, N)
|
| 126 |
+
|
| 127 |
+
x = x.transpose(-2, -1).reshape(B, N, C)
|
| 128 |
+
x = self.proj(x)
|
| 129 |
+
x = x + shortcut
|
| 130 |
+
|
| 131 |
+
x = x + self.ffn(self.norm_ffn(x))
|
| 132 |
+
return x
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
class AttentionPooling(nn.Module):
|
| 136 |
+
"""Learned-query attention pooling: [B, N, C] β [B, C]."""
|
| 137 |
+
|
| 138 |
+
def __init__(self, dim: int, num_heads: int = 8):
|
| 139 |
+
super().__init__()
|
| 140 |
+
self.pool_query = nn.Parameter(torch.randn(1, 1, dim))
|
| 141 |
+
self.pool_attn = nn.MultiheadAttention(
|
| 142 |
+
embed_dim=dim, num_heads=num_heads, batch_first=True
|
| 143 |
+
)
|
| 144 |
+
|
| 145 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 146 |
+
B = x.size(0)
|
| 147 |
+
query = self.pool_query.expand(B, -1, -1)
|
| 148 |
+
out, _ = self.pool_attn(query, x, x)
|
| 149 |
+
return out.squeeze(1)
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
class StyleNet(nn.Module):
|
| 153 |
+
"""
|
| 154 |
+
StyleNet head: TTB layers β AttentionPooling β Projection β L2 norm.
|
| 155 |
+
"""
|
| 156 |
+
|
| 157 |
+
def __init__(self, config: EgaraNetConfig):
|
| 158 |
+
super().__init__()
|
| 159 |
+
input_dim = config.effective_ttb_input_dim
|
| 160 |
+
hidden_dim = config.ttb_hidden_dim
|
| 161 |
+
|
| 162 |
+
self.input_proj = (
|
| 163 |
+
nn.Identity()
|
| 164 |
+
if input_dim == hidden_dim
|
| 165 |
+
else nn.Linear(input_dim, hidden_dim)
|
| 166 |
+
)
|
| 167 |
+
|
| 168 |
+
self.tab_layers = nn.ModuleList([
|
| 169 |
+
TransposedTransformerBlock(
|
| 170 |
+
dim=hidden_dim,
|
| 171 |
+
num_heads=config.ttb_num_heads,
|
| 172 |
+
eps=config.ttb_rms_norm_eps,
|
| 173 |
+
swiglu_multiple=config.ttb_swiglu_multiple,
|
| 174 |
+
)
|
| 175 |
+
for _ in range(config.ttb_num_layers)
|
| 176 |
+
])
|
| 177 |
+
|
| 178 |
+
self.attn_pool = AttentionPooling(
|
| 179 |
+
dim=hidden_dim, num_heads=config.attn_pool_num_heads
|
| 180 |
+
)
|
| 181 |
+
|
| 182 |
+
self.head = nn.Sequential(
|
| 183 |
+
nn.Linear(hidden_dim, hidden_dim),
|
| 184 |
+
nn.SiLU(),
|
| 185 |
+
nn.Linear(hidden_dim, config.ttb_output_dim),
|
| 186 |
+
)
|
| 187 |
+
|
| 188 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 189 |
+
x = self.input_proj(x)
|
| 190 |
+
for layer in self.tab_layers:
|
| 191 |
+
x = layer(x)
|
| 192 |
+
x = self.attn_pool(x)
|
| 193 |
+
x = self.head(x)
|
| 194 |
+
return F.normalize(x, p=2, dim=-1)
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 198 |
+
# EgaraNet Model
|
| 199 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 200 |
+
|
| 201 |
+
class EgaraNetModel(PreTrainedModel):
|
| 202 |
+
"""
|
| 203 |
+
EgaraNet: DINOv3 ViT backbone + StyleNet head.
|
| 204 |
+
|
| 205 |
+
Accepts ``pixel_values`` [B, C, H, W] and returns an
|
| 206 |
+
``EgaraNetOutput`` containing the L2-normalised style embedding.
|
| 207 |
+
"""
|
| 208 |
+
|
| 209 |
+
config_class = EgaraNetConfig
|
| 210 |
+
supports_gradient_checkpointing = False
|
| 211 |
+
|
| 212 |
+
def __init__(self, config: EgaraNetConfig):
|
| 213 |
+
super().__init__(config)
|
| 214 |
+
|
| 215 |
+
# Backbone
|
| 216 |
+
if config.backbone_config is not None:
|
| 217 |
+
self.backbone = AutoModel.from_config(config.backbone_config)
|
| 218 |
+
else:
|
| 219 |
+
self.backbone = AutoModel.from_pretrained(config.backbone_model_id)
|
| 220 |
+
|
| 221 |
+
# StyleNet head
|
| 222 |
+
self.style_net = StyleNet(config)
|
| 223 |
+
|
| 224 |
+
# Post-init (weight init for any uninitialised params)
|
| 225 |
+
self.post_init()
|
| 226 |
+
|
| 227 |
+
def forward(
|
| 228 |
+
self,
|
| 229 |
+
pixel_values: torch.Tensor,
|
| 230 |
+
output_backbone_features: bool = False,
|
| 231 |
+
) -> EgaraNetOutput:
|
| 232 |
+
"""
|
| 233 |
+
Args:
|
| 234 |
+
pixel_values: [B, C, H, W] β preprocessed image tensor.
|
| 235 |
+
output_backbone_features: if True, also return raw backbone features.
|
| 236 |
+
|
| 237 |
+
Returns:
|
| 238 |
+
EgaraNetOutput with ``style_embedding`` [B, output_dim].
|
| 239 |
+
"""
|
| 240 |
+
backbone_out = self.backbone(pixel_values=pixel_values)
|
| 241 |
+
features = backbone_out.last_hidden_state # [B, N, hidden_size]
|
| 242 |
+
|
| 243 |
+
style_emb = self.style_net(features) # [B, output_dim]
|
| 244 |
+
|
| 245 |
+
return EgaraNetOutput(
|
| 246 |
+
style_embedding=style_emb,
|
| 247 |
+
backbone_features=features if output_backbone_features else None,
|
| 248 |
+
)
|
| 249 |
+
|
| 250 |
+
|
| 251 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 252 |
+
# Auto-registration
|
| 253 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 254 |
+
|
| 255 |
+
try:
|
| 256 |
+
from transformers import AutoModel as _AM
|
| 257 |
+
_AM.register(EgaraNetConfig, EgaraNetModel)
|
| 258 |
+
except (ValueError, ImportError):
|
| 259 |
+
pass # already registered or not available
|