PrachiY commited on
Commit
fbdbb01
·
verified ·
1 Parent(s): f83a35f

initial commit

Browse files
.gitattributes ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ images/pants.jpg filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ venv/
2
+ .DS_Store
README.md ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: C2D Clothing1M
3
+ emoji: 🌖
4
+ colorFrom: blue
5
+ colorTo: yellow
6
+ sdk: gradio
7
+ sdk_version: 5.21.0
8
+ app_file: app.py
9
+ pinned: false
10
+ license: mit
11
+ ---
12
+
13
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch.nn.functional as F
3
+ import torchvision.transforms as transforms
4
+ from huggingface_hub import hf_hub_download
5
+ from PIL import Image
6
+ import torch
7
+ import os
8
+
9
+ from models.resnet import SupCEResNet
10
+
11
+ CLASS_NAMES = [
12
+ "T-shirt", "Shirt", "Knitwear", "Chiffon", "Sweater", "Hoodie",
13
+ "Windbreaker", "Jacket", "Down Coat", "Suit", "Shawl", "Dress",
14
+ "Vest", "Underwear"
15
+ ]
16
+
17
+ # Image normalization (matching Clothing1M training)
18
+ mean = (0.485, 0.456, 0.406)
19
+ std = (0.229, 0.224, 0.225)
20
+
21
+ # Define preprocessing for user-uploaded images
22
+ transform_input_image = transforms.Compose([
23
+ transforms.Resize(256),
24
+ transforms.CenterCrop(224),
25
+ transforms.ToTensor(),
26
+ transforms.Normalize(mean, std),
27
+ ])
28
+
29
+
30
+ def load_model_from_huggingface():
31
+ model_filename = "ckpt_clothing_resnet50.pth"
32
+ model_path = hf_hub_download(repo_id="austin-carnahan/c2d-clothing1M", filename=model_filename)
33
+
34
+ # Load checkpoint and check keys
35
+ checkpoint = torch.load(model_path, map_location=torch.device("cpu"), weights_only=False)
36
+
37
+
38
+ # Ensure the model state_dict is loaded properly
39
+ if "model" in checkpoint:
40
+ sd = {k.replace("module.", ""): v for k, v in checkpoint["model"].items()}
41
+ else:
42
+ sd = checkpoint # Try loading directly
43
+
44
+ model = SupCEResNet("resnet50", num_classes=14, pool=True)
45
+ model.load_state_dict(sd, strict=False)
46
+ model.eval()
47
+
48
+ print("✅ Model loaded successfully!")
49
+ return model
50
+
51
+ model = load_model_from_huggingface()
52
+
53
+ model = load_model_from_huggingface()
54
+ print("✅ Model loaded successfully from Hugging Face Hub!")
55
+
56
+
57
+ def gradio_inference(image):
58
+ """Process uploaded image, run inference, and return predicted class + confidence."""
59
+
60
+ image = image.convert("RGB")
61
+ input_tensor = transform_input_image(image).unsqueeze(0) # Add batch dimension
62
+
63
+ # Run inference
64
+ with torch.no_grad():
65
+ output = model(input_tensor)
66
+ probabilities = F.softmax(output, dim=1) # Convert logits to probabilities
67
+
68
+ predicted_class = torch.argmax(probabilities, dim=1).item()
69
+ confidence = probabilities[0, predicted_class].item()
70
+
71
+ # Get human-readable class name
72
+ class_name = CLASS_NAMES[predicted_class]
73
+
74
+ return f"Predicted: {class_name} ({confidence:.2%} confidence)"
75
+
76
+ # Define Gradio UI
77
+ interface = gr.Interface(
78
+ fn=gradio_inference,
79
+ inputs=gr.Image(type="pil"),
80
+ outputs="text",
81
+ title="Clothing Image Classifier",
82
+ description="Upload an image of clothing and get a predicted class with confidence score.",
83
+ examples=["images/tshirt.jpg", "images/pants.jpg"]
84
+ )
85
+
86
+ # Launch the interface
87
+ interface.launch()
images/pants.jpg ADDED

Git LFS Details

  • SHA256: d5729a9441ad3857218cce4ea1c5309d3531810d103a8be38b1a1c87ffebf0ae
  • Pointer size: 131 Bytes
  • Size of remote file: 566 kB
