Equimo 0.4.6a2__tar.gz → 0.4.6a3__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 (45) hide show
  1. {equimo-0.4.6a2/src/Equimo.egg-info → equimo-0.4.6a3}/PKG-INFO +1 -1
  2. {equimo-0.4.6a2 → equimo-0.4.6a3}/pyproject.toml +1 -1
  3. {equimo-0.4.6a2 → equimo-0.4.6a3/src/Equimo.egg-info}/PKG-INFO +1 -1
  4. equimo-0.4.6a3/src/equimo/__init__.py +1 -0
  5. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/layers/convolution.py +45 -18
  6. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/layers/wavelet.py +24 -10
  7. equimo-0.4.6a2/src/equimo/__init__.py +0 -1
  8. {equimo-0.4.6a2 → equimo-0.4.6a3}/LICENSE.md +0 -0
  9. {equimo-0.4.6a2 → equimo-0.4.6a3}/README.md +0 -0
  10. {equimo-0.4.6a2 → equimo-0.4.6a3}/setup.cfg +0 -0
  11. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/Equimo.egg-info/SOURCES.txt +0 -0
  12. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/Equimo.egg-info/dependency_links.txt +0 -0
  13. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/Equimo.egg-info/requires.txt +0 -0
  14. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/Equimo.egg-info/top_level.txt +0 -0
  15. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/conversion/__init__.py +0 -0
  16. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/conversion/utils.py +0 -0
  17. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/experimental/__init__.py +0 -0
  18. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/experimental/text.py +0 -0
  19. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/io.py +0 -0
  20. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/layers/__init__.py +0 -0
  21. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/layers/activation.py +0 -0
  22. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/layers/attention.py +0 -0
  23. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/layers/downsample.py +0 -0
  24. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/layers/dropout.py +0 -0
  25. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/layers/ffn.py +0 -0
  26. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/layers/generic.py +0 -0
  27. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/layers/mamba.py +0 -0
  28. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/layers/norm.py +0 -0
  29. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/layers/patch.py +0 -0
  30. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/layers/posemb.py +0 -0
  31. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/layers/sharing.py +0 -0
  32. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/layers/squeeze_excite.py +0 -0
  33. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/models/__init__.py +0 -0
  34. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/models/emamodel.py +0 -0
  35. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/models/fastervit.py +0 -0
  36. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/models/lowformer.py +0 -0
  37. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/models/mlla.py +0 -0
  38. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/models/partialformer.py +0 -0
  39. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/models/reduceformer.py +0 -0
  40. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/models/shvit.py +0 -0
  41. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/models/vit.py +0 -0
  42. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/models/vssd.py +0 -0
  43. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/ops/scan.py +0 -0
  44. {equimo-0.4.6a2 → equimo-0.4.6a3}/src/equimo/utils.py +0 -0
  45. {equimo-0.4.6a2 → equimo-0.4.6a3}/tests/test_models.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Equimo
3
- Version: 0.4.6a2
3
+ Version: 0.4.6a3
4
4
  Summary: Implementation of popular vision models in Jax
5
5
  Classifier: Development Status :: 4 - Beta
6
6
  Classifier: Intended Audience :: Developers
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "Equimo"
3
- version = "0.4.6a2"
3
+ version = "0.4.6a3"
4
4
  description = "Implementation of popular vision models in Jax"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Equimo
3
- Version: 0.4.6a2
3
+ Version: 0.4.6a3
4
4
  Summary: Implementation of popular vision models in Jax
5
5
  Classifier: Development Status :: 4 - Beta
6
6
  Classifier: Intended Audience :: Developers
@@ -0,0 +1 @@
1
+ __version__ = "0.4.6a3"
@@ -1300,16 +1300,33 @@ class GenericGhostModule(eqx.Module):
1300
1300
  inference: Optional[bool] = None,
1301
1301
  ):
1302
1302
  use_inference = self.inference if inference is None else inference
1303
- out = self.inference_features(x) if use_inference else self.training_features(x)
1303
+ use_inference = jnp.asarray(use_inference, dtype=bool)
1304
1304
 
