itslukeypookie commited on
Commit
df2cf07
·
verified ·
1 Parent(s): 38f18d9

Upload 26 files

Browse files
.gitignore ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ models/__pycache__/
2
+ __pycache__/
3
+ wandb/
4
+ data/
5
+ .DS_Store
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2017 liukuang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md CHANGED
@@ -1,12 +1,62 @@
1
- ---
2
- title: CIFAR-10 Model Training GUI
3
- emoji: 🌍
4
- colorFrom: red
5
- colorTo: blue
6
- sdk: gradio
7
- sdk_version: 4.16.0
8
- app_file: app.py
9
- pinned: false
10
- ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Train CIFAR10 with PyTorch
2
+
3
+ I'm playing with [PyTorch](http://pytorch.org/) on the CIFAR10 dataset.
4
+
5
+ ## Prerequisites
6
+ - Python 3.6+
7
+ - PyTorch 1.0+
8
+
9
+ - Install the dependencies from `requirements.txt` by running `pip install -r requirements.txt`
10
+ - Update the `requirements.txt` with `pip list --format=freeze > requirements.txt`
11
+
12
+ ## Dependencies for Weights and Biases
13
+ You must install weights and biases using the command below:
14
+ `pip install wandb`
15
+
16
+ Afterwards, you must run this command to login into weights and biases. A GitHub account can be used to login:
17
+ `wandb login`
18
+
19
+ Paste the API key into terminal.
20
+
21
+ Additionally, change this line in `main.py`:
22
+ `wandb.init(entity="balica15", project="tutorial")`
23
+
24
+ Where "balica15" is replaced by your username that you used to login with into Weights and Biases.
25
+
26
+ ## Training
27
+ ```
28
+ # Start training with:
29
+ python main.py
30
+
31
+ # You can manually resume the training with:
32
+ python main.py --resume --lr=0.01
33
+ ```
34
+
35
+ ## Features to Add
36
+ | Name | Feature |
37
+ | ----------------------------- | ----------- |
38
+ | Evelyn Atkins and Ethan White | Input and Error Protection |
39
+ | Keiane Balicanta | TorchVision Model Dropdown |
40
+ | Henry Conde | Weights and Biases API |
41
+ | Matthew Gerace | Iteration and Batch Size Sliders |
42
+ | Luke Wilkins | Image Classification |
43
+
44
+
45
+ ## Accuracy
46
+ | Model | Acc. |
47
+ | ----------------- | ----------- |
48
+ | [VGG16](https://arxiv.org/abs/1409.1556) | 92.64% |
49
+ | [ResNet18](https://arxiv.org/abs/1512.03385) | 93.02% |
50
+ | [ResNet50](https://arxiv.org/abs/1512.03385) | 93.62% |
51
+ | [ResNet101](https://arxiv.org/abs/1512.03385) | 93.75% |
52
+ | [RegNetX_200MF](https://arxiv.org/abs/2003.13678) | 94.24% |
53
+ | [RegNetY_400MF](https://arxiv.org/abs/2003.13678) | 94.29% |
54
+ | [MobileNetV2](https://arxiv.org/abs/1801.04381) | 94.43% |
55
+ | [ResNeXt29(32x4d)](https://arxiv.org/abs/1611.05431) | 94.73% |
56
+ | [ResNeXt29(2x64d)](https://arxiv.org/abs/1611.05431) | 94.82% |
57
+ | [SimpleDLA](https://arxiv.org/abs/1707.064) | 94.89% |
58
+ | [DenseNet121](https://arxiv.org/abs/1608.06993) | 95.04% |
59
+ | [PreActResNet18](https://arxiv.org/abs/1603.05027) | 95.11% |
60
+ | [DPN92](https://arxiv.org/abs/1707.01629) | 95.16% |
61
+ | [DLA](https://arxiv.org/pdf/1707.06484.pdf) | 95.47% |
62
+
app.py ADDED
@@ -0,0 +1,560 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ###### Train CIFAR10 with PyTorch. ######
2
+
3
+ ### IMPORT DEPENDENCIES
4
+
5
+ from torch.utils.data import DataLoader
6
+ import torch
7
+ import torch.nn as nn
8
+ import torch.optim as optim
9
+ import torch.nn.functional as F
10
+ import torch.backends.cudnn as cudnn
11
+ import gradio as gr
12
+ import wandb
13
+ import math
14
+ import numpy as np
15
+ import matplotlib.pyplot as plt
16
+
17
+
18
+ import torchvision
19
+ import torchvision.transforms as transforms
20
+ import torchvision.models as models
21
+ import torch.optim.lr_scheduler as lr_scheduler
22
+ import os
23
+ import argparse
24
+ import torchattacks
25
+
26
+ from models import *
27
+
28
+ from tqdm import tqdm
29
+ from PIL import Image
30
+ import gradio as gr
31
+
32
+ # from utils import progress_bar
33
+
34
+ # CSS theme styling
35
+ theme = gr.themes.Base(
36
+ font=[gr.themes.GoogleFont('Montserrat'), 'ui-sans-serif', 'system-ui', 'sans-serif'],
37
+ primary_hue="emerald",
38
+ secondary_hue="emerald",
39
+ neutral_hue="zinc"
40
+ ).set(
41
+ body_text_color='*neutral_950',
42
+ body_text_color_subdued='*neutral_950',
43
+ block_shadow='*shadow_drop_lg',
44
+ button_shadow='*shadow_drop_lg',
45
+ block_title_text_color='*neutral_950',
46
+ block_title_text_weight='500',
47
+ slider_color='*secondary_600'
48
+ )
49
+
50
+ def normalize(img):
51
+ min_im = np.min(img)
52
+ np_img = img - min_im
53
+ max_im = np.max(np_img)
54
+ np_img /= max_im
55
+ return np_img
56
+
57
+ def imshow(img, fig_name = "test_input.png"):
58
+ try:
59
+ img = img.clone().detach().cpu().numpy()
60
+ except:
61
+ print('img already numpy')
62
+
63
+ plt.imshow(normalize(np.transpose(img, (1, 2, 0))))
64
+ plt.savefig(fig_name)
65
+ print(f'Figure saved as {fig_name}')
66
+ return fig_name
67
+
68
+ def class_names(class_num, class_list): # converts the raw number label to text
69
+ if (class_num < 0) and (class_num >= 10):
70
+ gr.Warning("Class List Error")
71
+ return
72
+ return class_list[class_num]
73
+
74
+
75
+ ### MAIN FUNCTION
76
+ best_acc = 0
77
+ def main(drop_type, epochs_sldr, train_sldr, test_sldr, learning_rate, optimizer, sigma_sldr, adv_attack, username, scheduler):
78
+
79
+ ## Input protection
80
+ if not drop_type:
81
+ gr.Warning("Please select a model from the dropdown.")
82
+ return
83
+ if not username:
84
+ gr.Warning("Please enter a WandB username.")
85
+ return
86
+ if(epochs_sldr % 1 != 0):
87
+ gr.Warning("Number of epochs must be an integer.")
88
+ return
89
+ if(train_sldr % 1 != 0):
90
+ gr.Warning("Training batch size must be an integer.")
91
+ return
92
+ if(test_sldr % 1 != 0):
93
+ gr.Warning("Testing batch size must be an integer.")
94
+ return
95
+
96
+ num_epochs = int(epochs_sldr)
97
+ global learn_batch
98
+ learn_batch = int(train_sldr)
99
+ global test_batch
100
+ test_batch = int(test_sldr)
101
+ learning_rate = float(learning_rate)
102
+ optimizer_choose = str(optimizer)
103
+ sigma = float(sigma_sldr)
104
+ attack = str(adv_attack)
105
+ scheduler_choose = str(scheduler)
106
+
107
+ # REPLACE ENTITY WITH USERNAME BELOW
108
+ wandb.init(entity=username, project="model-training")
109
+
110
+ parser = argparse.ArgumentParser(description='PyTorch CIFAR10 Training')
111
+ parser.add_argument('--lr', default=0.1, type=float, help='learning rate')
112
+ parser.add_argument('--resume', '-r', action='store_true',
113
+ help='resume from checkpoint')
114
+ args = parser.parse_args()
115
+
116
+ if torch.cuda.is_available():
117
+ device = 'cuda'
118
+ gr.Info("Cuda detected - running on Cuda")
119
+ elif torch.backends.mps.is_available():
120
+ device = 'mps'
121
+ gr.Info("MPS detected - running on Metal")
122
+ else:
123
+ device = 'cpu'
124
+ gr.Info("No GPU Detected - running on CPU")
125
+
126
+ start_epoch = 0 # start from epoch 0 or last checkpoint epoch
127
+
128
+ ## Data
129
+ try:
130
+ print('==> Preparing data..')
131
+ transform_train = transforms.Compose([
132
+ transforms.RandomCrop(32, padding=4),
133
+ transforms.RandomHorizontalFlip(),
134
+ transforms.ToTensor(),
135
+ transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),
136
+ ])
137
+
138
+ transform_test = transforms.Compose([
139
+ transforms.ToTensor(),
140
+ transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),
141
+ ])
142
+
143
+ trainset = torchvision.datasets.CIFAR10(
144
+ root='./data', train=True, download=True, transform=transform_train)
145
+ trainloader = DataLoader(
146
+ trainset, batch_size=learn_batch, shuffle=True, num_workers=2)
147
+
148
+ testset = torchvision.datasets.CIFAR10(
149
+ root='./data', train=False, download=True, transform=transform_test)
150
+ testloader = DataLoader(
151
+ testset, batch_size=test_batch, shuffle=True, num_workers=2)
152
+
153
+ classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
154
+ except Exception as e:
155
+ print(f"Error: {e}")
156
+ gr.Warning(f"Data Loading Error: {e}")
157
+
158
+ ## Model
159
+ try:
160
+ print('==> Building model..')
161
+ net = models_dict.get(drop_type, None)
162
+
163
+ # Make list of models containing either classifer or fc functions
164
+ classifier_models = ['ConvNext_Small', 'ConvNext_Base', 'ConvNext_Large', 'DenseNet', 'EfficientNet_B0', 'MobileNetV2',
165
+ 'MaxVit', 'MnasNet0_5', 'SqueezeNet', 'VGG19']
166
+ fc_models = ['GoogLeNet', 'InceptionNetV3', 'RegNet_X_400MF', 'ResNet18', 'ShuffleNet_V2_X0_5']
167
+
168
+ # Check dropdown choice for fc or classifier function implementation
169
+ if net in classifier_models:
170
+ num_ftrs = net.classifier[-1].in_features
171
+ net.classifier[-1] = torch.nn.Linear(num_ftrs, len(classes))
172
+ elif net in fc_models:
173
+ num_ftrs = net.fc.in_features
174
+ net.fc = torch.nn.Linear(num_ftrs, len(classes))
175
+
176
+ net = net.to(device)
177
+
178
+ except Exception as e:
179
+ print(f"Error: {e}")
180
+ gr.Warning(f"Model Building Error: {e}")
181
+
182
+ # if args.resume:
183
+ # # Load checkpoint.
184
+ # print('==> Resuming from checkpoint..')
185
+ # assert os.path.isdir('checkpoint'), 'Error: no checkpoint directory found!'
186
+ # checkpoint = torch.load('./checkpoint/ckpt.pth')
187
+ # net.load_state_dict(checkpoint['net'])
188
+ # best_acc = checkpoint['acc']
189
+ # start_epoch = checkpoint['epoch']
190
+
191
+ SGDopt = optim.SGD(net.parameters(), lr=learning_rate,momentum=0.9, weight_decay=5e-4)
192
+ Adamopt = optim.Adam(net.parameters(), lr=learning_rate, weight_decay=5e-4)
193
+
194
+ criterion = nn.CrossEntropyLoss()
195
+
196
+ if optimizer_choose == "SGD":
197
+ optimizer = SGDopt
198
+ elif optimizer_choose == "Adam":
199
+ optimizer = Adamopt
200
+ print (f'optimizer: {optimizer}')
201
+
202
+ #scheduler = lr_scheduler.LinearLR(optimizer, start_factor=learning_rate, end_factor=0.0001, total_iters=10)
203
+ if scheduler_choose == "CosineAnnealingLR":
204
+ scheduler = lr_scheduler.CosineAnnealingLR(optimizer, T_max=200)
205
+ elif scheduler_choose == "ReduceLROnPlateau":
206
+ scheduler = lr_scheduler.ReduceLROnPlateau(optimizer, mode='max', patience=5)
207
+ elif scheduler_choose == "StepLR":
208
+ scheduler = lr_scheduler.StepLR(optimizer, step_size=30)
209
+ print (f'scheduler: {scheduler_choose}')
210
+
211
+ img_labels = [] # initialize list for label generation
212
+ raw_image_list = [] # initialize list for image generation
213
+ img_list1 = [] # initialize list for combined image/labels
214
+ img_list2 = [] # initialize list for gaussian image generation
215
+ img_list3 = [] # initialize list for adversarial attack image generation
216
+
217
+ # The following lists are used when generating all images in an epoch instead of 10:
218
+ full_img_labels = []
219
+ full_raw_image_list = []
220
+ full_img_list1 = []
221
+
222
+ adv_num = 1 # initialize adversarial image number for naming purposes
223
+ global gaussian_num
224
+ gaussian_num = 1 # initialize gaussian noise image number for naming purposes
225
+
226
+ for epoch in range(start_epoch, start_epoch+epochs_sldr):
227
+ if sigma == 0:
228
+ train(epoch, net, trainloader, device, optimizer, criterion, sigma)
229
+ else:
230
+ gaussian_fig = train(epoch, net, trainloader, device, optimizer, criterion, sigma)
231
+ acc, predicted = test(epoch, net, testloader, device, criterion)
232
+
233
+ if scheduler_choose == "ReduceLROnPlateau":
234
+ scheduler.step(metrics=acc)
235
+ elif not scheduler_choose == "None":
236
+ scheduler.step()
237
+
238
+ if (((epoch-1) % 10 == 0) or (epoch == 0)) and (epoch != 1): # generate images every 10 epochs (and the 0th epoch)
239
+ dataiter = iter(testloader)
240
+ imgs, labels = next(dataiter)
241
+ normalized_imgs = (imgs-imgs.min())/(imgs.max()-imgs.min())
242
+ atk = torchattacks.PGD(net, eps=0.00015, alpha=0.0000000000000001, steps=7)
243
+ if attack == "Yes":
244
+ if normalized_imgs is None:
245
+ print("error occured")
246
+ else:
247
+ print(torch.std(normalized_imgs))
248
+ atk.set_normalization_used(mean = torch.mean(normalized_imgs,axis=[0,2,3]), std=torch.std(normalized_imgs,axis=[0,2,3])/1.125)
249
+ adv_images = atk(imgs, labels)
250
+ fig_name = imshow(adv_images[0], fig_name = f'figures/adversarial_attack{adv_num}.png')
251
+ attack_fig = Image.open(fig_name)
252
+ for i in range(1): # generate 1 image per epoch
253
+ img_list3.append(attack_fig)
254
+ adv_num = adv_num + 1
255
+ for i in range(10): # generate 10 images per epoch
256
+ gradio_imgs = transforms.functional.to_pil_image(normalized_imgs[i])
257
+ raw_image_list.append(gradio_imgs)
258
+ predicted_text = class_names(predicted[i].item(), classes)
259
+ actual_text = class_names(labels[i].item(), classes)
260
+ label_text = f'Epoch: {epoch} | Predicted: {predicted_text} | Actual: {actual_text}'
261
+ img_labels.append(label_text)
262
+ for i in range(test_batch): # generate all images per epoch
263
+ full_gradio_imgs = transforms.functional.to_pil_image(normalized_imgs[i])
264
+ full_raw_image_list.append(full_gradio_imgs)
265
+ full_predicted_text = class_names(predicted[i].item(), classes)
266
+ full_actual_text = class_names(labels[i].item(), classes)
267
+ full_label_text = f'Epoch: {epoch} | Predicted: {full_predicted_text} | Actual: {full_actual_text}'
268
+ full_img_labels.append(full_label_text)
269
+ for i in range(len(raw_image_list)):
270
+ img_tuple = (raw_image_list[i], img_labels[i])
271
+ img_list1.append(img_tuple)
272
+ for i in range(len(full_raw_image_list)):
273
+ full_img_tuple = (full_raw_image_list[i], full_img_labels[i])
274
+ full_img_list1.append(full_img_tuple)
275
+ if sigma != 0:
276
+ for i in range(1): # generate 1 image per epoch
277
+ img_list2.append(gaussian_fig)
278
+ gaussian_num = gaussian_num + 1
279
+ if (sigma == 0) and (attack == "No"):
280
+ return str(acc)+"%", img_list1, full_img_list1, None, None
281
+ elif (sigma != 0) and (attack == "No"):
282
+ return str(acc)+"%", img_list1, full_img_list1, img_list2, None
283
+ elif (sigma == 0) and (attack == "Yes"):
284
+ return str(acc)+"%", img_list1, full_img_list1, None, img_list3
285
+ else:
286
+ return str(acc)+"%", img_list1, full_img_list1, img_list2, img_list3
287
+
288
+
289
+
290
+ ### TRAINING
291
+ def train(epoch, net, trainloader, device, optimizer, criterion, sigma, progress=gr.Progress()):
292
+ try:
293
+ print('\nEpoch: %d' % epoch)
294
+ net.train()
295
+ train_loss = 0
296
+ correct = 0
297
+ total = 0
298
+
299
+ iter_float = 50000/learn_batch
300
+ iterations = math.ceil(iter_float)
301
+ iter_prog = 0
302
+
303
+ for batch_idx, (inputs, targets) in tqdm(enumerate(trainloader)):
304
+ if sigma == 0:
305
+ inputs, targets = inputs.to(device), targets.to(device)
306
+ optimizer.zero_grad()
307
+ outputs = net(inputs)
308
+ else:
309
+ noise = np.random.normal(0, sigma, inputs.shape)
310
+ inputs += torch.tensor(noise)
311
+ inputs, targets = inputs.to(device), targets.to(device)
312
+ optimizer.zero_grad()
313
+ outputs = net(inputs)
314
+ n_inputs = inputs.clone().detach().cpu().numpy()
315
+ if(batch_idx%99 == 0):
316
+ fig_name = imshow(n_inputs[0], fig_name= f'figures/gaussian_noise{gaussian_num}.png')
317
+ gaussian_fig = Image.open(fig_name)
318
+
319
+ loss = criterion(outputs, targets)
320
+ loss.backward()
321
+ optimizer.step()
322
+
323
+ train_loss += loss.item()
324
+ _, predicted = outputs.max(1)
325
+ total += targets.size(0)
326
+ correct += predicted.eq(targets).sum().item()
327
+
328
+ iter_prog = iter_prog + 1 # Iterating iteration amount
329
+ progress(iter_prog/iterations, desc=f"Training Epoch {epoch}", total=iterations)
330
+
331
+
332
+ # progress_bar(batch_idx, len(trainloader), 'Loss: %.3f | Acc: %.3f%% (%d/%d)'
333
+ # % (train_loss/(batch_idx+1), 100.*correct/total, correct, total))
334
+
335
+ except Exception as e:
336
+ print(f"Error: {e}")
337
+ gr.Warning(f"Training Error: {e}")
338
+ if sigma != 0:
339
+ return gaussian_fig
340
+
341
+
342
+ ### TESTING
343
+
344
+ def test(epoch, net, testloader, device, criterion, progress = gr.Progress()):
345
+ try:
346
+ net.eval()
347
+ test_loss = 0
348
+ correct = 0
349
+ total = 0
350
+
351
+ iter_float = 10000/test_batch
352
+ iterations = math.ceil(iter_float)
353
+ iter_prog = 0
354
+
355
+ with torch.no_grad():
356
+ for batch_idx, (inputs, targets) in tqdm(enumerate(testloader)):
357
+ inputs, targets = inputs.to(device), targets.to(device)
358
+ outputs = net(inputs)
359
+ loss = criterion(outputs, targets)
360
+
361
+ test_loss += loss.item()
362
+ _, predicted = outputs.max(1)
363
+ total += targets.size(0)
364
+ correct += predicted.eq(targets).sum().item()
365
+
366
+ iter_prog = iter_prog + 1 # Iterating iteration amount
367
+ progress(iter_prog/iterations, desc=f"Testing Epoch {epoch}", total=iterations)
368
+
369
+ wandb.log({'epoch': epoch+1, 'loss': test_loss})
370
+ wandb.log({"acc": correct/total})
371
+
372
+ # progress_bar(batch_idx, len(testloader), 'Loss: %.3f | Acc: %.3f%% (%d/%d)'
373
+ # % (test_loss/(batch_idx+1), 100.*correct/total, correct, total))
374
+
375
+ # Save checkpoint.
376
+ global best_acc
377
+ global acc
378
+ acc = 100.*correct/total
379
+ print(acc)
380
+ if acc > best_acc:
381
+ best_acc = acc
382
+ return best_acc, predicted
383
+ else:
384
+ return acc, predicted
385
+ # if acc > best_acc:
386
+ # print('Saving..')
387
+ # state = {
388
+ # 'net': net.state_dict(),
389
+ # 'acc': acc,
390
+ # 'epoch': epoch,
391
+ # }
392
+ # if not os.path.isdir('checkpoint'):
393
+ # os.mkdir('checkpoint')
394
+ # torch.save(state, './checkpoint/ckpt.pth')
395
+ # best_acc = acc
396
+
397
+ except Exception as e:
398
+ print(f"Error: {e}")
399
+ gr.Warning(f"Testing Error: {e}")
400
+
401
+
402
+ models_dict = {
403
+ #"AlexNet": models.AlexNet(weights=models.AlexNet_Weights.DEFAULT),
404
+ #"ConvNext_Small": models.convnext_small(weights=models.ConvNeXt_Small_Weights.DEFAULT),
405
+ #"ConvNext_Base": models.convnext_base(weights=models.ConvNeXt_Base_Weights.DEFAULT),
406
+ #"ConvNext_Large": models.convnext_large(weights=models.ConvNeXt_Large_Weights.DEFAULT),
407
+ "DenseNet": models.densenet121(weights=models.DenseNet121_Weights.DEFAULT),
408
+ #"EfficientNet_B0": models.efficientnet_b0(weights=models.EfficientNet_B0_Weights.DEFAULT),
409
+ #"GoogLeNet": models.googlenet(weights=models.GoogLeNet_Weights.DEFAULT),
410
+ # "InceptionNetV3": models.inception_v3(weights=models.Inception_V3_Weights.DEFAULT),
411
+ # "MaxVit": models.maxvit_t(weights=models.MaxVit_T_Weights.DEFAULT),
412
+ #"MnasNet0_5": models.mnasnet0_5(weights=models.MNASNet0_5_Weights.DEFAULT),
413
+ #"MobileNetV2": models.mobilenet_v2(weights=models.MobileNet_V2_Weights.DEFAULT),
414
+ "ResNet18": models.resnet18(weights=models.ResNet18_Weights.DEFAULT),
415
+ "ResNet50": models.resnet50(weights=models.ResNet50_Weights.DEFAULT),
416
+ #"RegNet_X_400MF": models.regnet_x_400mf(weights=models.RegNet_X_400MF_Weights.DEFAULT),
417
+ #"ShuffleNet_V2_X0_5": models.shufflenet_v2_x0_5(weights=models.ShuffleNet_V2_X0_5_Weights.DEFAULT),
418
+ #"SqueezeNet": models.squeezenet1_0(weights=models.SqueezeNet1_0_Weights.DEFAULT),
419
+ "VGG19": models.vgg19(weights=models.VGG19_Weights.DEFAULT)
420
+ }
421
+
422
+ # Store dictionary keys into list for dropdown menu choices
423
+ names = list(models_dict.keys())
424
+
425
+ # Optimizer names
426
+ optimizers = ["SGD","Adam"]
427
+
428
+ # Scheduler names
429
+ schedulers = ["None","CosineAnnealingLR","ReduceLROnPlateau","StepLR"]
430
+
431
+ ### GRADIO APP INTERFACE
432
+
433
+ def togglepicsettings(choice):
434
+ yes=gr.Gallery(visible=True)
435
+ no=gr.Gallery(visible=False)
436
+ if choice == "Yes":
437
+ return yes,no
438
+ else:
439
+ return no,yes
440
+
441
+ def settings(choice):
442
+ if choice == "Advanced":
443
+ advanced = [
444
+ gr.Slider(visible=True),
445
+ gr.Slider(visible=True),
446
+ gr.Slider(visible=True),
447
+ gr.Dropdown(visible=True),
448
+ gr.Dropdown(visible=True),
449
+ gr.Radio(visible=True)
450
+ ]
451
+ return advanced
452
+ else:
453
+ basic = [
454
+ gr.Slider(visible=False),
455
+ gr.Slider(visible=False),
456
+ gr.Slider(visible=False),
457
+ gr.Dropdown(visible=False),
458
+ gr.Dropdown(visible=False),
459
+ gr.Radio(visible=False)
460
+ ]
461
+ return basic
462
+
463
+ def attacks(choice):
464
+ if choice == "Yes":
465
+ yes = [
466
+ gr.Markdown(visible=True),
467
+ gr.Radio(visible=True),
468
+ gr.Radio(visible=True)
469
+ ]
470
+ return yes
471
+ if choice == "No":
472
+ no = [
473
+ gr.Markdown(visible=False),
474
+ gr.Radio(visible=False),
475
+ gr.Radio(visible=False)
476
+ ]
477
+ return no
478
+
479
+ def gaussian(choice):
480
+ if choice == "Yes":
481
+ yes = [
482
+ gr.Slider(visible=True),
483
+ gr.Gallery(visible=True),
484
+ ]
485
+ return yes
486
+ else:
487
+ no = [
488
+ gr.Slider(visible=False),
489
+ gr.Gallery(visible=False),
490
+ ]
491
+ return no
492
+ def adversarial(choice):
493
+ if choice == "Yes":
494
+ yes = gr.Gallery(visible=True)
495
+ return yes
496
+ else:
497
+ no = gr.Gallery(visible=False)
498
+
499
+ ## Main app for functionality
500
+ with gr.Blocks(css=".caption-label {display:none}") as functionApp:
501
+ with gr.Row():
502
+ gr.Markdown("# CIFAR-10 Model Training GUI")
503
+ with gr.Row():
504
+ gr.Markdown("## Parameters")
505
+ with gr.Row():
506
+ inp = gr.Dropdown(choices=names, label="Training Model", value="ResNet18", info="Choose one of 13 common models provided in the dropdown to use for training.")
507
+ username = gr.Textbox(label="Weights and Biases", info="Enter your username or team name from the Weights and Biases API.")
508
+ epochs_sldr = gr.Slider(label="Number of Epochs", minimum=1, maximum=100, step=1, value=1, info="How many times the model will see the entire dataset during trianing.")
509
+ with gr.Column():
510
+ setting_radio = gr.Radio(["Basic", "Advanced"], label="Settings", value="Basic")
511
+ btn = gr.Button("Run")
512
+ with gr.Row():
513
+ train_sldr = gr.Slider(visible=False, label="Training Batch Size", minimum=1, maximum=1000, step=1, value=128, info="The number of training samples processed before the model's internal parameters are updated.")
514
+ test_sldr = gr.Slider(visible=False, label="Testing Batch Size", minimum=1, maximum=1000, step=1, value=100, info="The number of testing samples processed at once during the evaluation phase.")
515
+ learning_rate_sldr = gr.Slider(visible=False, label="Learning Rate", minimum=0.0001, maximum=0.1, step=0.0001, value=0.001, info="The learning rate of the optimization program.")
516
+ optimizer = gr.Dropdown(visible=False, label="Optimizer", choices=optimizers, value="SGD", info="The optimization algorithm used to minimize the loss function during training.")
517
+ scheduler = gr.Dropdown(visible=False, label="Scheduler", choices=schedulers, value="CosineAnnealingLR", info="The scheduler used to iteratively alter learning rate.")
518
+ use_attacks = gr.Radio(["Yes", "No"], visible=False, label="Use Attacking Methods?", value="No")
519
+ setting_radio.change(fn=settings, inputs=setting_radio, outputs=[train_sldr, test_sldr, learning_rate_sldr, optimizer, scheduler, use_attacks])
520
+ with gr.Row():
521
+ attack_method = gr.Markdown("## Attacking Methods", visible=False)
522
+ with gr.Row():
523
+ use_sigma = gr.Radio(["Yes","No"], visible=False, label="Use Gaussian Noise?", value="No")
524
+ sigma_sldr = gr.Slider(visible=False, label="Gaussian Noise", minimum=0, maximum=1, value=0, step=0.1, info="The sigma value of the gaussian noise eqaution. A value of 0 disables gaussian noise.")
525
+ adv_attack = gr.Radio(["Yes","No"], visible=False, label="Use Adversarial Attacks?", value="No")
526
+ with gr.Row():
527
+ gr.Markdown("## Training Results")
528
+ with gr.Row():
529
+ accuracy = gr.Textbox(label = "Accuracy", info="The validation accuracy of the trained model (accuracy evaluated on testing data).")
530
+ with gr.Column():
531
+ showpics = gr.Radio(["Yes","No"], visible = True, label = "Show all pictures?", value = "No")
532
+ pics = gr.Gallery(preview=False, selected_index=0, object_fit='contain', label="Testing Images")
533
+ allpics = gr.Gallery(preview=True, selected_index=0, object_fit='contain', label="Full Testing Images",visible = False)
534
+ showpics.change(fn=togglepicsettings, inputs=[showpics], outputs = [allpics, pics])
535
+ with gr.Row():
536
+ gaussian_pics = gr.Gallery(visible=False, preview=False, selected_index=0, object_fit='contain', label="Gaussian Noise")
537
+ attack_pics = gr.Gallery(visible=False, preview=False, selected_index=0, object_fit='contain', label="Adversarial Attack")
538
+ use_attacks.change(fn=attacks, inputs=use_attacks, outputs=[attack_method, use_sigma, adv_attack])
539
+ use_sigma.change(fn=gaussian, inputs=use_sigma, outputs=[sigma_sldr, gaussian_pics])
540
+ adv_attack.change(fn=adversarial, inputs=adv_attack, outputs=attack_pics)
541
+ btn.click(fn=main, inputs=[inp, epochs_sldr, train_sldr, test_sldr, learning_rate_sldr, optimizer, sigma_sldr, adv_attack, username, scheduler], outputs=[accuracy, pics, allpics, gaussian_pics, attack_pics])
542
+
543
+ ## Documentation app (implemented as second tab)
544
+
545
+ markdown_file_path = 'documentation.md'
546
+ with open(markdown_file_path, 'r') as file:
547
+ markdown_content = file.read()
548
+
549
+ with gr.Blocks() as documentationApp:
550
+ with gr.Row():
551
+ gr.Markdown("# CIFAR-10 Training Interface Documentation")
552
+ with gr.Row():
553
+ gr.Markdown(markdown_content) # Can be collapesed in VSCode to hide paragraphs from view. Vscode can also wrap text.
554
+
555
+ ### LAUNCH APP
556
+
557
+ if __name__ == '__main__':
558
+ mainApp = gr.TabbedInterface([functionApp, documentationApp], ["Welcome", "Documentation"], theme=theme)
559
+ mainApp.queue()
560
+ mainApp.launch()
documentation.md ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Overview
2
+ This interface facilitates training deep learning models on the CIFAR-10 dataset using PyTorch. Users can select from a
3
+ variety of models, set training parameters, and initiate training to evaluate model performance. Here's more about it:
4
+ # Training Parameters
5
+ In the training parameters section, users can customize the training process by adjusting several settings, sorted into basic and advanced. These parameters collectively allow users to tailor the training process to meet specific computational constraints and performance goals.
6
+ ## Basic Settings
7
+ ### Model Selection:
8
+ In the model selection section, users have the option to choose from a variety of predefined models, each with its unique architecture and set of parameters. The available models are tailored for different computational capabilities and objectives, thereby offering a diverse range of options for training on the CIFAR-10 dataset. By providing a selection of models, this interface facilitates a more flexible and tailored approach to exploring and understanding the performance of different neural network architectures on the CIFAR-10 dataset. Users can easily switch between models to observe how each performs and to find the one that best meets their requirements.
9
+ ### Weights and Biases:
10
+ Username required for weights and biases (wandb) website to save graphs regarding accuracy and loss. If you do not have a wandb account, input "balica15".
11
+ ### Number of Epochs:
12
+ The number of epochs controls how many times the entire training dataset is passed forward and backward through the neural network.
13
+ ### Run:
14
+ Run the program. Once pressed, the selected model begins training on the CIFAR-10 dataset using the specified training parameters. The training process includes both forward and backward passes through the network, optimizing the model's weights to minimize the loss function.
15
+ ## Advanced Settings
16
+ ### Training and Testing Batch Sizes:
17
+ The training and testing batch sizes determine the number of samples that will be propagated through the network at one time, affecting the speed and memory usage of the training process.
18
+ ### Learning Rate:
19
+ The starting learning rate optimization of the optimizers. The learning rate in the optional schedulers are unable to be edited as they were chosen specifically to heighten accuracy.
20
+ ### Optimizer:
21
+ The optimizer selection allows users to choose between different optimization algorithms, namely SGD (Stochastic Gradient Descent) or Adam, which have distinct behaviors and performance characteristics.
22
+ ### Scheduler:
23
+ The scheduler selection allows users to choose how they want learning rate to change over the course of the program. There are four options: None, CosineAnnealingLR, ReduceLROnPlateau, and StepLR.
24
+ - None: No scheduler. The learning rate remains constant the entire run.
25
+ - CosineAnnealingLR: The learning rate of each parameter group is determined using a cosine annealing schedule.
26
+ - ReduceLROnPlateau: The learning rate reduces when a parameter stops improving over a certain interval. In this case, if the accuracy stops improving for five epochs straight, the program will lower the learning rate.
27
+ - StepLR: The learning rate decreases at a set rate over a set interval. In this case, every 30 epochs the learning rate decreases by a factor of 0.1.
28
+ ### Attacking Methods:
29
+ If attacking methods are enabled, it reveals two mores settings: gaussian noise and advarsarial attack.
30
+
31
+ When gaussian noise is enabled, the user can choose a value for the sigma value of gaussian noise, controlling how much it influences the model. A sigma value of 0 disables gaussian noise, even if the setting is enabled.
32
+
33
+ The advarsarial attack is simply a toggle that causes almost unnoticable changes to the pictures the model is looking at, which can cause incorrect results.
34
+ # Training Results
35
+ Upon completion of the training across the defined number of epochs, the interface will evaluate the model on the test dataset and display the achieved accuracy, 10 testing pictures per every 10 epochs, the gaussian noise on an image (if enabled), and the advarsarial attack result on an image (if enabled).
36
+ # Warnings
37
+ Any warnings during training will be displayed in a yellow popup at the top right of the interface.
38
+ # Data
39
+ The CIFAR-10 dataset used in this interface comprises 60,000 32x32 color images spread across 10 different classes, with a training set of 50,000 images and a testing set of 10,000 images. Before training, the dataset undergoes specific transformations such as random cropping and normalization to augment the data and standardize the pixel values, respectively. These preprocessing steps help in enhancing the model's ability to learn and generalize well from the data. The interface automatically handles the downloading and preparation of the CIFAR-10 dataset, making it effortless for users to start training models without worrying about data management.
models/__init__.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .vgg import *
2
+ from .dpn import *
3
+ from .lenet import *
4
+ from .senet import *
5
+ from .pnasnet import *
6
+ from .densenet import *
7
+ from .googlenet import *
8
+ from .shufflenet import *
9
+ from .shufflenetv2 import *
10
+ from .resnet import *
11
+ from .resnext import *
12
+ from .preact_resnet import *
13
+ from .mobilenet import *
14
+ from .mobilenetv2 import *
15
+ from .efficientnet import *
16
+ from .regnet import *
17
+ from .dla_simple import *
18
+ from .dla import *
models/densenet.py ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''DenseNet in PyTorch.'''
2
+ import math
3
+
4
+ import torch
5
+ import torch.nn as nn
6
+ import torch.nn.functional as F
7
+
8
+
9
+ class Bottleneck(nn.Module):
10
+ def __init__(self, in_planes, growth_rate):
11
+ super(Bottleneck, self).__init__()
12
+ self.bn1 = nn.BatchNorm2d(in_planes)
13
+ self.conv1 = nn.Conv2d(in_planes, 4*growth_rate, kernel_size=1, bias=False)
14
+ self.bn2 = nn.BatchNorm2d(4*growth_rate)
15
+ self.conv2 = nn.Conv2d(4*growth_rate, growth_rate, kernel_size=3, padding=1, bias=False)
16
+
17
+ def forward(self, x):
18
+ out = self.conv1(F.relu(self.bn1(x)))
19
+ out = self.conv2(F.relu(self.bn2(out)))
20
+ out = torch.cat([out,x], 1)
21
+ return out
22
+
23
+
24
+ class Transition(nn.Module):
25
+ def __init__(self, in_planes, out_planes):
26
+ super(Transition, self).__init__()
27
+ self.bn = nn.BatchNorm2d(in_planes)
28
+ self.conv = nn.Conv2d(in_planes, out_planes, kernel_size=1, bias=False)
29
+
30
+ def forward(self, x):
31
+ out = self.conv(F.relu(self.bn(x)))
32
+ out = F.avg_pool2d(out, 2)
33
+ return out
34
+
35
+
36
+ class DenseNet(nn.Module):
37
+ def __init__(self, block, nblocks, growth_rate=12, reduction=0.5, num_classes=10):
38
+ super(DenseNet, self).__init__()
39
+ self.growth_rate = growth_rate
40
+
41
+ num_planes = 2*growth_rate
42
+ self.conv1 = nn.Conv2d(3, num_planes, kernel_size=3, padding=1, bias=False)
43
+
44
+ self.dense1 = self._make_dense_layers(block, num_planes, nblocks[0])
45
+ num_planes += nblocks[0]*growth_rate
46
+ out_planes = int(math.floor(num_planes*reduction))
47
+ self.trans1 = Transition(num_planes, out_planes)
48
+ num_planes = out_planes
49
+
50
+ self.dense2 = self._make_dense_layers(block, num_planes, nblocks[1])
51
+ num_planes += nblocks[1]*growth_rate
52
+ out_planes = int(math.floor(num_planes*reduction))
53
+ self.trans2 = Transition(num_planes, out_planes)
54
+ num_planes = out_planes
55
+
56
+ self.dense3 = self._make_dense_layers(block, num_planes, nblocks[2])
57
+ num_planes += nblocks[2]*growth_rate
58
+ out_planes = int(math.floor(num_planes*reduction))
59
+ self.trans3 = Transition(num_planes, out_planes)
60
+ num_planes = out_planes
61
+
62
+ self.dense4 = self._make_dense_layers(block, num_planes, nblocks[3])
63
+ num_planes += nblocks[3]*growth_rate
64
+
65
+ self.bn = nn.BatchNorm2d(num_planes)
66
+ self.linear = nn.Linear(num_planes, num_classes)
67
+
68
+ def _make_dense_layers(self, block, in_planes, nblock):
69
+ layers = []
70
+ for i in range(nblock):
71
+ layers.append(block(in_planes, self.growth_rate))
72
+ in_planes += self.growth_rate
73
+ return nn.Sequential(*layers)
74
+
75
+ def forward(self, x):
76
+ out = self.conv1(x)
77
+ out = self.trans1(self.dense1(out))
78
+ out = self.trans2(self.dense2(out))
79
+ out = self.trans3(self.dense3(out))
80
+ out = self.dense4(out)
81
+ out = F.avg_pool2d(F.relu(self.bn(out)), 4)
82
+ out = out.view(out.size(0), -1)
83
+ out = self.linear(out)
84
+ return out
85
+
86
+ def DenseNet121():
87
+ return DenseNet(Bottleneck, [6,12,24,16], growth_rate=32)
88
+
89
+ def DenseNet169():
90
+ return DenseNet(Bottleneck, [6,12,32,32], growth_rate=32)
91
+
92
+ def DenseNet201():
93
+ return DenseNet(Bottleneck, [6,12,48,32], growth_rate=32)
94
+
95
+ def DenseNet161():
96
+ return DenseNet(Bottleneck, [6,12,36,24], growth_rate=48)
97
+
98
+ def densenet_cifar():
99
+ return DenseNet(Bottleneck, [6,12,24,16], growth_rate=12)
100
+
101
+ def test():
102
+ net = densenet_cifar()
103
+ x = torch.randn(1,3,32,32)
104
+ y = net(x)
105
+ print(y)
106
+
107
+ # test()
models/dla.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''DLA in PyTorch.
2
+
3
+ Reference:
4
+ Deep Layer Aggregation. https://arxiv.org/abs/1707.06484
5
+ '''
6
+ import torch
7
+ import torch.nn as nn
8
+ import torch.nn.functional as F
9
+
10
+
11
+ class BasicBlock(nn.Module):
12
+ expansion = 1
13
+
14
+ def __init__(self, in_planes, planes, stride=1):
15
+ super(BasicBlock, self).__init__()
16
+ self.conv1 = nn.Conv2d(
17
+ in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
18
+ self.bn1 = nn.BatchNorm2d(planes)
19
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3,
20
+ 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,
27
+ kernel_size=1, stride=stride, bias=False),
28
+ nn.BatchNorm2d(self.expansion*planes)
29
+ )
30
+
31
+ def forward(self, x):
32
+ out = F.relu(self.bn1(self.conv1(x)))
33
+ out = self.bn2(self.conv2(out))
34
+ out += self.shortcut(x)
35
+ out = F.relu(out)
36
+ return out
37
+
38
+
39
+ class Root(nn.Module):
40
+ def __init__(self, in_channels, out_channels, kernel_size=1):
41
+ super(Root, self).__init__()
42
+ self.conv = nn.Conv2d(
43
+ in_channels, out_channels, kernel_size,
44
+ stride=1, padding=(kernel_size - 1) // 2, bias=False)
45
+ self.bn = nn.BatchNorm2d(out_channels)
46
+
47
+ def forward(self, xs):
48
+ x = torch.cat(xs, 1)
49
+ out = F.relu(self.bn(self.conv(x)))
50
+ return out
51
+
52
+
53
+ class Tree(nn.Module):
54
+ def __init__(self, block, in_channels, out_channels, level=1, stride=1):
55
+ super(Tree, self).__init__()
56
+ self.level = level
57
+ if level == 1:
58
+ self.root = Root(2*out_channels, out_channels)
59
+ self.left_node = block(in_channels, out_channels, stride=stride)
60
+ self.right_node = block(out_channels, out_channels, stride=1)
61
+ else:
62
+ self.root = Root((level+2)*out_channels, out_channels)
63
+ for i in reversed(range(1, level)):
64
+ subtree = Tree(block, in_channels, out_channels,
65
+ level=i, stride=stride)
66
+ self.__setattr__('level_%d' % i, subtree)
67
+ self.prev_root = block(in_channels, out_channels, stride=stride)
68
+ self.left_node = block(out_channels, out_channels, stride=1)
69
+ self.right_node = block(out_channels, out_channels, stride=1)
70
+
71
+ def forward(self, x):
72
+ xs = [self.prev_root(x)] if self.level > 1 else []
73
+ for i in reversed(range(1, self.level)):
74
+ level_i = self.__getattr__('level_%d' % i)
75
+ x = level_i(x)
76
+ xs.append(x)
77
+ x = self.left_node(x)
78
+ xs.append(x)
79
+ x = self.right_node(x)
80
+ xs.append(x)
81
+ out = self.root(xs)
82
+ return out
83
+
84
+
85
+ class DLA(nn.Module):
86
+ def __init__(self, block=BasicBlock, num_classes=10):
87
+ super(DLA, self).__init__()
88
+ self.base = nn.Sequential(
89
+ nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1, bias=False),
90
+ nn.BatchNorm2d(16),
91
+ nn.ReLU(True)
92
+ )
93
+
94
+ self.layer1 = nn.Sequential(
95
+ nn.Conv2d(16, 16, kernel_size=3, stride=1, padding=1, bias=False),
96
+ nn.BatchNorm2d(16),
97
+ nn.ReLU(True)
98
+ )
99
+
100
+ self.layer2 = nn.Sequential(
101
+ nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1, bias=False),
102
+ nn.BatchNorm2d(32),
103
+ nn.ReLU(True)
104
+ )
105
+
106
+ self.layer3 = Tree(block, 32, 64, level=1, stride=1)
107
+ self.layer4 = Tree(block, 64, 128, level=2, stride=2)
108
+ self.layer5 = Tree(block, 128, 256, level=2, stride=2)
109
+ self.layer6 = Tree(block, 256, 512, level=1, stride=2)
110
+ self.linear = nn.Linear(512, num_classes)
111
+
112
+ def forward(self, x):
113
+ out = self.base(x)
114
+ out = self.layer1(out)
115
+ out = self.layer2(out)
116
+ out = self.layer3(out)
117
+ out = self.layer4(out)
118
+ out = self.layer5(out)
119
+ out = self.layer6(out)
120
+ out = F.avg_pool2d(out, 4)
121
+ out = out.view(out.size(0), -1)
122
+ out = self.linear(out)
123
+ return out
124
+
125
+
126
+ def test():
127
+ net = DLA()
128
+ print(net)
129
+ x = torch.randn(1, 3, 32, 32)
130
+ y = net(x)
131
+ print(y.size())
132
+
133
+
134
+ if __name__ == '__main__':
135
+ test()
models/dla_simple.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''Simplified version of DLA in PyTorch.
2
+
3
+ Note this implementation is not identical to the original paper version.
4
+ But it seems works fine.
5
+
6
+ See dla.py for the original paper version.
7
+
8
+ Reference:
9
+ Deep Layer Aggregation. https://arxiv.org/abs/1707.06484
10
+ '''
11
+ import torch
12
+ import torch.nn as nn
13
+ import torch.nn.functional as F
14
+
15
+
16
+ class BasicBlock(nn.Module):
17
+ expansion = 1
18
+
19
+ def __init__(self, in_planes, planes, stride=1):
20
+ super(BasicBlock, self).__init__()
21
+ self.conv1 = nn.Conv2d(
22
+ in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
23
+ self.bn1 = nn.BatchNorm2d(planes)
24
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3,
25
+ stride=1, padding=1, bias=False)
26
+ self.bn2 = nn.BatchNorm2d(planes)
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,
32
+ kernel_size=1, stride=stride, bias=False),
33
+ nn.BatchNorm2d(self.expansion*planes)
34
+ )
35
+
36
+ def forward(self, x):
37
+ out = F.relu(self.bn1(self.conv1(x)))
38
+ out = self.bn2(self.conv2(out))
39
+ out += self.shortcut(x)
40
+ out = F.relu(out)
41
+ return out
42
+
43
+
44
+ class Root(nn.Module):
45
+ def __init__(self, in_channels, out_channels, kernel_size=1):
46
+ super(Root, self).__init__()
47
+ self.conv = nn.Conv2d(
48
+ in_channels, out_channels, kernel_size,
49
+ stride=1, padding=(kernel_size - 1) // 2, bias=False)
50
+ self.bn = nn.BatchNorm2d(out_channels)
51
+
52
+ def forward(self, xs):
53
+ x = torch.cat(xs, 1)
54
+ out = F.relu(self.bn(self.conv(x)))
55
+ return out
56
+
57
+
58
+ class Tree(nn.Module):
59
+ def __init__(self, block, in_channels, out_channels, level=1, stride=1):
60
+ super(Tree, self).__init__()
61
+ self.root = Root(2*out_channels, out_channels)
62
+ if level == 1:
63
+ self.left_tree = block(in_channels, out_channels, stride=stride)
64
+ self.right_tree = block(out_channels, out_channels, stride=1)
65
+ else:
66
+ self.left_tree = Tree(block, in_channels,
67
+ out_channels, level=level-1, stride=stride)
68
+ self.right_tree = Tree(block, out_channels,
69
+ out_channels, level=level-1, stride=1)
70
+
71
+ def forward(self, x):
72
+ out1 = self.left_tree(x)
73
+ out2 = self.right_tree(out1)
74
+ out = self.root([out1, out2])
75
+ return out
76
+
77
+
78
+ class SimpleDLA(nn.Module):
79
+ def __init__(self, block=BasicBlock, num_classes=10):
80
+ super(SimpleDLA, self).__init__()
81
+ self.base = nn.Sequential(
82
+ nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1, bias=False),
83
+ nn.BatchNorm2d(16),
84
+ nn.ReLU(True)
85
+ )
86
+
87
+ self.layer1 = nn.Sequential(
88
+ nn.Conv2d(16, 16, kernel_size=3, stride=1, padding=1, bias=False),
89
+ nn.BatchNorm2d(16),
90
+ nn.ReLU(True)
91
+ )
92
+
93
+ self.layer2 = nn.Sequential(
94
+ nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1, bias=False),
95
+ nn.BatchNorm2d(32),
96
+ nn.ReLU(True)
97
+ )
98
+
99
+ self.layer3 = Tree(block, 32, 64, level=1, stride=1)
100
+ self.layer4 = Tree(block, 64, 128, level=2, stride=2)
101
+ self.layer5 = Tree(block, 128, 256, level=2, stride=2)
102
+ self.layer6 = Tree(block, 256, 512, level=1, stride=2)
103
+ self.linear = nn.Linear(512, num_classes)
104
+
105
+ def forward(self, x):
106
+ out = self.base(x)
107
+ out = self.layer1(out)
108
+ out = self.layer2(out)
109
+ out = self.layer3(out)
110
+ out = self.layer4(out)
111
+ out = self.layer5(out)
112
+ out = self.layer6(out)
113
+ out = F.avg_pool2d(out, 4)
114
+ out = out.view(out.size(0), -1)
115
+ out = self.linear(out)
116
+ return out
117
+
118
+
119
+ def test():
120
+ net = SimpleDLA()
121
+ print(net)
122
+ x = torch.randn(1, 3, 32, 32)
123
+ y = net(x)
124
+ print(y.size())
125
+
126
+
127
+ if __name__ == '__main__':
128
+ test()
models/dpn.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''Dual Path Networks in PyTorch.'''
2
+ import torch
3
+ import torch.nn as nn
4
+ import torch.nn.functional as F
5
+
6
+
7
+ class Bottleneck(nn.Module):
8
+ def __init__(self, last_planes, in_planes, out_planes, dense_depth, stride, first_layer):
9
+ super(Bottleneck, self).__init__()
10
+ self.out_planes = out_planes
11
+ self.dense_depth = dense_depth
12
+
13
+ self.conv1 = nn.Conv2d(last_planes, in_planes, kernel_size=1, bias=False)
14
+ self.bn1 = nn.BatchNorm2d(in_planes)
15
+ self.conv2 = nn.Conv2d(in_planes, in_planes, kernel_size=3, stride=stride, padding=1, groups=32, bias=False)
16
+ self.bn2 = nn.BatchNorm2d(in_planes)
17
+ self.conv3 = nn.Conv2d(in_planes, out_planes+dense_depth, kernel_size=1, bias=False)
18
+ self.bn3 = nn.BatchNorm2d(out_planes+dense_depth)
19
+
20
+ self.shortcut = nn.Sequential()
21
+ if first_layer:
22
+ self.shortcut = nn.Sequential(
23
+ nn.Conv2d(last_planes, out_planes+dense_depth, kernel_size=1, stride=stride, bias=False),
24
+ nn.BatchNorm2d(out_planes+dense_depth)
25
+ )
26
+
27
+ def forward(self, x):
28
+ out = F.relu(self.bn1(self.conv1(x)))
29
+ out = F.relu(self.bn2(self.conv2(out)))
30
+ out = self.bn3(self.conv3(out))
31
+ x = self.shortcut(x)
32
+ d = self.out_planes
33
+ out = torch.cat([x[:,:d,:,:]+out[:,:d,:,:], x[:,d:,:,:], out[:,d:,:,:]], 1)
34
+ out = F.relu(out)
35
+ return out
36
+
37
+
38
+ class DPN(nn.Module):
39
+ def __init__(self, cfg):
40
+ super(DPN, self).__init__()
41
+ in_planes, out_planes = cfg['in_planes'], cfg['out_planes']
42
+ num_blocks, dense_depth = cfg['num_blocks'], cfg['dense_depth']
43
+
44
+ self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)
45
+ self.bn1 = nn.BatchNorm2d(64)
46
+ self.last_planes = 64
47
+ self.layer1 = self._make_layer(in_planes[0], out_planes[0], num_blocks[0], dense_depth[0], stride=1)
48
+ self.layer2 = self._make_layer(in_planes[1], out_planes[1], num_blocks[1], dense_depth[1], stride=2)
49
+ self.layer3 = self._make_layer(in_planes[2], out_planes[2], num_blocks[2], dense_depth[2], stride=2)
50
+ self.layer4 = self._make_layer(in_planes[3], out_planes[3], num_blocks[3], dense_depth[3], stride=2)
51
+ self.linear = nn.Linear(out_planes[3]+(num_blocks[3]+1)*dense_depth[3], 10)
52
+
53
+ def _make_layer(self, in_planes, out_planes, num_blocks, dense_depth, stride):
54
+ strides = [stride] + [1]*(num_blocks-1)
55
+ layers = []
56
+ for i,stride in enumerate(strides):
57
+ layers.append(Bottleneck(self.last_planes, in_planes, out_planes, dense_depth, stride, i==0))
58
+ self.last_planes = out_planes + (i+2) * dense_depth
59
+ return nn.Sequential(*layers)
60
+
61
+ def forward(self, x):
62
+ out = F.relu(self.bn1(self.conv1(x)))
63
+ out = self.layer1(out)
64
+ out = self.layer2(out)
65
+ out = self.layer3(out)
66
+ out = self.layer4(out)
67
+ out = F.avg_pool2d(out, 4)
68
+ out = out.view(out.size(0), -1)
69
+ out = self.linear(out)
70
+ return out
71
+
72
+
73
+ def DPN26():
74
+ cfg = {
75
+ 'in_planes': (96,192,384,768),
76
+ 'out_planes': (256,512,1024,2048),
77
+ 'num_blocks': (2,2,2,2),
78
+ 'dense_depth': (16,32,24,128)
79
+ }
80
+ return DPN(cfg)
81
+
82
+ def DPN92():
83
+ cfg = {
84
+ 'in_planes': (96,192,384,768),
85
+ 'out_planes': (256,512,1024,2048),
86
+ 'num_blocks': (3,4,20,3),
87
+ 'dense_depth': (16,32,24,128)
88
+ }
89
+ return DPN(cfg)
90
+
91
+
92
+ def test():
93
+ net = DPN92()
94
+ x = torch.randn(1,3,32,32)
95
+ y = net(x)
96
+ print(y)
97
+
98
+ # test()
models/efficientnet.py ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''EfficientNet in PyTorch.
2
+
3
+ Paper: "EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks".
4
+
5
+ Reference: https://github.com/keras-team/keras-applications/blob/master/keras_applications/efficientnet.py
6
+ '''
7
+ import torch
8
+ import torch.nn as nn
9
+ import torch.nn.functional as F
10
+
11
+
12
+ def swish(x):
13
+ return x * x.sigmoid()
14
+
15
+
16
+ def drop_connect(x, drop_ratio):
17
+ keep_ratio = 1.0 - drop_ratio
18
+ mask = torch.empty([x.shape[0], 1, 1, 1], dtype=x.dtype, device=x.device)
19
+ mask.bernoulli_(keep_ratio)
20
+ x.div_(keep_ratio)
21
+ x.mul_(mask)
22
+ return x
23
+
24
+
25
+ class SE(nn.Module):
26
+ '''Squeeze-and-Excitation block with Swish.'''
27
+
28
+ def __init__(self, in_channels, se_channels):
29
+ super(SE, self).__init__()
30
+ self.se1 = nn.Conv2d(in_channels, se_channels,
31
+ kernel_size=1, bias=True)
32
+ self.se2 = nn.Conv2d(se_channels, in_channels,
33
+ kernel_size=1, bias=True)
34
+
35
+ def forward(self, x):
36
+ out = F.adaptive_avg_pool2d(x, (1, 1))
37
+ out = swish(self.se1(out))
38
+ out = self.se2(out).sigmoid()
39
+ out = x * out
40
+ return out
41
+
42
+
43
+ class Block(nn.Module):
44
+ '''expansion + depthwise + pointwise + squeeze-excitation'''
45
+
46
+ def __init__(self,
47
+ in_channels,
48
+ out_channels,
49
+ kernel_size,
50
+ stride,
51
+ expand_ratio=1,
52
+ se_ratio=0.,
53
+ drop_rate=0.):
54
+ super(Block, self).__init__()
55
+ self.stride = stride
56
+ self.drop_rate = drop_rate
57
+ self.expand_ratio = expand_ratio
58
+
59
+ # Expansion
60
+ channels = expand_ratio * in_channels
61
+ self.conv1 = nn.Conv2d(in_channels,
62
+ channels,
63
+ kernel_size=1,
64
+ stride=1,
65
+ padding=0,
66
+ bias=False)
67
+ self.bn1 = nn.BatchNorm2d(channels)
68
+
69
+ # Depthwise conv
70
+ self.conv2 = nn.Conv2d(channels,
71
+ channels,
72
+ kernel_size=kernel_size,
73
+ stride=stride,
74
+ padding=(1 if kernel_size == 3 else 2),
75
+ groups=channels,
76
+ bias=False)
77
+ self.bn2 = nn.BatchNorm2d(channels)
78
+
79
+ # SE layers
80
+ se_channels = int(in_channels * se_ratio)
81
+ self.se = SE(channels, se_channels)
82
+
83
+ # Output
84
+ self.conv3 = nn.Conv2d(channels,
85
+ out_channels,
86
+ kernel_size=1,
87
+ stride=1,
88
+ padding=0,
89
+ bias=False)
90
+ self.bn3 = nn.BatchNorm2d(out_channels)
91
+
92
+ # Skip connection if in and out shapes are the same (MV-V2 style)
93
+ self.has_skip = (stride == 1) and (in_channels == out_channels)
94
+
95
+ def forward(self, x):
96
+ out = x if self.expand_ratio == 1 else swish(self.bn1(self.conv1(x)))
97
+ out = swish(self.bn2(self.conv2(out)))
98
+ out = self.se(out)
99
+ out = self.bn3(self.conv3(out))
100
+ if self.has_skip:
101
+ if self.training and self.drop_rate > 0:
102
+ out = drop_connect(out, self.drop_rate)
103
+ out = out + x
104
+ return out
105
+
106
+
107
+ class EfficientNet(nn.Module):
108
+ def __init__(self, cfg, num_classes=10):
109
+ super(EfficientNet, self).__init__()
110
+ self.cfg = cfg
111
+ self.conv1 = nn.Conv2d(3,
112
+ 32,
113
+ kernel_size=3,
114
+ stride=1,
115
+ padding=1,
116
+ bias=False)
117
+ self.bn1 = nn.BatchNorm2d(32)
118
+ self.layers = self._make_layers(in_channels=32)
119
+ self.linear = nn.Linear(cfg['out_channels'][-1], num_classes)
120
+
121
+ def _make_layers(self, in_channels):
122
+ layers = []
123
+ cfg = [self.cfg[k] for k in ['expansion', 'out_channels', 'num_blocks', 'kernel_size',
124
+ 'stride']]
125
+ b = 0
126
+ blocks = sum(self.cfg['num_blocks'])
127
+ for expansion, out_channels, num_blocks, kernel_size, stride in zip(*cfg):
128
+ strides = [stride] + [1] * (num_blocks - 1)
129
+ for stride in strides:
130
+ drop_rate = self.cfg['drop_connect_rate'] * b / blocks
131
+ layers.append(
132
+ Block(in_channels,
133
+ out_channels,
134
+ kernel_size,
135
+ stride,
136
+ expansion,
137
+ se_ratio=0.25,
138
+ drop_rate=drop_rate))
139
+ in_channels = out_channels
140
+ return nn.Sequential(*layers)
141
+
142
+ def forward(self, x):
143
+ out = swish(self.bn1(self.conv1(x)))
144
+ out = self.layers(out)
145
+ out = F.adaptive_avg_pool2d(out, 1)
146
+ out = out.view(out.size(0), -1)
147
+ dropout_rate = self.cfg['dropout_rate']
148
+ if self.training and dropout_rate > 0:
149
+ out = F.dropout(out, p=dropout_rate)
150
+ out = self.linear(out)
151
+ return out
152
+
153
+
154
+ def EfficientNetB0():
155
+ cfg = {
156
+ 'num_blocks': [1, 2, 2, 3, 3, 4, 1],
157
+ 'expansion': [1, 6, 6, 6, 6, 6, 6],
158
+ 'out_channels': [16, 24, 40, 80, 112, 192, 320],
159
+ 'kernel_size': [3, 3, 5, 3, 5, 5, 3],
160
+ 'stride': [1, 2, 2, 2, 1, 2, 1],
161
+ 'dropout_rate': 0.2,
162
+ 'drop_connect_rate': 0.2,
163
+ }
164
+ return EfficientNet(cfg)
165
+
166
+
167
+ def test():
168
+ net = EfficientNetB0()
169
+ x = torch.randn(2, 3, 32, 32)
170
+ y = net(x)
171
+ print(y.shape)
172
+
173
+
174
+ if __name__ == '__main__':
175
+ test()
models/googlenet.py ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''GoogLeNet with PyTorch.'''
2
+ import torch
3
+ import torch.nn as nn
4
+ import torch.nn.functional as F
5
+
6
+
7
+ class Inception(nn.Module):
8
+ def __init__(self, in_planes, n1x1, n3x3red, n3x3, n5x5red, n5x5, pool_planes):
9
+ super(Inception, self).__init__()
10
+ # 1x1 conv branch
11
+ self.b1 = nn.Sequential(
12
+ nn.Conv2d(in_planes, n1x1, kernel_size=1),
13
+ nn.BatchNorm2d(n1x1),
14
+ nn.ReLU(True),
15
+ )
16
+
17
+ # 1x1 conv -> 3x3 conv branch
18
+ self.b2 = nn.Sequential(
19
+ nn.Conv2d(in_planes, n3x3red, kernel_size=1),
20
+ nn.BatchNorm2d(n3x3red),
21
+ nn.ReLU(True),
22
+ nn.Conv2d(n3x3red, n3x3, kernel_size=3, padding=1),
23
+ nn.BatchNorm2d(n3x3),
24
+ nn.ReLU(True),
25
+ )
26
+
27
+ # 1x1 conv -> 5x5 conv branch
28
+ self.b3 = nn.Sequential(
29
+ nn.Conv2d(in_planes, n5x5red, kernel_size=1),
30
+ nn.BatchNorm2d(n5x5red),
31
+ nn.ReLU(True),
32
+ nn.Conv2d(n5x5red, n5x5, kernel_size=3, padding=1),
33
+ nn.BatchNorm2d(n5x5),
34
+ nn.ReLU(True),
35
+ nn.Conv2d(n5x5, n5x5, kernel_size=3, padding=1),
36
+ nn.BatchNorm2d(n5x5),
37
+ nn.ReLU(True),
38
+ )
39
+
40
+ # 3x3 pool -> 1x1 conv branch
41
+ self.b4 = nn.Sequential(
42
+ nn.MaxPool2d(3, stride=1, padding=1),
43
+ nn.Conv2d(in_planes, pool_planes, kernel_size=1),
44
+ nn.BatchNorm2d(pool_planes),
45
+ nn.ReLU(True),
46
+ )
47
+
48
+ def forward(self, x):
49
+ y1 = self.b1(x)
50
+ y2 = self.b2(x)
51
+ y3 = self.b3(x)
52
+ y4 = self.b4(x)
53
+ return torch.cat([y1,y2,y3,y4], 1)
54
+
55
+
56
+ class GoogLeNet(nn.Module):
57
+ def __init__(self):
58
+ super(GoogLeNet, self).__init__()
59
+ self.pre_layers = nn.Sequential(
60
+ nn.Conv2d(3, 192, kernel_size=3, padding=1),
61
+ nn.BatchNorm2d(192),
62
+ nn.ReLU(True),
63
+ )
64
+
65
+ self.a3 = Inception(192, 64, 96, 128, 16, 32, 32)
66
+ self.b3 = Inception(256, 128, 128, 192, 32, 96, 64)
67
+
68
+ self.maxpool = nn.MaxPool2d(3, stride=2, padding=1)
69
+
70
+ self.a4 = Inception(480, 192, 96, 208, 16, 48, 64)
71
+ self.b4 = Inception(512, 160, 112, 224, 24, 64, 64)
72
+ self.c4 = Inception(512, 128, 128, 256, 24, 64, 64)
73
+ self.d4 = Inception(512, 112, 144, 288, 32, 64, 64)
74
+ self.e4 = Inception(528, 256, 160, 320, 32, 128, 128)
75
+
76
+ self.a5 = Inception(832, 256, 160, 320, 32, 128, 128)
77
+ self.b5 = Inception(832, 384, 192, 384, 48, 128, 128)
78
+
79
+ self.avgpool = nn.AvgPool2d(8, stride=1)
80
+ self.linear = nn.Linear(1024, 10)
81
+
82
+ def forward(self, x):
83
+ out = self.pre_layers(x)
84
+ out = self.a3(out)
85
+ out = self.b3(out)
86
+ out = self.maxpool(out)
87
+ out = self.a4(out)
88
+ out = self.b4(out)
89
+ out = self.c4(out)
90
+ out = self.d4(out)
91
+ out = self.e4(out)
92
+ out = self.maxpool(out)
93
+ out = self.a5(out)
94
+ out = self.b5(out)
95
+ out = self.avgpool(out)
96
+ out = out.view(out.size(0), -1)
97
+ out = self.linear(out)
98
+ return out
99
+
100
+
101
+ def test():
102
+ net = GoogLeNet()
103
+ x = torch.randn(1,3,32,32)
104
+ y = net(x)
105
+ print(y.size())
106
+
107
+ # test()
models/lenet.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''LeNet in PyTorch.'''
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+
5
+ class LeNet(nn.Module):
6
+ def __init__(self):
7
+ super(LeNet, self).__init__()
8
+ self.conv1 = nn.Conv2d(3, 6, 5)
9
+ self.conv2 = nn.Conv2d(6, 16, 5)
10
+ self.fc1 = nn.Linear(16*5*5, 120)
11
+ self.fc2 = nn.Linear(120, 84)
12
+ self.fc3 = nn.Linear(84, 10)
13
+
14
+ def forward(self, x):
15
+ out = F.relu(self.conv1(x))
16
+ out = F.max_pool2d(out, 2)
17
+ out = F.relu(self.conv2(out))
18
+ out = F.max_pool2d(out, 2)
19
+ out = out.view(out.size(0), -1)
20
+ out = F.relu(self.fc1(out))
21
+ out = F.relu(self.fc2(out))
22
+ out = self.fc3(out)
23
+ return out
models/mobilenet.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''MobileNet in PyTorch.
2
+
3
+ See the paper "MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications"
4
+ for more details.
5
+ '''
6
+ import torch
7
+ import torch.nn as nn
8
+ import torch.nn.functional as F
9
+
10
+
11
+ class Block(nn.Module):
12
+ '''Depthwise conv + Pointwise conv'''
13
+ def __init__(self, in_planes, out_planes, stride=1):
14
+ super(Block, self).__init__()
15
+ self.conv1 = nn.Conv2d(in_planes, in_planes, kernel_size=3, stride=stride, padding=1, groups=in_planes, bias=False)
16
+ self.bn1 = nn.BatchNorm2d(in_planes)
17
+ self.conv2 = nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False)
18
+ self.bn2 = nn.BatchNorm2d(out_planes)
19
+
20
+ def forward(self, x):
21
+ out = F.relu(self.bn1(self.conv1(x)))
22
+ out = F.relu(self.bn2(self.conv2(out)))
23
+ return out
24
+
25
+
26
+ class MobileNet(nn.Module):
27
+ # (128,2) means conv planes=128, conv stride=2, by default conv stride=1
28
+ cfg = [64, (128,2), 128, (256,2), 256, (512,2), 512, 512, 512, 512, 512, (1024,2), 1024]
29
+
30
+ def __init__(self, num_classes=10):
31
+ super(MobileNet, self).__init__()
32
+ self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1, bias=False)
33
+ self.bn1 = nn.BatchNorm2d(32)
34
+ self.layers = self._make_layers(in_planes=32)
35
+ self.linear = nn.Linear(1024, num_classes)
36
+
37
+ def _make_layers(self, in_planes):
38
+ layers = []
39
+ for x in self.cfg:
40
+ out_planes = x if isinstance(x, int) else x[0]
41
+ stride = 1 if isinstance(x, int) else x[1]
42
+ layers.append(Block(in_planes, out_planes, stride))
43
+ in_planes = out_planes
44
+ return nn.Sequential(*layers)
45
+
46
+ def forward(self, x):
47
+ out = F.relu(self.bn1(self.conv1(x)))
48
+ out = self.layers(out)
49
+ out = F.avg_pool2d(out, 2)
50
+ out = out.view(out.size(0), -1)
51
+ out = self.linear(out)
52
+ return out
53
+
54
+
55
+ def test():
56
+ net = MobileNet()
57
+ x = torch.randn(1,3,32,32)
58
+ y = net(x)
59
+ print(y.size())
60
+
61
+ # test()
models/mobilenetv2.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''MobileNetV2 in PyTorch.
2
+
3
+ See the paper "Inverted Residuals and Linear Bottlenecks:
4
+ Mobile Networks for Classification, Detection and Segmentation" for more details.
5
+ '''
6
+ import torch
7
+ import torch.nn as nn
8
+ import torch.nn.functional as F
9
+
10
+
11
+ class Block(nn.Module):
12
+ '''expand + depthwise + pointwise'''
13
+ def __init__(self, in_planes, out_planes, expansion, stride):
14
+ super(Block, self).__init__()
15
+ self.stride = stride
16
+
17
+ planes = expansion * in_planes
18
+ self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, stride=1, padding=0, bias=False)
19
+ self.bn1 = nn.BatchNorm2d(planes)
20
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, groups=planes, bias=False)
21
+ self.bn2 = nn.BatchNorm2d(planes)
22
+ self.conv3 = nn.Conv2d(planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False)
23
+ self.bn3 = nn.BatchNorm2d(out_planes)
24
+
25
+ self.shortcut = nn.Sequential()
26
+ if stride == 1 and in_planes != out_planes:
27
+ self.shortcut = nn.Sequential(
28
+ nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False),
29
+ nn.BatchNorm2d(out_planes),
30
+ )
31
+
32
+ def forward(self, x):
33
+ out = F.relu(self.bn1(self.conv1(x)))
34
+ out = F.relu(self.bn2(self.conv2(out)))
35
+ out = self.bn3(self.conv3(out))
36
+ out = out + self.shortcut(x) if self.stride==1 else out
37
+ return out
38
+
39
+
40
+ class MobileNetV2(nn.Module):
41
+ # (expansion, out_planes, num_blocks, stride)
42
+ cfg = [(1, 16, 1, 1),
43
+ (6, 24, 2, 1), # NOTE: change stride 2 -> 1 for CIFAR10
44
+ (6, 32, 3, 2),
45
+ (6, 64, 4, 2),
46
+ (6, 96, 3, 1),
47
+ (6, 160, 3, 2),
48
+ (6, 320, 1, 1)]
49
+
50
+ def __init__(self, num_classes=10):
51
+ super(MobileNetV2, self).__init__()
52
+ # NOTE: change conv1 stride 2 -> 1 for CIFAR10
53
+ self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1, bias=False)
54
+ self.bn1 = nn.BatchNorm2d(32)
55
+ self.layers = self._make_layers(in_planes=32)
56
+ self.conv2 = nn.Conv2d(320, 1280, kernel_size=1, stride=1, padding=0, bias=False)
57
+ self.bn2 = nn.BatchNorm2d(1280)
58
+ self.linear = nn.Linear(1280, num_classes)
59
+
60
+ def _make_layers(self, in_planes):
61
+ layers = []
62
+ for expansion, out_planes, num_blocks, stride in self.cfg:
63
+ strides = [stride] + [1]*(num_blocks-1)
64
+ for stride in strides:
65
+ layers.append(Block(in_planes, out_planes, expansion, stride))
66
+ in_planes = out_planes
67
+ return nn.Sequential(*layers)
68
+
69
+ def forward(self, x):
70
+ out = F.relu(self.bn1(self.conv1(x)))
71
+ out = self.layers(out)
72
+ out = F.relu(self.bn2(self.conv2(out)))
73
+ # NOTE: change pooling kernel_size 7 -> 4 for CIFAR10
74
+ out = F.avg_pool2d(out, 4)
75
+ out = out.view(out.size(0), -1)
76
+ out = self.linear(out)
77
+ return out
78
+
79
+
80
+ def test():
81
+ net = MobileNetV2()
82
+ x = torch.randn(2,3,32,32)
83
+ y = net(x)
84
+ print(y.size())
85
+
86
+ # test()
models/pnasnet.py ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''PNASNet in PyTorch.
2
+
3
+ Paper: Progressive Neural Architecture Search
4
+ '''
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+
9
+
10
+ class SepConv(nn.Module):
11
+ '''Separable Convolution.'''
12
+ def __init__(self, in_planes, out_planes, kernel_size, stride):
13
+ super(SepConv, self).__init__()
14
+ self.conv1 = nn.Conv2d(in_planes, out_planes,
15
+ kernel_size, stride,
16
+ padding=(kernel_size-1)//2,
17
+ bias=False, groups=in_planes)
18
+ self.bn1 = nn.BatchNorm2d(out_planes)
19
+
20
+ def forward(self, x):
21
+ return self.bn1(self.conv1(x))
22
+
23
+
24
+ class CellA(nn.Module):
25
+ def __init__(self, in_planes, out_planes, stride=1):
26
+ super(CellA, self).__init__()
27
+ self.stride = stride
28
+ self.sep_conv1 = SepConv(in_planes, out_planes, kernel_size=7, stride=stride)
29
+ if stride==2:
30
+ self.conv1 = nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False)
31
+ self.bn1 = nn.BatchNorm2d(out_planes)
32
+
33
+ def forward(self, x):
34
+ y1 = self.sep_conv1(x)
35
+ y2 = F.max_pool2d(x, kernel_size=3, stride=self.stride, padding=1)
36
+ if self.stride==2:
37
+ y2 = self.bn1(self.conv1(y2))
38
+ return F.relu(y1+y2)
39
+
40
+ class CellB(nn.Module):
41
+ def __init__(self, in_planes, out_planes, stride=1):
42
+ super(CellB, self).__init__()
43
+ self.stride = stride
44
+ # Left branch
45
+ self.sep_conv1 = SepConv(in_planes, out_planes, kernel_size=7, stride=stride)
46
+ self.sep_conv2 = SepConv(in_planes, out_planes, kernel_size=3, stride=stride)
47
+ # Right branch
48
+ self.sep_conv3 = SepConv(in_planes, out_planes, kernel_size=5, stride=stride)
49
+ if stride==2:
50
+ self.conv1 = nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False)
51
+ self.bn1 = nn.BatchNorm2d(out_planes)
52
+ # Reduce channels
53
+ self.conv2 = nn.Conv2d(2*out_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False)
54
+ self.bn2 = nn.BatchNorm2d(out_planes)
55
+
56
+ def forward(self, x):
57
+ # Left branch
58
+ y1 = self.sep_conv1(x)
59
+ y2 = self.sep_conv2(x)
60
+ # Right branch
61
+ y3 = F.max_pool2d(x, kernel_size=3, stride=self.stride, padding=1)
62
+ if self.stride==2:
63
+ y3 = self.bn1(self.conv1(y3))
64
+ y4 = self.sep_conv3(x)
65
+ # Concat & reduce channels
66
+ b1 = F.relu(y1+y2)
67
+ b2 = F.relu(y3+y4)
68
+ y = torch.cat([b1,b2], 1)
69
+ return F.relu(self.bn2(self.conv2(y)))
70
+
71
+ class PNASNet(nn.Module):
72
+ def __init__(self, cell_type, num_cells, num_planes):
73
+ super(PNASNet, self).__init__()
74
+ self.in_planes = num_planes
75
+ self.cell_type = cell_type
76
+
77
+ self.conv1 = nn.Conv2d(3, num_planes, kernel_size=3, stride=1, padding=1, bias=False)
78
+ self.bn1 = nn.BatchNorm2d(num_planes)
79
+
80
+ self.layer1 = self._make_layer(num_planes, num_cells=6)
81
+ self.layer2 = self._downsample(num_planes*2)
82
+ self.layer3 = self._make_layer(num_planes*2, num_cells=6)
83
+ self.layer4 = self._downsample(num_planes*4)
84
+ self.layer5 = self._make_layer(num_planes*4, num_cells=6)
85
+
86
+ self.linear = nn.Linear(num_planes*4, 10)
87
+
88
+ def _make_layer(self, planes, num_cells):
89
+ layers = []
90
+ for _ in range(num_cells):
91
+ layers.append(self.cell_type(self.in_planes, planes, stride=1))
92
+ self.in_planes = planes
93
+ return nn.Sequential(*layers)
94
+
95
+ def _downsample(self, planes):
96
+ layer = self.cell_type(self.in_planes, planes, stride=2)
97
+ self.in_planes = planes
98
+ return layer
99
+
100
+ def forward(self, x):
101
+ out = F.relu(self.bn1(self.conv1(x)))
102
+ out = self.layer1(out)
103
+ out = self.layer2(out)
104
+ out = self.layer3(out)
105
+ out = self.layer4(out)
106
+ out = self.layer5(out)
107
+ out = F.avg_pool2d(out, 8)
108
+ out = self.linear(out.view(out.size(0), -1))
109
+ return out
110
+
111
+
112
+ def PNASNetA():
113
+ return PNASNet(CellA, num_cells=6, num_planes=44)
114
+
115
+ def PNASNetB():
116
+ return PNASNet(CellB, num_cells=6, num_planes=32)
117
+
118
+
119
+ def test():
120
+ net = PNASNetB()
121
+ x = torch.randn(1,3,32,32)
122
+ y = net(x)
123
+ print(y)
124
+
125
+ # test()
models/preact_resnet.py ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''Pre-activation ResNet in PyTorch.
2
+
3
+ Reference:
4
+ [1] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun
5
+ Identity Mappings in Deep Residual Networks. arXiv:1603.05027
6
+ '''
7
+ import torch
8
+ import torch.nn as nn
9
+ import torch.nn.functional as F
10
+
11
+
12
+ class PreActBlock(nn.Module):
13
+ '''Pre-activation version of the BasicBlock.'''
14
+ expansion = 1
15
+
16
+ def __init__(self, in_planes, planes, stride=1):
17
+ super(PreActBlock, self).__init__()
18
+ self.bn1 = nn.BatchNorm2d(in_planes)
19
+ self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
20
+ self.bn2 = nn.BatchNorm2d(planes)
21
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False)
22
+
23
+ if stride != 1 or in_planes != self.expansion*planes:
24
+ self.shortcut = nn.Sequential(
25
+ nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False)
26
+ )
27
+
28
+ def forward(self, x):
29
+ out = F.relu(self.bn1(x))
30
+ shortcut = self.shortcut(out) if hasattr(self, 'shortcut') else x
31
+ out = self.conv1(out)
32
+ out = self.conv2(F.relu(self.bn2(out)))
33
+ out += shortcut
34
+ return out
35
+
36
+
37
+ class PreActBottleneck(nn.Module):
38
+ '''Pre-activation version of the original Bottleneck module.'''
39
+ expansion = 4
40
+
41
+ def __init__(self, in_planes, planes, stride=1):
42
+ super(PreActBottleneck, self).__init__()
43
+ self.bn1 = nn.BatchNorm2d(in_planes)
44
+ self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False)
45
+ self.bn2 = nn.BatchNorm2d(planes)
46
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
47
+ self.bn3 = nn.BatchNorm2d(planes)
48
+ self.conv3 = nn.Conv2d(planes, self.expansion*planes, kernel_size=1, bias=False)
49
+
50
+ if stride != 1 or in_planes != self.expansion*planes:
51
+ self.shortcut = nn.Sequential(
52
+ nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False)
53
+ )
54
+
55
+ def forward(self, x):
56
+ out = F.relu(self.bn1(x))
57
+ shortcut = self.shortcut(out) if hasattr(self, 'shortcut') else x
58
+ out = self.conv1(out)
59
+ out = self.conv2(F.relu(self.bn2(out)))
60
+ out = self.conv3(F.relu(self.bn3(out)))
61
+ out += shortcut
62
+ return out
63
+
64
+
65
+ class PreActResNet(nn.Module):
66
+ def __init__(self, block, num_blocks, num_classes=10):
67
+ super(PreActResNet, self).__init__()
68
+ self.in_planes = 64
69
+
70
+ self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)
71
+ self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1)
72
+ self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2)
73
+ self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2)
74
+ self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2)
75
+ self.linear = nn.Linear(512*block.expansion, num_classes)
76
+
77
+ def _make_layer(self, block, planes, num_blocks, stride):
78
+ strides = [stride] + [1]*(num_blocks-1)
79
+ layers = []
80
+ for stride in strides:
81
+ layers.append(block(self.in_planes, planes, stride))
82
+ self.in_planes = planes * block.expansion
83
+ return nn.Sequential(*layers)
84
+
85
+ def forward(self, x):
86
+ out = self.conv1(x)
87
+ out = self.layer1(out)
88
+ out = self.layer2(out)
89
+ out = self.layer3(out)
90
+ out = self.layer4(out)
91
+ out = F.avg_pool2d(out, 4)
92
+ out = out.view(out.size(0), -1)
93
+ out = self.linear(out)
94
+ return out
95
+
96
+
97
+ def PreActResNet18():
98
+ return PreActResNet(PreActBlock, [2,2,2,2])
99
+
100
+ def PreActResNet34():
101
+ return PreActResNet(PreActBlock, [3,4,6,3])
102
+
103
+ def PreActResNet50():
104
+ return PreActResNet(PreActBottleneck, [3,4,6,3])
105
+
106
+ def PreActResNet101():
107
+ return PreActResNet(PreActBottleneck, [3,4,23,3])
108
+
109
+ def PreActResNet152():
110
+ return PreActResNet(PreActBottleneck, [3,8,36,3])
111
+
112
+
113
+ def test():
114
+ net = PreActResNet18()
115
+ y = net((torch.randn(1,3,32,32)))
116
+ print(y.size())
117
+
118
+ # test()
models/regnet.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''RegNet in PyTorch.
2
+
3
+ Paper: "Designing Network Design Spaces".
4
+
5
+ Reference: https://github.com/keras-team/keras-applications/blob/master/keras_applications/efficientnet.py
6
+ '''
7
+ import torch
8
+ import torch.nn as nn
9
+ import torch.nn.functional as F
10
+
11
+
12
+ class SE(nn.Module):
13
+ '''Squeeze-and-Excitation block.'''
14
+
15
+ def __init__(self, in_planes, se_planes):
16
+ super(SE, self).__init__()
17
+ self.se1 = nn.Conv2d(in_planes, se_planes, kernel_size=1, bias=True)
18
+ self.se2 = nn.Conv2d(se_planes, in_planes, kernel_size=1, bias=True)
19
+
20
+ def forward(self, x):
21
+ out = F.adaptive_avg_pool2d(x, (1, 1))
22
+ out = F.relu(self.se1(out))
23
+ out = self.se2(out).sigmoid()
24
+ out = x * out
25
+ return out
26
+
27
+
28
+ class Block(nn.Module):
29
+ def __init__(self, w_in, w_out, stride, group_width, bottleneck_ratio, se_ratio):
30
+ super(Block, self).__init__()
31
+ # 1x1
32
+ w_b = int(round(w_out * bottleneck_ratio))
33
+ self.conv1 = nn.Conv2d(w_in, w_b, kernel_size=1, bias=False)
34
+ self.bn1 = nn.BatchNorm2d(w_b)
35
+ # 3x3
36
+ num_groups = w_b // group_width
37
+ self.conv2 = nn.Conv2d(w_b, w_b, kernel_size=3,
38
+ stride=stride, padding=1, groups=num_groups, bias=False)
39
+ self.bn2 = nn.BatchNorm2d(w_b)
40
+ # se
41
+ self.with_se = se_ratio > 0
42
+ if self.with_se:
43
+ w_se = int(round(w_in * se_ratio))
44
+ self.se = SE(w_b, w_se)
45
+ # 1x1
46
+ self.conv3 = nn.Conv2d(w_b, w_out, kernel_size=1, bias=False)
47
+ self.bn3 = nn.BatchNorm2d(w_out)
48
+
49
+ self.shortcut = nn.Sequential()
50
+ if stride != 1 or w_in != w_out:
51
+ self.shortcut = nn.Sequential(
52
+ nn.Conv2d(w_in, w_out,
53
+ kernel_size=1, stride=stride, bias=False),
54
+ nn.BatchNorm2d(w_out)
55
+ )
56
+
57
+ def forward(self, x):
58
+ out = F.relu(self.bn1(self.conv1(x)))
59
+ out = F.relu(self.bn2(self.conv2(out)))
60
+ if self.with_se:
61
+ out = self.se(out)
62
+ out = self.bn3(self.conv3(out))
63
+ out += self.shortcut(x)
64
+ out = F.relu(out)
65
+ return out
66
+
67
+
68
+ class RegNet(nn.Module):
69
+ def __init__(self, cfg, num_classes=10):
70
+ super(RegNet, self).__init__()
71
+ self.cfg = cfg
72
+ self.in_planes = 64
73
+ self.conv1 = nn.Conv2d(3, 64, kernel_size=3,
74
+ stride=1, padding=1, bias=False)
75
+ self.bn1 = nn.BatchNorm2d(64)
76
+ self.layer1 = self._make_layer(0)
77
+ self.layer2 = self._make_layer(1)
78
+ self.layer3 = self._make_layer(2)
79
+ self.layer4 = self._make_layer(3)
80
+ self.linear = nn.Linear(self.cfg['widths'][-1], num_classes)
81
+
82
+ def _make_layer(self, idx):
83
+ depth = self.cfg['depths'][idx]
84
+ width = self.cfg['widths'][idx]
85
+ stride = self.cfg['strides'][idx]
86
+ group_width = self.cfg['group_width']
87
+ bottleneck_ratio = self.cfg['bottleneck_ratio']
88
+ se_ratio = self.cfg['se_ratio']
89
+
90
+ layers = []
91
+ for i in range(depth):
92
+ s = stride if i == 0 else 1
93
+ layers.append(Block(self.in_planes, width,
94
+ s, group_width, bottleneck_ratio, se_ratio))
95
+ self.in_planes = width
96
+ return nn.Sequential(*layers)
97
+
98
+ def forward(self, x):
99
+ out = F.relu(self.bn1(self.conv1(x)))
100
+ out = self.layer1(out)
101
+ out = self.layer2(out)
102
+ out = self.layer3(out)
103
+ out = self.layer4(out)
104
+ out = F.adaptive_avg_pool2d(out, (1, 1))
105
+ out = out.view(out.size(0), -1)
106
+ out = self.linear(out)
107
+ return out
108
+
109
+
110
+ def RegNetX_200MF():
111
+ cfg = {
112
+ 'depths': [1, 1, 4, 7],
113
+ 'widths': [24, 56, 152, 368],
114
+ 'strides': [1, 1, 2, 2],
115
+ 'group_width': 8,
116
+ 'bottleneck_ratio': 1,
117
+ 'se_ratio': 0,
118
+ }
119
+ return RegNet(cfg)
120
+
121
+
122
+ def RegNetX_400MF():
123
+ cfg = {
124
+ 'depths': [1, 2, 7, 12],
125
+ 'widths': [32, 64, 160, 384],
126
+ 'strides': [1, 1, 2, 2],
127
+ 'group_width': 16,
128
+ 'bottleneck_ratio': 1,
129
+ 'se_ratio': 0,
130
+ }
131
+ return RegNet(cfg)
132
+
133
+
134
+ def RegNetY_400MF():
135
+ cfg = {
136
+ 'depths': [1, 2, 7, 12],
137
+ 'widths': [32, 64, 160, 384],
138
+ 'strides': [1, 1, 2, 2],
139
+ 'group_width': 16,
140
+ 'bottleneck_ratio': 1,
141
+ 'se_ratio': 0.25,
142
+ }
143
+ return RegNet(cfg)
144
+
145
+
146
+ def test():
147
+ net = RegNetX_200MF()
148
+ print(net)
149
+ x = torch.randn(2, 3, 32, 32)
150
+ y = net(x)
151
+ print(y.shape)
152
+
153
+
154
+ if __name__ == '__main__':
155
+ test()
models/resnet.py ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''ResNet in PyTorch.
2
+
3
+ For Pre-activation ResNet, see 'preact_resnet.py'.
4
+
5
+ Reference:
6
+ [1] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun
7
+ Deep Residual Learning for Image Recognition. arXiv:1512.03385
8
+ '''
9
+ import torch
10
+ import torch.nn as nn
11
+ import torch.nn.functional as F
12
+
13
+
14
+ class BasicBlock(nn.Module):
15
+ expansion = 1
16
+
17
+ def __init__(self, in_planes, planes, stride=1):
18
+ super(BasicBlock, self).__init__()
19
+ self.conv1 = nn.Conv2d(
20
+ in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
21
+ self.bn1 = nn.BatchNorm2d(planes)
22
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3,
23
+ stride=1, padding=1, bias=False)
24
+ self.bn2 = nn.BatchNorm2d(planes)
25
+
26
+ self.shortcut = nn.Sequential()
27
+ if stride != 1 or in_planes != self.expansion*planes:
28
+ self.shortcut = nn.Sequential(
29
+ nn.Conv2d(in_planes, self.expansion*planes,
30
+ kernel_size=1, stride=stride, bias=False),
31
+ nn.BatchNorm2d(self.expansion*planes)
32
+ )
33
+
34
+ def forward(self, x):
35
+ out = F.relu(self.bn1(self.conv1(x)))
36
+ out = self.bn2(self.conv2(out))
37
+ out += self.shortcut(x)
38
+ out = F.relu(out)
39
+ return out
40
+
41
+
42
+ class Bottleneck(nn.Module):
43
+ expansion = 4
44
+
45
+ def __init__(self, in_planes, planes, stride=1):
46
+ super(Bottleneck, self).__init__()
47
+ self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False)
48
+ self.bn1 = nn.BatchNorm2d(planes)
49
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3,
50
+ stride=stride, padding=1, bias=False)
51
+ self.bn2 = nn.BatchNorm2d(planes)
52
+ self.conv3 = nn.Conv2d(planes, self.expansion *
53
+ planes, kernel_size=1, bias=False)
54
+ self.bn3 = nn.BatchNorm2d(self.expansion*planes)
55
+
56
+ self.shortcut = nn.Sequential()
57
+ if stride != 1 or in_planes != self.expansion*planes:
58
+ self.shortcut = nn.Sequential(
59
+ nn.Conv2d(in_planes, self.expansion*planes,
60
+ kernel_size=1, stride=stride, bias=False),
61
+ nn.BatchNorm2d(self.expansion*planes)
62
+ )
63
+
64
+ def forward(self, x):
65
+ out = F.relu(self.bn1(self.conv1(x)))
66
+ out = F.relu(self.bn2(self.conv2(out)))
67
+ out = self.bn3(self.conv3(out))
68
+ out += self.shortcut(x)
69
+ out = F.relu(out)
70
+ return out
71
+
72
+
73
+ class ResNet(nn.Module):
74
+ def __init__(self, block, num_blocks, num_classes=10):
75
+ super(ResNet, self).__init__()
76
+ self.in_planes = 64
77
+
78
+ self.conv1 = nn.Conv2d(3, 64, kernel_size=3,
79
+ stride=1, padding=1, bias=False)
80
+ self.bn1 = nn.BatchNorm2d(64)
81
+ self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1)
82
+ self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2)
83
+ self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2)
84
+ self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2)
85
+ self.linear = nn.Linear(512*block.expansion, num_classes)
86
+
87
+ def _make_layer(self, block, planes, num_blocks, stride):
88
+ strides = [stride] + [1]*(num_blocks-1)
89
+ layers = []
90
+ for stride in strides:
91
+ layers.append(block(self.in_planes, planes, stride))
92
+ self.in_planes = planes * block.expansion
93
+ return nn.Sequential(*layers)
94
+
95
+ def forward(self, x):
96
+ out = F.relu(self.bn1(self.conv1(x)))
97
+ out = self.layer1(out)
98
+ out = self.layer2(out)
99
+ out = self.layer3(out)
100
+ out = self.layer4(out)
101
+ out = F.avg_pool2d(out, 4)
102
+ out = out.view(out.size(0), -1)
103
+ out = self.linear(out)
104
+ return out
105
+
106
+
107
+ def ResNet18():
108
+ return ResNet(BasicBlock, [2, 2, 2, 2])
109
+
110
+
111
+ def ResNet34():
112
+ return ResNet(BasicBlock, [3, 4, 6, 3])
113
+
114
+
115
+ def ResNet50():
116
+ return ResNet(Bottleneck, [3, 4, 6, 3])
117
+
118
+
119
+ def ResNet101():
120
+ return ResNet(Bottleneck, [3, 4, 23, 3])
121
+
122
+
123
+ def ResNet152():
124
+ return ResNet(Bottleneck, [3, 8, 36, 3])
125
+
126
+
127
+ def test():
128
+ net = ResNet18()
129
+ y = net(torch.randn(1, 3, 32, 32))
130
+ print(y.size())
131
+
132
+ # test()
models/resnext.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''ResNeXt in PyTorch.
2
+
3
+ See the paper "Aggregated Residual Transformations for Deep Neural Networks" for more details.
4
+ '''
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+
9
+
10
+ class Block(nn.Module):
11
+ '''Grouped convolution block.'''
12
+ expansion = 2
13
+
14
+ def __init__(self, in_planes, cardinality=32, bottleneck_width=4, stride=1):
15
+ super(Block, self).__init__()
16
+ group_width = cardinality * bottleneck_width
17
+ self.conv1 = nn.Conv2d(in_planes, group_width, kernel_size=1, bias=False)
18
+ self.bn1 = nn.BatchNorm2d(group_width)
19
+ self.conv2 = nn.Conv2d(group_width, group_width, kernel_size=3, stride=stride, padding=1, groups=cardinality, bias=False)
20
+ self.bn2 = nn.BatchNorm2d(group_width)
21
+ self.conv3 = nn.Conv2d(group_width, self.expansion*group_width, kernel_size=1, bias=False)
22
+ self.bn3 = nn.BatchNorm2d(self.expansion*group_width)
23
+
24
+ self.shortcut = nn.Sequential()
25
+ if stride != 1 or in_planes != self.expansion*group_width:
26
+ self.shortcut = nn.Sequential(
27
+ nn.Conv2d(in_planes, self.expansion*group_width, kernel_size=1, stride=stride, bias=False),
28
+ nn.BatchNorm2d(self.expansion*group_width)
29
+ )
30
+
31
+ def forward(self, x):
32
+ out = F.relu(self.bn1(self.conv1(x)))
33
+ out = F.relu(self.bn2(self.conv2(out)))
34
+ out = self.bn3(self.conv3(out))
35
+ out += self.shortcut(x)
36
+ out = F.relu(out)
37
+ return out
38
+
39
+
40
+ class ResNeXt(nn.Module):
41
+ def __init__(self, num_blocks, cardinality, bottleneck_width, num_classes=10):
42
+ super(ResNeXt, self).__init__()
43
+ self.cardinality = cardinality
44
+ self.bottleneck_width = bottleneck_width
45
+ self.in_planes = 64
46
+
47
+ self.conv1 = nn.Conv2d(3, 64, kernel_size=1, bias=False)
48
+ self.bn1 = nn.BatchNorm2d(64)
49
+ self.layer1 = self._make_layer(num_blocks[0], 1)
50
+ self.layer2 = self._make_layer(num_blocks[1], 2)
51
+ self.layer3 = self._make_layer(num_blocks[2], 2)
52
+ # self.layer4 = self._make_layer(num_blocks[3], 2)
53
+ self.linear = nn.Linear(cardinality*bottleneck_width*8, num_classes)
54
+
55
+ def _make_layer(self, num_blocks, stride):
56
+ strides = [stride] + [1]*(num_blocks-1)
57
+ layers = []
58
+ for stride in strides:
59
+ layers.append(Block(self.in_planes, self.cardinality, self.bottleneck_width, stride))
60
+ self.in_planes = Block.expansion * self.cardinality * self.bottleneck_width
61
+ # Increase bottleneck_width by 2 after each stage.
62
+ self.bottleneck_width *= 2
63
+ return nn.Sequential(*layers)
64
+
65
+ def forward(self, x):
66
+ out = F.relu(self.bn1(self.conv1(x)))
67
+ out = self.layer1(out)
68
+ out = self.layer2(out)
69
+ out = self.layer3(out)
70
+ # out = self.layer4(out)
71
+ out = F.avg_pool2d(out, 8)
72
+ out = out.view(out.size(0), -1)
73
+ out = self.linear(out)
74
+ return out
75
+
76
+
77
+ def ResNeXt29_2x64d():
78
+ return ResNeXt(num_blocks=[3,3,3], cardinality=2, bottleneck_width=64)
79
+
80
+ def ResNeXt29_4x64d():
81
+ return ResNeXt(num_blocks=[3,3,3], cardinality=4, bottleneck_width=64)
82
+
83
+ def ResNeXt29_8x64d():
84
+ return ResNeXt(num_blocks=[3,3,3], cardinality=8, bottleneck_width=64)
85
+
86
+ def ResNeXt29_32x4d():
87
+ return ResNeXt(num_blocks=[3,3,3], cardinality=32, bottleneck_width=4)
88
+
89
+ def test_resnext():
90
+ net = ResNeXt29_2x64d()
91
+ x = torch.randn(1,3,32,32)
92
+ y = net(x)
93
+ print(y.size())
94
+
95
+ # test_resnext()
models/senet.py ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''SENet in PyTorch.
2
+
3
+ SENet is the winner of ImageNet-2017. The paper is not released yet.
4
+ '''
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+
9
+
10
+ class BasicBlock(nn.Module):
11
+ def __init__(self, in_planes, planes, stride=1):
12
+ super(BasicBlock, self).__init__()
13
+ self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
14
+ self.bn1 = nn.BatchNorm2d(planes)
15
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False)
16
+ self.bn2 = nn.BatchNorm2d(planes)
17
+
18
+ self.shortcut = nn.Sequential()
19
+ if stride != 1 or in_planes != planes:
20
+ self.shortcut = nn.Sequential(
21
+ nn.Conv2d(in_planes, planes, kernel_size=1, stride=stride, bias=False),
22
+ nn.BatchNorm2d(planes)
23
+ )
24
+
25
+ # SE layers
26
+ self.fc1 = nn.Conv2d(planes, planes//16, kernel_size=1) # Use nn.Conv2d instead of nn.Linear
27
+ self.fc2 = nn.Conv2d(planes//16, planes, kernel_size=1)
28
+
29
+ def forward(self, x):
30
+ out = F.relu(self.bn1(self.conv1(x)))
31
+ out = self.bn2(self.conv2(out))
32
+
33
+ # Squeeze
34
+ w = F.avg_pool2d(out, out.size(2))
35
+ w = F.relu(self.fc1(w))
36
+ w = F.sigmoid(self.fc2(w))
37
+ # Excitation
38
+ out = out * w # New broadcasting feature from v0.2!
39
+
40
+ out += self.shortcut(x)
41
+ out = F.relu(out)
42
+ return out
43
+
44
+
45
+ class PreActBlock(nn.Module):
46
+ def __init__(self, in_planes, planes, stride=1):
47
+ super(PreActBlock, self).__init__()
48
+ self.bn1 = nn.BatchNorm2d(in_planes)
49
+ self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
50
+ self.bn2 = nn.BatchNorm2d(planes)
51
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False)
52
+
53
+ if stride != 1 or in_planes != planes:
54
+ self.shortcut = nn.Sequential(
55
+ nn.Conv2d(in_planes, planes, kernel_size=1, stride=stride, bias=False)
56
+ )
57
+
58
+ # SE layers
59
+ self.fc1 = nn.Conv2d(planes, planes//16, kernel_size=1)
60
+ self.fc2 = nn.Conv2d(planes//16, planes, kernel_size=1)
61
+
62
+ def forward(self, x):
63
+ out = F.relu(self.bn1(x))
64
+ shortcut = self.shortcut(out) if hasattr(self, 'shortcut') else x
65
+ out = self.conv1(out)
66
+ out = self.conv2(F.relu(self.bn2(out)))
67
+
68
+ # Squeeze
69
+ w = F.avg_pool2d(out, out.size(2))
70
+ w = F.relu(self.fc1(w))
71
+ w = F.sigmoid(self.fc2(w))
72
+ # Excitation
73
+ out = out * w
74
+
75
+ out += shortcut
76
+ return out
77
+
78
+
79
+ class SENet(nn.Module):
80
+ def __init__(self, block, num_blocks, num_classes=10):
81
+ super(SENet, self).__init__()
82
+ self.in_planes = 64
83
+
84
+ self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)
85
+ self.bn1 = nn.BatchNorm2d(64)
86
+ self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1)
87
+ self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2)
88
+ self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2)
89
+ self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2)
90
+ self.linear = nn.Linear(512, num_classes)
91
+
92
+ def _make_layer(self, block, planes, num_blocks, stride):
93
+ strides = [stride] + [1]*(num_blocks-1)
94
+ layers = []
95
+ for stride in strides:
96
+ layers.append(block(self.in_planes, planes, stride))
97
+ self.in_planes = planes
98
+ return nn.Sequential(*layers)
99
+
100
+ def forward(self, x):
101
+ out = F.relu(self.bn1(self.conv1(x)))
102
+ out = self.layer1(out)
103
+ out = self.layer2(out)
104
+ out = self.layer3(out)
105
+ out = self.layer4(out)
106
+ out = F.avg_pool2d(out, 4)
107
+ out = out.view(out.size(0), -1)
108
+ out = self.linear(out)
109
+ return out
110
+
111
+
112
+ def SENet18():
113
+ return SENet(PreActBlock, [2,2,2,2])
114
+
115
+
116
+ def test():
117
+ net = SENet18()
118
+ y = net(torch.randn(1,3,32,32))
119
+ print(y.size())
120
+
121
+ # test()
models/shufflenet.py ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''ShuffleNet in PyTorch.
2
+
3
+ See the paper "ShuffleNet: An Extremely Efficient Convolutional Neural Network for Mobile Devices" for more details.
4
+ '''
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+
9
+
10
+ class ShuffleBlock(nn.Module):
11
+ def __init__(self, groups):
12
+ super(ShuffleBlock, self).__init__()
13
+ self.groups = groups
14
+
15
+ def forward(self, x):
16
+ '''Channel shuffle: [N,C,H,W] -> [N,g,C/g,H,W] -> [N,C/g,g,H,w] -> [N,C,H,W]'''
17
+ N,C,H,W = x.size()
18
+ g = self.groups
19
+ return x.view(N,g,C//g,H,W).permute(0,2,1,3,4).reshape(N,C,H,W)
20
+
21
+
22
+ class Bottleneck(nn.Module):
23
+ def __init__(self, in_planes, out_planes, stride, groups):
24
+ super(Bottleneck, self).__init__()
25
+ self.stride = stride
26
+
27
+ mid_planes = out_planes/4
28
+ g = 1 if in_planes==24 else groups
29
+ self.conv1 = nn.Conv2d(in_planes, mid_planes, kernel_size=1, groups=g, bias=False)
30
+ self.bn1 = nn.BatchNorm2d(mid_planes)
31
+ self.shuffle1 = ShuffleBlock(groups=g)
32
+ self.conv2 = nn.Conv2d(mid_planes, mid_planes, kernel_size=3, stride=stride, padding=1, groups=mid_planes, bias=False)
33
+ self.bn2 = nn.BatchNorm2d(mid_planes)
34
+ self.conv3 = nn.Conv2d(mid_planes, out_planes, kernel_size=1, groups=groups, bias=False)
35
+ self.bn3 = nn.BatchNorm2d(out_planes)
36
+
37
+ self.shortcut = nn.Sequential()
38
+ if stride == 2:
39
+ self.shortcut = nn.Sequential(nn.AvgPool2d(3, stride=2, padding=1))
40
+
41
+ def forward(self, x):
42
+ out = F.relu(self.bn1(self.conv1(x)))
43
+ out = self.shuffle1(out)
44
+ out = F.relu(self.bn2(self.conv2(out)))
45
+ out = self.bn3(self.conv3(out))
46
+ res = self.shortcut(x)
47
+ out = F.relu(torch.cat([out,res], 1)) if self.stride==2 else F.relu(out+res)
48
+ return out
49
+
50
+
51
+ class ShuffleNet(nn.Module):
52
+ def __init__(self, cfg):
53
+ super(ShuffleNet, self).__init__()
54
+ out_planes = cfg['out_planes']
55
+ num_blocks = cfg['num_blocks']
56
+ groups = cfg['groups']
57
+
58
+ self.conv1 = nn.Conv2d(3, 24, kernel_size=1, bias=False)
59
+ self.bn1 = nn.BatchNorm2d(24)
60
+ self.in_planes = 24
61
+ self.layer1 = self._make_layer(out_planes[0], num_blocks[0], groups)
62
+ self.layer2 = self._make_layer(out_planes[1], num_blocks[1], groups)
63
+ self.layer3 = self._make_layer(out_planes[2], num_blocks[2], groups)
64
+ self.linear = nn.Linear(out_planes[2], 10)
65
+
66
+ def _make_layer(self, out_planes, num_blocks, groups):
67
+ layers = []
68
+ for i in range(num_blocks):
69
+ stride = 2 if i == 0 else 1
70
+ cat_planes = self.in_planes if i == 0 else 0
71
+ layers.append(Bottleneck(self.in_planes, out_planes-cat_planes, stride=stride, groups=groups))
72
+ self.in_planes = out_planes
73
+ return nn.Sequential(*layers)
74
+
75
+ def forward(self, x):
76
+ out = F.relu(self.bn1(self.conv1(x)))
77
+ out = self.layer1(out)
78
+ out = self.layer2(out)
79
+ out = self.layer3(out)
80
+ out = F.avg_pool2d(out, 4)
81
+ out = out.view(out.size(0), -1)
82
+ out = self.linear(out)
83
+ return out
84
+
85
+
86
+ def ShuffleNetG2():
87
+ cfg = {
88
+ 'out_planes': [200,400,800],
89
+ 'num_blocks': [4,8,4],
90
+ 'groups': 2
91
+ }
92
+ return ShuffleNet(cfg)
93
+
94
+ def ShuffleNetG3():
95
+ cfg = {
96
+ 'out_planes': [240,480,960],
97
+ 'num_blocks': [4,8,4],
98
+ 'groups': 3
99
+ }
100
+ return ShuffleNet(cfg)
101
+
102
+
103
+ def test():
104
+ net = ShuffleNetG2()
105
+ x = torch.randn(1,3,32,32)
106
+ y = net(x)
107
+ print(y)
108
+
109
+ # test()
models/shufflenetv2.py ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''ShuffleNetV2 in PyTorch.
2
+
3
+ See the paper "ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" for more details.
4
+ '''
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+
9
+
10
+ class ShuffleBlock(nn.Module):
11
+ def __init__(self, groups=2):
12
+ super(ShuffleBlock, self).__init__()
13
+ self.groups = groups
14
+
15
+ def forward(self, x):
16
+ '''Channel shuffle: [N,C,H,W] -> [N,g,C/g,H,W] -> [N,C/g,g,H,w] -> [N,C,H,W]'''
17
+ N, C, H, W = x.size()
18
+ g = self.groups
19
+ return x.view(N, g, C//g, H, W).permute(0, 2, 1, 3, 4).reshape(N, C, H, W)
20
+
21
+
22
+ class SplitBlock(nn.Module):
23
+ def __init__(self, ratio):
24
+ super(SplitBlock, self).__init__()
25
+ self.ratio = ratio
26
+
27
+ def forward(self, x):
28
+ c = int(x.size(1) * self.ratio)
29
+ return x[:, :c, :, :], x[:, c:, :, :]
30
+
31
+
32
+ class BasicBlock(nn.Module):
33
+ def __init__(self, in_channels, split_ratio=0.5):
34
+ super(BasicBlock, self).__init__()
35
+ self.split = SplitBlock(split_ratio)
36
+ in_channels = int(in_channels * split_ratio)
37
+ self.conv1 = nn.Conv2d(in_channels, in_channels,
38
+ kernel_size=1, bias=False)
39
+ self.bn1 = nn.BatchNorm2d(in_channels)
40
+ self.conv2 = nn.Conv2d(in_channels, in_channels,
41
+ kernel_size=3, stride=1, padding=1, groups=in_channels, bias=False)
42
+ self.bn2 = nn.BatchNorm2d(in_channels)
43
+ self.conv3 = nn.Conv2d(in_channels, in_channels,
44
+ kernel_size=1, bias=False)
45
+ self.bn3 = nn.BatchNorm2d(in_channels)
46
+ self.shuffle = ShuffleBlock()
47
+
48
+ def forward(self, x):
49
+ x1, x2 = self.split(x)
50
+ out = F.relu(self.bn1(self.conv1(x2)))
51
+ out = self.bn2(self.conv2(out))
52
+ out = F.relu(self.bn3(self.conv3(out)))
53
+ out = torch.cat([x1, out], 1)
54
+ out = self.shuffle(out)
55
+ return out
56
+
57
+
58
+ class DownBlock(nn.Module):
59
+ def __init__(self, in_channels, out_channels):
60
+ super(DownBlock, self).__init__()
61
+ mid_channels = out_channels // 2
62
+ # left
63
+ self.conv1 = nn.Conv2d(in_channels, in_channels,
64
+ kernel_size=3, stride=2, padding=1, groups=in_channels, bias=False)
65
+ self.bn1 = nn.BatchNorm2d(in_channels)
66
+ self.conv2 = nn.Conv2d(in_channels, mid_channels,
67
+ kernel_size=1, bias=False)
68
+ self.bn2 = nn.BatchNorm2d(mid_channels)
69
+ # right
70
+ self.conv3 = nn.Conv2d(in_channels, mid_channels,
71
+ kernel_size=1, bias=False)
72
+ self.bn3 = nn.BatchNorm2d(mid_channels)
73
+ self.conv4 = nn.Conv2d(mid_channels, mid_channels,
74
+ kernel_size=3, stride=2, padding=1, groups=mid_channels, bias=False)
75
+ self.bn4 = nn.BatchNorm2d(mid_channels)
76
+ self.conv5 = nn.Conv2d(mid_channels, mid_channels,
77
+ kernel_size=1, bias=False)
78
+ self.bn5 = nn.BatchNorm2d(mid_channels)
79
+
80
+ self.shuffle = ShuffleBlock()
81
+
82
+ def forward(self, x):
83
+ # left
84
+ out1 = self.bn1(self.conv1(x))
85
+ out1 = F.relu(self.bn2(self.conv2(out1)))
86
+ # right
87
+ out2 = F.relu(self.bn3(self.conv3(x)))
88
+ out2 = self.bn4(self.conv4(out2))
89
+ out2 = F.relu(self.bn5(self.conv5(out2)))
90
+ # concat
91
+ out = torch.cat([out1, out2], 1)
92
+ out = self.shuffle(out)
93
+ return out
94
+
95
+
96
+ class ShuffleNetV2(nn.Module):
97
+ def __init__(self, net_size):
98
+ super(ShuffleNetV2, self).__init__()
99
+ out_channels = configs[net_size]['out_channels']
100
+ num_blocks = configs[net_size]['num_blocks']
101
+
102
+ self.conv1 = nn.Conv2d(3, 24, kernel_size=3,
103
+ stride=1, padding=1, bias=False)
104
+ self.bn1 = nn.BatchNorm2d(24)
105
+ self.in_channels = 24
106
+ self.layer1 = self._make_layer(out_channels[0], num_blocks[0])
107
+ self.layer2 = self._make_layer(out_channels[1], num_blocks[1])
108
+ self.layer3 = self._make_layer(out_channels[2], num_blocks[2])
109
+ self.conv2 = nn.Conv2d(out_channels[2], out_channels[3],
110
+ kernel_size=1, stride=1, padding=0, bias=False)
111
+ self.bn2 = nn.BatchNorm2d(out_channels[3])
112
+ self.linear = nn.Linear(out_channels[3], 10)
113
+
114
+ def _make_layer(self, out_channels, num_blocks):
115
+ layers = [DownBlock(self.in_channels, out_channels)]
116
+ for i in range(num_blocks):
117
+ layers.append(BasicBlock(out_channels))
118
+ self.in_channels = out_channels
119
+ return nn.Sequential(*layers)
120
+
121
+ def forward(self, x):
122
+ out = F.relu(self.bn1(self.conv1(x)))
123
+ # out = F.max_pool2d(out, 3, stride=2, padding=1)
124
+ out = self.layer1(out)
125
+ out = self.layer2(out)
126
+ out = self.layer3(out)
127
+ out = F.relu(self.bn2(self.conv2(out)))
128
+ out = F.avg_pool2d(out, 4)
129
+ out = out.view(out.size(0), -1)
130
+ out = self.linear(out)
131
+ return out
132
+
133
+
134
+ configs = {
135
+ 0.5: {
136
+ 'out_channels': (48, 96, 192, 1024),
137
+ 'num_blocks': (3, 7, 3)
138
+ },
139
+
140
+ 1: {
141
+ 'out_channels': (116, 232, 464, 1024),
142
+ 'num_blocks': (3, 7, 3)
143
+ },
144
+ 1.5: {
145
+ 'out_channels': (176, 352, 704, 1024),
146
+ 'num_blocks': (3, 7, 3)
147
+ },
148
+ 2: {
149
+ 'out_channels': (224, 488, 976, 2048),
150
+ 'num_blocks': (3, 7, 3)
151
+ }
152
+ }
153
+
154
+
155
+ def test():
156
+ net = ShuffleNetV2(net_size=0.5)
157
+ x = torch.randn(3, 3, 32, 32)
158
+ y = net(x)
159
+ print(y.shape)
160
+
161
+
162
+ # test()
models/vgg.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''VGG11/13/16/19 in Pytorch.'''
2
+ import torch
3
+ import torch.nn as nn
4
+
5
+
6
+ cfg = {
7
+ 'VGG11': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
8
+ 'VGG13': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
9
+ 'VGG16': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'],
10
+ 'VGG19': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'],
11
+ }
12
+
13
+
14
+ class VGG(nn.Module):
15
+ def __init__(self, vgg_name):
16
+ super(VGG, self).__init__()
17
+ self.features = self._make_layers(cfg[vgg_name])
18
+ self.classifier = nn.Linear(512, 10)
19
+
20
+ def forward(self, x):
21
+ out = self.features(x)
22
+ out = out.view(out.size(0), -1)
23
+ out = self.classifier(out)
24
+ return out
25
+
26
+ def _make_layers(self, cfg):
27
+ layers = []
28
+ in_channels = 3
29
+ for x in cfg:
30
+ if x == 'M':
31
+ layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
32
+ else:
33
+ layers += [nn.Conv2d(in_channels, x, kernel_size=3, padding=1),
34
+ nn.BatchNorm2d(x),
35
+ nn.ReLU(inplace=True)]
36
+ in_channels = x
37
+ layers += [nn.AvgPool2d(kernel_size=1, stride=1)]
38
+ return nn.Sequential(*layers)
39
+
40
+
41
+ def test():
42
+ net = VGG('VGG11')
43
+ x = torch.randn(2,3,32,32)
44
+ y = net(x)
45
+ print(y.size())
46
+
47
+ # test()
requirements.txt ADDED
Binary file (8.01 kB). View file
 
utils.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''Some helper functions for PyTorch, including:
2
+ - get_mean_and_std: calculate the mean and std value of dataset.
3
+ - msr_init: net parameter initialization.
4
+ - progress_bar: progress bar mimic xlua.progress.
5
+ '''
6
+ import os
7
+ import sys
8
+ import time
9
+ import math
10
+
11
+ import torch
12
+ import torch.nn as nn
13
+ import torch.nn.init as init
14
+
15
+
16
+ def get_mean_and_std(dataset):
17
+ '''Compute the mean and std value of dataset.'''
18
+ dataloader = torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=True, num_workers=2)
19
+ mean = torch.zeros(3)
20
+ std = torch.zeros(3)
21
+ print('==> Computing mean and std..')
22
+ for inputs, targets in dataloader:
23
+ for i in range(3):
24
+ mean[i] += inputs[:,i,:,:].mean()
25
+ std[i] += inputs[:,i,:,:].std()
26
+ mean.div_(len(dataset))
27
+ std.div_(len(dataset))
28
+ return mean, std
29
+
30
+ def init_params(net):
31
+ '''Init layer parameters.'''
32
+ for m in net.modules():
33
+ if isinstance(m, nn.Conv2d):
34
+ init.kaiming_normal(m.weight, mode='fan_out')
35
+ if m.bias:
36
+ init.constant(m.bias, 0)
37
+ elif isinstance(m, nn.BatchNorm2d):
38
+ init.constant(m.weight, 1)
39
+ init.constant(m.bias, 0)
40
+ elif isinstance(m, nn.Linear):
41
+ init.normal(m.weight, std=1e-3)
42
+ if m.bias:
43
+ init.constant(m.bias, 0)
44
+
45
+
46
+ term_width = os.popen('stty size', 'r').read().split()
47
+ # term_width = int(term_width)
48
+
49
+ print(f"Term Width: {(term_width)}")
50
+
51
+ TOTAL_BAR_LENGTH = 65.
52
+ last_time = time.time()
53
+ begin_time = last_time
54
+ def progress_bar(current, total, msg=None):
55
+ global last_time, begin_time
56
+ if current == 0:
57
+ begin_time = time.time() # Reset for new bar.
58
+
59
+ cur_len = int(TOTAL_BAR_LENGTH*current/total)
60
+ rest_len = int(TOTAL_BAR_LENGTH - cur_len) - 1
61
+
62
+ sys.stdout.write(' [')
63
+ for i in range(cur_len):
64
+ sys.stdout.write('=')
65
+ sys.stdout.write('>')
66
+ for i in range(rest_len):
67
+ sys.stdout.write('.')
68
+ sys.stdout.write(']')
69
+
70
+ cur_time = time.time()
71
+ step_time = cur_time - last_time
72
+ last_time = cur_time
73
+ tot_time = cur_time - begin_time
74
+
75
+ L = []
76
+ L.append(' Step: %s' % format_time(step_time))
77
+ L.append(' | Tot: %s' % format_time(tot_time))
78
+ if msg:
79
+ L.append(' | ' + msg)
80
+
81
+ msg = ''.join(L)
82
+ sys.stdout.write(msg)
83
+ for i in range(term_width-int(TOTAL_BAR_LENGTH)-len(msg)-3):
84
+ sys.stdout.write(' ')
85
+
86
+ # Go back to the center of the bar.
87
+ for i in range(term_width-int(TOTAL_BAR_LENGTH/2)+2):
88
+ sys.stdout.write('\b')
89
+ sys.stdout.write(' %d/%d ' % (current+1, total))
90
+
91
+ if current < total-1:
92
+ sys.stdout.write('\r')
93
+ else:
94
+ sys.stdout.write('\n')
95
+ sys.stdout.flush()
96
+
97
+ def format_time(seconds):
98
+ days = int(seconds / 3600/24)
99
+ seconds = seconds - days*3600*24
100
+ hours = int(seconds / 3600)
101
+ seconds = seconds - hours*3600
102
+ minutes = int(seconds / 60)
103
+ seconds = seconds - minutes*60
104
+ secondsf = int(seconds)
105
+ seconds = seconds - secondsf
106
+ millis = int(seconds*1000)
107
+
108
+ f = ''
109
+ i = 1
110
+ if days > 0:
111
+ f += str(days) + 'D'
112
+ i += 1
113
+ if hours > 0 and i <= 2:
114
+ f += str(hours) + 'h'
115
+ i += 1
116
+ if minutes > 0 and i <= 2:
117
+ f += str(minutes) + 'm'
118
+ i += 1
119
+ if secondsf > 0 and i <= 2:
120
+ f += str(secondsf) + 's'
121
+ i += 1
122
+ if millis > 0 and i <= 2:
123
+ f += str(millis) + 'ms'
124
+ i += 1
125
+ if f == '':
126
+ f = '0ms'
127
+ return f