Equimo 0.2.3__tar.gz → 0.2.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. {equimo-0.2.3 → equimo-0.2.4}/Equimo.egg-info/PKG-INFO +8 -3
  2. {equimo-0.2.3 → equimo-0.2.4}/Equimo.egg-info/SOURCES.txt +0 -4
  3. {equimo-0.2.3 → equimo-0.2.4}/PKG-INFO +8 -3
  4. {equimo-0.2.3 → equimo-0.2.4}/README.md +7 -2
  5. equimo-0.2.4/equimo/__init__.py +1 -0
  6. {equimo-0.2.3 → equimo-0.2.4}/equimo/io.py +1 -0
  7. {equimo-0.2.3 → equimo-0.2.4}/pyproject.toml +2 -1
  8. equimo-0.2.3/equimo/__init__.py +0 -1
  9. equimo-0.2.3/equimo/converters/__init__.py +0 -1
  10. equimo-0.2.3/equimo/converters/dinov2.py +0 -69
  11. equimo-0.2.3/equimo/converters/siglip2.py +0 -105
  12. equimo-0.2.3/equimo/converters/utils.py +0 -205
  13. {equimo-0.2.3 → equimo-0.2.4}/Equimo.egg-info/dependency_links.txt +0 -0
  14. {equimo-0.2.3 → equimo-0.2.4}/Equimo.egg-info/requires.txt +0 -0
  15. {equimo-0.2.3 → equimo-0.2.4}/Equimo.egg-info/top_level.txt +0 -0
  16. {equimo-0.2.3 → equimo-0.2.4}/LICENSE.md +0 -0
  17. {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/__init__.py +0 -0
  18. {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/activation.py +0 -0
  19. {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/attention.py +0 -0
  20. {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/convolution.py +0 -0
  21. {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/downsample.py +0 -0
  22. {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/dropout.py +0 -0
  23. {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/ffn.py +0 -0
  24. {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/generic.py +0 -0
  25. {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/mamba.py +0 -0
  26. {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/norm.py +0 -0
  27. {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/patch.py +0 -0
  28. {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/posemb.py +0 -0
  29. {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/sharing.py +0 -0
  30. {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/squeeze_excite.py +0 -0
  31. {equimo-0.2.3 → equimo-0.2.4}/equimo/models/__init__.py +0 -0
  32. {equimo-0.2.3 → equimo-0.2.4}/equimo/models/emamodel.py +0 -0
  33. {equimo-0.2.3 → equimo-0.2.4}/equimo/models/fastervit.py +0 -0
  34. {equimo-0.2.3 → equimo-0.2.4}/equimo/models/mlla.py +0 -0
  35. {equimo-0.2.3 → equimo-0.2.4}/equimo/models/partialformer.py +0 -0
  36. {equimo-0.2.3 → equimo-0.2.4}/equimo/models/shvit.py +0 -0
  37. {equimo-0.2.3 → equimo-0.2.4}/equimo/models/vit.py +0 -0
  38. {equimo-0.2.3 → equimo-0.2.4}/equimo/models/vssd.py +0 -0
  39. {equimo-0.2.3 → equimo-0.2.4}/equimo/ops/scan.py +0 -0
  40. {equimo-0.2.3 → equimo-0.2.4}/equimo/utils.py +0 -0
  41. {equimo-0.2.3 → equimo-0.2.4}/setup.cfg +0 -0
  42. {equimo-0.2.3 → equimo-0.2.4}/tests/test_models.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: Equimo
3
- Version: 0.2.3
3
+ Version: 0.2.4
4
4
  Summary: Implementation of popular vision models in Jax
5
5
  Classifier: Development Status :: 4 - Beta
6
6
  Classifier: Intended Audience :: Developers
@@ -155,9 +155,13 @@ model = load_model(
155
155
 
156
156
  #### List of pretrained models
157
157
 
158
- Currently, only [DinoV2](https://github.com/facebookresearch/dinov2/) and SigLIP2 have been ported.
158
+ The following models have pretrained weights available in Equimo:
159
159
 
160
- Model identifiers allows downloading from equimo's [repository on huggingface](https://huggingface.co/poiretclement/equimo/tree/main/models/default)
160
+ - [DinoV2](https://arxiv.org/abs/2304.07193),
161
+ - [SigLIP2](https://arxiv.org/abs/2502.14786),
162
+ - [TIPS](https://arxiv.org/abs/2410.16512).
163
+
164
+ Model identifiers allow downloading from equimo's [repository on huggingface](https://huggingface.co/poiretclement/equimo/tree/main/models/default)
161
165
 
162
166
  Identifiers are filenames without the extensions, such as:
163
167
 
@@ -165,6 +169,7 @@ Identifiers are filenames without the extensions, such as:
165
169
  - `dinov2_vits14_reg`
166
170
  - `siglip2_vitl16_512`
167
171
  - `siglip2_vitso400m16_384`
172
+ - `tips_vitg14_lr`
168
173
 
169
174
  ## Contributing
170
175
 
@@ -9,10 +9,6 @@ Equimo.egg-info/top_level.txt
9
9
  equimo/__init__.py
10
10
  equimo/io.py
11
11
  equimo/utils.py
12
- equimo/converters/__init__.py
13
- equimo/converters/dinov2.py
14
- equimo/converters/siglip2.py
15
- equimo/converters/utils.py
16
12
  equimo/layers/__init__.py
17
13
  equimo/layers/activation.py
18
14
  equimo/layers/attention.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: Equimo
3
- Version: 0.2.3
3
+ Version: 0.2.4
4
4
  Summary: Implementation of popular vision models in Jax
5
5
  Classifier: Development Status :: 4 - Beta
6
6
  Classifier: Intended Audience :: Developers
@@ -155,9 +155,13 @@ model = load_model(
155
155
 
156
156
  #### List of pretrained models
157
157
 
158
- Currently, only [DinoV2](https://github.com/facebookresearch/dinov2/) and SigLIP2 have been ported.
158
+ The following models have pretrained weights available in Equimo:
159
159
 
160
- Model identifiers allows downloading from equimo's [repository on huggingface](https://huggingface.co/poiretclement/equimo/tree/main/models/default)
160
+ - [DinoV2](https://arxiv.org/abs/2304.07193),
161
+ - [SigLIP2](https://arxiv.org/abs/2502.14786),
162
+ - [TIPS](https://arxiv.org/abs/2410.16512).
163
+
164
+ Model identifiers allow downloading from equimo's [repository on huggingface](https://huggingface.co/poiretclement/equimo/tree/main/models/default)
161
165
 
162
166
  Identifiers are filenames without the extensions, such as:
163
167
 
@@ -165,6 +169,7 @@ Identifiers are filenames without the extensions, such as:
165
169
  - `dinov2_vits14_reg`
166
170
  - `siglip2_vitl16_512`
167
171
  - `siglip2_vitso400m16_384`
172
+ - `tips_vitg14_lr`
168
173
 
169
174
  ## Contributing
170
175
 
@@ -128,9 +128,13 @@ model = load_model(
128
128
 
129
129
  #### List of pretrained models
130
130
 
131
- Currently, only [DinoV2](https://github.com/facebookresearch/dinov2/) and SigLIP2 have been ported.
131
+ The following models have pretrained weights available in Equimo:
132
132
 
133
- Model identifiers allows downloading from equimo's [repository on huggingface](https://huggingface.co/poiretclement/equimo/tree/main/models/default)
133
+ - [DinoV2](https://arxiv.org/abs/2304.07193),
134
+ - [SigLIP2](https://arxiv.org/abs/2502.14786),
135
+ - [TIPS](https://arxiv.org/abs/2410.16512).
136
+
137
+ Model identifiers allow downloading from equimo's [repository on huggingface](https://huggingface.co/poiretclement/equimo/tree/main/models/default)
134
138
 
135
139
  Identifiers are filenames without the extensions, such as:
136
140
 
@@ -138,6 +142,7 @@ Identifiers are filenames without the extensions, such as:
138
142
  - `dinov2_vits14_reg`
139
143
  - `siglip2_vitl16_512`
140
144
  - `siglip2_vitso400m16_384`
145
+ - `tips_vitg14_lr`
141
146
 
142
147
  ## Contributing
143
148
 
@@ -0,0 +1 @@
1
+ __version__ = "0.2.4"
@@ -72,6 +72,7 @@ def save_model(
72
72
  eqx.tree_serialise_leaves(tmp_path / "weights.eqx", model)
73
73
 
74
74
  # Create compressed archive
75
+ path.parent.mkdir(parents=True, exist_ok=True)
75
76
  with lz4.frame.open(path, "wb") as f_out:
76
77
  with tarfile.open(fileobj=f_out, mode="w") as tar:
77
78
  tar.add(tmp_path / "metadata.json", arcname="metadata.json")
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "Equimo"
3
- version = "0.2.3"
3
+ version = "0.2.4"
4
4
  description = "Implementation of popular vision models in Jax"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -43,3 +43,4 @@ dev = [
43
43
 
44
44
  [tool.setuptools]
45
45
  license-files = []
46
+ packages = ["equimo"]
@@ -1 +0,0 @@
1
- __version__ = "0.2.3"
@@ -1 +0,0 @@
1
-
@@ -1,69 +0,0 @@
1
- from pathlib import Path
2
-
3
- import jax
4
-
5
- import equimo.models as em
6
- from equimo.converters.utils import convert_torch_to_equinox
7
- from equimo.io import load_model, save_model
8
-
9
-
10
- def main():
11
- key = jax.random.PRNGKey(42)
12
- dinov2_vits14_reg_config = {
13
- "img_size": 518,
14
- "in_channels": 3,
15
- "dim": 384,
16
- "patch_size": 14,
17
- "num_heads": [6],
18
- "depths": [12],
19
- "num_classes": 0,
20
- "use_mask_token": True,
21
- "reg_tokens": 4,
22
- "init_values": 1e-5,
23
- "eps": 1e-6,
24
- "dynamic_img_size": True,
25
- }
26
-
27
- dinov2_vits14_reg = em.VisionTransformer(
28
- **dinov2_vits14_reg_config,
29
- key=key,
30
- )
31
-
32
- torch_hub_cfg = ["facebookresearch/dinov2", "dinov2_vits14_reg"]
33
-
34
- replace_cfg = {
35
- "reg_tokens": "register_tokens",
36
- "blocks.0.blocks": "blocks",
37
- ".prenorm.": ".norm1.",
38
- ".norm.": ".norm2.",
39
- }
40
- expand_cfg = {"patch_embed.proj.bias": ["after", 2]}
41
- squeeze_cfg = {
42
- "pos_embed": 0,
43
- "cls_token": 0,
44
- "register_tokens": 0,
45
- }
46
- whitelist = []
47
-
48
- dinov2_vits14_reg = convert_torch_to_equinox(
49
- dinov2_vits14_reg,
50
- torch_hub_cfg,
51
- replace_cfg,
52
- expand_cfg,
53
- squeeze_cfg,
54
- whitelist,
55
- strict=True,
56
- )
57
-
58
- save_model(
59
- Path("~/.cache/equimo/dinov2_vits14_reg").expanduser(),
60
- dinov2_vits14_reg,
61
- dinov2_vits14_reg_config,
62
- torch_hub_cfg,
63
- compression=True,
64
- )
65
-
66
- _ = load_model(
67
- cls="vit",
68
- path=Path("~/.cache/equimo/dinov2_vits14_reg.tar.lz4").expanduser(),
69
- )
@@ -1,105 +0,0 @@
1
- from pathlib import Path
2
-
3
- import jax
4
- import jax.numpy as jnp
5
- import numpy as np
6
-
7
- import equimo.models as em
8
- from equimo.converters.utils import convert_torch_to_equinox
9
- from equimo.io import load_model, save_model
10
-
11
-
12
- def compare(j, t) -> float:
13
- j = np.array(j)
14
- t = t.squeeze().detach().numpy()
15
- return float(np.mean(np.abs(j - t)))
16
-
17
-
18
- def main():
19
- try:
20
- import torch
21
- except:
22
- raise ImportError("`torch` not available")
23
-
24
- key = jax.random.PRNGKey(42)
25
- siglip2_config = {
26
- "img_size": 384,
27
- "in_channels": 3,
28
- "dim": 1536,
29
- "patch_size": 16,
30
- "num_heads": [16],
31
- "depths": [40],
32
- "mlp_ratio": 4,
33
- "num_classes": 0,
34
- "use_mask_token": False,
35
- "reg_tokens": 0,
36
- "class_token": False,
37
- "no_embed_class": True,
38
- "init_values": None,
39
- "eps": 1e-6,
40
- "dynamic_img_size": False,
41
- # "act_layer": "exactgelu",
42
- "act_layer": "gelu",
43
- }
44
-
45
- siglip2 = em.VisionTransformer(
46
- **siglip2_config,
47
- key=key,
48
- )
49
-
50
- timm_cfg = ["vit_giantopt_patch16_siglip_gap_384.v2_webli", True]
51
- _n = timm_cfg[0].split("_")
52
- mname = f"siglip2_vitgiantopt{_n[2][-2:]}_{_n[-2][:3]}"
53
- # mname = f"siglip2_vit{_n[1][0]}{_n[2][-2:]}_{_n[-2][:3]}"
54
-
55
- print(f"Converting {mname}...")
56
-
57
- replace_cfg = {
58
- "blocks.0.blocks": "blocks",
59
- ".prenorm.": ".norm1.",
60
- ".norm.": ".norm2.",
61
- }
62
- expand_cfg = {"patch_embed.proj.bias": ["after", 2]}
63
- squeeze_cfg = {
64
- "pos_embed": 0,
65
- "cls_token": 0,
66
- "register_tokens": 0,
67
- }
68
- whitelist = []
69
-
70
- siglip2, torch_model = convert_torch_to_equinox(
71
- siglip2,
72
- replace_cfg,
73
- expand_cfg,
74
- squeeze_cfg,
75
- whitelist,
76
- strict=True,
77
- source="timm",
78
- timm_cfg=timm_cfg,
79
- return_torch=True,
80
- )
81
-
82
- arr = np.random.randn(3, siglip2_config["img_size"], siglip2_config["img_size"])
83
- jax_arr = jnp.array(arr)
84
- torch_arr = torch.tensor(arr).unsqueeze(0).float()
85
-
86
- assert (
87
- compare(
88
- jax.vmap(siglip2.norm)(siglip2.features(jax_arr, key)),
89
- torch_model.forward_features(torch_arr),
90
- )
91
- < 1e-5
92
- )
93
-
94
- save_model(
95
- Path(f"~/.cache/equimo/{mname}").expanduser(),
96
- siglip2,
97
- siglip2_config,
98
- timm_cfg=timm_cfg,
99
- compression=True,
100
- )
101
-
102
- _ = load_model(
103
- cls="vit",
104
- path=Path(f"~/.cache/equimo/{mname}.tar.lz4").expanduser(),
105
- )
@@ -1,205 +0,0 @@
1
- import re
2
- from typing import Any, Dict, Literal, Optional, Tuple
3
-
4
- import equinox as eqx
5
- import jax
6
- import jax.numpy as jnp
7
- from jax.tree_util import GetAttrKey, SequenceKey
8
- from loguru import logger
9
-
10
-
11
- def stringify_name(path: Tuple) -> str:
12
- stringified = []
13
- for p in path:
14
- if isinstance(p, GetAttrKey):
15
- stringified.append(p.name)
16
- if isinstance(p, SequenceKey):
17
- stringified.append(str(p.idx))
18
- return ".".join(stringified)
19
-
20
-
21
- def expand_torch_tensor(tensor, pos: str, n: int):
22
- padding = [None] * n
23
- match pos:
24
- case "before":
25
- return tensor[*padding, ...]
26
- case "after":
27
- return tensor[..., *padding]
28
- case _:
29
- raise ValueError(
30
- f"Invalid `pos`, expected one of [`before`, `after`], got: {pos}"
31
- )
32
-
33
-
34
- def convert_params_from_torch_hub(
35
- jax_model: eqx.Module,
36
- replace_cfg: Dict[str, str],
37
- expand_cfg: Dict[str, list],
38
- squeeze_cfg: Dict[str, int | None],
39
- whitelist: list[str],
40
- strict: bool = True,
41
- source: Literal["torchhub", "timm"] = "torchhub",
42
- torch_hub_cfg: Optional[list[str]] = None,
43
- timm_cfg: Optional[list] = None,
44
- return_torch: bool = False,
45
- ):
46
- """
47
- Load weights from a torch hub model into an Equinox module.
48
-
49
- Args:
50
- jax_model (eqx.Module): A preexisting Jax model corresponding to the checkpoint to download.
51
- torch_hub_cfg (Tuple[str]): Arguments passed to `torch.hub.load()`.
52
- replace_cfg (Dict[str, str]): Rename parameters from key to value.
53
- expand_cfg (Dict[str, list]): Config to reshape params, see `expand_torch_tensor`
54
- sqeeze_cfg (Dict[str, int|None]): Config to squeeze tensors, opposite of expand.
55
- whitelist (Set[str]): Parameters to exclude from format conversion.
56
- strict (bool): Whether to crash on missing parameters one of the models.
57
- source (str): Torch Hub or timm.
58
- torch_hub_cfg (Optional[list]): args to pass to `torch.hub.load`.
59
- timm_cfg (Optional[list]): args to pass to `timm.create_model`.
60
- return_torch (bool): Return both jax and torch models.
61
- """
62
- try:
63
- import timm
64
- import torch
65
- except:
66
- raise ImportError("`torch` not available")
67
-
68
- # Load the pytorch model
69
- match source:
70
- case "torchhub":
71
- if torch_hub_cfg is None:
72
- raise ValueError(
73
- "The `torchhub` source is selected but `torch_hub_cfg` is None."
74
- )
75
- torch_model = torch.hub.load(*torch_hub_cfg)
76
- case "timm":
77
- if timm_cfg is None:
78
- raise ValueError(
79
- "The `timm` source is selected but `timm_cfg` is None."
80
- )
81
- torch_model = timm.create_model(*timm_cfg)
82
-
83
- torch_params = dict(torch_model.named_parameters())
84
-
85
- # Extract the parameters from the defined Jax model
86
- jax_params = eqx.filter(jax_model, eqx.is_array)
87
- # _, jax_params, _ = nnx.split(jax_model, nnx.Param, ...)
88
- jax_params_flat, jax_param_pytree = jax.tree_util.tree_flatten_with_path(jax_params)
89
-
90
- torch_params_flat = []
91
- for path, param in jax_params_flat:
92
- # Match the parameters' path of pytorch
93
- param_path = stringify_name(path)
94
- param_path = re.sub(r"\.scale|.kernel", ".weight", param_path)
95
-
96
- for old, new in replace_cfg.items():
97
- param_path = param_path.replace(old, new)
98
-
99
- shape = param.shape
100
-
101
- if param_path not in torch_params:
102
- _msg = f"{param_path} ({shape}) not found in PyTorch model."
103
- if strict:
104
- logger.error(_msg)
105
- raise AttributeError(_msg)
106
-
107
- logger.warning(f"{_msg} Appending `None` to flat param list.")
108
- torch_params_flat.append(None)
109
- continue
110
-
111
- logger.info(f"Converting {param_path}...")
112
- torch_param = torch_params[param_path]
113
-
114
- if param_path in expand_cfg:
115
- torch_param = expand_torch_tensor(torch_param, *expand_cfg[param_path])
116
- if param_path in squeeze_cfg:
117
- torch_param = torch.squeeze(torch_param, dim=squeeze_cfg[param_path])
118
-
119
- if shape != torch_param.shape:
120
- _msg = f"`{param_path}`: expected shape ({shape}) does not match its pytorch implementation ({torch_param.shape})."
121
- logger.error(_msg)
122
- raise ValueError(_msg)
123
-
124
- torch_params_flat.append(jnp.asarray(torch_param.detach().numpy()))
125
- _ = torch_params.pop(param_path)
126
-
127
- loaded_params = jax.tree_util.tree_unflatten(jax_param_pytree, torch_params_flat)
128
-
129
- for path, param in torch_params.items():
130
- logger.warning(
131
- f"PyTorch parameters `{path}` ({param.shape}) were not converted."
132
- )
133
- if strict and path not in whitelist:
134
- _msg = f"The PyTorch model contains parameters ({path}) that do not have a Jax counterpart."
135
- logger.error(_msg)
136
- raise AttributeError(_msg)
137
-
138
- if return_torch:
139
- return loaded_params, torch_model
140
- return loaded_params
141
-
142
-
143
- def convert_torch_to_equinox(
144
- jax_model: eqx.Module,
145
- replace_cfg: dict = {},
146
- expand_cfg: dict = {},
147
- squeeze_cfg: dict = {},
148
- whitelist: list[str] = [],
149
- strict: bool = True,
150
- source: Literal["torchhub", "timm"] = "torchhub",
151
- torch_hub_cfg: Optional[list[str]] = None,
152
- timm_cfg: Optional[list] = None,
153
- return_torch: bool = False,
154
- ) -> eqx.Module | Tuple[eqx.Module, Any]:
155
- """
156
- Convert a PyTorch model from torch.hub to Equinox format.
157
-
158
- Args:
159
- jax_model: The Equinox model
160
- replace_cfg: Dict of parameter name replacements
161
- expand_cfg: Dict of dimensions to expand
162
- squeeze_cfg: Dict of dimensions to squeeze
163
- whitelist: List of parameters to keep from JAX model
164
- strict: Wether to raise an issue if not all weights are converted
165
- source (str): Torch Hub or timm.
166
- torch_hub_cfg: [repo, model_name] for torch.hub.load
167
- timm_cfg (Optional[list]): args to pass to `timm.create_model`.
168
- return_torch (bool): Return both jax and torch models.
169
-
170
- Returns:
171
- eqx.Module: Converted Equinox model in inference mode
172
- """
173
- dynamic, static = eqx.partition(jax_model, eqx.is_array)
174
- if return_torch:
175
- converted_params, torch_model = convert_params_from_torch_hub(
176
- dynamic,
177
- replace_cfg,
178
- expand_cfg,
179
- squeeze_cfg,
180
- whitelist,
181
- strict,
182
- source,
183
- torch_hub_cfg,
184
- timm_cfg,
185
- return_torch,
186
- )
187
-
188
- return eqx.nn.inference_mode(
189
- eqx.combine(converted_params, static), value=True
190
- ), torch_model.eval()
191
- else:
192
- converted_params = convert_params_from_torch_hub(
193
- dynamic,
194
- replace_cfg,
195
- expand_cfg,
196
- squeeze_cfg,
197
- whitelist,
198
- strict,
199
- source,
200
- torch_hub_cfg,
201
- timm_cfg,
202
- return_torch,
203
- )
204
-
205
- return eqx.nn.inference_mode(eqx.combine(converted_params, static), value=True)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes