ddecosmo commited on
Commit
d3315e0
·
verified ·
1 Parent(s): 471083d

Upload tanet_architecture.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. tanet_architecture.py +427 -0
tanet_architecture.py ADDED
@@ -0,0 +1,427 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import print_function, division
2
+ import os
3
+ import torch
4
+ import numpy as np
5
+ import math
6
+ import torch.optim as optim
7
+ import option
8
+ import nni
9
+ from torch import nn
10
+ from torch.utils.data import Dataset, DataLoader
11
+ from torch.nn import functional as F
12
+ from torchvision import models
13
+ from dataset import AVADataset
14
+ from util import EDMLoss, AverageMeter
15
+ from tensorboardX import SummaryWriter
16
+ from tqdm import tqdm
17
+ from scipy.stats import pearsonr
18
+ from scipy.stats import spearmanr
19
+ from sklearn.metrics import accuracy_score
20
+ from nni.utils import merge_parameter
21
+
22
+ def adjust_learning_rate(params, optimizer, epoch):
23
+ """Sets the learning rate to the initial LR
24
+ decayed by 10 every 30 epochs"""
25
+ lr = params.init_lr * (0.1 ** (epoch // 10))
26
+ for param_group in optimizer.param_groups:
27
+ param_group['lr'] = lr
28
+
29
+ def conv_bn(inp, oup, stride):
30
+ return nn.Sequential(
31
+ nn.Conv2d(inp, oup, 3, stride, 1, bias=False),
32
+ nn.BatchNorm2d(oup),
33
+ nn.ReLU(inplace=True)
34
+ )
35
+
36
+ def conv_1x1_bn(inp, oup):
37
+ return nn.Sequential(
38
+ nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
39
+ nn.BatchNorm2d(oup),
40
+ nn.ReLU(inplace=True)
41
+ )
42
+
43
+ class InvertedResidual(nn.Module):
44
+ def __init__(self, inp, oup, stride, expand_ratio):
45
+ super(InvertedResidual, self).__init__()
46
+ self.stride = stride
47
+ assert stride in [1, 2]
48
+
49
+ self.use_res_connect = self.stride == 1 and inp == oup
50
+
51
+ self.conv = nn.Sequential(
52
+ # pw
53
+ nn.Conv2d(inp, inp * expand_ratio, 1, 1, 0, bias=False),
54
+ nn.BatchNorm2d(inp * expand_ratio),
55
+ nn.ReLU6(inplace=True),
56
+ # dw
57
+ nn.Conv2d(inp * expand_ratio, inp * expand_ratio, 3, stride, 1, groups=inp * expand_ratio, bias=False),
58
+ nn.BatchNorm2d(inp * expand_ratio),
59
+ nn.ReLU6(inplace=True),
60
+ # pw-linear
61
+ nn.Conv2d(inp * expand_ratio, oup, 1, 1, 0, bias=False),
62
+ nn.BatchNorm2d(oup),
63
+ )
64
+
65
+ def forward(self, x):
66
+ if self.use_res_connect:
67
+ return x + self.conv(x)
68
+ else:
69
+ return self.conv(x)
70
+
71
+ class MobileNetV2(nn.Module):
72
+ def __init__(self, n_class=1000, input_size=224, width_mult=1.):
73
+ super(MobileNetV2, self).__init__()
74
+ # setting of inverted residual blocks
75
+ self.interverted_residual_setting = [
76
+ # t, c, n, s
77
+ [1, 16, 1, 1],
78
+ [6, 24, 2, 2],
79
+ [6, 32, 3, 2],
80
+ [6, 64, 4, 2],
81
+ [6, 96, 3, 1],
82
+ [6, 160, 3, 2],
83
+ [6, 320, 1, 1],
84
+ ]
85
+
86
+ # building first layer
87
+ assert input_size % 32 == 0
88
+ input_channel = int(32 * width_mult)
89
+ self.last_channel = int(1280 * width_mult) if width_mult > 1.0 else 1280
90
+ self.features = [conv_bn(3, input_channel, 2)]
91
+ # building inverted residual blocks
92
+ for t, c, n, s in self.interverted_residual_setting:
93
+ output_channel = int(c * width_mult)
94
+ for i in range(n):
95
+ if i == 0:
96
+ self.features.append(InvertedResidual(input_channel, output_channel, s, t))
97
+ else:
98
+ self.features.append(InvertedResidual(input_channel, output_channel, 1, t))
99
+ input_channel = output_channel
100
+ # building last several layers
101
+ self.features.append(conv_1x1_bn(input_channel, self.last_channel))
102
+ # self.features.append(nn.AvgPool2d(input_size // 32))
103
+ # make it nn.Sequential
104
+ self.features = nn.Sequential(*self.features)
105
+
106
+ # avgpool
107
+ self.avgpool = nn.AvgPool2d(input_size // 32)
108
+
109
+ # building classifier
110
+ self.classifier = nn.Sequential(
111
+ nn.Dropout(),
112
+ nn.Linear(self.last_channel, n_class),
113
+ )
114
+
115
+ self._initialize_weights()
116
+
117
+ def forward(self, x):
118
+ x = self.features(x)
119
+ x = self.avgpool(x)
120
+ x = x.view(-1, self.last_channel)
121
+ x = self.classifier(x)
122
+ return x
123
+
124
+ def _initialize_weights(self):
125
+ for m in self.modules():
126
+ if isinstance(m, nn.Conv2d):
127
+ n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
128
+ m.weight.data.normal_(0, math.sqrt(2. / n))
129
+ if m.bias is not None:
130
+ m.bias.data.zero_()
131
+ elif isinstance(m, nn.BatchNorm2d):
132
+ m.weight.data.fill_(1)
133
+ m.bias.data.zero_()
134
+ elif isinstance(m, nn.Linear):
135
+ n = m.weight.size(1)
136
+ m.weight.data.normal_(0, 0.01)
137
+ m.bias.data.zero_()
138
+
139
+ def resnet365_backbone():
140
+ arch = 'resnet18'
141
+ model_file = './resnet18_places365.pth.tar'
142
+ last_model = models.__dict__[arch](num_classes=365)
143
+
144
+ checkpoint = torch.load(model_file, map_location=lambda storage, loc: storage)
145
+ state_dict = {str.replace(k, 'module.', ''): v for k, v in checkpoint['state_dict'].items()}
146
+ last_model.load_state_dict(state_dict)
147
+
148
+ return last_model
149
+
150
+ def mobile_net_v2(pretrained=False):
151
+ model = MobileNetV2()
152
+ if pretrained:
153
+ print("read mobilenet weights")
154
+ path_to_model = '/root/tmp/pycharm_project_815/M_M_Semi-Supervised/code/AVA/pretrain_model/mobilenetv2.pth.tar'
155
+ state_dict = torch.load(path_to_model, map_location=lambda storage, loc: storage)
156
+ model.load_state_dict(state_dict)
157
+ return model
158
+
159
+ def Attention(x):
160
+ batch_size, in_channels, h, w = x.size()
161
+ quary = x.view(batch_size, in_channels, -1)
162
+ key = quary
163
+ quary = quary.permute(0, 2, 1)
164
+
165
+ sim_map = torch.matmul(quary, key)
166
+
167
+ ql2 = torch.norm(quary, dim=2, keepdim=True)
168
+ kl2 = torch.norm(key, dim=1, keepdim=True)
169
+ sim_map = torch.div(sim_map, torch.matmul(ql2, kl2).clamp(min=1e-8))
170
+ return sim_map
171
+
172
+ def MV2():
173
+ model = mobile_net_v2()
174
+ model = nn.Sequential(*list(model.children())[:-1])
175
+ # model_dict = model.state_dict()
176
+ return model
177
+
178
+ class L5(nn.Module):
179
+ def __init__(self):
180
+ super(L5, self).__init__()
181
+ back_model = MV2()
182
+ self.base_model = back_model
183
+ self.head = nn.Sequential(
184
+ nn.ReLU(inplace=True),
185
+ nn.Dropout(p=0.75),
186
+ nn.Linear(1280, 10),
187
+ # nn.Softmax(dim=1)
188
+ )
189
+
190
+ def forward(self, x):
191
+ x = self.base_model(x)
192
+ x = x.view(x.size(0), -1)
193
+ x = self.head(x)
194
+ return x
195
+
196
+ class L1(nn.Module):
197
+
198
+ def __init__(self):
199
+ super(L1, self).__init__()
200
+
201
+ self.last_out_w = nn.Linear(365, 100)
202
+ self.last_out_b = nn.Linear(365, 1)
203
+ for i, m_name in enumerate(self._modules):
204
+ if i > 2:
205
+ nn.init.kaiming_normal_(self._modules[m_name].weight.data)
206
+
207
+ def forward(self, x):
208
+ res_last_out_w = self.last_out_w(x)
209
+ res_last_out_b = self.last_out_b(x)
210
+ param_out = {}
211
+ param_out['res_last_out_w'] = res_last_out_w
212
+ param_out['res_last_out_b'] = res_last_out_b
213
+ return param_out
214
+
215
+ class TargetNet(nn.Module):
216
+ def __init__(self):
217
+ super(TargetNet, self).__init__()
218
+
219
+ # L2
220
+ self.fc1 = nn.Linear(365, 100)
221
+ for i, m_name in enumerate(self._modules):
222
+ if i > 2:
223
+ nn.init.kaiming_normal_(self._modules[m_name].weight.data)
224
+ self.bn1 = nn.BatchNorm1d(100).cuda()
225
+ self.relu1 = nn.PReLU()
226
+ self.drop1 = nn.Dropout(1 - 0.5)
227
+
228
+ self.relu7 = nn.PReLU()
229
+ self.relu7.cuda()
230
+ self.sig = nn.Sigmoid()
231
+
232
+ def forward(self, x, paras):
233
+ q = self.fc1(x)
234
+ q = self.bn1(q)
235
+ q = self.relu1(q)
236
+ q = self.drop1(q)
237
+
238
+ self.lin = nn.Sequential(TargetFC(paras['res_last_out_w'], paras['res_last_out_b']))
239
+ q = self.lin(q)
240
+ bn7 = nn.BatchNorm1d(q.shape[0])
241
+ bn7.cuda()
242
+ q = bn7(q)
243
+ q = self.relu7(q)
244
+
245
+ return q
246
+
247
+ class TargetFC(nn.Module):
248
+ def __init__(self, weight, bias):
249
+ super(TargetFC, self).__init__()
250
+ self.weight = weight
251
+ self.bias = bias
252
+
253
+ def forward(self, input_):
254
+ out = F.linear(input_, self.weight, self.bias)
255
+ return out
256
+
257
+ class TANet(nn.Module):
258
+ def __init__(self):
259
+ super(TANet, self).__init__()
260
+ self.res365_last = resnet365_backbone()
261
+ self.hypernet = L1()
262
+
263
+ # L3
264
+ self.tygertnet = TargetNet()
265
+
266
+ self.avg = nn.AdaptiveAvgPool2d((10, 1))
267
+ self.avg_RGB = nn.AdaptiveAvgPool2d((12, 12))
268
+
269
+ self.mobileNet = L5()
270
+ self.softmax = nn.Softmax(dim=1)
271
+
272
+ # L4
273
+ self.head_rgb = nn.Sequential(
274
+ nn.ReLU(),
275
+ nn.Dropout(p=0.75),
276
+ nn.Linear(20736, 10),
277
+ nn.Softmax(dim=1)
278
+ )
279
+
280
+ # L6
281
+ self.head = nn.Sequential(
282
+ nn.ReLU(),
283
+ nn.Dropout(p=0.75),
284
+ nn.Linear(30, 10),
285
+ nn.Softmax(dim=1)
286
+ )
287
+
288
+ def forward(self, x):
289
+
290
+ x_temp = self.avg_RGB(x)
291
+ x_temp = Attention(x_temp)
292
+ x_temp = x_temp.view(x_temp.size(0), -1)
293
+ x_temp = self.head_rgb(x_temp)
294
+
295
+ res365_last_out = self.res365_last(x)
296
+ res365_last_out_weights = self.hypernet(res365_last_out)
297
+ res365_last_out_weights_mul_out = self.tygertnet(res365_last_out, res365_last_out_weights)
298
+
299
+ x2 = res365_last_out_weights_mul_out.unsqueeze(dim=2)
300
+ x2 = self.avg(x2)
301
+ x2 = x2.squeeze(dim=2)
302
+
303
+ x1 = self.mobileNet(x)
304
+ x = torch.cat([x1, x2, x_temp], 1)
305
+ x = self.head(x)
306
+ return x
307
+
308
+ def get_score(opt, y_pred):
309
+ w = torch.from_numpy(np.linspace(1, 10, 10))
310
+ w = w.type(torch.FloatTensor)
311
+ w = w.to(device)
312
+
313
+ w_batch = w.repeat(y_pred.size(0), 1)
314
+
315
+ score = (y_pred * w_batch).sum(dim=1)
316
+ score_np = score.data.cpu().numpy()
317
+ return score, score_np
318
+
319
+ def create_data_part(opt):
320
+ train_csv_path = os.path.join(opt['path_to_save_csv'], 'train.csv')
321
+ val_csv_path = os.path.join(opt['path_to_save_csv'], 'val.csv')
322
+ test_csv_path = os.path.join(opt['path_to_save_csv'], 'test.csv')
323
+
324
+ train_ds = AVADataset(train_csv_path, opt['path_to_images'], if_train=True)
325
+ val_ds = AVADataset(val_csv_path, opt['path_to_images'], if_train=False)
326
+ test_ds = AVADataset(test_csv_path, opt['path_to_images'], if_train=False)
327
+
328
+ train_loader = DataLoader(train_ds, batch_size=opt['batch_size'], num_workers=opt['num_workers'], shuffle=True)
329
+ val_loader = DataLoader(val_ds, batch_size=opt['batch_size'], num_workers=opt['num_workers'], shuffle=False)
330
+ test_loader = DataLoader(test_ds, batch_size=opt['batch_size'], num_workers=opt['num_workers'], shuffle=False)
331
+
332
+ return train_loader, val_loader, test_loader
333
+
334
+ def train(opt, model, loader, optimizer, criterion, writer=None, global_step=None, name=None):
335
+ model.train()
336
+
337
+ # Freeze
338
+ for name, param in model.named_parameters():
339
+ if name[:11] == "res365_last":
340
+ param.requires_grad = False
341
+ else:
342
+ param.requires_grad = True
343
+
344
+ train_losses = AverageMeter()
345
+ for idx, (x, y) in enumerate(tqdm(loader)):
346
+ x = x.type(torch.FloatTensor).to(device)
347
+ y = y.to(device).view(y.size(0), -1).float()
348
+ y_pred = model(x).float()
349
+ loss = criterion(y_pred, y)
350
+ optimizer.zero_grad()
351
+ loss.backward()
352
+ optimizer.step()
353
+ train_losses.update(loss.item(), x.size(0))
354
+ return train_losses.avg
355
+
356
+ def validate(opt,model, loader, criterion, writer=None, global_step=None, name=None, test_or_valid_flag = 'test'):
357
+ model.eval()
358
+ validate_losses = AverageMeter()
359
+ torch.set_printoptions(precision=3)
360
+ true_score = []
361
+ pred_score = []
362
+
363
+ for idx, (x, y) in enumerate(tqdm(loader)):
364
+ x = x.type(torch.FloatTensor).to(device)
365
+ y = y.to(device).view(y.size(0), -1)
366
+ y_pred = model(x)
367
+ pscore, pscore_np = get_score(opt, y_pred)
368
+ tscore, tscore_np = get_score(opt, y)
369
+ pred_score += pscore_np.tolist()
370
+ true_score += tscore_np.tolist()
371
+ loss = criterion(y_pred, y).float()
372
+ validate_losses.update(loss.item(), x.size(0))
373
+
374
+ lcc_mean = pearsonr(pred_score, true_score)
375
+ srcc_mean = spearmanr(pred_score, true_score)
376
+ true_score = np.array(true_score)
377
+ true_score_lable = np.where(true_score <= 5.00, 0, 1)
378
+ pred_score = np.array(pred_score)
379
+ pred_score_lable = np.where(pred_score <= 5.00, 0, 1)
380
+ acc = accuracy_score(true_score_lable, pred_score_lable)
381
+ print('{}, accuracy: {}, lcc_mean: {}, srcc_mean: {}, validate_losses: {}'.format(test_or_valid_flag, acc,
382
+ lcc_mean[0], srcc_mean[0],
383
+ validate_losses.avg))
384
+ return validate_losses.avg, acc, lcc_mean, srcc_mean
385
+
386
+ def start_train(opt):
387
+ dataloader_train, dataloader_valid, dataloader_test = create_data_part(opt)
388
+ criterion = EDMLoss()
389
+ criterion.to(device)
390
+ model = TANet()
391
+
392
+ model.load_state_dict(torch.load(opt['path_to_model_weight'], map_location='cuda:0'))
393
+ model = model.to(device)
394
+
395
+ optimizer = optim.Adam([
396
+ # {'params': other_params},
397
+ {'params': model.res365_last.parameters(), 'lr': opt['init_lr_res365_last']},
398
+ {'params': model.mobileNet.parameters(), 'lr': opt['init_lr_mobileNet']},
399
+ {'params': model.head.parameters(), 'lr': opt['init_lr_head']},
400
+ {'params': model.head_rgb.parameters(), 'lr': opt['init_lr_head_rgb']},
401
+ {'params': model.hypernet.parameters(), 'lr': opt['init_lr_hypernet']},
402
+ {'params': model.tygertnet.parameters(), 'lr': opt['init_lr_tygertnet']},
403
+ ], lr=opt['init_lr'])
404
+
405
+ writer = SummaryWriter(log_dir=os.path.join(opt['experiment_dir_name'], 'logs'))
406
+ srcc_best = 0
407
+ vacc_best = 0
408
+
409
+ for e in range(opt['num_epoch']):
410
+ # please set util.py r = 2 of EMD
411
+ # train_loss = train(opt,model=model, loader=dataloader_train, optimizer=optimizer, criterion=criterion,
412
+ # writer=writer, global_step=len(dataloader_train) * e,
413
+ # name=f"{opt['experiment_dir_name']}_by_batch")
414
+ # val_loss,vacc,vlcc,vsrcc = validate(opt,model=model, loader=dataloader_valid, criterion=criterion,
415
+ # writer=writer, global_step=len(dataloader_valid) * e,
416
+ # name=f"{opt['experiment_dir_name']}_by_batch", test_or_valid_flag='valid')
417
+
418
+ # please set util.py r = 1 of EMD
419
+ test_loss, tacc, tlcc, tsrcc = validate(opt, model=model, loader=dataloader_test, criterion=criterion,
420
+ writer=writer, global_step=len(dataloader_test) * e,
421
+ name=f"{opt['experiment_dir_name']}_by_batch",
422
+ test_or_valid_flag='test')
423
+ nni.report_intermediate_result(
424
+ {'default': tacc, "vsrcc": tsrcc[0], "val_loss": test_loss})
425
+ nni.report_final_result({'default': tacc, "vsrcc": tsrcc[0]})
426
+ writer.close()
427
+