-
Notifications
You must be signed in to change notification settings - Fork 3
/
utils.py
154 lines (130 loc) · 5.51 KB
/
utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import torch
import numpy as np
import torch.nn as nn
class MixUpLoss(nn.Module):
"""
Mixup implementation heavily borrowed from https://github.com/fastai/fastai/blob/master/fastai/callbacks/mixup.py#L42
Adapt the loss function `crit` to go with mixup.
"""
def __init__(self, crit, reduction='mean'):
super().__init__()
if hasattr(crit, 'reduction'):
self.crit = crit
self.old_red = crit.reduction
setattr(self.crit, 'reduction', 'none')
self.reduction = reduction
def forward(self, output, target):
if len(target.size()) == 2:
loss1, loss2 = self.crit(output, target[:, 0].long()), self.crit(output, target[:, 1].long())
d = loss1 * target[:, 2] + loss2 * (1 - target[:, 2])
else:
d = self.crit(output, target)
if self.reduction == 'mean':
return d.mean()
elif self.reduction == 'sum':
return d.sum()
return d
def get_old(self):
if hasattr(self, 'old_crit'):
return self.old_crit
elif hasattr(self, 'old_red'):
setattr(self.crit, 'reduction', self.old_red)
return self.crit
def mixup_data(x, y, alpha=0.4):
"""
Returns mixed inputs, pairs of targets, and lambda
"""
batch_size = x.shape[0]
lam = np.random.beta(alpha, alpha, batch_size)
# t = max(t, 1-t)
lam = np.concatenate([lam[:, None], 1 - lam[:, None]], 1).max(1)
# tensor and cuda version of lam
lam = x.new(lam)
shuffle = torch.randperm(batch_size).cuda()
x1, y1 = x[shuffle], y[shuffle]
# out_shape = [bs, 1, 1]
out_shape = [lam.size(0)] + [1 for _ in range(len(x1.shape) - 1)]
# [bs, temporal, sensor]
mixed_x = (x * lam.view(out_shape) + x1 * (1 - lam).view(out_shape))
# [bs, 3]
y_a_y_b_lam = torch.cat([y[:, None].float(), y1[:, None].float(), lam[:, None].float()], 1)
return mixed_x, y_a_y_b_lam
class EarlyStopping:
"""Early stops the training if validation loss doesn't improve after a given patience."""
def __init__(self, patience=7, verbose=False, delta=0):
"""
Args:
patience (int): How long to wait after last time validation loss improved.
Default: 7
verbose (bool): If True, prints a message for each validation loss improvement.
Default: False
delta (float): Minimum change in the monitored quantity to qualify as an improvement.
Default: 0
path (str): Path for the checkpoint to be saved to.
Default: 'checkpoint.pt'
"""
self.patience = patience
self.verbose = verbose
self.counter = 0
self.best_score = None
self.early_stop = False
self.val_loss_min = np.Inf
self.delta = delta
def __call__(self, val_loss, model, path, f_macro = None, f_weighted = None, log=None):
score = -val_loss
if self.best_score is None:
self.best_score = score
self.save_checkpoint(val_loss, model, path ,f_macro, f_weighted)
elif score < self.best_score + self.delta:
self.counter += 1
print(f'EarlyStopping counter: {self.counter} out of {self.patience}')
if self.counter >= self.patience:
self.early_stop = True
else:
print("new best score!!!!")
#print("log shi ", log)
if log is not None:
log.write("new best score!!!! Saving model ... \n")
log.write("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \n")
self.best_score = score
self.save_checkpoint(val_loss, model,path,f_macro, f_weighted)
self.counter = 0
def save_checkpoint(self, val_loss, model, path, f_macro = None, f_weighted = None):
'''Saves model when validation loss decrease.'''
if self.verbose:
print(f'Validation loss decreased ({self.val_loss_min:.6f} --> {val_loss:.6f}). Saving model ...')
torch.save(model.state_dict(), path+'/'+'best_vali.pth')
self.val_loss_min = val_loss
class adjust_learning_rate_class:
def __init__(self, args, verbose):
self.patience = args.learning_rate_patience
self.factor = args.learning_rate_factor
self.learning_rate = args.learning_rate
self.args = args
self.verbose = verbose
self.val_loss_min = np.Inf
self.counter = 0
self.best_score = None
def __call__(self, optimizer, val_loss):
# val_loss 是正值,越小越好
# 但是这里加了负值,score愈大越好
score = -val_loss
if self.best_score is None:
self.best_score = score
self.counter += 1
elif score <= self.best_score :
self.counter += 1
if self.verbose:
print(f'Learning rate adjusting counter: {self.counter} out of {self.patience}')
else:
if self.verbose:
print("new best score!!!!")
self.best_score = score
self.counter = 0
if self.counter == self.patience:
self.learning_rate = self.learning_rate * self.factor
for param_group in optimizer.param_groups:
param_group['lr'] = self.learning_rate
if self.verbose:
print('Updating learning rate to {}'.format(self.learning_rate))
self.counter = 0