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.
- {equimo-0.2.3 → equimo-0.2.4}/Equimo.egg-info/PKG-INFO +8 -3
- {equimo-0.2.3 → equimo-0.2.4}/Equimo.egg-info/SOURCES.txt +0 -4
- {equimo-0.2.3 → equimo-0.2.4}/PKG-INFO +8 -3
- {equimo-0.2.3 → equimo-0.2.4}/README.md +7 -2
- equimo-0.2.4/equimo/__init__.py +1 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/io.py +1 -0
- {equimo-0.2.3 → equimo-0.2.4}/pyproject.toml +2 -1
- equimo-0.2.3/equimo/__init__.py +0 -1
- equimo-0.2.3/equimo/converters/__init__.py +0 -1
- equimo-0.2.3/equimo/converters/dinov2.py +0 -69
- equimo-0.2.3/equimo/converters/siglip2.py +0 -105
- equimo-0.2.3/equimo/converters/utils.py +0 -205
- {equimo-0.2.3 → equimo-0.2.4}/Equimo.egg-info/dependency_links.txt +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/Equimo.egg-info/requires.txt +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/Equimo.egg-info/top_level.txt +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/LICENSE.md +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/__init__.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/activation.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/attention.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/convolution.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/downsample.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/dropout.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/ffn.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/generic.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/mamba.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/norm.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/patch.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/posemb.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/sharing.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/layers/squeeze_excite.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/models/__init__.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/models/emamodel.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/models/fastervit.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/models/mlla.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/models/partialformer.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/models/shvit.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/models/vit.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/models/vssd.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/ops/scan.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/equimo/utils.py +0 -0
- {equimo-0.2.3 → equimo-0.2.4}/setup.cfg +0 -0
- {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
|
+
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
|
-
|
|
158
|
+
The following models have pretrained weights available in Equimo:
|
|
159
159
|
|
|
160
|
-
|
|
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
|
+
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
|
-
|
|
158
|
+
The following models have pretrained weights available in Equimo:
|
|
159
159
|
|
|
160
|
-
|
|
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
|
-
|
|
131
|
+
The following models have pretrained weights available in Equimo:
|
|
132
132
|
|
|
133
|
-
|
|
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
|
+
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"]
|
equimo-0.2.3/equimo/__init__.py
DELETED
|
@@ -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
|
|
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
|