1305
- if self.mode == "shortcut":
1306
- res = self.short_conv(self.pool2(x))
1307
- gating_signal = jax.image.resize(
1305
+ out = jax.lax.cond(
1306
+ use_inference,
1307
+ lambda x_: self.inference_features(x_),
1308
+ lambda x_: self.training_features(x_),
1309
+ operand=x,
1310
+ )
1311
+
1312
+ shortcut_pred = bool(self.mode == "shortcut")
1313
+
1314
+ def _shortcut_branch(ox):
1315
+ out_, x_ = ox
1316
+ res = self.short_conv(self.pool2(x_))
1317
+ gating = jax.image.resize(
1308
1318
  image=jax.nn.sigmoid(res / self.gate_scale),
1309
- shape=(res.shape[0], out.shape[1], out.shape[2]),
1319
+ shape=(res.shape[0], out_.shape[1], out_.shape[2]),
1310
1320
  method="nearest",
1311
1321
  )
1312
- out = out[: self.out_channels, :, :] * gating_signal
1322
+ return out_[: self.out_channels, :, :] * gating
1323
+
1324
+ out = jax.lax.cond(
1325
+ shortcut_pred,
1326
+ _shortcut_branch,
1327
+ lambda ox: ox[0],
1328
+ operand=(out, x),
1329
+ )
1313
1330
 
1314
1331
  return out
1315
1332
 
@@ -1347,7 +1364,6 @@ class GhostBottleneck(eqx.Module):
1347
1364
  stride: int = 1,
1348
1365
  act_layer: Callable = jax.nn.relu,
1349
1366
  se_ratio: float = 0.0,
1350
- layer_id: Optional[int] = None,
1351
1367
  use_shortcut_mode_in_ghost1: bool = True,
1352
1368
  allow_identity_residual: bool = True,
1353
1369
  key: PRNGKeyArray,
@@ -1490,30 +1506,41 @@ class GhostBottleneck(eqx.Module):
1490
1506
  inference: Optional[bool] = None,
1491
1507
  ) -> Float[Array, "channels height width"]:
1492
1508
  use_inference = self.inference if inference is None else inference
1493
- k_g1, k_g2 = jr.split(key, 2)
1509
+ use_inference = jax.numpy.asarray(use_inference, dtype=bool)
1494
1510
 
1511
+ k_g1, k_g2 = jr.split(key, 2)
1495
1512
  residual = x
1496
1513
 
1497
1514
  x = self.ghost1(x, key=k_g1, inference=use_inference)
1498
1515
 
1499
1516
  if self.stride > 1:
1500
- if use_inference:
1501
- x = self.dw_shared_norm(self.dw_conv(x))
1502
- else:
1503
- terms = []
1504
- if not isinstance(self.dw_rpr_scale, eqx.nn.Identity):
1505
- terms.append(self.dw_rpr_scale(x))
1506
- terms.extend(conv(x) for conv in self.dw_rpr_conv)
1507
- x = self.dw_shared_norm(jax.tree_util.tree_reduce(operator.add, terms))
1517
+ x = jax.lax.cond(
1518
+ use_inference,
1519
+ lambda y: self.dw_shared_norm(self.dw_conv(y)),
1520
+ lambda y: self.dw_shared_norm(
1521
+ jax.tree_util.tree_reduce(
1522
+ operator.add,
1523
+ (
1524
+ (
1525
+ []
1526
+ if isinstance(self.dw_rpr_scale, eqx.nn.Identity)
1527
+ else [self.dw_rpr_scale(y)]
1528
+ )
1529
+ + [conv(y) for conv in self.dw_rpr_conv]
1530
+ ),
1531
+ )
1532
+ ),
1533
+ operand=x,
1534
+ )
1508
1535
 
1509
1536
  x = self.se(x)
1510
1537
 
1511
1538
  x = self.ghost2(x, key=k_g2, inference=use_inference)
1512
1539
 
1513
1540
  if not isinstance(self.shortcut, eqx.nn.Identity):
