Permalink
Switch branches/tags
Nothing to show
Find file Copy path
849a1c9 Jun 23, 2017
1 contributor

Users who have contributed to this file

101 lines (68 sloc) 2.84 KB
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