IncreasingLoss commited on
Commit
4985e90
·
verified ·
1 Parent(s): c1673e8

Upload LW_VIT.py

Browse files
Files changed (1) hide show
  1. LW_VIT.py +181 -0
LW_VIT.py ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """LW-Vit"""
2
+
3
+ import torch
4
+ import torch.nn as nn
5
+ import torch.nn.functional as F
6
+
7
+ class HSwish(nn.Module):
8
+ """Hard Swish activation function"""
9
+ def forward(self, x):
10
+ out = x * F.relu6(x + 3, inplace=True) / 6
11
+ return out
12
+
13
+ class MV2_Block(nn.Module):
14
+ """MobileNetV2 Inverted Residual Block with h-swish activation"""
15
+ def __init__(self, in_channels, expand_channels, out_channels, stride):
16
+ super().__init__()
17
+ self.stride = stride
18
+ self.use_res_connect = self.stride == 1 and in_channels == out_channels
19
+
20
+ self.expand = nn.Sequential(
21
+ nn.Conv2d(in_channels, expand_channels, kernel_size=1, stride=1, padding=0, bias=False),
22
+ nn.BatchNorm2d(expand_channels),
23
+ HSwish()
24
+ )
25
+
26
+ self.depthwise = nn.Sequential(
27
+ nn.Conv2d(expand_channels, expand_channels, kernel_size=3, stride=stride,
28
+ padding=1, groups=expand_channels, bias=False),
29
+ nn.BatchNorm2d(expand_channels),
30
+ HSwish()
31
+ )
32
+
33
+ self.project = nn.Sequential(
34
+ nn.Conv2d(expand_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=False),
35
+ nn.BatchNorm2d(out_channels)
36
+ )
37
+
38
+ def forward(self, x):
39
+ if self.use_res_connect:
40
+ return x + self.project(self.depthwise(self.expand(x)))
41
+ else:
42
+ return self.project(self.depthwise(self.expand(x)))
43
+
44
+ class LW_ViT_Transformer_Block(nn.Module):
45
+ """Lightweight Vision Transformer Block"""
46
+ def __init__(self, in_channels, out_channels, patch_size=2, heads=4, dim=128):
47
+ super().__init__()
48
+ self.patch_size = patch_size
49
+ self.in_channels = in_channels
50
+ self.out_channels = out_channels
51
+ self.dim = dim
52
+
53
+ # Downsampling and channel adjustment
54
+ self.downsample = nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=2, padding=1)
55
+ self.channel_adjust = nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1)
56
+
57
+ # Calculate patch dimension
58
+ patch_dim = out_channels * patch_size * patch_size
59
+ # Add projection layer if needed
60
+ self.projection = nn.Identity() if patch_dim == dim else nn.Linear(patch_dim, dim)
61
+
62
+ # Transformer components
63
+ self.norm1 = nn.LayerNorm(dim)
64
+ self.attn = nn.MultiheadAttention(embed_dim=dim, num_heads=heads, batch_first=True)
65
+ self.norm2 = nn.LayerNorm(dim)
66
+ self.ffn = nn.Sequential(
67
+ nn.Linear(dim, dim * 4),
68
+ nn.GELU(),
69
+ nn.Linear(dim * 4, dim)
70
+ )
71
+
72
+ # Final processing
73
+ self.final_conv = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False)
74
+ self.norm_out = nn.BatchNorm2d(out_channels)
75
+ self.act = HSwish()
76
+
77
+ def forward(self, x):
78
+ # Initial downsampling and channel adjustment
79
+ x = self.downsample(x)
80
+ x = self.channel_adjust(x)
81
+
82
+ B, C, H, W = x.shape
83
+
84
+ # Convert feature map to patches and embed
85
+ # Reshape to [B, C, H/P, P, W/P, P]
86
+ x_reshaped = x.reshape(B, C, H // self.patch_size, self.patch_size,
87
+ W // self.patch_size, self.patch_size)
88
+ # Permute to [B, H/P, W/P, C, P, P]
89
+ x_permuted = x_reshaped.permute(0, 2, 4, 1, 3, 5)
90
+ # Reshape to [B, H/P * W/P, C * P * P]
91
+ patches = x_permuted.reshape(B, (H // self.patch_size) * (W // self.patch_size), -1)
92
+
93
+ # Apply projection if needed
94
+ patches = self.projection(patches)
95
+
96
+ # Apply transformer operations
97
+ normed_patches = self.norm1(patches)
98
+ attn_out, _ = self.attn(normed_patches, normed_patches, normed_patches)
99
+ patches = patches + attn_out
100
+
101
+ normed_patches = self.norm2(patches)
102
+ ffn_out = self.ffn(normed_patches)
103
+ patches = patches + ffn_out
104
+
105
+ # Reshape back to feature map
106
+ # Reshape to [B, H/P, W/P, C, P, P]
107
+ x_back = patches.reshape(B, H // self.patch_size, W // self.patch_size,
108
+ C, self.patch_size, self.patch_size)
109
+ # Permute to [B, C, H/P, P, W/P, P]
110
+ x_back = x_back.permute(0, 3, 1, 4, 2, 5)
111
+ # Reshape to [B, C, H, W]
112
+ x_out = x_back.reshape(B, C, H, W)
113
+
114
+ # Final processing
115
+ out = self.final_conv(x_out)
116
+ out = self.norm_out(out)
117
+ out = self.act(out)
118
+
119
+ return out
120
+
121
+ class LW_ViT(nn.Module):
122
+ """Lightweight Vision Transformer for Chinese Character Recognition"""
123
+ def __init__(self, base_channels=16, num_classes=3892):
124
+ super().__init__()
125
+
126
+ # Stem layer
127
+ self.stem = nn.Sequential(
128
+ nn.Conv2d(3, base_channels, 3, stride=2, padding=1, bias=False),
129
+ nn.BatchNorm2d(base_channels),
130
+ HSwish()
131
+ )
132
+
133
+ # Feature extraction layers
134
+ self.features = nn.Sequential(
135
+ # MV2 blocks
136
+ MV2_Block(base_channels, 4*base_channels, base_channels, stride=1),
137
+ MV2_Block(base_channels, 4*base_channels, base_channels, stride=2),
138
+ MV2_Block(base_channels, 4*base_channels, base_channels, stride=1),
139
+ MV2_Block(base_channels, 4*base_channels, base_channels, stride=2),
140
+
141
+ # Transformer block
142
+ LW_ViT_Transformer_Block(
143
+ in_channels=base_channels,
144
+ out_channels=2*base_channels,
145
+ patch_size=2,
146
+ heads=4,
147
+ dim=128
148
+ ),
149
+
150
+ # Final convolutional layer
151
+ nn.Conv2d(2*base_channels, 4*base_channels, kernel_size=1, stride=1),
152
+ nn.BatchNorm2d(4*base_channels),
153
+ HSwish()
154
+ )
155
+
156
+ # Global pooling and classifier
157
+ self.global_pool = nn.AdaptiveAvgPool2d(1)
158
+ self.dropout = nn.Dropout(0.1) # Added dropout for regularization
159
+
160
+ self.classifier = nn.Sequential(
161
+ nn.Linear(4*base_channels, 8*base_channels),
162
+ nn.BatchNorm1d(8*base_channels),
163
+ HSwish(),
164
+ nn.Dropout(0.1), # Added dropout for regularization
165
+ nn.Linear(8*base_channels, num_classes)
166
+ )
167
+
168
+ def forward(self, x):
169
+ x = self.stem(x)
170
+ x = self.features(x)
171
+ x = self.global_pool(x)
172
+ x = torch.flatten(x, 1)
173
+ x = self.dropout(x)
174
+ x = self.classifier(x)
175
+ return x
176
+
177
+
178
+ num_cls = 3892
179
+ num_epochs = 100
180
+ user_device = "cuda" if torch.cuda.is_available() else "cpu"
181
+ LW_model = LW_ViT(base_channels=16, num_classes=num_cls)