6
6
7
7
from autoPyTorch .utils .config_space_hyperparameter import add_hyperparameter , get_hyperparameter
8
8
9
+ import numpy as np
10
+ import math
9
11
import torch
10
12
import torch .optim .lr_scheduler as lr_scheduler
13
+ from torch .optim import Optimizer
11
14
12
15
import ConfigSpace as CS
13
16
import ConfigSpace .hyperparameters as CSH
16
19
__version__ = "0.0.1"
17
20
__license__ = "BSD"
18
21
22
+
19
23
class AutoNetLearningRateSchedulerBase (object ):
20
24
def __new__ (cls , optimizer , config ):
21
25
"""Get a new instance of the scheduler
@@ -42,12 +46,17 @@ def _get_scheduler(self, optimizer, config):
42
46
def get_config_space ():
43
47
return CS .ConfigurationSpace ()
44
48
49
+
45
50
class SchedulerNone (AutoNetLearningRateSchedulerBase ):
46
51
47
52
def _get_scheduler (self , optimizer , config ):
48
53
return NoScheduling (optimizer = optimizer )
49
54
55
+
50
56
class SchedulerStepLR (AutoNetLearningRateSchedulerBase ):
57
+ """
58
+ Step learning rate scheduler
59
+ """
51
60
52
61
def _get_scheduler (self , optimizer , config ):
53
62
return lr_scheduler .StepLR (optimizer = optimizer , step_size = config ['step_size' ], gamma = config ['gamma' ], last_epoch = - 1 )
@@ -62,8 +71,12 @@ def get_config_space(
62
71
add_hyperparameter (cs , CSH .UniformFloatHyperparameter , 'gamma' , gamma )
63
72
return cs
64
73
74
+
65
75
class SchedulerExponentialLR (AutoNetLearningRateSchedulerBase ):
66
-
76
+ """
77
+ Exponential learning rate scheduler
78
+ """
79
+
67
80
def _get_scheduler (self , optimizer , config ):
68
81
return lr_scheduler .ExponentialLR (optimizer = optimizer , gamma = config ['gamma' ], last_epoch = - 1 )
69
82
@@ -75,11 +88,17 @@ def get_config_space(
75
88
add_hyperparameter (cs , CSH .UniformFloatHyperparameter , 'gamma' , gamma )
76
89
return cs
77
90
91
+
78
92
class SchedulerReduceLROnPlateau (AutoNetLearningRateSchedulerBase ):
93
+ """
94
+ Reduce LR on plateau learning rate scheduler
95
+ """
79
96
80
97
def _get_scheduler (self , optimizer , config ):
81
- return lr_scheduler .ReduceLROnPlateau (optimizer = optimizer )
82
-
98
+ return lr_scheduler .ReduceLROnPlateau (optimizer = optimizer ,
99
+ factor = config ['factor' ],
100
+ patience = config ['patience' ])
101
+
83
102
@staticmethod
84
103
def get_config_space (
85
104
factor = (0.05 , 0.5 ),
@@ -90,7 +109,112 @@ def get_config_space(
90
109
add_hyperparameter (cs , CSH .UniformIntegerHyperparameter , 'patience' , patience )
91
110
return cs
92
111
112
+
113
+ class SchedulerAdaptiveLR (AutoNetLearningRateSchedulerBase ):
114
+ """
115
+ Adaptive cosine learning rate scheduler
116
+ """
117
+
118
+ def _get_scheduler (self , optimizer , config ):
119
+ return AdaptiveLR (optimizer = optimizer ,
120
+ T_max = config ['T_max' ],
121
+ T_mul = config ['T_mult' ],
122
+ patience = config ['patience' ],
123
+ threshold = config ['threshold' ])
124
+
125
+ @staticmethod
126
+ def get_config_space (
127
+ T_max = (300 ,1000 ),
128
+ patience = (2 ,5 ),
129
+ T_mult = (1.0 ,2.0 ),
130
+ threshold = (0.001 , 0.5 )
131
+ ):
132
+ cs = CS .ConfigurationSpace ()
133
+ add_hyperparameter (cs , CSH .UniformIntegerHyperparameter , 'T_max' , T_max )
134
+ add_hyperparameter (cs , CSH .UniformIntegerHyperparameter , 'patience' , patience )
135
+ add_hyperparameter (cs , CSH .UniformFloatHyperparameter , 'T_mult' , T_mult )
136
+ add_hyperparameter (cs , CSH .UniformFloatHyperparameter , 'threshold' , threshold )
137
+ return cs
138
+
139
+
140
+ class AdaptiveLR (object ):
141
+
142
+ def __init__ (self , optimizer , mode = 'min' , T_max = 30 , T_mul = 2.0 , eta_min = 0 , patience = 3 , threshold = 0.1 , min_lr = 0 , eps = 1e-8 , last_epoch = - 1 ):
143
+
144
+ if not isinstance (optimizer , Optimizer ):
145
+ raise TypeError ('{} is not an Optimizer' .format (
146
+ type (optimizer ).__name__ ))
147
+
148
+ self .optimizer = optimizer
149
+
150
+ if last_epoch == - 1 :
151
+ for group in optimizer .param_groups :
152
+ group .setdefault ('initial_lr' , group ['lr' ])
153
+ else :
154
+ for i , group in enumerate (optimizer .param_groups ):
155
+ if 'initial_lr' not in group :
156
+ raise KeyError ("param 'initial_lr' is not specified "
157
+ "in param_groups[{}] when resuming an optimizer" .format (i ))
158
+
159
+ self .base_lrs = list (map (lambda group : group ['initial_lr' ], optimizer .param_groups ))
160
+ self .last_epoch = last_epoch
161
+
162
+ if isinstance (min_lr , list ) or isinstance (min_lr , tuple ):
163
+ if len (min_lr ) != len (optimizer .param_groups ):
164
+ raise ValueError ("expected {} min_lrs, got {}" .format (
165
+ len (optimizer .param_groups ), len (min_lr )))
166
+ self .min_lrs = list (min_lr )
167
+ else :
168
+ self .min_lrs = [min_lr ] * len (optimizer .param_groups )
169
+
170
+ self .T_max = T_max
171
+ self .T_mul = T_mul
172
+ self .eta_min = eta_min
173
+ self .current_base_lrs = self .base_lrs
174
+ self .metric_values = []
175
+ self .threshold = threshold
176
+ self .patience = patience
177
+ self .steps = 0
178
+
179
+ def step (self , metrics , epoch = None ):
180
+ if epoch is None :
181
+ epoch = self .last_epoch + 1
182
+ self .last_epoch = epoch
183
+
184
+ self .metric_values .append (metrics )
185
+ if len (self .metric_values ) > self .patience :
186
+ self .metric_values = self .metric_values [1 :]
187
+
188
+ if max (self .metric_values ) - metrics > self .threshold :
189
+ self .current_base_lrs = self .get_lr ()
190
+ self .steps = 0
191
+ else :
192
+ self .steps += 1
193
+
194
+ self .last_metric_value = metrics
195
+
196
+ for param_group , lr in zip (self .optimizer .param_groups , self .get_lr ()):
197
+ param_group ['lr' ] = lr
198
+
199
+ def get_lr (self ):
200
+ '''
201
+ Override this method to the existing get_lr() of the parent class
202
+ '''
203
+ if self .steps >= self .T_max :
204
+ self .T_max = self .T_max * self .T_mul
205
+ self .current_base_lrs = self .base_lrs
206
+ self .metric_values = []
207
+ self .steps = 0
208
+
209
+ return [self .eta_min + (base_lr - self .eta_min ) *
210
+ (1 + math .cos (math .pi * self .steps / self .T_max )) / 2
211
+ for base_lr in self .current_base_lrs ]
212
+
213
+
93
214
class SchedulerCyclicLR (AutoNetLearningRateSchedulerBase ):
215
+ """
216
+ Cyclic learning rate scheduler
217
+ """
94
218
95
219
def _get_scheduler (self , optimizer , config ):
96
220
maf = config ['max_factor' ]
@@ -118,7 +242,11 @@ def get_config_space(
118
242
add_hyperparameter (cs , CSH .UniformIntegerHyperparameter , 'cycle_length' , cycle_length )
119
243
return cs
120
244
245
+
121
246
class SchedulerCosineAnnealingWithRestartsLR (AutoNetLearningRateSchedulerBase ):
247
+ """
248
+ Cosine annealing learning rate scheduler with warm restarts
249
+ """
122
250
123
251
def _get_scheduler (self , optimizer , config ):
124
252
scheduler = CosineAnnealingWithRestartsLR (optimizer , T_max = config ['T_max' ], T_mult = config ['T_mult' ],last_epoch = - 1 )
@@ -151,7 +279,6 @@ def get_lr(self):
151
279
return [None ]
152
280
153
281
154
- import math
155
282
class CosineAnnealingWithRestartsLR (torch .optim .lr_scheduler ._LRScheduler ):
156
283
157
284
r"""Copyright: pytorch
@@ -205,3 +332,62 @@ def get_lr(self):
205
332
if self .step_n >= self .restart_every :
206
333
self .restart ()
207
334
return [self .cosine (base_lr ) for base_lr in self .base_lrs ]
335
+
336
+ def needs_checkpoint (self ):
337
+ return self .step_n + 1 >= self .restart_every
338
+
339
+
340
+ class SchedulerAlternatingCosineLR (AutoNetLearningRateSchedulerBase ):
341
+ """
342
+ Alternating cosine learning rate scheduler
343
+ """
344
+
345
+ def _get_scheduler (self , optimizer , config ):
346
+ scheduler = AlternatingCosineLR (optimizer , T_max = config ['T_max' ], T_mul = config ['T_mult' ], amplitude_reduction = config ['amp_reduction' ], last_epoch = - 1 )
347
+ return scheduler
348
+
349
+ @staticmethod
350
+ def get_config_space (
351
+ T_max = (1 , 20 ),
352
+ T_mult = (1.0 , 2.0 ),
353
+ amp_reduction = (0.1 ,1 )
354
+ ):
355
+ cs = CS .ConfigurationSpace ()
356
+ add_hyperparameter (cs , CSH .UniformIntegerHyperparameter , 'T_max' , T_max )
357
+ add_hyperparameter (cs , CSH .UniformFloatHyperparameter , 'T_mult' , T_mult )
358
+ add_hyperparameter (cs , CSH .UniformFloatHyperparameter , 'amp_reduction' , amp_reduction )
359
+ return cs
360
+
361
+
362
+ class AlternatingCosineLR (torch .optim .lr_scheduler ._LRScheduler ):
363
+ def __init__ (self , optimizer , T_max , T_mul = 1 , amplitude_reduction = 0.9 , eta_min = 0 , last_epoch = - 1 ):
364
+ '''
365
+ Here last_epoch actually means last_step since the
366
+ learning rate is decayed after each batch step.
367
+ '''
368
+
369
+ self .T_max = T_max
370
+ self .T_mul = T_mul
371
+ self .eta_min = eta_min
372
+ self .cumulative_time = 0
373
+ self .amplitude_mult = amplitude_reduction
374
+ self .base_lr_mult = 1
375
+ self .frequency_mult = 1
376
+ self .time_offset = 0
377
+ self .last_step = 0
378
+ super (AlternatingCosineLR , self ).__init__ (optimizer , last_epoch )
379
+
380
+ def get_lr (self ):
381
+ '''
382
+ Override this method to the existing get_lr() of the parent class
383
+ '''
384
+ if self .last_epoch >= self .T_max :
385
+ self .T_max = self .T_max * self .T_mul
386
+ self .time_offset = self .T_max / 2
387
+ self .last_epoch = 0
388
+ self .base_lr_mult *= self .amplitude_mult
389
+ self .frequency_mult = 2
390
+ self .cumulative_time = 0
391
+ return [self .eta_min + (base_lr * self .base_lr_mult - self .eta_min ) *
392
+ (1 + math .cos (math .pi * (self .time_offset + self .cumulative_time ) / self .T_max * self .frequency_mult )) / 2
393
+ for base_lr in self .base_lrs ]
0 commit comments