Equimo 0.3.5__tar.gz → 0.4.0a2__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.3.5/src/Equimo.egg-info → equimo-0.4.0a2}/PKG-INFO +3 -1
- {equimo-0.3.5 → equimo-0.4.0a2}/README.md +2 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/pyproject.toml +1 -1
- {equimo-0.3.5 → equimo-0.4.0a2/src/Equimo.egg-info}/PKG-INFO +3 -1
- {equimo-0.3.5 → equimo-0.4.0a2}/src/Equimo.egg-info/SOURCES.txt +2 -0
- equimo-0.4.0a2/src/equimo/__init__.py +1 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/layers/attention.py +484 -1
- equimo-0.4.0a2/src/equimo/layers/convolution.py +871 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/layers/patch.py +3 -3
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/models/__init__.py +6 -0
- equimo-0.4.0a2/src/equimo/models/lowformer.py +387 -0
- equimo-0.4.0a2/src/equimo/models/reduceformer.py +329 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/utils.py +51 -4
- {equimo-0.3.5 → equimo-0.4.0a2}/tests/test_models.py +24 -0
- equimo-0.3.5/src/equimo/__init__.py +0 -1
- equimo-0.3.5/src/equimo/layers/convolution.py +0 -329
- {equimo-0.3.5 → equimo-0.4.0a2}/LICENSE.md +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/setup.cfg +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/Equimo.egg-info/dependency_links.txt +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/Equimo.egg-info/requires.txt +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/Equimo.egg-info/top_level.txt +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/conversion/__init__.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/conversion/utils.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/experimental/__init__.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/experimental/text.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/io.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/layers/__init__.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/layers/activation.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/layers/downsample.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/layers/dropout.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/layers/ffn.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/layers/generic.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/layers/mamba.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/layers/norm.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/layers/posemb.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/layers/sharing.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/layers/squeeze_excite.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/models/emamodel.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/models/fastervit.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/models/mlla.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/models/partialformer.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/models/shvit.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/models/vit.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/models/vssd.py +0 -0
- {equimo-0.3.5 → equimo-0.4.0a2}/src/equimo/ops/scan.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Equimo
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0a2
|
|
4
4
|
Summary: Implementation of popular vision models in Jax
|
|
5
5
|
Classifier: Development Status :: 4 - Beta
|
|
6
6
|
Classifier: Intended Audience :: Developers
|
|
@@ -76,6 +76,8 @@ Beyond normal ViT (e.g., dinov2 or siglip), equimo proposes other SotA architect
|
|
|
76
76
|
| PartialFormer | [Efficient Vision Transformers with Partial Attention](https://eccv.ecva.net/virtual/2024/poster/1877) | 2024 | ✅ |
|
|
77
77
|
| SHViT | [SHViT: Single-Head Vision Transformer with Memory Efficient Macro Design](https://arxiv.org/abs/2401.16456) | 2024 | ✅ |
|
|
78
78
|
| VSSD | [VSSD: Vision Mamba with Non-Causal State Space Duality](https://arxiv.org/abs/2407.18559) | 2024 | ✅ |
|
|
79
|
+
| ReduceFormer | [ReduceFormer: Attention with Tensor Reduction by Summation](https://arxiv.org/abs/2406.07488) | 2024 | ✅ |
|
|
80
|
+
| LowFormer | [LowFormer: Hardware Efficient Design for Convolutional Transformer Backbones](https://arxiv.org/abs/2409.03460) | 2024 | ✅ |
|
|
79
81
|
|
|
80
82
|
\*: Only contains the [Linear Angular Attention](https://github.com/clementpoiret/Equimo/blob/f8fcc79e45ca65e9deb1d970c4286c0b8562f9c2/equimo/layers/attention.py#L1407) module. It is straight forward to build a ViT around it, but may require an additional `__call__` kwarg to control the `sparse_reg` bool.
|
|
81
83
|
|
|
@@ -40,6 +40,8 @@ Beyond normal ViT (e.g., dinov2 or siglip), equimo proposes other SotA architect
|
|
|
40
40
|
| PartialFormer | [Efficient Vision Transformers with Partial Attention](https://eccv.ecva.net/virtual/2024/poster/1877) | 2024 | ✅ |
|
|
41
41
|
| SHViT | [SHViT: Single-Head Vision Transformer with Memory Efficient Macro Design](https://arxiv.org/abs/2401.16456) | 2024 | ✅ |
|
|
42
42
|
| VSSD | [VSSD: Vision Mamba with Non-Causal State Space Duality](https://arxiv.org/abs/2407.18559) | 2024 | ✅ |
|
|
43
|
+
| ReduceFormer | [ReduceFormer: Attention with Tensor Reduction by Summation](https://arxiv.org/abs/2406.07488) | 2024 | ✅ |
|
|
44
|
+
| LowFormer | [LowFormer: Hardware Efficient Design for Convolutional Transformer Backbones](https://arxiv.org/abs/2409.03460) | 2024 | ✅ |
|
|
43
45
|
|
|
44
46
|
\*: Only contains the [Linear Angular Attention](https://github.com/clementpoiret/Equimo/blob/f8fcc79e45ca65e9deb1d970c4286c0b8562f9c2/equimo/layers/attention.py#L1407) module. It is straight forward to build a ViT around it, but may require an additional `__call__` kwarg to control the `sparse_reg` bool.
|
|
45
47
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Equimo
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0a2
|
|
4
4
|
Summary: Implementation of popular vision models in Jax
|
|
5
5
|
Classifier: Development Status :: 4 - Beta
|
|
6
6
|
Classifier: Intended Audience :: Developers
|
|
@@ -76,6 +76,8 @@ Beyond normal ViT (e.g., dinov2 or siglip), equimo proposes other SotA architect
|
|
|
76
76
|
| PartialFormer | [Efficient Vision Transformers with Partial Attention](https://eccv.ecva.net/virtual/2024/poster/1877) | 2024 | ✅ |
|
|
77
77
|
| SHViT | [SHViT: Single-Head Vision Transformer with Memory Efficient Macro Design](https://arxiv.org/abs/2401.16456) | 2024 | ✅ |
|
|
78
78
|
| VSSD | [VSSD: Vision Mamba with Non-Causal State Space Duality](https://arxiv.org/abs/2407.18559) | 2024 | ✅ |
|
|
79
|
+
| ReduceFormer | [ReduceFormer: Attention with Tensor Reduction by Summation](https://arxiv.org/abs/2406.07488) | 2024 | ✅ |
|
|
80
|
+
| LowFormer | [LowFormer: Hardware Efficient Design for Convolutional Transformer Backbones](https://arxiv.org/abs/2409.03460) | 2024 | ✅ |
|
|
79
81
|
|
|
80
82
|
\*: Only contains the [Linear Angular Attention](https://github.com/clementpoiret/Equimo/blob/f8fcc79e45ca65e9deb1d970c4286c0b8562f9c2/equimo/layers/attention.py#L1407) module. It is straight forward to build a ViT around it, but may require an additional `__call__` kwarg to control the `sparse_reg` bool.
|
|
81
83
|
|
|
@@ -30,8 +30,10 @@ src/equimo/layers/squeeze_excite.py
|
|
|
30
30
|
src/equimo/models/__init__.py
|
|
31
31
|
src/equimo/models/emamodel.py
|
|
32
32
|
src/equimo/models/fastervit.py
|
|
33
|
+
src/equimo/models/lowformer.py
|
|
33
34
|
src/equimo/models/mlla.py
|
|
34
35
|
src/equimo/models/partialformer.py
|
|
36
|
+
src/equimo/models/reduceformer.py
|
|
35
37
|
src/equimo/models/shvit.py
|
|
36
38
|
src/equimo/models/vit.py
|
|
37
39
|
src/equimo/models/vssd.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.4.0-alpha.2"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
from typing import Callable, List, Optional, Tuple
|
|
1
|
+
from typing import Callable, List, Literal, Optional, Sequence, Tuple
|
|
2
|
+
|
|
2
3
|
import equinox as eqx
|
|
3
4
|
import jax
|
|
4
5
|
import jax.numpy as jnp
|
|
@@ -6,6 +7,7 @@ import jax.random as jr
|
|
|
6
7
|
from einops import rearrange, reduce
|
|
7
8
|
from jaxtyping import Array, Float, PRNGKeyArray
|
|
8
9
|
|
|
10
|
+
from equimo.layers.convolution import ConvBlock, SingleConvBlock, MBConv
|
|
9
11
|
from equimo.layers.dropout import DropPathAdd
|
|
10
12
|
from equimo.layers.ffn import Mlp
|
|
11
13
|
from equimo.layers.mamba import Mamba2Mixer
|
|
@@ -1565,6 +1567,487 @@ class LinearAngularAttention(eqx.Module):
|
|
|
1565
1567
|
return x
|
|
1566
1568
|
|
|
1567
1569
|
|
|
1570
|
+
class RFAttention(eqx.Module):
|
|
1571
|
+
"""Attention with Tensor Reduction by Summation[1].
|
|
1572
|
+
|
|
1573
|
+
A ReLU Linear Attention mechanism replacing matmuls with global
|
|
1574
|
+
summation and element-wise multiplications.
|
|
1575
|
+
|
|
1576
|
+
Attributes:
|
|
1577
|
+
dim: Total dimension of the input/output
|
|
1578
|
+
num_heads: Number of attention heads
|
|
1579
|
+
head_dim: Dimension of each attention head (dim // num_heads)
|
|
1580
|
+
|
|
1581
|
+
References:
|
|
1582
|
+
[1]. Yang, J., An, L., & Park, S. I. (2024). ReduceFormer: Attention
|
|
1583
|
+
with Tensor Reduction by Summation (No. arXiv:2406.07488). arXiv.
|
|
1584
|
+
https://doi.org/10.48550/arXiv.2406.07488
|
|
1585
|
+
"""
|
|
1586
|
+
|
|
1587
|
+
total_dim: int = eqx.field(static=True)
|
|
1588
|
+
kernel_func: Callable = eqx.field(static=True)
|
|
1589
|
+
eps: float = eqx.field(static=True)
|
|
1590
|
+
|
|
1591
|
+
qkv: eqx.nn.Conv2d
|
|
1592
|
+
aggreg: list[eqx.nn.Conv2d]
|
|
1593
|
+
proj: SingleConvBlock
|
|
1594
|
+
|
|
1595
|
+
def __init__(
|
|
1596
|
+
self,
|
|
1597
|
+
in_channels: int,
|
|
1598
|
+
out_channels: int,
|
|
1599
|
+
*,
|
|
1600
|
+
key: PRNGKeyArray,
|
|
1601
|
+
num_heads: int | None = None,
|
|
1602
|
+
head_dim: int = 8,
|
|
1603
|
+
heads_ratio: float = 1.0,
|
|
1604
|
+
scales: Sequence[int] = (5,),
|
|
1605
|
+
use_bias: bool = False,
|
|
1606
|
+
kernel_func: Callable = jax.nn.relu,
|
|
1607
|
+
# TODO: Benchmark against LN, RMSN, NsLN
|
|
1608
|
+
norm_layer: eqx.Module = eqx.nn.GroupNorm,
|
|
1609
|
+
norm_kwargs: dict = {},
|
|
1610
|
+
eps: float = 1e-15,
|
|
1611
|
+
**kwargs,
|
|
1612
|
+
):
|
|
1613
|
+
key_qkv, key_aggreg, key_proj = jr.split(key, 3)
|
|
1614
|
+
|
|
1615
|
+
self.kernel_func = kernel_func
|
|
1616
|
+
self.eps = eps
|
|
1617
|
+
num_heads = num_heads or int(in_channels // head_dim * heads_ratio)
|
|
1618
|
+
total_dim = num_heads * head_dim
|
|
1619
|
+
self.total_dim = total_dim * (1 + len(scales))
|
|
1620
|
+
|
|
1621
|
+
self.qkv = eqx.nn.Conv2d(
|
|
1622
|
+
in_channels=in_channels,
|
|
1623
|
+
out_channels=3 * total_dim,
|
|
1624
|
+
kernel_size=1,
|
|
1625
|
+
padding="SAME",
|
|
1626
|
+
use_bias=use_bias,
|
|
1627
|
+
key=key_qkv,
|
|
1628
|
+
)
|
|
1629
|
+
self.aggreg = [
|
|
1630
|
+
eqx.nn.Conv2d(
|
|
1631
|
+
in_channels=3 * total_dim,
|
|
1632
|
+
out_channels=3 * total_dim,
|
|
1633
|
+
kernel_size=scale,
|
|
1634
|
+
padding="SAME",
|
|
1635
|
+
groups=3 * total_dim,
|
|
1636
|
+
key=key_aggreg,
|
|
1637
|
+
use_bias=use_bias,
|
|
1638
|
+
)
|
|
1639
|
+
for scale in scales
|
|
1640
|
+
]
|
|
1641
|
+
# TODO: test different normalizations
|
|
1642
|
+
self.proj = SingleConvBlock(
|
|
1643
|
+
in_channels=self.total_dim,
|
|
1644
|
+
out_channels=out_channels,
|
|
1645
|
+
kernel_size=1,
|
|
1646
|
+
use_bias=use_bias,
|
|
1647
|
+
norm_layer=norm_layer,
|
|
1648
|
+
norm_kwargs=norm_kwargs,
|
|
1649
|
+
key=key_proj,
|
|
1650
|
+
)
|
|
1651
|
+
|
|
1652
|
+
def __call__(
|
|
1653
|
+
self,
|
|
1654
|
+
x: Float[Array, "seqlen height width"],
|
|
1655
|
+
key: PRNGKeyArray,
|
|
1656
|
+
inference: Optional[bool] = None,
|
|
1657
|
+
) -> Float[Array, "seqlen height width"]:
|
|
1658
|
+
qkv_base = self.qkv(x)
|
|
1659
|
+
|
|
1660
|
+
aggregated_qkvs = [op(qkv_base) for op in self.aggreg]
|
|
1661
|
+
all_qkvs = [qkv_base] + aggregated_qkvs
|
|
1662
|
+
|
|
1663
|
+
rearranged_qkvs = [
|
|
1664
|
+
rearrange(qkv, "(n d) h w -> n d h w", n=3) for qkv in all_qkvs
|
|
1665
|
+
]
|
|
1666
|
+
multiscale_qkv = jnp.concatenate(rearranged_qkvs, axis=1)
|
|
1667
|
+
|
|
1668
|
+
q, k, v = multiscale_qkv
|
|
1669
|
+
|
|
1670
|
+
q = self.kernel_func(q)
|
|
1671
|
+
k = self.kernel_func(k)
|
|
1672
|
+
|
|
1673
|
+
sum_k = jnp.sum(k, axis=(-1, -2), keepdims=True)
|
|
1674
|
+
sum_v = jnp.sum(v, axis=(-1, -2), keepdims=True)
|
|
1675
|
+
sum_kv = jnp.sum(k * sum_v, axis=(-1, -2), keepdims=True)
|
|
1676
|
+
sum_q = jnp.sum(q, axis=0, keepdims=True)
|
|
1677
|
+
|
|
1678
|
+
out = (q * sum_kv) / (sum_q * sum_k + self.eps)
|
|
1679
|
+
out = self.proj(out)
|
|
1680
|
+
|
|
1681
|
+
return out
|
|
1682
|
+
|
|
1683
|
+
|
|
1684
|
+
class RFAttentionBlock(eqx.Module):
|
|
1685
|
+
context_module: RFAttention
|
|
1686
|
+
local_module: MBConv
|
|
1687
|
+
|
|
1688
|
+
def __init__(
|
|
1689
|
+
self,
|
|
1690
|
+
in_channels: int,
|
|
1691
|
+
*,
|
|
1692
|
+
key,
|
|
1693
|
+
head_dim: int = 32,
|
|
1694
|
+
heads_ratio: float = 1.0,
|
|
1695
|
+
scales: Sequence[int] = (5,),
|
|
1696
|
+
rfattn_norm_layer: eqx.Module = eqx.nn.GroupNorm,
|
|
1697
|
+
norm_kwargs: dict = {},
|
|
1698
|
+
expand_ratio: float = 4.0,
|
|
1699
|
+
mbconv_norm_layers: tuple = (None, None, eqx.nn.GroupNorm),
|
|
1700
|
+
mbconv_act_layers: tuple = (jax.nn.hard_swish, jax.nn.hard_swish, None),
|
|
1701
|
+
fuse_mbconv: bool = False,
|
|
1702
|
+
**kwargs,
|
|
1703
|
+
):
|
|
1704
|
+
key_context, key_local = jr.split(key, 2)
|
|
1705
|
+
|
|
1706
|
+
self.context_module = RFAttention(
|
|
1707
|
+
in_channels=in_channels,
|
|
1708
|
+
out_channels=in_channels,
|
|
1709
|
+
head_dim=head_dim,
|
|
1710
|
+
heads_ratio=heads_ratio,
|
|
1711
|
+
scales=scales,
|
|
1712
|
+
norm_layer=rfattn_norm_layer,
|
|
1713
|
+
norm_kwargs=norm_kwargs,
|
|
1714
|
+
key=key_context,
|
|
1715
|
+
)
|
|
1716
|
+
self.local_module = MBConv(
|
|
1717
|
+
in_channels=in_channels,
|
|
1718
|
+
out_channels=in_channels,
|
|
1719
|
+
expand_ratio=expand_ratio,
|
|
1720
|
+
norm_layers=mbconv_norm_layers,
|
|
1721
|
+
act_layers=mbconv_act_layers,
|
|
1722
|
+
use_bias=(True, True, False),
|
|
1723
|
+
fuse=fuse_mbconv,
|
|
1724
|
+
key=key_local,
|
|
1725
|
+
)
|
|
1726
|
+
|
|
1727
|
+
def __call__(
|
|
1728
|
+
self,
|
|
1729
|
+
x: Float[Array, "dim height width"],
|
|
1730
|
+
key: PRNGKeyArray,
|
|
1731
|
+
inference: Optional[bool] = None,
|
|
1732
|
+
):
|
|
1733
|
+
key_context, key_local = jr.split(key, 2)
|
|
1734
|
+
|
|
1735
|
+
x += self.context_module(x, inference=inference, key=key_context)
|
|
1736
|
+
x += self.local_module(x, inference=inference, key=key_local)
|
|
1737
|
+
|
|
1738
|
+
return x
|
|
1739
|
+
|
|
1740
|
+
|
|
1741
|
+
class ConvAttention(eqx.Module):
|
|
1742
|
+
"""Lightweight ConvAttention from LowFormer."""
|
|
1743
|
+
|
|
1744
|
+
num_heads: int = eqx.field(static=True)
|
|
1745
|
+
head_dim: int = eqx.field(static=True)
|
|
1746
|
+
attention_type: Literal["softmax", "sigmoid"] = eqx.field(static=True)
|
|
1747
|
+
|
|
1748
|
+
qkv: eqx.nn.Sequential
|
|
1749
|
+
out_proj: eqx.nn.Conv2d | eqx.nn.Identity
|
|
1750
|
+
upsample: eqx.nn.ConvTranspose2d
|
|
1751
|
+
|
|
1752
|
+
def __init__(
|
|
1753
|
+
self,
|
|
1754
|
+
in_channels: int,
|
|
1755
|
+
*,
|
|
1756
|
+
key: PRNGKeyArray,
|
|
1757
|
+
att_kernel: int = 7,
|
|
1758
|
+
att_stride: int = 4,
|
|
1759
|
+
fuse: bool = True,
|
|
1760
|
+
attention_type: Literal["softmax", "sigmoid"] = "softmax",
|
|
1761
|
+
norm_layer: eqx.Module | None = eqx.nn.GroupNorm,
|
|
1762
|
+
norm_kwargs: dict = {},
|
|
1763
|
+
**kwargs,
|
|
1764
|
+
):
|
|
1765
|
+
key_qkv1, key_qkv2, key_oproj, key_upsampling = jr.split(key, 4)
|
|
1766
|
+
|
|
1767
|
+
self.attention_type = attention_type
|
|
1768
|
+
self.num_heads = int(max(1, in_channels // 30))
|
|
1769
|
+
self.head_dim = in_channels // self.num_heads
|
|
1770
|
+
total_dim = int(self.head_dim * self.num_heads * 3)
|
|
1771
|
+
|
|
1772
|
+
self.qkv = eqx.nn.Sequential(
|
|
1773
|
+
[
|
|
1774
|
+
SingleConvBlock(
|
|
1775
|
+
in_channels=in_channels,
|
|
1776
|
+
out_channels=in_channels,
|
|
1777
|
+
kernel_size=att_kernel,
|
|
1778
|
+
stride=att_stride,
|
|
1779
|
+
padding=att_kernel // 2,
|
|
1780
|
+
groups=in_channels,
|
|
1781
|
+
use_bias=False,
|
|
1782
|
+
norm_layer=norm_layer,
|
|
1783
|
+
act_layer=None,
|
|
1784
|
+
key=key_qkv1,
|
|
1785
|
+
),
|
|
1786
|
+
eqx.nn.Conv2d(
|
|
1787
|
+
in_channels=in_channels,
|
|
1788
|
+
out_channels=total_dim,
|
|
1789
|
+
kernel_size=1,
|
|
1790
|
+
stride=1,
|
|
1791
|
+
padding=0,
|
|
1792
|
+
use_bias=False,
|
|
1793
|
+
key=key_qkv2,
|
|
1794
|
+
),
|
|
1795
|
+
]
|
|
1796
|
+
)
|
|
1797
|
+
|
|
1798
|
+
if fuse:
|
|
1799
|
+
self.out_proj = eqx.nn.Identity()
|
|
1800
|
+
self.upsample = eqx.nn.ConvTranspose2d(
|
|
1801
|
+
in_channels=self.head_dim * self.num_heads,
|
|
1802
|
+
out_channels=in_channels,
|
|
1803
|
+
kernel_size=3 if att_stride == 1 else (att_stride * 2),
|
|
1804
|
+
stride=att_stride,
|
|
1805
|
+
padding=1 if att_stride == 1 else (att_stride // 2),
|
|
1806
|
+
key=key_upsampling,
|
|
1807
|
+
)
|
|
1808
|
+
else:
|
|
1809
|
+
self.out_proj = eqx.nn.Conv2d(
|
|
1810
|
+
self.head_dim * self.num_heads,
|
|
1811
|
+
in_channels,
|
|
1812
|
+
kernel_size=1,
|
|
1813
|
+
stride=1,
|
|
1814
|
+
padding=0,
|
|
1815
|
+
key=key_oproj,
|
|
1816
|
+
)
|
|
1817
|
+
self.upsample = eqx.nn.ConvTranspose2d(
|
|
1818
|
+
in_channels=in_channels,
|
|
1819
|
+
out_channels=in_channels,
|
|
1820
|
+
kernel_size=3 if att_stride == 1 else (att_stride * 2),
|
|
1821
|
+
stride=att_stride,
|
|
1822
|
+
padding=1 if att_stride == 1 else (att_stride // 2),
|
|
1823
|
+
groups=in_channels,
|
|
1824
|
+
key=key_upsampling,
|
|
1825
|
+
)
|
|
1826
|
+
|
|
1827
|
+
def __call__(
|
|
1828
|
+
self,
|
|
1829
|
+
x: Float[Array, "seqlen height width"],
|
|
1830
|
+
key: PRNGKeyArray,
|
|
1831
|
+
inference: Optional[bool] = None,
|
|
1832
|
+
) -> Float[Array, "seqlen height width"]:
|
|
1833
|
+
q, k, v = rearrange(
|
|
1834
|
+
self.qkv(x),
|
|
1835
|
+
"(n h d) s1 s2 -> n h (s1 s2) d",
|
|
1836
|
+
n=3,
|
|
1837
|
+
h=self.num_heads,
|
|
1838
|
+
d=self.head_dim,
|
|
1839
|
+
)
|
|
1840
|
+
|
|
1841
|
+
_, s, _ = q.shape
|
|
1842
|
+
h = w = int(s**0.5)
|
|
1843
|
+
|
|
1844
|
+
attn_logits = q @ rearrange(k, "h s d -> h d s")
|
|
1845
|
+
attn_logits /= self.head_dim**0.5
|
|
1846
|
+
|
|
1847
|
+
if self.attention_type == "softmax":
|
|
1848
|
+
attn = jax.nn.softmax(attn_logits, axis=-1)
|
|
1849
|
+
elif self.attention_type == "sigmoid":
|
|
1850
|
+
attn = jax.nn.sigmoid(attn_logits)
|
|
1851
|
+
|
|
1852
|
+
v = attn @ v
|
|
1853
|
+
|
|
1854
|
+
out = self.out_proj(rearrange(v, "h (s1 s2) d -> (h d) s1 s2", s1=h, s2=w))
|
|
1855
|
+
out = self.upsample(out)
|
|
1856
|
+
|
|
1857
|
+
return out
|
|
1858
|
+
|
|
1859
|
+
|
|
1860
|
+
class ConvAttentionBlock(eqx.Module):
|
|
1861
|
+
prenorm: eqx.Module
|
|
1862
|
+
postnorm: eqx.Module
|
|
1863
|
+
norm: eqx.Module
|
|
1864
|
+
attn: eqx.Module
|
|
1865
|
+
mlp: eqx.Module
|
|
1866
|
+
drop_path1: DropPathAdd
|
|
1867
|
+
drop_path2: DropPathAdd
|
|
1868
|
+
|
|
1869
|
+
def __init__(
|
|
1870
|
+
self,
|
|
1871
|
+
in_channels: int,
|
|
1872
|
+
*,
|
|
1873
|
+
key: PRNGKeyArray,
|
|
1874
|
+
mlp_ratio: float = 4.0,
|
|
1875
|
+
att_stride: int = 1,
|
|
1876
|
+
attention_type: Literal["softmax", "sigmoid"] = "softmax",
|
|
1877
|
+
fuse: bool = True, # TODO: verify
|
|
1878
|
+
drop_path: float | List[float] = 0.0,
|
|
1879
|
+
act_layer: Callable = jax.nn.gelu, # TODO: try hardswish
|
|
1880
|
+
norm_layer: eqx.Module = eqx.nn.GroupNorm,
|
|
1881
|
+
norm_max_group: int = 32,
|
|
1882
|
+
post_attention_norm: bool = False,
|
|
1883
|
+
eps: float = 1e-5,
|
|
1884
|
+
**kwargs,
|
|
1885
|
+
):
|
|
1886
|
+
key_attn, key_mlp = jr.split(key, 2)
|
|
1887
|
+
|
|
1888
|
+
if isinstance(drop_path, list):
|
|
1889
|
+
if len(drop_path) != 2:
|
|
1890
|
+
raise AssertionError(
|
|
1891
|
+
f"`drop_path` needs to have 2 elements, got {len(drop_path)} ({drop_path})."
|
|
1892
|
+
)
|
|
1893
|
+
dr1, dr2 = drop_path
|
|
1894
|
+
dr1 = float(dr1)
|
|
1895
|
+
dr2 = float(dr2)
|
|
1896
|
+
else:
|
|
1897
|
+
dr1 = dr2 = float(drop_path)
|
|
1898
|
+
|
|
1899
|
+
num_groups = nearest_power_of_2_divisor(in_channels, norm_max_group)
|
|
1900
|
+
self.prenorm = norm_layer(num_groups, in_channels, eps=eps)
|
|
1901
|
+
self.postnorm = (
|
|
1902
|
+
norm_layer(num_groups, in_channels, eps=eps)
|
|
1903
|
+
if post_attention_norm
|
|
1904
|
+
else eqx.nn.Identity()
|
|
1905
|
+
)
|
|
1906
|
+
self.norm = norm_layer(num_groups, in_channels, eps=eps)
|
|
1907
|
+
|
|
1908
|
+
self.attn = ConvAttention(
|
|
1909
|
+
in_channels=in_channels,
|
|
1910
|
+
att_kernel=5 if att_stride > 1 else 3,
|
|
1911
|
+
att_stride=att_stride,
|
|
1912
|
+
fuse=fuse,
|
|
1913
|
+
attention_type=attention_type,
|
|
1914
|
+
key=key_attn,
|
|
1915
|
+
)
|
|
1916
|
+
|
|
1917
|
+
self.mlp = ConvBlock(
|
|
1918
|
+
dim=in_channels,
|
|
1919
|
+
hidden_dim=int(in_channels * mlp_ratio),
|
|
1920
|
+
kernel_size=1,
|
|
1921
|
+
stride=1,
|
|
1922
|
+
padding=0,
|
|
1923
|
+
drop_path=dr1,
|
|
1924
|
+
act_layer=act_layer,
|
|
1925
|
+
key=key_mlp,
|
|
1926
|
+
)
|
|
1927
|
+
|
|
1928
|
+
self.drop_path1 = DropPathAdd(dr1)
|
|
1929
|
+
self.drop_path2 = DropPathAdd(dr2)
|
|
1930
|
+
|
|
1931
|
+
def __call__(
|
|
1932
|
+
self,
|
|
1933
|
+
x: Float[Array, "seqlen dim"],
|
|
1934
|
+
key: PRNGKeyArray,
|
|
1935
|
+
inference: Optional[bool] = None,
|
|
1936
|
+
) -> Float[Array, "seqlen dim"]:
|
|
1937
|
+
key_attn, key_mlp, key_dr1, key_dr2 = jr.split(key, 4)
|
|
1938
|
+
|
|
1939
|
+
x = self.drop_path1(
|
|
1940
|
+
x,
|
|
1941
|
+
self.postnorm(
|
|
1942
|
+
self.attn(
|
|
1943
|
+
self.prenorm(x),
|
|
1944
|
+
inference=inference,
|
|
1945
|
+
key=key_attn,
|
|
1946
|
+
)
|
|
1947
|
+
),
|
|
1948
|
+
inference=inference,
|
|
1949
|
+
key=key_dr1,
|
|
1950
|
+
)
|
|
1951
|
+
x = self.drop_path2(
|
|
1952
|
+
x,
|
|
1953
|
+
self.mlp(
|
|
1954
|
+
self.norm(x),
|
|
1955
|
+
inference=inference,
|
|
1956
|
+
key=key_mlp,
|
|
1957
|
+
),
|
|
1958
|
+
inference=inference,
|
|
1959
|
+
key=key_dr2,
|
|
1960
|
+
)
|
|
1961
|
+
|
|
1962
|
+
return x
|
|
1963
|
+
|
|
1964
|
+
|
|
1965
|
+
class LowFormerBlock(eqx.Module):
|
|
1966
|
+
context_module: ConvAttentionBlock
|
|
1967
|
+
local_module: MBConv
|
|
1968
|
+
drop_path1: DropPathAdd
|
|
1969
|
+
drop_path2: DropPathAdd
|
|
1970
|
+
|
|
1971
|
+
def __init__(
|
|
1972
|
+
self,
|
|
1973
|
+
in_channels: int,
|
|
1974
|
+
*,
|
|
1975
|
+
key,
|
|
1976
|
+
mlp_ratio: float = 4.0,
|
|
1977
|
+
att_stride: int = 1,
|
|
1978
|
+
attention_type: Literal["softmax", "sigmoid"] = "softmax",
|
|
1979
|
+
fuse_conv: bool = True,
|
|
1980
|
+
drop_path: float | List[float] = 0.0,
|
|
1981
|
+
act_layer: Callable = jax.nn.hard_swish,
|
|
1982
|
+
norm_layer: eqx.Module = eqx.nn.GroupNorm,
|
|
1983
|
+
expand_ratio: float = 4.0,
|
|
1984
|
+
mbconv_norm_layers: tuple = (None, None, eqx.nn.GroupNorm),
|
|
1985
|
+
mbconv_act_layers: tuple = (jax.nn.hard_swish, jax.nn.hard_swish, None),
|
|
1986
|
+
fuse_mbconv: bool = False,
|
|
1987
|
+
**kwargs,
|
|
1988
|
+
):
|
|
1989
|
+
key_context, key_local = jr.split(key, 2)
|
|
1990
|
+
|
|
1991
|
+
if isinstance(drop_path, list):
|
|
1992
|
+
if len(drop_path) != 2:
|
|
1993
|
+
raise AssertionError(
|
|
1994
|
+
f"`drop_path` needs to have 2 elements, got {len(drop_path)} ({drop_path})."
|
|
1995
|
+
)
|
|
1996
|
+
dr1, dr2 = drop_path
|
|
1997
|
+
dr1 = float(dr1)
|
|
1998
|
+
dr2 = float(dr2)
|
|
1999
|
+
else:
|
|
2000
|
+
dr1 = dr2 = float(drop_path)
|
|
2001
|
+
|
|
2002
|
+
self.context_module = ConvAttentionBlock(
|
|
2003
|
+
in_channels=in_channels,
|
|
2004
|
+
mlp_ratio=mlp_ratio,
|
|
2005
|
+
att_stride=att_stride,
|
|
2006
|
+
attention_type=attention_type,
|
|
2007
|
+
fuse=fuse_conv,
|
|
2008
|
+
drop_path=drop_path,
|
|
2009
|
+
act_layer=act_layer,
|
|
2010
|
+
norm_layer=norm_layer,
|
|
2011
|
+
key=key_context,
|
|
2012
|
+
)
|
|
2013
|
+
self.local_module = MBConv(
|
|
2014
|
+
in_channels=in_channels,
|
|
2015
|
+
out_channels=in_channels,
|
|
2016
|
+
expand_ratio=expand_ratio,
|
|
2017
|
+
norm_layers=mbconv_norm_layers,
|
|
2018
|
+
act_layers=mbconv_act_layers,
|
|
2019
|
+
use_bias=(True, True, False),
|
|
2020
|
+
fuse=fuse_mbconv,
|
|
2021
|
+
key=key_local,
|
|
2022
|
+
)
|
|
2023
|
+
|
|
2024
|
+
self.drop_path1 = DropPathAdd(dr1)
|
|
2025
|
+
self.drop_path2 = DropPathAdd(dr2)
|
|
2026
|
+
|
|
2027
|
+
def __call__(
|
|
2028
|
+
self,
|
|
2029
|
+
x: Float[Array, "dim height width"],
|
|
2030
|
+
key: PRNGKeyArray,
|
|
2031
|
+
inference: Optional[bool] = None,
|
|
2032
|
+
):
|
|
2033
|
+
key_context, key_local, key_dr1, key_dr2 = jr.split(key, 4)
|
|
2034
|
+
|
|
2035
|
+
x = self.drop_path1(
|
|
2036
|
+
x,
|
|
2037
|
+
self.context_module(x, inference=inference, key=key_context),
|
|
2038
|
+
inference=inference,
|
|
2039
|
+
key=key_dr1,
|
|
2040
|
+
)
|
|
2041
|
+
x = self.drop_path2(
|
|
2042
|
+
x,
|
|
2043
|
+
self.local_module(x, inference=inference, key=key_local),
|
|
2044
|
+
inference=inference,
|
|
2045
|
+
key=key_dr2,
|
|
2046
|
+
)
|
|
2047
|
+
|
|
2048
|
+
return x
|
|
2049
|
+
|
|
2050
|
+
|
|
1568
2051
|
def get_attention(module: str | eqx.Module) -> eqx.Module:
|
|
1569
2052
|
"""Get an `eqx.Module` from its common name.
|
|
1570
2053
|
|