-
Notifications
You must be signed in to change notification settings - Fork 75
/
hyperband.py
100 lines (68 loc) · 2.84 KB
/
hyperband.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
import numpy as np
from random import random
from math import log, ceil
from time import time, ctime
class Hyperband:
def __init__( self, get_params_function, try_params_function ):
self.get_params = get_params_function
self.try_params = try_params_function
self.max_iter = 81 # maximum iterations per configuration
self.eta = 3 # defines configuration downsampling rate (default = 3)
self.logeta = lambda x: log( x ) / log( self.eta )
self.s_max = int( self.logeta( self.max_iter ))
self.B = ( self.s_max + 1 ) * self.max_iter
self.results = [] # list of dicts
self.counter = 0
self.best_loss = np.inf
self.best_counter = -1
# can be called multiple times
def run( self, skip_last = 0, dry_run = False ):
for s in reversed( range( self.s_max + 1 )):
# initial number of configurations
n = int( ceil( self.B / self.max_iter / ( s + 1 ) * self.eta ** s ))
# initial number of iterations per config
r = self.max_iter * self.eta ** ( -s )
# n random configurations
T = [ self.get_params() for i in range( n )]
for i in range(( s + 1 ) - int( skip_last )): # changed from s + 1
# Run each of the n configs for <iterations>
# and keep best (n_configs / eta) configurations
n_configs = n * self.eta ** ( -i )
n_iterations = r * self.eta ** ( i )
print "\n*** {} configurations x {:.1f} iterations each".format(
n_configs, n_iterations )
val_losses = []
early_stops = []
for t in T:
self.counter += 1
print "\n{} | {} | lowest loss so far: {:.4f} (run {})\n".format(
self.counter, ctime(), self.best_loss, self.best_counter )
start_time = time()
if dry_run:
result = { 'loss': random(), 'log_loss': random(), 'auc': random()}
else:
result = self.try_params( n_iterations, t ) # <---
assert( type( result ) == dict )
assert( 'loss' in result )
seconds = int( round( time() - start_time ))
print "\n{} seconds.".format( seconds )
loss = result['loss']
val_losses.append( loss )
early_stop = result.get( 'early_stop', False )
early_stops.append( early_stop )
# keeping track of the best result so far (for display only)
# could do it be checking results each time, but hey
if loss < self.best_loss:
self.best_loss = loss
self.best_counter = self.counter
result['counter'] = self.counter
result['seconds'] = seconds
result['params'] = t
result['iterations'] = n_iterations
self.results.append( result )
# select a number of best configurations for the next loop
# filter out early stops, if any
indices = np.argsort( val_losses )
T = [ T[i] for i in indices if not early_stops[i]]
T = T[ 0:int( n_configs / self.eta )]
return self.results