Equimo 0.4.3__tar.gz → 0.4.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.4.3/src/Equimo.egg-info → equimo-0.4.4}/PKG-INFO +1 -1
- {equimo-0.4.3 → equimo-0.4.4}/pyproject.toml +1 -1
- {equimo-0.4.3 → equimo-0.4.4/src/Equimo.egg-info}/PKG-INFO +1 -1
- equimo-0.4.4/src/equimo/__init__.py +1 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/layers/convolution.py +291 -0
- equimo-0.4.3/src/equimo/__init__.py +0 -1
- {equimo-0.4.3 → equimo-0.4.4}/LICENSE.md +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/README.md +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/setup.cfg +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/Equimo.egg-info/SOURCES.txt +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/Equimo.egg-info/dependency_links.txt +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/Equimo.egg-info/requires.txt +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/Equimo.egg-info/top_level.txt +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/conversion/__init__.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/conversion/utils.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/experimental/__init__.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/experimental/text.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/io.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/layers/__init__.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/layers/activation.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/layers/attention.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/layers/downsample.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/layers/dropout.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/layers/ffn.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/layers/generic.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/layers/mamba.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/layers/norm.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/layers/patch.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/layers/posemb.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/layers/sharing.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/layers/squeeze_excite.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/models/__init__.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/models/emamodel.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/models/fastervit.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/models/lowformer.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/models/mlla.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/models/partialformer.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/models/reduceformer.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/models/shvit.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/models/vit.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/models/vssd.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/ops/scan.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/src/equimo/utils.py +0 -0
- {equimo-0.4.3 → equimo-0.4.4}/tests/test_models.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.4.4"
|
|
@@ -1403,3 +1403,294 @@ def finalize_ghostnet(model: eqx.Module) -> eqx.Module:
|
|
|
1403
1403
|
|
|
1404
1404
|
is_g_module = lambda m: isinstance(m, GenericGhostModule)
|
|
1405
1405
|
return jax.tree_util.tree_map(_finalize_leaf, model, is_leaf=is_g_module)
|
|
1406
|
+
|
|
1407
|
+
|
|
1408
|
+
class PartialConv2d(eqx.Module):
|
|
1409
|
+
"""Partial 2D convolution on the channel dimension.
|
|
1410
|
+
|
|
1411
|
+
This layer applies a standard 2D convolution only to the first `C // n_dim`
|
|
1412
|
+
input channels and leaves the remaining channels untouched (identity). It
|
|
1413
|
+
follows the "partial convolution" idea used to increase throughput by
|
|
1414
|
+
reducing compute on a subset of channels while preserving overall tensor
|
|
1415
|
+
shape, as explored in [1].
|
|
1416
|
+
|
|
1417
|
+
References:
|
|
1418
|
+
[1]. Chen et al., "Run, Don't Walk: Chasing Higher FLOPS for Faster Neural
|
|
1419
|
+
Networks" [arXiv:2303.03667](https://arxiv.org/abs/2303.03667).
|
|
1420
|
+
|
|
1421
|
+
Implementation details:
|
|
1422
|
+
- Let `C` be `in_channels` and `c = C // n_dim`. Only the first `c`
|
|
1423
|
+
channels are convolved with a `Conv2d(c, c, ...)`. The remaining
|
|
1424
|
+
`C - c` channels are forwarded unchanged.
|
|
1425
|
+
- The forward pass uses a functional "update-slice" pattern
|
|
1426
|
+
(`x.at[:c, ...].set(y1)`), which compiles to an efficient
|
|
1427
|
+
`dynamic_update_slice` under XLA. With JIT buffer donation, this can be
|
|
1428
|
+
performed in-place by the compiler.
|
|
1429
|
+
- Spatial dimensions must be preserved by the convolution so that the
|
|
1430
|
+
updated slice matches the input slice shape (e.g., use `stride=1` and
|
|
1431
|
+
`padding="SAME"`). If spatial dimensions change, the slice update will
|
|
1432
|
+
fail with a shape error.
|
|
1433
|
+
|
|
1434
|
+
Attributes
|
|
1435
|
+
- dim: Number of channels to be convolved, computed as `in_channels // n_dim`.
|
|
1436
|
+
This is treated as a static field for compilation stability.
|
|
1437
|
+
- conv: The underlying `eqx.nn.Conv2d(c, c, ...)` applied to the first `c`
|
|
1438
|
+
channels.
|
|
1439
|
+
|
|
1440
|
+
Notes
|
|
1441
|
+
- FLOPs reduction is approximately `c / C = 1 / n_dim` relative to a full
|
|
1442
|
+
convolution with the same kernel.
|
|
1443
|
+
"""
|
|
1444
|
+
|
|
1445
|
+
dim: int = eqx.field(static=True)
|
|
1446
|
+
|
|
1447
|
+
conv: eqx.nn.Conv2d
|
|
1448
|
+
|
|
1449
|
+
def __init__(
|
|
1450
|
+
self,
|
|
1451
|
+
in_channels: int,
|
|
1452
|
+
n_dim: int,
|
|
1453
|
+
*,
|
|
1454
|
+
key: PRNGKeyArray,
|
|
1455
|
+
kernel_size: int = 3,
|
|
1456
|
+
padding: str | int = "SAME",
|
|
1457
|
+
use_bias: bool = False,
|
|
1458
|
+
**kwargs,
|
|
1459
|
+
):
|
|
1460
|
+
"""
|
|
1461
|
+
Initialize a PartialConv2d layer.
|
|
1462
|
+
|
|
1463
|
+
Parameters
|
|
1464
|
+
- in_channels: Total number of input channels `C`.
|
|
1465
|
+
- n_dim: Divisor used to determine the number of convolved channels.
|
|
1466
|
+
The layer will convolve `C // n_dim` channels and leave the
|
|
1467
|
+
remaining channels untouched. Must be > 0, and
|
|
1468
|
+
`C // n_dim` must be >= 1 for a meaningful layer.
|
|
1469
|
+
- key: PRNG key used to initialize the underlying convolution weights.
|
|
1470
|
+
- kernel_size: Convolution kernel size (passed to `eqx.nn.Conv2d`).
|
|
1471
|
+
- padding: Convolution padding (passed to `eqx.nn.Conv2d`). Use
|
|
1472
|
+
`"SAME"` to preserve spatial dimensions with `stride=1`.
|
|
1473
|
+
Integer or other forms supported by `eqx.nn.Conv2d` are also
|
|
1474
|
+
accepted, but must preserve H and W for the slice update.
|
|
1475
|
+
- use_bias: Whether to include a bias term in the underlying convolution.
|
|
1476
|
+
- **kwargs: Forwarded to `eqx.nn.Conv2d` (e.g., `dilation`, `groups`).
|
|
1477
|
+
"""
|
|
1478
|
+
self.dim = in_channels // n_dim
|
|
1479
|
+
assert self.dim >= 1, "in_channels // n_dim must be >= 1"
|
|
1480
|
+
assert self.dim <= in_channels, (
|
|
1481
|
+
"Computed convolved channels exceed total channels"
|
|
1482
|
+
)
|
|
1483
|
+
|
|
1484
|
+
if isinstance(padding, str):
|
|
1485
|
+
assert padding.upper() == "SAME", (
|
|
1486
|
+
'When padding is a string, it must be "SAME"'
|
|
1487
|
+
)
|
|
1488
|
+
else:
|
|
1489
|
+
# If padding is numeric, ensure it preserves H, W for stride=1
|
|
1490
|
+
# For Conv2d with dilation d and kernel k, effective kernel is k_eff = (k - 1) * d + 1.
|
|
1491
|
+
# Output H' = H + 2*pad - k_eff + 1; preserving H requires k_eff odd and pad = k_eff // 2.
|
|
1492
|
+
dilation = kwargs.get("dilation", 1)
|
|
1493
|
+
if isinstance(dilation, (tuple, list)):
|
|
1494
|
+
# Require isotropic dilation for simplicity
|
|
1495
|
+
assert len(dilation) == 2 and dilation[0] == dilation[1], (
|
|
1496
|
+
"dilation must be an int or an equal pair"
|
|
1497
|
+
)
|
|
1498
|
+
dilation = dilation[0]
|
|
1499
|
+
assert isinstance(dilation, int) and dilation >= 1, (
|
|
1500
|
+
"dilation must be a positive int"
|
|
1501
|
+
)
|
|
1502
|
+
assert isinstance(kernel_size, int) and kernel_size >= 1, (
|
|
1503
|
+
"kernel_size must be a positive int"
|
|
1504
|
+
)
|
|
1505
|
+
|
|
1506
|
+
k_eff = (kernel_size - 1) * dilation + 1
|
|
1507
|
+
assert isinstance(padding, int) and padding >= 0, (
|
|
1508
|
+
"padding must be a non-negative int"
|
|
1509
|
+
)
|
|
1510
|
+
assert k_eff % 2 == 1 and padding == k_eff // 2, (
|
|
1511
|
+
"Integer padding must preserve spatial size: require effective kernel odd and "
|
|
1512
|
+
f"padding == ((kernel_size-1)*dilation+1)//2; got k_eff={k_eff}, padding={padding}"
|
|
1513
|
+
)
|
|
1514
|
+
|
|
1515
|
+
self.conv = eqx.nn.Conv2d(
|
|
1516
|
+
in_channels=self.dim,
|
|
1517
|
+
out_channels=self.dim,
|
|
1518
|
+
kernel_size=kernel_size,
|
|
1519
|
+
stride=1,
|
|
1520
|
+
padding=padding,
|
|
1521
|
+
use_bias=use_bias,
|
|
1522
|
+
key=key,
|
|
1523
|
+
**kwargs,
|
|
1524
|
+
)
|
|
1525
|
+
|
|
1526
|
+
def __call__(
|
|
1527
|
+
self,
|
|
1528
|
+
x: Float[Array, "channels height width"],
|
|
1529
|
+
*args,
|
|
1530
|
+
**kwargs,
|
|
1531
|
+
) -> Float[Array, "channels height width"]:
|
|
1532
|
+
c = self.dim
|
|
1533
|
+
x1 = x[:c, :, :]
|
|
1534
|
+
y1 = self.conv(x1)
|
|
1535
|
+
|
|
1536
|
+
return x.at[:c, :, :].set(y1)
|
|
1537
|
+
|
|
1538
|
+
|
|
1539
|
+
class FasterNetBlock(eqx.Module):
|
|
1540
|
+
"""
|
|
1541
|
+
FasterNet-style residual block with Partial Convolution-based spatial mixing
|
|
1542
|
+
and pointwise MLP, adapted to Equinox/JAX.
|
|
1543
|
+
|
|
1544
|
+
Structure
|
|
1545
|
+
- Spatial mixing: `PartialConv2d` applies a 3×3 convolution to the first
|
|
1546
|
+
`C // n_dim` channels and leaves the remaining channels unchanged. This
|
|
1547
|
+
reduces compute while keeping the tensor shape intact. See [1].
|
|
1548
|
+
- Channel MLP: two pointwise (1*1) convolutions expand and then project
|
|
1549
|
+
channels (`C -> mlp_ratio*C -> C`), with normalization and activation
|
|
1550
|
+
in between.
|
|
1551
|
+
- Regularization: includes dropout after the MLP and optional stochastic
|
|
1552
|
+
depth (DropPath) on the residual branch.
|
|
1553
|
+
- Residual: optional residual connection `y = x + DropPath(MLP(SpatialMix(x)))`.
|
|
1554
|
+
|
|
1555
|
+
Shape invariants
|
|
1556
|
+
- Input: `[channels, height, width]`
|
|
1557
|
+
- Output: `[channels, height, width]` (same spatial and channel dimensions)
|
|
1558
|
+
|
|
1559
|
+
References
|
|
1560
|
+
- [1] Chen et al., "Run, Don't Walk: Chasing Higher FLOPS for Faster Neural
|
|
1561
|
+
Networks" [arXiv:2303.03667](https://arxiv.org/abs/2303.03667).
|
|
1562
|
+
|
|
1563
|
+
Attributes
|
|
1564
|
+
- residual: Whether to use a residual connection with stochastic depth.
|
|
1565
|
+
- spatial_mixing: `PartialConv2d` performing partial 3×3 spatial mixing.
|
|
1566
|
+
- pw_conv1: Pointwise convolution expanding channels to `mlp_ratio * C`.
|
|
1567
|
+
- pw_conv2: Pointwise convolution projecting channels back to `C`.
|
|
1568
|
+
- norm: Normalization layer applied on the expanded channels.
|
|
1569
|
+
- act: Activation applied after normalization (defaults to identity if none).
|
|
1570
|
+
- dropout: Dropout applied after the MLP.
|
|
1571
|
+
- drop_path: Stochastic depth module for residual addition.
|
|
1572
|
+
"""
|
|
1573
|
+
|
|
1574
|
+
residual: bool = eqx.field(static=True)
|
|
1575
|
+
|
|
1576
|
+
spatial_mixing: eqx.nn.Conv2d
|
|
1577
|
+
pw_conv1: eqx.nn.Conv2d
|
|
1578
|
+
pw_conv2: eqx.nn.Conv2d
|
|
1579
|
+
norm: eqx.Module
|
|
1580
|
+
act: eqx.Module
|
|
1581
|
+
dropout: eqx.nn.Dropout
|
|
1582
|
+
drop_path: DropPathAdd
|
|
1583
|
+
|
|
1584
|
+
def __init__(
|
|
1585
|
+
self,
|
|
1586
|
+
in_channels: int,
|
|
1587
|
+
*,
|
|
1588
|
+
key: PRNGKeyArray,
|
|
1589
|
+
n_dim: int = 4,
|
|
1590
|
+
mlp_ratio: int = 3,
|
|
1591
|
+
kernel_size: int = 3,
|
|
1592
|
+
padding: str | int = "SAME",
|
|
1593
|
+
norm_layer: eqx.Module | None = eqx.nn.GroupNorm,
|
|
1594
|
+
norm_max_group: int = 32,
|
|
1595
|
+
act_layer: Callable | None = None,
|
|
1596
|
+
dropout: float = 0.0,
|
|
1597
|
+
drop_path: float = 0.0,
|
|
1598
|
+
norm_kwargs: dict = {},
|
|
1599
|
+
residual: bool = True,
|
|
1600
|
+
**kwargs,
|
|
1601
|
+
):
|
|
1602
|
+
"""
|
|
1603
|
+
Initialize a FasterNetBlock.
|
|
1604
|
+
|
|
1605
|
+
Parameters
|
|
1606
|
+
- in_channels: Number of input/output channels `C`.
|
|
1607
|
+
- key: PRNG key used to initialize submodules. Internally split for
|
|
1608
|
+
spatial mixing and pointwise convolutions.
|
|
1609
|
+
- n_dim: Divisor determining the fraction of channels convolved by
|
|
1610
|
+
`PartialConv2d`; the convolved channels are `C // n_dim`.
|
|
1611
|
+
- mlp_ratio: Expansion ratio for the MLP (1×1 convs): hidden size is
|
|
1612
|
+
`mlp_ratio * C`.
|
|
1613
|
+
- kernel_size: Kernel size for the spatial mixing convolution (passed
|
|
1614
|
+
to `PartialConv2d`).
|
|
1615
|
+
- padding: Padding for the spatial mixing convolution. Use `"SAME"`
|
|
1616
|
+
to preserve spatial dimensions.
|
|
1617
|
+
- norm_layer: Normalization constructor applied on the expanded
|
|
1618
|
+
channels. If `eqx.nn.GroupNorm`, the number of groups is chosen as
|
|
1619
|
+
the largest power-of-two divisor of `hidden_channels` not exceeding
|
|
1620
|
+
`norm_max_group`. If `None`, uses identity.
|
|
1621
|
+
- norm_max_group: Maximum group count when using `GroupNorm`.
|
|
1622
|
+
- act_layer: Callable used to construct an activation function. If
|
|
1623
|
+
`None`, uses identity. Passed to `eqx.nn.Lambda`.
|
|
1624
|
+
- dropout: Dropout probability applied after the MLP branch.
|
|
1625
|
+
- drop_path: Stochastic depth probability on the residual branch.
|
|
1626
|
+
- norm_kwargs: Extra keyword arguments forwarded to the normalization
|
|
1627
|
+
layer constructor.
|
|
1628
|
+
- residual: Whether to add the residual connection (with DropPath).
|
|
1629
|
+
- **kwargs: Reserved for future extensions; forwarded where applicable.
|
|
1630
|
+
|
|
1631
|
+
Notes
|
|
1632
|
+
- The block preserves `[H, W]`. Ensure `PartialConv2d` is configured
|
|
1633
|
+
to preserve spatial dimensions (e.g., `"SAME"` padding).
|
|
1634
|
+
- When `norm_layer` is not `GroupNorm`, it should accept the channel
|
|
1635
|
+
count as its first argument.
|
|
1636
|
+
- The same input/output channel count `C` is used throughout the block.
|
|
1637
|
+
"""
|
|
1638
|
+
|
|
1639
|
+
key_sm, key_pw1, key_pw2 = jr.split(key, 3)
|
|
1640
|
+
self.residual = residual
|
|
1641
|
+
|
|
1642
|
+
self.spatial_mixing = PartialConv2d(
|
|
1643
|
+
in_channels=in_channels, n_dim=n_dim, key=key_sm
|
|
1644
|
+
)
|
|
1645
|
+
|
|
1646
|
+
hidden_channels = mlp_ratio * in_channels
|
|
1647
|
+
self.pw_conv1 = eqx.nn.Conv2d(
|
|
1648
|
+
in_channels,
|
|
1649
|
+
hidden_channels,
|
|
1650
|
+
kernel_size=1,
|
|
1651
|
+
stride=1,
|
|
1652
|
+
padding="SAME",
|
|
1653
|
+
use_bias=False,
|
|
1654
|
+
key=key_pw1,
|
|
1655
|
+
)
|
|
1656
|
+
self.pw_conv2 = eqx.nn.Conv2d(
|
|
1657
|
+
hidden_channels,
|
|
1658
|
+
in_channels,
|
|
1659
|
+
kernel_size=1,
|
|
1660
|
+
stride=1,
|
|
1661
|
+
padding="SAME",
|
|
1662
|
+
use_bias=False,
|
|
1663
|
+
key=key_pw2,
|
|
1664
|
+
)
|
|
1665
|
+
|
|
1666
|
+
if norm_layer is not None:
|
|
1667
|
+
if norm_layer == eqx.nn.GroupNorm:
|
|
1668
|
+
num_groups = nearest_power_of_2_divisor(hidden_channels, norm_max_group)
|
|
1669
|
+
self.norm = eqx.nn.GroupNorm(num_groups, hidden_channels, **norm_kwargs)
|
|
1670
|
+
else:
|
|
1671
|
+
self.norm = norm_layer(hidden_channels, **norm_kwargs)
|
|
1672
|
+
else:
|
|
1673
|
+
self.norm = eqx.nn.Identity()
|
|
1674
|
+
|
|
1675
|
+
self.dropout = eqx.nn.Dropout(dropout)
|
|
1676
|
+
self.drop_path = DropPathAdd(drop_path)
|
|
1677
|
+
self.act = eqx.nn.Lambda(act_layer) if act_layer else eqx.nn.Identity()
|
|
1678
|
+
|
|
1679
|
+
def __call__(
|
|
1680
|
+
self,
|
|
1681
|
+
x: Float[Array, "channels height width"],
|
|
1682
|
+
key: PRNGKeyArray,
|
|
1683
|
+
inference: Optional[bool] = None,
|
|
1684
|
+
) -> Float[Array, "channels height width"]:
|
|
1685
|
+
key_dropout, key_droppath = jr.split(key, 2)
|
|
1686
|
+
x1 = self.spatial_mixing(x)
|
|
1687
|
+
out = self.dropout(
|
|
1688
|
+
self.pw_conv2(self.act(self.norm(self.pw_conv1(x1)))),
|
|
1689
|
+
inference=inference,
|
|
1690
|
+
key=key_dropout,
|
|
1691
|
+
)
|
|
1692
|
+
|
|
1693
|
+
if self.residual:
|
|
1694
|
+
out = self.drop_path(x, out, inference=inference, key=key_droppath)
|
|
1695
|
+
|
|
1696
|
+
return out
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.4.3"
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|