images/tshirt.jpg ADDED
models/InceptionResNetV2.py ADDED
@@ -0,0 +1,304 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import print_function, division, absolute_import
2
+
3
+ import torch
4
+ import torch.nn as nn
5
+
6
+
7
+ class BasicConv2d(nn.Module):
8
+
9
+ def __init__(self, in_planes, out_planes, kernel_size, stride, padding=0):
10
+ super(BasicConv2d, self).__init__()
11
+ self.conv = nn.Conv2d(in_planes, out_planes,
12
+ kernel_size=kernel_size, stride=stride,
13
+ padding=padding, bias=False) # verify bias false
14
+ self.bn = nn.BatchNorm2d(out_planes,
15
+ eps=0.001, # value found in tensorflow
16
+ momentum=0.1, # default pytorch value
17
+ affine=True)
18
+ self.relu = nn.ReLU(inplace=False)
19
+
20
+ def forward(self, x):
21
+ x = self.conv(x)
22
+ x = self.bn(x)
23
+ x = self.relu(x)
24
+ return x
25
+
26
+
27
+ class Mixed_5b(nn.Module):
28
+
29
+ def __init__(self):
30
+ super(Mixed_5b, self).__init__()
31
+
32
+ self.branch0 = BasicConv2d(192, 96, kernel_size=1, stride=1)
33
+
34
+ self.branch1 = nn.Sequential(
35
+ BasicConv2d(192, 48, kernel_size=1, stride=1),
36
+ BasicConv2d(48, 64, kernel_size=5, stride=1, padding=2)
37
+ )
38
+
39
+ self.branch2 = nn.Sequential(
40
+ BasicConv2d(192, 64, kernel_size=1, stride=1),
41
+ BasicConv2d(64, 96, kernel_size=3, stride=1, padding=1),
42
+ BasicConv2d(96, 96, kernel_size=3, stride=1, padding=1)
43
+ )
44
+
45
+ self.branch3 = nn.Sequential(
46
+ nn.AvgPool2d(3, stride=1, padding=1, count_include_pad=False),
47
+ BasicConv2d(192, 64, kernel_size=1, stride=1)
48
+ )
49
+
50
+ def forward(self, x):
51
+ x0 = self.branch0(x)
52
+ x1 = self.branch1(x)
53
+ x2 = self.branch2(x)
54
+ x3 = self.branch3(x)
55
+ out = torch.cat((x0, x1, x2, x3), 1)
56
+ return out
57
+
58
+
59
+ class Block35(nn.Module):
60
+
61
+ def __init__(self, scale=1.0):
62
+ super(Block35, self).__init__()
63
+
64
+ self.scale = scale
65
+
66
+ self.branch0 = BasicConv2d(320, 32, kernel_size=1, stride=1)
67
+
68
+ self.branch1 = nn.Sequential(
69
+ BasicConv2d(320, 32, kernel_size=1, stride=1),
70
+ BasicConv2d(32, 32, kernel_size=3, stride=1, padding=1)
71
+ )
72
+
73
+ self.branch2 = nn.Sequential(
74
+ BasicConv2d(320, 32, kernel_size=1, stride=1),
75
+ BasicConv2d(32, 48, kernel_size=3, stride=1, padding=1),
76
+ BasicConv2d(48, 64, kernel_size=3, stride=1, padding=1)
77
+ )
78
+
79
+ self.conv2d = nn.Conv2d(128, 320, kernel_size=1, stride=1)
80
+ self.relu = nn.ReLU(inplace=False)
81
+
82
+ def forward(self, x):
83
+ x0 = self.branch0(x)
84
+ x1 = self.branch1(x)
85
+ x2 = self.branch2(x)
86
+ out = torch.cat((x0, x1, x2), 1)
87
+ out = self.conv2d(out)
88
+ out = out * self.scale + x
89
+ out = self.relu(out)
90
+ return out
91
+
92
+
93
+ class Mixed_6a(nn.Module):
94
+
95
+ def __init__(self):
96
+ super(Mixed_6a, self).__init__()
97
+
98
+ self.branch0 = BasicConv2d(320, 384, kernel_size=3, stride=2)
99
+
100
+ self.branch1 = nn.Sequential(
101
+ BasicConv2d(320, 256, kernel_size=1, stride=1),
102
+ BasicConv2d(256, 256, kernel_size=3, stride=1, padding=1),
103
+ BasicConv2d(256, 384, kernel_size=3, stride=2)
104
+ )
105
+
106
+ self.branch2 = nn.MaxPool2d(3, stride=2)
107
+
108
+ def forward(self, x):
109
+ x0 = self.branch0(x)
110
+ x1 = self.branch1(x)
111
+ x2 = self.branch2(x)
112
+ out = torch.cat((x0, x1, x2), 1)
113
+ return out
114
+
115
+
116
+ class Block17(nn.Module):
117
+
118
+ def __init__(self, scale=1.0):
119
+ super(Block17, self).__init__()
120
+
121
+ self.scale = scale
122
+
123
+ self.branch0 = BasicConv2d(1088, 192, kernel_size=1, stride=1)
124
+
125
+ self.branch1 = nn.Sequential(
126
+ BasicConv2d(1088, 128, kernel_size=1, stride=1),
127
+ BasicConv2d(128, 160, kernel_size=(1, 7), stride=1, padding=(0, 3)),
128
+ BasicConv2d(160, 192, kernel_size=(7, 1), stride=1, padding=(3, 0))
129
+ )
130
+
131
+ self.conv2d = nn.Conv2d(384, 1088, kernel_size=1, stride=1)
132
+ self.relu = nn.ReLU(inplace=False)
133
+
134
+ def forward(self, x):
135
+ x0 = self.branch0(x)
136
+ x1 = self.branch1(x)
137
+ out = torch.cat((x0, x1), 1)
138
+ out = self.conv2d(out)
139
+ out = out * self.scale + x
140
+ out = self.relu(out)
141
+ return out
142
+
143
+
144
+ class Mixed_7a(nn.Module):
145
+
146
+ def __init__(self):
147
+ super(Mixed_7a, self).__init__()
148
+
149
+ self.branch0 = nn.Sequential(
150
+ BasicConv2d(1088, 256, kernel_size=1, stride=1),
151
+ BasicConv2d(256, 384, kernel_size=3, stride=2)
152
+ )
153
+
154
+ self.branch1 = nn.Sequential(
155
+ BasicConv2d(1088, 256, kernel_size=1, stride=1),
156
+ BasicConv2d(256, 288, kernel_size=3, stride=2)
157
+ )
158
+
159
+ self.branch2 = nn.Sequential(
160
+ BasicConv2d(1088, 256, kernel_size=1, stride=1),
161
+ BasicConv2d(256, 288, kernel_size=3, stride=1, padding=1),
162
+ BasicConv2d(288, 320, kernel_size=3, stride=2)
163
+ )
164
+
165
+ self.branch3 = nn.MaxPool2d(3, stride=2)
166
+
167
+ def forward(self, x):
168
+ x0 = self.branch0(x)
169
+ x1 = self.branch1(x)
170
+ x2 = self.branch2(x)
171
+ x3 = self.branch3(x)
172
+ out = torch.cat((x0, x1, x2, x3), 1)
173
+ return out
174
+
175
+
176
+ class Block8(nn.Module):
177
+
178
+ def __init__(self, scale=1.0, noReLU=False):
179
+ super(Block8, self).__init__()
180
+
181
+ self.scale = scale
182
+ self.noReLU = noReLU
183
+
184
+ self.branch0 = BasicConv2d(2080, 192, kernel_size=1, stride=1)
185
+
186
+ self.branch1 = nn.Sequential(
187
+ BasicConv2d(2080, 192, kernel_size=1, stride=1),
188
+ BasicConv2d(192, 224, kernel_size=(1, 3), stride=1, padding=(0, 1)),
189
+ BasicConv2d(224, 256, kernel_size=(3, 1), stride=1, padding=(1, 0))
190
+ )
191
+
192
+ self.conv2d = nn.Conv2d(448, 2080, kernel_size=1, stride=1)
193
+ if not self.noReLU:
194
+ self.relu = nn.ReLU(inplace=False)
195
+
196
+ def forward(self, x):
197
+ x0 = self.branch0(x)
198
+ x1 = self.branch1(x)
199
+ out = torch.cat((x0, x1), 1)
200
+ out = self.conv2d(out)
201
+ out = out * self.scale + x
202
+ if not self.noReLU:
203
+ out = self.relu(out)
204
+ return out
205
+
206
+
207
+ class InceptionResNetV2(nn.Module):
208
+
209
+ def __init__(self, num_classes=1001):
210
+ super(InceptionResNetV2, self).__init__()
211
+ # Special attributs
212
+ self.input_space = None
213
+ self.input_size = (299, 299, 3)
214
+ self.mean = None
215
+ self.std = None
216
+ # Modules
217
+ self.conv2d_1a = BasicConv2d(3, 32, kernel_size=3, stride=2)
218
+ self.conv2d_2a = BasicConv2d(32, 32, kernel_size=3, stride=1)
219
+ self.conv2d_2b = BasicConv2d(32, 64, kernel_size=3, stride=1, padding=1)
220
+ self.maxpool_3a = nn.MaxPool2d(3, stride=2)
221
+ self.conv2d_3b = BasicConv2d(64, 80, kernel_size=1, stride=1)
222
+ self.conv2d_4a = BasicConv2d(80, 192, kernel_size=3, stride=1)
223
+ self.maxpool_5a = nn.MaxPool2d(3, stride=2)
224
+ self.mixed_5b = Mixed_5b()
225
+ self.repeat = nn.Sequential(
226
+ Block35(scale=0.17),
227
+ Block35(scale=0.17),
228
+ Block35(scale=0.17),
229
+ Block35(scale=0.17),
230
+ Block35(scale=0.17),
231
+ Block35(scale=0.17),
232
+ Block35(scale=0.17),
233
+ Block35(scale=0.17),
234
+ Block35(scale=0.17),
235
+ Block35(scale=0.17)
236
+ )
237
+ self.mixed_6a = Mixed_6a()
238
+ self.repeat_1 = nn.Sequential(
239
+ Block17(scale=0.10),
240
+ Block17(scale=0.10),
241
+ Block17(scale=0.10),
242
+ Block17(scale=0.10),
243
+ Block17(scale=0.10),
244
+ Block17(scale=0.10),
245
+ Block17(scale=0.10),
246
+ Block17(scale=0.10),
247
+ Block17(scale=0.10),
248
+ Block17(scale=0.10),
249
+ Block17(scale=0.10),
250
+ Block17(scale=0.10),
251
+ Block17(scale=0.10),
252
+ Block17(scale=0.10),
253
+ Block17(scale=0.10),
254
+ Block17(scale=0.10),
255
+ Block17(scale=0.10),
256
+ Block17(scale=0.10),
257
+ Block17(scale=0.10),
258
+ Block17(scale=0.10)
259
+ )
260
+ self.mixed_7a = Mixed_7a()
261
+ self.repeat_2 = nn.Sequential(
262
+ Block8(scale=0.20),
263
+ Block8(scale=0.20),
264
+ Block8(scale=0.20),
265
+ Block8(scale=0.20),
266
+ Block8(scale=0.20),
267
+ Block8(scale=0.20),
268
+ Block8(scale=0.20),
269
+ Block8(scale=0.20),
270
+ Block8(scale=0.20)
271
+ )
272
+ self.block8 = Block8(noReLU=True)
273
+ self.conv2d_7b = BasicConv2d(2080, 1536, kernel_size=1, stride=1)
274
+ self.avgpool_1a = nn.AvgPool2d(8, count_include_pad=False)
275
+ self.last_linear = nn.Linear(1536, num_classes)
276
+
277
+ def features(self, input):
278
+ x = self.conv2d_1a(input)
279
+ x = self.conv2d_2a(x)
280
+ x = self.conv2d_2b(x)
281
+ x = self.maxpool_3a(x)
282
+ x = self.conv2d_3b(x)
283
+ x = self.conv2d_4a(x)
284
+ x = self.maxpool_5a(x)
285
+ x = self.mixed_5b(x)
286
+ x = self.repeat(x)
287
+ x = self.mixed_6a(x)
288
+ x = self.repeat_1(x)
289
+ x = self.mixed_7a(x)
290
+ x = self.repeat_2(x)
291
+ x = self.block8(x)
292
+ x = self.conv2d_7b(x)
293
+ return x
294
+
295
+ def logits(self, features):
296
+ x = self.avgpool_1a(features)
297
+ x = x.view(x.size(0), -1)
298
+ x = self.last_linear(x)
299
+ return x
300
+
301
+ def forward(self, input):
302
+ x = self.features(input)
303
+ x = self.logits(x)
304
+ return x
models/PreResNet.py ADDED
@@ -0,0 +1,251 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+ from torch.autograd import Variable
5
+
6
+ from models.drop import DropBlock2d
7
+
8
+
9
+ def conv3x3(in_planes, out_planes, stride=1):
10
+ return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, padding=1, bias=False)
11
+
12
+
13
+ class BasicBlock(nn.Module):
14
+ expansion = 1
15
+
16
+ def __init__(self, in_planes, planes, stride=1, drop=False, block_size=4):
17
+ super(BasicBlock, self).__init__()
18
+ self.drop = drop
19
+ self.conv1 = conv3x3(in_planes, planes, stride)
20
+ self.bn1 = nn.BatchNorm2d(planes)
21
+ if drop:
22
+ self.drop1 = DropBlock2d(block_size=block_size)
23
+ self.conv2 = conv3x3(planes, planes)
24
+ if drop:
25
+ self.bn2 = nn.BatchNorm2d(planes)
26
+ self.drop2 = DropBlock2d(block_size=block_size)
27
+
28
+ self.shortcut = nn.Sequential()
29
+ if stride != 1 or in_planes != self.expansion * planes:
30
+ self.shortcut = nn.Sequential(
31
+ nn.Conv2d(in_planes, self.expansion * planes, kernel_size=1, stride=stride, bias=False),
32
+ nn.BatchNorm2d(self.expansion * planes)
33
+ )
34
+
35
+ def forward(self, x):
36
+ if self.drop:
37
+ out = self.drop1(F.relu(self.bn1(self.conv1(x))))
38
+ out = self.bn2(self.conv2(out))
39
+ out += self.shortcut(x)
40
+ out = self.drop2(F.relu(out))
41
+ else:
42
+ out = F.relu(self.bn1(self.conv1(x)))
43
+ out = self.bn2(self.conv2(out))
44
+ out += self.shortcut(x)
45
+ out = F.relu(out)
46
+ return out
47
+
48
+
49
+ class PreActBlock(nn.Module):
50
+ '''Pre-activation version of the BasicBlock.'''
51
+ expansion = 1
52
+
53
+ def __init__(self, in_planes, planes, stride=1, drop=False, block_size=4):
54
+ super(PreActBlock, self).__init__()
55
+ self.drop = drop
56
+ self.bn1 = nn.BatchNorm2d(in_planes)
57
+ self.conv1 = conv3x3(in_planes, planes, stride)
58
+ if drop:
59
+ self.drop1 = DropBlock2d(block_size=block_size)
60
+ self.bn2 = nn.BatchNorm2d(planes)
61
+ self.conv2 = conv3x3(planes, planes)
62
+ if drop:
63
+ self.drop2 = DropBlock2d(block_size=block_size)
64
+
65
+ self.shortcut = nn.Sequential()
66
+ if stride != 1 or in_planes != self.expansion * planes:
67
+ self.shortcut = nn.Sequential(
68
+ nn.Conv2d(in_planes, self.expansion * planes, kernel_size=1, stride=stride, bias=False)
69
+ )
70
+
71
+ def forward(self, x):
72
+ if self.drop:
73
+ out = self.drop1(F.relu(self.bn1(x)))
74
+ shortcut = self.shortcut(out)
75
+ out = self.conv1(out)
76
+ out = self.conv2(F.relu(self.bn2(out)))
77
+ out += shortcut
78
+ out = self.drop2(out)
79
+ else:
80
+ out = F.relu(self.bn1(x))
81
+ shortcut = self.shortcut(out)
82
+ out = self.conv1(out)
83
+ out = self.conv2(F.relu(self.bn2(out)))
84
+ out += shortcut
85
+ return out
86
+
87
+
88
+ class Bottleneck(nn.Module):
89
+ expansion = 4
90
+
91
+ def __init__(self, in_planes, planes, stride=1, drop=False, block_size=4):
92
+ super(Bottleneck, self).__init__()
93
+ self.drop = drop
94
+ self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False)
95
+ self.bn1 = nn.BatchNorm2d(planes)
96
+ if drop:
97
+ self.drop1 = DropBlock2d(block_size=block_size)
98
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
99
+ self.bn2 = nn.BatchNorm2d(planes)
100
+ if drop:
101
+ self.drop2 = DropBlock2d(block_size=block_size)
102
+ self.conv3 = nn.Conv2d(planes, self.expansion * planes, kernel_size=1, bias=False)
103
+ self.bn3 = nn.BatchNorm2d(self.expansion * planes)
104
+ if drop:
105
+ self.drop3 = DropBlock2d(block_size=block_size)
106
+
107
+ self.shortcut = nn.Sequential()
108
+ if stride != 1 or in_planes != self.expansion * planes:
109
+ self.shortcut = nn.Sequential(
110
+ nn.Conv2d(in_planes, self.expansion * planes, kernel_size=1, stride=stride, bias=False),
111
+ nn.BatchNorm2d(self.expansion * planes)
112
+ )
113
+
114
+ def forward(self, x):
115
+ if self.drop:
116
+ out = self.drop1(F.relu(self.bn1(self.conv1(x))))
117
+ out = self.drop2(F.relu(self.bn2(self.conv2(out))))
118
+ out = self.bn3(self.conv3(out))
119
+ out += self.shortcut(x)
120
+ out = self.drop3(F.relu(out))
121
+ else:
122
+ out = F.relu(self.bn1(self.conv1(x)))
123
+ out = F.relu(self.bn2(self.conv2(out)))
124
+ out = self.bn3(self.conv3(out))
125
+ out += self.shortcut(x)
126
+ out = F.relu(out)
127
+ return out
128
+
129
+
130
+ class PreActBottleneck(nn.Module):
131
+ '''Pre-activation version of the original Bottleneck module.'''
132
+ expansion = 4
133
+
134
+ def __init__(self, in_planes, planes, stride=1, drop=False, block_size=4):
135
+ super(PreActBottleneck, self).__init__()
136
+ self.drop = drop
137
+ self.bn1 = nn.BatchNorm2d(in_planes)
138
+ self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False)
139
+ if drop:
140
+ self.drop1 = DropBlock2d(block_size=block_size)
141
+ self.bn2 = nn.BatchNorm2d(planes)
142
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
143
+ if drop:
144
+ self.drop2 = DropBlock2d(block_size=block_size)
145
+ self.bn3 = nn.BatchNorm2d(planes)
146
+ self.conv3 = nn.Conv2d(planes, self.expansion * planes, kernel_size=1, bias=False)
147
+ if drop:
148
+ self.drop3 = DropBlock2d(block_size=block_size)
149
+
150
+ self.shortcut = nn.Sequential()
151
+ if stride != 1 or in_planes != self.expansion * planes:
152
+ self.shortcut = nn.Sequential(
153
+ nn.Conv2d(in_planes, self.expansion * planes, kernel_size=1, stride=stride, bias=False)
154
+ )
155
+
156
+ def forward(self, x):
157
+ if self.drop:
158
+ out = self.drop1(F.relu(self.bn1(x)))
159
+ shortcut = self.shortcut(out)
160
+ out = self.conv1(out)
161
+ out = self.conv2(self.drop2(F.relu(self.bn2(out))))
162
+ out = self.conv3(F.relu(self.bn3(out)))
163
+ out += shortcut
164
+ out = self.drop3(out)
165
+ else:
166
+ out = F.relu(self.bn1(x))
167
+ shortcut = self.shortcut(out)
168
+ out = self.conv1(out)
169
+ out = self.conv2(F.relu(self.bn2(out)))
170
+ out = self.conv3(F.relu(self.bn3(out)))
171
+ out += shortcut
172
+ return out
173
+
174
+
175
+ class ResNet(nn.Module):
176
+ def __init__(self, block, num_blocks, num_classes=10, drop=False):
177
+ super(ResNet, self).__init__()
178
+ self.drop = drop
179
+ self.in_planes = 64
180
+
181
+ self.conv1 = conv3x3(3, 64)
182
+ self.bn1 = nn.BatchNorm2d(64)
183
+ self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1)
184
+ self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2)
185
+ self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2, drop=drop, block_size=5)
186
+ self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2, drop=drop, block_size=3)
187
+ self.linear = nn.Linear(512 * block.expansion, num_classes)
188
+
189
+ def _make_layer(self, block, planes, num_blocks, stride, drop=False, block_size=2):
190
+ strides = [stride] + [1] * (num_blocks - 1)
191
+ layers = []
192
+ for stride in strides:
193
+ layers.append(block(self.in_planes, planes, stride, drop=drop, block_size=block_size))
194
+ self.in_planes = planes * block.expansion
195
+ return nn.Sequential(*layers)
196
+
197
+ def features(self, x, lin=0, lout=5):
198
+ out = x
199
+ if lin < 1 and lout > -1:
200
+ out = self.conv1(out)
201
+ out = self.bn1(out)
202
+ out = F.relu(out)
203
+ if lin < 2 and lout > 0:
204
+ out = self.layer1(out)
205
+ if lin < 3 and lout > 1:
206
+ out = self.layer2(out)
207
+ if lin < 4 and lout > 2:
208
+ out = self.layer3(out)
209
+ if lin < 5 and lout > 3:
210
+ out = self.layer4(out)
211
+ if lout > 4:
212
+ out = F.avg_pool2d(out, 4)
213
+ out = out.view(out.size(0), -1)
214
+ return out
215
+
216
+ def classifier(self, x, lin=0, lout=5):
217
+ out = x
218
+ if lout > 4:
219
+ out = self.linear(out)
220
+ return out
221
+
222
+ def forward(self, x, lin=0, lout=5):
223
+ out = self.features(x, lin, lout)
224
+ out = self.classifier(out, lin, lout)
225
+ return out
226
+
227
+
228
+ def ResNet18(num_classes=10, **kwargs):
229
+ return ResNet(PreActBlock, [2, 2, 2, 2], num_classes=num_classes, **kwargs)
230
+
231
+
232
+ def ResNet34(num_classes=10, **kwargs):
233
+ return ResNet(BasicBlock, [3, 4, 6, 3], num_classes=num_classes, **kwargs)
234
+
235
+
236
+ def ResNet50(num_classes=10, **kwargs):
237
+ return ResNet(Bottleneck, [3, 4, 6, 3], num_classes=num_classes, **kwargs)
238
+
239
+
240
+ def ResNet101(num_classes=10, **kwargs):
241
+ return ResNet(Bottleneck, [3, 4, 23, 3], num_classes=num_classes, **kwargs)
242
+
243
+
244
+ def ResNet152(num_classes=10, **kwargs):
245
+ return ResNet(Bottleneck, [3, 8, 36, 3], num_classes=num_classes, **kwargs)
246
+
247
+
248
+ def test():
249
+ net = ResNet18()
250
+ y = net(Variable(torch.randn(1, 3, 32, 32)))
251
+ print(y.size())
models/__pycache__/resnet.cpython-312.pyc ADDED
Binary file (13.2 kB). View file
 