1514
- x += self.shortcut(residual)
1541
+ x = x + self.shortcut(residual)
1515
1542
  elif self.allow_identity_residual:
1516
- x += residual
1543
+ x = x + residual
1517
1544
 
1518
1545
  return x
1519
1546
 
@@ -63,7 +63,7 @@ def haar_dwt_split(
63
63
 
64
64
 
65
65
  class HWDConv(eqx.Module):
66
- mode: Literal["h_discard", "accurate"] = eqx.field(static=True)
66
+ mode: Literal["h_discard", "band_grouped", "accurate"] = eqx.field(static=True)
67
67
 
68
68
  pre_norm: eqx.nn.GroupNorm
69
69
  proj: eqx.nn.Conv2d
@@ -78,31 +78,43 @@ class HWDConv(eqx.Module):
78
78
  kernel_size: int = 1,
79
79
  use_bias: bool = False,
80
80
  act: Callable = jax.nn.relu,
81
- mode: Literal["h_discard", "accurate"] = "accurate",
81
+ mode: Literal["h_discard", "band_grouped", "accurate"] = "accurate",
82
82
  dropout: float = 0.0,
83
83
  key: PRNGKeyArray,
84
84
  ):
85
85
  self.mode = mode
86
86
 
87
- # Channels entering the projection (and thus the pre-norm)
88
87
  channels_in = in_channels if mode == "h_discard" else 4 * in_channels
89
88
 
90
- # Choose groups so no group crosses sub-band boundaries.
91
- # For accurate mode: total_groups = 4 * groups_per_band, each band has groups_per_band groups.
92
- # For h_discard mode: total_groups = groups_per_band (single band).
89
+ # GroupNorm: align groups to sub-band boundaries
90
+ # groups_per_band divides in_channels; total_groups = 4 * groups_per_band for 4 bands
93
91
  groups_per_band = nearest_power_of_2_divisor(in_channels, 32)
94
92
  total_groups = groups_per_band if mode == "h_discard" else 4 * groups_per_band
95
-
96
93
  self.pre_norm = eqx.nn.GroupNorm(channels=channels_in, groups=total_groups)
97
94
 
95
+ # Projection 1x1 conv
96
+ # - accurate: dense projection (groups=1)
97
+ # - band_grouped: independent per-band projections (groups=4), no cross-band mixing
98
+ # - h_discard: single-band dense projection (groups=1)
99
+ proj_groups = 1
100
+ if mode == "band_grouped":
101
+ if out_channels % 4 != 0:
102
+ raise ValueError(
103
+ "band_grouped mode requires out_channels to be divisible by 4 "
104
+ "so each sub-band produces an equal share."
105
+ )
106
+ proj_groups = 4
107
+
98
108
  self.proj = eqx.nn.Conv2d(
99
- channels_in,
100
- out_channels,
109
+ in_channels=channels_in,
110
+ out_channels=out_channels,
101
111
  kernel_size=kernel_size,
102
112
  use_bias=use_bias,
103
113
  padding="SAME",
114
+ groups=proj_groups,
104
115
  key=key,
105
116
  )
117
+
106
118
  self.act = act
107
119
 
108
120
  self.dropout = eqx.nn.Dropout(dropout)
@@ -115,11 +127,13 @@ class HWDConv(eqx.Module):
115
127
  if self.mode == "h_discard":
116
128
  y = LL # (C, H/2, W/2)
117
129
  else:
130
+ # Keep sub-bands contiguous and ordered so GN groups and grouped conv line up
118
131
  y = jnp.concatenate([LL, HL, LH, HH], axis=0) # (4*C, H/2, W/2)
119
132
 
133
+ # Band-aligned normalization (no cross-band statistics)
120
134
  y = self.pre_norm(y)
121
135
 
122
- y = self.proj(y) # (out_ch, H/2, W/2)
136
+ y = self.proj(y) # (out_channels, H/2, W/2)
123
137
  y = self.act(y)
124
138
 
125
139
  y = self.dropout(y, inference=inference, key=key)
@@ -1 +0,0 @@
1
- __version__ = "0.4.6a2"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes