hyper-connections 0.3.8__tar.gz → 0.3.9__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.
- {hyper_connections-0.3.8 → hyper_connections-0.3.9}/PKG-INFO +1 -1
- {hyper_connections-0.3.8 → hyper_connections-0.3.9}/hyper_connections/manifold_constrained_hyper_connections.py +2 -0
- hyper_connections-0.3.9/hyper_connections/vit.py +163 -0
- {hyper_connections-0.3.8 → hyper_connections-0.3.9}/pyproject.toml +1 -1
- {hyper_connections-0.3.8 → hyper_connections-0.3.9}/tests/test_hyper_connections.py +21 -0
- {hyper_connections-0.3.8 → hyper_connections-0.3.9}/.github/workflows/python-publish.yml +0 -0
- {hyper_connections-0.3.8 → hyper_connections-0.3.9}/.github/workflows/test.yml +0 -0
- {hyper_connections-0.3.8 → hyper_connections-0.3.9}/.gitignore +0 -0
- {hyper_connections-0.3.8 → hyper_connections-0.3.9}/LICENSE +0 -0
- {hyper_connections-0.3.8 → hyper_connections-0.3.9}/README.md +0 -0
- {hyper_connections-0.3.8 → hyper_connections-0.3.9}/hyper-connections.png +0 -0
- {hyper_connections-0.3.8 → hyper_connections-0.3.9}/hyper_connections/__init__.py +0 -0
- {hyper_connections-0.3.8 → hyper_connections-0.3.9}/hyper_connections/hyper_connections.py +0 -0
- {hyper_connections-0.3.8 → hyper_connections-0.3.9}/hyper_connections/hyper_connections_channel_first.py +0 -0
- {hyper_connections-0.3.8 → hyper_connections-0.3.9}/hyper_connections/hyper_connections_with_multi_branch_inputs.py +0 -0
- {hyper_connections-0.3.8 → hyper_connections-0.3.9}/hyper_connections/hyper_connections_with_multi_input_streams.py +0 -0
- {hyper_connections-0.3.8 → hyper_connections-0.3.9}/hyper_connections/residuals.py +0 -0
|
@@ -486,6 +486,8 @@ class ManifoldConstrainedHyperConnections(Module):
|
|
|
486
486
|
|
|
487
487
|
return add_residual_fn(branch_output)
|
|
488
488
|
|
|
489
|
+
mHC = ManifoldConstrainedHyperConnections
|
|
490
|
+
|
|
489
491
|
ManifoldConstrainedHyperConnections.get_expand_reduce_stream_functions = staticmethod(get_expand_reduce_stream_functions)
|
|
490
492
|
ManifoldConstrainedHyperConnections.get_init_and_expand_reduce_stream_functions = staticmethod(get_init_and_expand_reduce_stream_functions)
|
|
491
493
|
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
from torch import nn
|
|
3
|
+
from torch.nn import Module, ModuleList
|
|
4
|
+
|
|
5
|
+
from einops import rearrange, repeat
|
|
6
|
+
from einops.layers.torch import Rearrange
|
|
7
|
+
|
|
8
|
+
from hyper_connections.manifold_constrained_hyper_connections import mHC
|
|
9
|
+
|
|
10
|
+
# helpers
|
|
11
|
+
|
|
12
|
+
def pair(t):
|
|
13
|
+
return t if isinstance(t, tuple) else (t, t)
|
|
14
|
+
|
|
15
|
+
# classes
|
|
16
|
+
|
|
17
|
+
class FeedForward(Module):
|
|
18
|
+
def __init__(self, dim, hidden_dim, dropout = 0.):
|
|
19
|
+
super().__init__()
|
|
20
|
+
self.net = nn.Sequential(
|
|
21
|
+
nn.LayerNorm(dim),
|
|
22
|
+
nn.Linear(dim, hidden_dim),
|
|
23
|
+
nn.GELU(),
|
|
24
|
+
nn.Dropout(dropout),
|
|
25
|
+
nn.Linear(hidden_dim, dim),
|
|
26
|
+
nn.Dropout(dropout)
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
def forward(self, x):
|
|
30
|
+
return self.net(x)
|
|
31
|
+
|
|
32
|
+
class Attention(Module):
|
|
33
|
+
def __init__(self, dim, heads = 8, dim_head = 64, dropout = 0.):
|
|
34
|
+
super().__init__()
|
|
35
|
+
inner_dim = dim_head * heads
|
|
36
|
+
project_out = not (heads == 1 and dim_head == dim)
|
|
37
|
+
|
|
38
|
+
self.heads = heads
|
|
39
|
+
self.scale = dim_head ** -0.5
|
|
40
|
+
|
|
41
|
+
self.norm = nn.LayerNorm(dim)
|
|
42
|
+
|
|
43
|
+
self.attend = nn.Softmax(dim = -1)
|
|
44
|
+
self.dropout = nn.Dropout(dropout)
|
|
45
|
+
|
|
46
|
+
self.to_qkv = nn.Linear(dim, inner_dim * 3, bias = False)
|
|
47
|
+
|
|
48
|
+
self.to_out = nn.Sequential(
|
|
49
|
+
nn.Linear(inner_dim, dim),
|
|
50
|
+
nn.Dropout(dropout)
|
|
51
|
+
) if project_out else nn.Identity()
|
|
52
|
+
|
|
53
|
+
def forward(self, x):
|
|
54
|
+
x = self.norm(x)
|
|
55
|
+
|
|
56
|
+
qkv = self.to_qkv(x).chunk(3, dim = -1)
|
|
57
|
+
q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> b h n d', h = self.heads), qkv)
|
|
58
|
+
|
|
59
|
+
dots = torch.matmul(q, k.transpose(-1, -2)) * self.scale
|
|
60
|
+
|
|
61
|
+
attn = self.attend(dots)
|
|
62
|
+
attn = self.dropout(attn)
|
|
63
|
+
|
|
64
|
+
out = torch.matmul(attn, v)
|
|
65
|
+
out = rearrange(out, 'b h n d -> b n (h d)')
|
|
66
|
+
return self.to_out(out)
|
|
67
|
+
|
|
68
|
+
class Transformer(Module):
|
|
69
|
+
def __init__(self, dim, depth, heads, dim_head, mlp_dim, dropout = 0., num_residual_streams = 4):
|
|
70
|
+
super().__init__()
|
|
71
|
+
self.norm = nn.LayerNorm(dim)
|
|
72
|
+
self.layers = ModuleList([])
|
|
73
|
+
|
|
74
|
+
init_hyper_conn, self.expand_streams, self.reduce_streams = mHC.get_init_and_expand_reduce_stream_functions(num_residual_streams)
|
|
75
|
+
|
|
76
|
+
for _ in range(depth):
|
|
77
|
+
self.layers.append(ModuleList([
|
|
78
|
+
init_hyper_conn(dim = dim , branch = Attention(dim, heads = heads, dim_head = dim_head, dropout = dropout)),
|
|
79
|
+
init_hyper_conn(dim = dim, branch = FeedForward(dim, mlp_dim, dropout = dropout))
|
|
80
|
+
]))
|
|
81
|
+
|
|
82
|
+
def forward(self, x):
|
|
83
|
+
|
|
84
|
+
x = self.expand_streams(x)
|
|
85
|
+
|
|
86
|
+
for attn, ff in self.layers:
|
|
87
|
+
x = attn(x)
|
|
88
|
+
x = ff(x)
|
|
89
|
+
|
|
90
|
+
x = self.reduce_streams(x)
|
|
91
|
+
|
|
92
|
+
return self.norm(x)
|
|
93
|
+
|
|
94
|
+
class ViT(Module):
|
|
95
|
+
def __init__(self, *, image_size, patch_size, num_classes, dim, depth, heads, mlp_dim, pool = 'cls', channels = 3, dim_head = 64, dropout = 0., emb_dropout = 0., num_residual_streams = 4):
|
|
96
|
+
super().__init__()
|
|
97
|
+
image_height, image_width = pair(image_size)
|
|
98
|
+
patch_height, patch_width = pair(patch_size)
|
|
99
|
+
|
|
100
|
+
assert image_height % patch_height == 0 and image_width % patch_width == 0, 'Image dimensions must be divisible by the patch size.'
|
|
101
|
+
|
|
102
|
+
num_patches = (image_height // patch_height) * (image_width // patch_width)
|
|
103
|
+
patch_dim = channels * patch_height * patch_width
|
|
104
|
+
|
|
105
|
+
assert pool in {'cls', 'mean'}, 'pool type must be either cls (cls token) or mean (mean pooling)'
|
|
106
|
+
num_cls_tokens = 1 if pool == 'cls' else 0
|
|
107
|
+
|
|
108
|
+
self.to_patch_embedding = nn.Sequential(
|
|
109
|
+
Rearrange('b c (h p1) (w p2) -> b (h w) (p1 p2 c)', p1 = patch_height, p2 = patch_width),
|
|
110
|
+
nn.LayerNorm(patch_dim),
|
|
111
|
+
nn.Linear(patch_dim, dim),
|
|
112
|
+
nn.LayerNorm(dim),
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
self.cls_token = nn.Parameter(torch.randn(num_cls_tokens, dim))
|
|
116
|
+
self.pos_embedding = nn.Parameter(torch.randn(num_patches + num_cls_tokens, dim))
|
|
117
|
+
|
|
118
|
+
self.dropout = nn.Dropout(emb_dropout)
|
|
119
|
+
|
|
120
|
+
self.transformer = Transformer(dim, depth, heads, dim_head, mlp_dim, dropout)
|
|
121
|
+
|
|
122
|
+
self.pool = pool
|
|
123
|
+
self.to_latent = nn.Identity()
|
|
124
|
+
|
|
125
|
+
self.mlp_head = nn.Linear(dim, num_classes)
|
|
126
|
+
|
|
127
|
+
def forward(self, img):
|
|
128
|
+
batch = img.shape[0]
|
|
129
|
+
x = self.to_patch_embedding(img)
|
|
130
|
+
|
|
131
|
+
cls_tokens = repeat(self.cls_token, '... d -> b ... d', b = batch)
|
|
132
|
+
x = torch.cat((cls_tokens, x), dim = 1)
|
|
133
|
+
|
|
134
|
+
seq = x.shape[1]
|
|
135
|
+
|
|
136
|
+
x = x + self.pos_embedding[:seq]
|
|
137
|
+
x = self.dropout(x)
|
|
138
|
+
|
|
139
|
+
x = self.transformer(x)
|
|
140
|
+
|
|
141
|
+
x = x.mean(dim = 1) if self.pool == 'mean' else x[:, 0]
|
|
142
|
+
|
|
143
|
+
x = self.to_latent(x)
|
|
144
|
+
return self.mlp_head(x)
|
|
145
|
+
|
|
146
|
+
if __name__ == '__main__':
|
|
147
|
+
v = ViT(
|
|
148
|
+
image_size = 256,
|
|
149
|
+
patch_size = 32,
|
|
150
|
+
num_classes = 1000,
|
|
151
|
+
dim = 1024,
|
|
152
|
+
depth = 6,
|
|
153
|
+
heads = 16,
|
|
154
|
+
mlp_dim = 2048,
|
|
155
|
+
dropout = 0.1,
|
|
156
|
+
emb_dropout = 0.1,
|
|
157
|
+
num_residual_streams = 4
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
img = torch.randn(1, 3, 256, 256)
|
|
161
|
+
|
|
162
|
+
preds = v(img) # (1, 1000)
|
|
163
|
+
assert preds.shape == (1, 1000)
|
|
@@ -252,3 +252,24 @@ def test_mhc_dtype_restoration():
|
|
|
252
252
|
residual = mhc.depth_connection(branch_output, residual, **residual_kwargs)
|
|
253
253
|
|
|
254
254
|
assert residual.dtype == torch.half
|
|
255
|
+
|
|
256
|
+
def test_mhc_vit():
|
|
257
|
+
from hyper_connections.vit import ViT
|
|
258
|
+
|
|
259
|
+
v = ViT(
|
|
260
|
+
image_size = 256,
|
|
261
|
+
patch_size = 32,
|
|
262
|
+
num_classes = 1000,
|
|
263
|
+
dim = 1024,
|
|
264
|
+
depth = 6,
|
|
265
|
+
heads = 16,
|
|
266
|
+
mlp_dim = 2048,
|
|
267
|
+
dropout = 0.1,
|
|
268
|
+
emb_dropout = 0.1,
|
|
269
|
+
num_residual_streams = 4
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
img = torch.randn(1, 3, 256, 256)
|
|
273
|
+
|
|
274
|
+
preds = v(img) # (1, 1000)
|
|
275
|
+
assert preds.shape == (1, 1000)
|
|
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
|