models/bit_models.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2020 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # Lint as: python3
16
+ """Bottleneck ResNet v2 with GroupNorm and Weight Standardization."""
17
+
18
+ from collections import OrderedDict # pylint: disable=g-importing-member
19
+
20
+ import torch
21
+ import torch.nn as nn
22
+ import torch.nn.functional as F
23
+
24
+
25
+ class StdConv2d(nn.Conv2d):
26
+
27
+ def forward(self, x):
28
+ w = self.weight
29
+ v, m = torch.var_mean(w, dim=[1, 2, 3], keepdim=True, unbiased=False)
30
+ w = (w - m) / torch.sqrt(v + 1e-10)
31
+ return F.conv2d(x, w, self.bias, self.stride, self.padding,
32
+ self.dilation, self.groups)
33
+
34
+
35
+ def conv3x3(cin, cout, stride=1, groups=1, bias=False):
36
+ return StdConv2d(cin, cout, kernel_size=3, stride=stride,
37
+ padding=1, bias=bias, groups=groups)
38
+
39
+
40
+ def conv1x1(cin, cout, stride=1, bias=False):
41
+ return StdConv2d(cin, cout, kernel_size=1, stride=stride,
42
+ padding=0, bias=bias)
43
+
44
+
45
+ def tf2th(conv_weights):
46
+ """Possibly convert HWIO to OIHW."""
47
+ if conv_weights.ndim == 4:
48
+ conv_weights = conv_weights.transpose([3, 2, 0, 1])
49
+ return torch.from_numpy(conv_weights)
50
+
51
+
52
+ class PreActBottleneck(nn.Module):
53
+ """Pre-activation (v2) bottleneck block.
54
+
55
+ Follows the implementation of "Identity Mappings in Deep Residual Networks":
56
+ https://github.com/KaimingHe/resnet-1k-layers/blob/master/resnet-pre-act.lua
57
+
58
+ Except it puts the stride on 3x3 conv when available.
59
+ """
60
+
61
+ def __init__(self, cin, cout=None, cmid=None, stride=1):
62
+ super().__init__()
63
+ cout = cout or cin
64
+ cmid = cmid or cout // 4
65
+
66
+ self.gn1 = nn.GroupNorm(32, cin)
67
+ self.conv1 = conv1x1(cin, cmid)
68
+ self.gn2 = nn.GroupNorm(32, cmid)
69
+ self.conv2 = conv3x3(cmid, cmid, stride) # Original code has it on conv1!!
70
+ self.gn3 = nn.GroupNorm(32, cmid)
71
+ self.conv3 = conv1x1(cmid, cout)
72
+ self.relu = nn.ReLU(inplace=True)
73
+
74
+ if (stride != 1 or cin != cout):
75
+ # Projection also with pre-activation according to paper.
76
+ self.downsample = conv1x1(cin, cout, stride)
77
+
78
+ def forward(self, x):
79
+ out = self.relu(self.gn1(x))
80
+
81
+ # Residual branch
82
+ residual = x
83
+ if hasattr(self, 'downsample'):
84
+ residual = self.downsample(out)
85
+
86
+ # Unit's branch
87
+ out = self.conv1(out)
88
+ out = self.conv2(self.relu(self.gn2(out)))
89
+ out = self.conv3(self.relu(self.gn3(out)))
90
+
91
+ return out + residual
92
+
93
+ def load_from(self, weights, prefix=''):
94
+ convname = 'standardized_conv2d'
95
+ with torch.no_grad():
96
+ self.conv1.weight.copy_(tf2th(weights[f'{prefix}a/{convname}/kernel']))
97
+ self.conv2.weight.copy_(tf2th(weights[f'{prefix}b/{convname}/kernel']))
98
+ self.conv3.weight.copy_(tf2th(weights[f'{prefix}c/{convname}/kernel']))
99
+ self.gn1.weight.copy_(tf2th(weights[f'{prefix}a/group_norm/gamma']))
100
+ self.gn2.weight.copy_(tf2th(weights[f'{prefix}b/group_norm/gamma']))
101
+ self.gn3.weight.copy_(tf2th(weights[f'{prefix}c/group_norm/gamma']))
102
+ self.gn1.bias.copy_(tf2th(weights[f'{prefix}a/group_norm/beta']))
103
+ self.gn2.bias.copy_(tf2th(weights[f'{prefix}b/group_norm/beta']))
104
+ self.gn3.bias.copy_(tf2th(weights[f'{prefix}c/group_norm/beta']))
105
+ if hasattr(self, 'downsample'):
106
+ w = weights[f'{prefix}a/proj/{convname}/kernel']
107
+ self.downsample.weight.copy_(tf2th(w))
108
+
109
+
110
+ class ResNetV2(nn.Module):
111
+ """Implementation of Pre-activation (v2) ResNet mode."""
112
+
113
+ def __init__(self, block_units, width_factor, head_size=21843, zero_head=False):
114
+ super().__init__()
115
+ wf = width_factor # shortcut 'cause we'll use it a lot.
116
+
117
+ # The following will be unreadable if we split lines.
118
+ # pylint: disable=line-too-long
119
+ self.root = nn.Sequential(OrderedDict([
120
+ ('conv', StdConv2d(3, 64 * wf, kernel_size=7, stride=2, padding=3, bias=False)),
121
+ ('pad', nn.ConstantPad2d(1, 0)),
122
+ ('pool', nn.MaxPool2d(kernel_size=3, stride=2, padding=0)),
123
+ # The following is subtly not the same!
124
+ # ('pool', nn.MaxPool2d(kernel_size=3, stride=2, padding=1)),
125
+ ]))
126
+
127
+ self.body = nn.Sequential(OrderedDict([
128
+ ('block1', nn.Sequential(OrderedDict(
129
+ [('unit01', PreActBottleneck(cin=64 * wf, cout=256 * wf, cmid=64 * wf))] +
130
+ [(f'unit{i:02d}', PreActBottleneck(cin=256 * wf, cout=256 * wf, cmid=64 * wf)) for i in
131
+ range(2, block_units[0] + 1)],
132
+ ))),
133
+ ('block2', nn.Sequential(OrderedDict(
134
+ [('unit01', PreActBottleneck(cin=256 * wf, cout=512 * wf, cmid=128 * wf, stride=2))] +
135
+ [(f'unit{i:02d}', PreActBottleneck(cin=512 * wf, cout=512 * wf, cmid=128 * wf)) for i in
136
+ range(2, block_units[1] + 1)],
137
+ ))),
138
+ ('block3', nn.Sequential(OrderedDict(
139
+ [('unit01', PreActBottleneck(cin=512 * wf, cout=1024 * wf, cmid=256 * wf, stride=2))] +
140
+ [(f'unit{i:02d}', PreActBottleneck(cin=1024 * wf, cout=1024 * wf, cmid=256 * wf)) for i in
141
+ range(2, block_units[2] + 1)],
142
+ ))),
143
+ ('block4', nn.Sequential(OrderedDict(
144
+ [('unit01', PreActBottleneck(cin=1024 * wf, cout=2048 * wf, cmid=512 * wf, stride=2))] +
145
+ [(f'unit{i:02d}', PreActBottleneck(cin=2048 * wf, cout=2048 * wf, cmid=512 * wf)) for i in
146
+ range(2, block_units[3] + 1)],
147
+ ))),
148
+ ]))
149
+ # pylint: enable=line-too-long
150
+
151
+ self.zero_head = zero_head
152
+ self.head = nn.Sequential(OrderedDict([
153
+ ('gn', nn.GroupNorm(32, 2048 * wf)),
154
+ ('relu', nn.ReLU(inplace=True)),
155
+ ('avg', nn.AdaptiveAvgPool2d(output_size=1)),
156
+ ('conv', nn.Conv2d(2048 * wf, head_size, kernel_size=1, bias=True)),
157
+ ]))
158
+
159
+ def forward(self, x):
160
+ x = self.head(self.body(self.root(x)))
161
+ assert x.shape[-2:] == (1, 1) # We should have no spatial shape left.
162
+ return x[..., 0, 0]
163
+
164
+ def load_from(self, weights, prefix='resnet/'):
165
+ with torch.no_grad():
166
+ self.root.conv.weight.copy_(
167
+ tf2th(weights[f'{prefix}root_block/standardized_conv2d/kernel'])) # pylint: disable=line-too-long
168
+ self.head.gn.weight.copy_(tf2th(weights[f'{prefix}group_norm/gamma']))
169
+ self.head.gn.bias.copy_(tf2th(weights[f'{prefix}group_norm/beta']))
170
+ if self.zero_head:
171
+ nn.init.zeros_(self.head.conv.weight)
172
+ nn.init.zeros_(self.head.conv.bias)
173
+ else:
174
+ self.head.conv.weight.copy_(
175
+ tf2th(weights[f'{prefix}head/conv2d/kernel'])) # pylint: disable=line-too-long
176
+ self.head.conv.bias.copy_(tf2th(weights[f'{prefix}head/conv2d/bias']))
177
+
178
+ for bname, block in self.body.named_children():
179
+ for uname, unit in block.named_children():
180
+ unit.load_from(weights, prefix=f'{prefix}{bname}/{uname}/')
181
+
182
+
183
+ KNOWN_MODELS = OrderedDict([
184
+ ('BiT-M-R50x1', lambda *a, **kw: ResNetV2([3, 4, 6, 3], 1, *a, **kw)),
185
+ ('BiT-M-R50x3', lambda *a, **kw: ResNetV2([3, 4, 6, 3], 3, *a, **kw)),
186
+ ('BiT-M-R101x1', lambda *a, **kw: ResNetV2([3, 4, 23, 3], 1, *a, **kw)),
187
+ ('BiT-M-R101x3', lambda *a, **kw: ResNetV2([3, 4, 23, 3], 3, *a, **kw)),
188
+ ('BiT-M-R152x2', lambda *a, **kw: ResNetV2([3, 8, 36, 3], 2, *a, **kw)),
189
+ ('BiT-M-R152x4', lambda *a, **kw: ResNetV2([3, 8, 36, 3], 4, *a, **kw)),
190
+ ('BiT-S-R50x1', lambda *a, **kw: ResNetV2([3, 4, 6, 3], 1, *a, **kw)),
191
+ ('BiT-S-R50x3', lambda *a, **kw: ResNetV2([3, 4, 6, 3], 3, *a, **kw)),
192
+ ('BiT-S-R101x1', lambda *a, **kw: ResNetV2([3, 4, 23, 3], 1, *a, **kw)),
193
+ ('BiT-S-R101x3', lambda *a, **kw: ResNetV2([3, 4, 23, 3], 3, *a, **kw)),
194
+ ('BiT-S-R152x2', lambda *a, **kw: ResNetV2([3, 8, 36, 3], 2, *a, **kw)),
195
+ ('BiT-S-R152x4', lambda *a, **kw: ResNetV2([3, 8, 36, 3], 4, *a, **kw)),
196
+ ])
models/drop.py ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ DropBlock, DropPath
2
+
3
+ PyTorch implementations of DropBlock and DropPath (Stochastic Depth) regularization layers.
4
+
5
+ Papers:
6
+ DropBlock: A regularization method for convolutional networks (https://arxiv.org/abs/1810.12890)
7
+
8
+ Deep Networks with Stochastic Depth (https://arxiv.org/abs/1603.09382)
9
+
10
+ Code:
11
+ DropBlock impl inspired by two Tensorflow impl that I liked:
12
+ - https://github.com/tensorflow/tpu/blob/master/models/official/resnet/resnet_model.py#L74
13
+ - https://github.com/clovaai/assembled-cnn/blob/master/nets/blocks.py
14
+
15
+ Hacked together by Ross Wightman
16
+ """
17
+ import torch
18
+ import torch.nn as nn
19
+ import torch.nn.functional as F
20
+
21
+
22
+ def drop_block_2d(
23
+ x, drop_prob: float = 0.1, block_size: int = 7, gamma_scale: float = 1.0,
24
+ with_noise: bool = False, inplace: bool = False, batchwise: bool = False):
25
+ """ DropBlock. See https://arxiv.org/pdf/1810.12890.pdf
26
+
27
+ DropBlock with an experimental gaussian noise option. This layer has been tested on a few training
28
+ runs with success, but needs further validation and possibly optimization for lower runtime impact.
29
+ """
30
+ B, C, H, W = x.shape
31
+ total_size = W * H
32
+ clipped_block_size = min(block_size, min(W, H))
33
+ # seed_drop_rate, the gamma parameter
34
+ gamma = gamma_scale * drop_prob * total_size / clipped_block_size ** 2 / (
35
+ (W - block_size + 1) * (H - block_size + 1))
36
+
37
+ # Forces the block to be inside the feature map.
38
+ w_i, h_i = torch.meshgrid(torch.arange(W).to(x.device), torch.arange(H).to(x.device))
39
+ valid_block = ((w_i >= clipped_block_size // 2) & (w_i < W - (clipped_block_size - 1) // 2)) & \
40
+ ((h_i >= clipped_block_size // 2) & (h_i < H - (clipped_block_size - 1) // 2))
41
+ valid_block = torch.reshape(valid_block, (1, 1, H, W)).to(dtype=x.dtype)
42
+
43
+ if batchwise:
44
+ # one mask for whole batch, quite a bit faster
45
+ uniform_noise = torch.rand((1, C, H, W), dtype=x.dtype, device=x.device)
46
+ else:
47
+ uniform_noise = torch.rand_like(x)
48
+ block_mask = ((2 - gamma - valid_block + uniform_noise) >= 1).to(dtype=x.dtype)
49
+ block_mask = -F.max_pool2d(
50
+ -block_mask,
51
+ kernel_size=clipped_block_size, # block_size,
52
+ stride=1,
53
+ padding=clipped_block_size // 2)
54
+
55
+ if with_noise:
56
+ normal_noise = torch.randn((1, C, H, W), dtype=x.dtype, device=x.device) if batchwise else torch.randn_like(x)
57
+ if inplace:
58
+ x.mul_(block_mask).add_(normal_noise * (1 - block_mask))
59
+ else:
60
+ x = x * block_mask + normal_noise * (1 - block_mask)
61
+ else:
62
+ normalize_scale = (block_mask.numel() / block_mask.to(dtype=torch.float32).sum().add(1e-7)).to(x.dtype)
63
+ if inplace:
64
+ x.mul_(block_mask * normalize_scale)
65
+ else:
66
+ x = x * block_mask * normalize_scale
67
+ return x
68
+
69
+
70
+ def drop_block_fast_2d(
71
+ x: torch.Tensor, drop_prob: float = 0.1, block_size: int = 7,
72
+ gamma_scale: float = 1.0, with_noise: bool = False, inplace: bool = False, batchwise: bool = False):
73
+ """ DropBlock. See https://arxiv.org/pdf/1810.12890.pdf
74
+
75
+ DropBlock with an experimental gaussian noise option. Simplied from above without concern for valid
76
+ block mask at edges.
77
+ """
78
+ B, C, H, W = x.shape
79
+ total_size = W * H
80
+ clipped_block_size = min(block_size, min(W, H))
81
+ gamma = gamma_scale * drop_prob * total_size / clipped_block_size ** 2 / (
82
+ (W - block_size + 1) * (H - block_size + 1))
83
+
84
+ if batchwise:
85
+ # one mask for whole batch, quite a bit faster
86
+ block_mask = torch.rand((1, C, H, W), dtype=x.dtype, device=x.device) < gamma
87
+ else:
88
+ # mask per batch element
89
+ block_mask = torch.rand_like(x) < gamma
90
+ block_mask = F.max_pool2d(
91
+ block_mask.to(x.dtype), kernel_size=clipped_block_size, stride=1,
92
+ padding=clipped_block_size // 2) # TODO: even blocks
93
+
94
+ if with_noise:
95
+ normal_noise = torch.randn((1, C, H, W), dtype=x.dtype, device=x.device) if batchwise else torch.randn_like(x)
96
+ if inplace:
97
+ x.mul_(1. - block_mask).add_(normal_noise * block_mask)
98
+ else:
99
+ x = x * (1. - block_mask) + normal_noise * block_mask
100
+ else:
101
+ block_mask = 1 - block_mask
102
+ normalize_scale = (block_mask.numel() / block_mask.to(dtype=torch.float32).sum().add(1e-7)).to(dtype=x.dtype)
103
+ if inplace:
104
+ x.mul_(block_mask * normalize_scale)
105
+ else:
106
+ x = x * block_mask * normalize_scale
107
+ return x
108
+
109
+
110
+ class DropBlock2d(nn.Module):
111
+ """ DropBlock. See https://arxiv.org/pdf/1810.12890.pdf
112
+ """
113
+
114
+ def __init__(self,
115
+ drop_prob=0.1,
116
+ block_size=7,
117
+ gamma_scale=1.0,
118
+ with_noise=False,
119
+ inplace=False,
120
+ batchwise=False,
121
+ fast=True):
122
+ super(DropBlock2d, self).__init__()
123
+ self.drop_prob = drop_prob
124
+ self.gamma_scale = gamma_scale
125
+ self.block_size = block_size
126
+ self.with_noise = with_noise
127
+ self.inplace = inplace
128
+ self.batchwise = batchwise
129
+ self.fast = fast # FIXME finish comparisons of fast vs not
130
+
131
+ def forward(self, x):
132
+ if not self.training or not self.drop_prob:
133
+ return x
134
+ if self.fast:
135
+ return drop_block_fast_2d(
136
+ x, self.drop_prob, self.block_size, self.gamma_scale, self.with_noise, self.inplace, self.batchwise)
137
+ else:
138
+ return drop_block_2d(
139
+ x, self.drop_prob, self.block_size, self.gamma_scale, self.with_noise, self.inplace, self.batchwise)
140
+
141
+
142
+ def drop_path(x, drop_prob: float = 0., training: bool = False):
143
+ """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
144
+
145
+ This is the same as the DropConnect impl I created for EfficientNet, etc networks, however,
146
+ the original name is misleading as 'Drop Connect' is a different form of dropout in a separate paper...
147
+ See discussion: https://github.com/tensorflow/tpu/issues/494#issuecomment-532968956 ... I've opted for
148
+ changing the layer and argument names to 'drop path' rather than mix DropConnect as a layer name and use
149
+ 'survival rate' as the argument.
150
+
151
+ """
152
+ if drop_prob == 0. or not training:
153
+ return x
154
+ keep_prob = 1 - drop_prob
155
+ random_tensor = keep_prob + torch.rand((x.size()[0], 1, 1, 1), dtype=x.dtype, device=x.device)
156
+ random_tensor.floor_() # binarize
157
+ output = x.div(keep_prob) * random_tensor
158
+ return output
159
+
160
+
161
+ class DropPath(nn.ModuleDict):
162
+ """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
163
+ """
164
+
165
+ def __init__(self, drop_prob=None):
166
+ super(DropPath, self).__init__()
167
+ self.drop_prob = drop_prob
168
+
169
+ def forward(self, x):
170
+ return drop_path(x, self.drop_prob, self.training)
models/resnet.py ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ResNet in PyTorch.
2
+ ImageNet-Style ResNet
3
+ [1] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun
4
+ Deep Residual Learning for Image Recognition. arXiv:1512.03385
5
+ Adapted from: https://github.com/bearpaw/pytorch-classification
6
+ """
7
+ import torch
8
+ import torch.nn as nn
9
+ import torch.nn.functional as F
10
+
11
+
12
+ class BasicBlock(nn.Module):
13
+ expansion = 1
14
+
15
+ def __init__(self, in_planes, planes, stride=1, is_last=False):
16
+ super(BasicBlock, self).__init__()
17
+ self.is_last = is_last
18
+ self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
19
+ self.bn1 = nn.BatchNorm2d(planes)
20
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False)
21
+ self.bn2 = nn.BatchNorm2d(planes)
22
+
23
+ self.shortcut = nn.Sequential()
24
+ if stride != 1 or in_planes != self.expansion * planes:
25
+ self.shortcut = nn.Sequential(
26
+ nn.Conv2d(in_planes, self.expansion * planes, kernel_size=1, stride=stride, bias=False),
27
+ nn.BatchNorm2d(self.expansion * planes)
28
+ )
29
+
30
+ def forward(self, x):
31
+ out = F.relu(self.bn1(self.conv1(x)))
32
+ out = self.bn2(self.conv2(out))
33
+ out += self.shortcut(x)
34
+ preact = out
35
+ out = F.relu(out)
36
+ if self.is_last:
37
+ return out, preact
38
+ else:
39
+ return out
40
+
41
+
42
+ class Bottleneck(nn.Module):
43
+ expansion = 4
44
+
45
+ def __init__(self, in_planes, planes, stride=1, is_last=False):
46
+ super(Bottleneck, self).__init__()
47
+ self.is_last = is_last
48
+ self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False)
49
+ self.bn1 = nn.BatchNorm2d(planes)
50
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
51
+ self.bn2 = nn.BatchNorm2d(planes)
52
+ self.conv3 = nn.Conv2d(planes, self.expansion * planes, kernel_size=1, bias=False)
53
+ self.bn3 = nn.BatchNorm2d(self.expansion * planes)
54
+
55
+ self.shortcut = nn.Sequential()
56
+ if stride != 1 or in_planes != self.expansion * planes:
57
+ self.shortcut = nn.Sequential(
58
+ nn.Conv2d(in_planes, self.expansion * planes, kernel_size=1, stride=stride, bias=False),
59
+ nn.BatchNorm2d(self.expansion * planes)
60
+ )
61
+
62
+ def forward(self, x):
63
+ out = F.relu(self.bn1(self.conv1(x)))
64
+ out = F.relu(self.bn2(self.conv2(out)))
65
+ out = self.bn3(self.conv3(out))
66
+ out += self.shortcut(x)
67
+ preact = out
68
+ out = F.relu(out)
69
+ if self.is_last:
70
+ return out, preact
71
+ else:
72
+ return out
73
+
74
+
75
+ class ResNet(nn.Module):
76
+ def __init__(self, block, num_blocks, in_channel=3, zero_init_residual=False, pool=False):
77
+ super(ResNet, self).__init__()
78
+ self.in_planes = 64
79
+
80
+ if pool:
81
+ self.conv1 = nn.Conv2d(in_channel, 64, kernel_size=7, stride=2, padding=3, bias=False)
82
+ else:
83
+ self.conv1 = nn.Conv2d(in_channel, 64, kernel_size=3, stride=1, padding=1, bias=False)
84
+ self.bn1 = nn.BatchNorm2d(64)
85
+
86
+ self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) if pool else nn.Identity()
87
+ self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1)
88
+ self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2)
89
+ self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2)
90
+ self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2)
91
+ self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
92
+
93
+ for m in self.modules():
94
+ if isinstance(m, nn.Conv2d):
95
+ nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
96
+ elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
97
+ nn.init.constant_(m.weight, 1)
98
+ nn.init.constant_(m.bias, 0)
99
+
100
+ # Zero-initialize the last BN in each residual branch,
101
+ # so that the residual branch starts with zeros, and each residual block behaves
102
+ # like an identity. This improves the model by 0.2~0.3% according to:
103
+ # https://arxiv.org/abs/1706.02677
104
+ if zero_init_residual:
105
+ for m in self.modules():
106
+ if isinstance(m, Bottleneck):
107
+ nn.init.constant_(m.bn3.weight, 0)
108
+ elif isinstance(m, BasicBlock):
109
+ nn.init.constant_(m.bn2.weight, 0)
110
+
111
+ def _make_layer(self, block, planes, num_blocks, stride):
112
+ strides = [stride] + [1] * (num_blocks - 1)
113
+ layers = []
114
+ for i in range(num_blocks):
115
+ stride = strides[i]
116
+ layers.append(block(self.in_planes, planes, stride))
117
+ self.in_planes = planes * block.expansion
118
+ return nn.Sequential(*layers)
119
+
120
+ def forward(self, x, layer=100):
121
+ out = self.maxpool(F.relu(self.bn1(self.conv1(x))))
122
+ out = self.layer1(out)
123
+ out = self.layer2(out)
124
+ out = self.layer3(out)
125
+ out = self.layer4(out)
126
+ out = self.avgpool(out)
127
+ out = torch.flatten(out, 1)
128
+ return out
129
+
130
+
131
+ def resnet18(**kwargs):
132
+ return ResNet(BasicBlock, [2, 2, 2, 2], **kwargs)
133
+
134
+
135
+ def resnet34(**kwargs):
136
+ return ResNet(BasicBlock, [3, 4, 6, 3], **kwargs)
137
+
138
+
139
+ def resnet50(**kwargs):
140
+ return ResNet(Bottleneck, [3, 4, 6, 3], **kwargs)
141
+
142
+
143
+ def resnet101(**kwargs):
144
+ return ResNet(Bottleneck, [3, 4, 23, 3], **kwargs)
145
+
146
+
147
+ model_dict = {
148
+ 'resnet18': [resnet18, 512],
149
+ 'resnet34': [resnet34, 512],
150
+ 'resnet50': [resnet50, 2048],
151
+ 'resnet101': [resnet101, 2048],
152
+ }
153
+
154
+
155
+ class LinearBatchNorm(nn.Module):
156
+ """Implements BatchNorm1d by BatchNorm2d, for SyncBN purpose"""
157
+
158
+ def __init__(self, dim, affine=True):
159
+ super(LinearBatchNorm, self).__init__()
160
+ self.dim = dim
161
+ self.bn = nn.BatchNorm2d(dim, affine=affine)
162
+
163
+ def forward(self, x):
164
+ x = x.view(-1, self.dim, 1, 1)
165
+ x = self.bn(x)
166
+ x = x.view(-1, self.dim)
167
+ return x
168
+
169
+
170
+ class SupConResNet(nn.Module):
171
+ """backbone + projection head"""
172
+
173
+ def __init__(self, name='resnet50', head='mlp', feat_dim=128, pool=False):
174
+ super(SupConResNet, self).__init__()
175
+ model_fun, dim_in = model_dict[name]
176
+ self.encoder = model_fun(pool=pool)
177
+ if head == 'linear':
178
+ self.head = nn.Linear(dim_in, feat_dim)
179
+ elif head == 'mlp':
180
+ self.head = nn.Sequential(
181
+ nn.Linear(dim_in, dim_in),
182
+ nn.ReLU(inplace=True),
183
+ nn.Linear(dim_in, feat_dim)
184
+ )
185
+ else:
186
+ raise NotImplementedError(
187
+ 'head not supported: {}'.format(head))
188
+
189
+ def forward(self, x):
190
+ feat = self.encoder(x)
191
+ feat = F.normalize(self.head(feat), dim=1)
192
+ return feat
193
+
194
+
195
+ class SupCEResNet(nn.Module):
196
+ """encoder + classifier"""
197
+
198
+ def __init__(self, name='resnet50', num_classes=10, pool=False):
199
+ super(SupCEResNet, self).__init__()
200
+ model_fun, dim_in = model_dict[name]
201
+ self.encoder = model_fun(pool=pool)
202
+ self.fc = nn.Linear(dim_in, num_classes)
203
+
204
+ def forward(self, x):
205
+ return self.fc(self.encoder(x))
206
+
207
+
208
+ class LinearClassifier(nn.Module):
209
+ """Linear classifier"""
210
+
211
+ def __init__(self, name='resnet50', num_classes=10):
212
+ super(LinearClassifier, self).__init__()
213
+ _, feat_dim = model_dict[name]
214
+ self.fc = nn.Linear(feat_dim, num_classes)
215
+
216
+ def forward(self, features):
217
+ return self.fc(features)
models/wideresnet.py ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+
3
+ import torch
4
+ import torch.nn as nn
5
+ import torch.nn.functional as F
6
+
7
+
8
+ class BasicBlock(nn.Module):
9
+ def __init__(self, in_planes, out_planes, stride, dropRate=0.0, activate_before_residual=False):
10
+ super(BasicBlock, self).__init__()
11
+ self.bn1 = nn.BatchNorm2d(in_planes, momentum=0.001)
12
+ self.relu1 = nn.LeakyReLU(negative_slope=0.1, inplace=True)
13
+ self.conv1 = nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
14
+ padding=1, bias=False)
15
+ self.bn2 = nn.BatchNorm2d(out_planes, momentum=0.001)
16
+ self.relu2 = nn.LeakyReLU(negative_slope=0.1, inplace=True)
17
+ self.conv2 = nn.Conv2d(out_planes, out_planes, kernel_size=3, stride=1,
18
+ padding=1, bias=False)
19
+ self.droprate = dropRate
20
+ self.equalInOut = (in_planes == out_planes)
21
+ self.convShortcut = (not self.equalInOut) and nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride,
22
+ padding=0, bias=False) or None
23
+ self.activate_before_residual = activate_before_residual
24
+
25
+ def forward(self, x):
26
+ if not self.equalInOut and self.activate_before_residual == True:
27
+ x = self.relu1(self.bn1(x))
28
+ else:
29
+ out = self.relu1(self.bn1(x))
30
+ out = self.relu2(self.bn2(self.conv1(out if self.equalInOut else x)))
31
+ if self.droprate > 0:
32
+ out = F.dropout(out, p=self.droprate, training=self.training)
33
+ out = self.conv2(out)
34
+ return torch.add(x if self.equalInOut else self.convShortcut(x), out)
35
+
36
+
37
+ class NetworkBlock(nn.Module):
38
+ def __init__(self, nb_layers, in_planes, out_planes, block, stride, dropRate=0.0, activate_before_residual=False):
39
+ super(NetworkBlock, self).__init__()
40
+ self.layer = self._make_layer(block, in_planes, out_planes, nb_layers, stride, dropRate,
41
+ activate_before_residual)
42
+
43
+ def _make_layer(self, block, in_planes, out_planes, nb_layers, stride, dropRate, activate_before_residual):
44
+ layers = []
45
+ for i in range(int(nb_layers)):
46
+ layers.append(block(i == 0 and in_planes or out_planes, out_planes, i == 0 and stride or 1, dropRate,
47
+ activate_before_residual))
48
+ return nn.Sequential(*layers)
49
+
50
+ def forward(self, x):
51
+ return self.layer(x)
52
+
53
+
54
+ class WideResNet(nn.Module):
55
+ def __init__(self, num_classes, depth=28, widen_factor=2, dropRate=0.0):
56
+ super(WideResNet, self).__init__()
57
+ nChannels = [16, 16 * widen_factor, 32 * widen_factor, 64 * widen_factor]
58
+ assert ((depth - 4) % 6 == 0)
59
+ n = (depth - 4) / 6
60
+ block = BasicBlock
61
+ # 1st conv before any network block
62
+ self.conv1 = nn.Conv2d(3, nChannels[0], kernel_size=3, stride=1, padding=1, bias=False)
63
+ # 1st block
64
+ self.block1 = NetworkBlock(n, nChannels[0], nChannels[1], block, 1, dropRate, activate_before_residual=True)
65
+ # 2nd block
66
+ self.block2 = NetworkBlock(n, nChannels[1], nChannels[2], block, 2, dropRate)
67
+ # 3rd block
68
+ self.block3 = NetworkBlock(n, nChannels[2], nChannels[3], block, 2, dropRate)
69
+ # global average pooling and classifier
70
+ self.bn1 = nn.BatchNorm2d(nChannels[3], momentum=0.001)
71
+ self.relu = nn.LeakyReLU(negative_slope=0.1, inplace=True)
72
+ self.fc = nn.Linear(nChannels[3], num_classes)
73
+ self.nChannels = nChannels[3]
74
+
75
+ for m in self.modules():
76
+ if isinstance(m, nn.Conv2d):
77
+ n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
78
+ m.weight.data.normal_(0, math.sqrt(2. / n))
79
+ elif isinstance(m, nn.BatchNorm2d):
80
+ m.weight.data.fill_(1)
81
+ m.bias.data.zero_()
82
+ elif isinstance(m, nn.Linear):
83
+ nn.init.xavier_normal_(m.weight.data)
84
+ m.bias.data.zero_()
85
+
86
+ def forward(self, x):
87
+ out = self.conv1(x)
88
+ out = self.block1(out)
89
+ out = self.block2(out)
90
+ out = self.block3(out)
91
+ out = self.relu(self.bn1(out))
92
+ out = F.adaptive_avg_pool2d(out, (1, 1))
93
+ out = out.view(-1, self.nChannels)
94
+ return self.fc(out)
95
+
96
+
97
+ def WideResNet28(num_classes=10, widen_factor=2):
98
+ return WideResNet(num_classes=num_classes, depth=28, widen_factor=widen_factor)
99
+
100
+
101
+ def WideResNet34(num_classes=10, widen_factor=10):
102
+ return WideResNet(num_classes=num_classes, depth=34, widen_factor=widen_factor)
requirements.txt ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aiofiles==23.2.1
2
+ annotated-types==0.7.0
3
+ anyio==4.9.0
4
+ certifi==2025.1.31
5
+ charset-normalizer==3.4.1
6
+ click==8.1.8
7
+ fastapi==0.115.11
8
+ ffmpy==0.5.0
9
+ filelock==3.18.0
10
+ fsspec==2025.3.0
11
+ gradio==5.21.0
12
+ gradio_client==1.7.2
13
+ groovy==0.1.2
14
+ h11==0.14.0
15
+ httpcore==1.0.7
16
+ httpx==0.28.1
17
+ huggingface-hub==0.29.3
18
+ idna==3.10
19
+ Jinja2==3.1.6
20
+ markdown-it-py==3.0.0
21
+ MarkupSafe==2.1.5
22
+ mdurl==0.1.2
23
+ mpmath==1.3.0
24
+ networkx==3.4.2
25
+ numpy==2.2.4
26
+ orjson==3.10.15
27
+ packaging==24.2
28
+ pandas==2.2.3
29
+ pillow==11.1.0
30
+ pydantic==2.10.6
31
+ pydantic_core==2.27.2
32
+ pydub==0.25.1
33
+ Pygments==2.19.1
34
+ python-dateutil==2.9.0.post0
35
+ python-multipart==0.0.20
36
+ pytz==2025.1
37
+ PyYAML==6.0.2
38
+ requests==2.32.3
39
+ rich==13.9.4
40
+ ruff==0.11.0
41
+ safehttpx==0.1.6
42
+ semantic-version==2.10.0
43
+ setuptools==76.0.0
44
+ shellingham==1.5.4
45
+ six==1.17.0
46
+ sniffio==1.3.1
47
+ starlette==0.46.1
48
+ sympy==1.13.1
49
+ tomlkit==0.13.2
50
+ torch==2.6.0
51
+ torchvision==0.21.0
52
+ tqdm==4.67.1
53
+ typer==0.15.2
54
+ typing_extensions==4.12.2
55
+ tzdata==2025.1
56
+ urllib3==2.3.0
57
+ uvicorn==0.34.0
58
+ websockets==15.0.1