Permalink
Browse files

Basic NN learner implementation

I've pulled the actual network logic out into a new class, to
keep the TF stuff separate from everything else and to keep a
clear separation between what's modelling the landscape and
what's doing prediction.
  • Loading branch information...
1 parent 2efd317 commit d5c57497b3c1b6b8f8f7fc93c3f9cb22d35b1e48 @charmasaur charmasaur committed Dec 2, 2016
Showing with 119 additions and 58 deletions.
  1. +3 −58 mloop/learners.py
  2. +116 −0 mloop/nnlearner.py
View
@@ -1583,18 +1583,11 @@ def __init__(self,
self.cost_scaler = skp.StandardScaler()
-
- #--- FAKE NN CONSTRUCTOR START ---#
-
self.length_scale = 1
self.cost_has_noise = True
self.noise_level = 1
- self.create_neural_net()
-
-
-
- #--- FAKE NN CONSTRUCTOR END ---#
+ self.neural_net_impl = NeuralNetImpl(self.num_params)
self.archive_dict.update({'archive_type':'neural_net_learner',
'bad_run_indexs':self.bad_run_indexs,
@@ -1611,58 +1604,14 @@ def __init__(self,
#Remove logger so gaussian process can be safely picked for multiprocessing on Windows
self.log = None
-
- #--- FAKE NN METHODS START ---#
-
-
- def create_neural_net(self):
- '''
- Create the neural net.
-
- '''
- #TODO: Do.
- gp_kernel = skk.RBF(length_scale=self.length_scale) + skk.WhiteKernel(noise_level=self.noise_level)
-
- if self.update_hyperparameters:
- self.gaussian_process = skg.GaussianProcessRegressor(kernel=gp_kernel,n_restarts_optimizer=self.hyperparameter_searches)
- else:
- self.gaussian_process = skg.GaussianProcessRegressor(kernel=gp_kernel,optimizer=None)
-
def fit_neural_net(self):
'''
Determine the appropriate number of layers for the NN given the data.
Fit the Neural Net with the appropriate topology to the data
'''
- #TODO: Do.
- self.log.debug('Fitting Gaussian process.')
- if self.all_params.size==0 or self.all_costs.size==0 or self.all_uncers.size==0:
- self.log.error('Asked to fit GP but no data is in all_costs, all_params or all_uncers.')
- raise ValueError
-
- self.scaled_costs = self.cost_scaler.fit_transform(self.all_costs[:,np.newaxis])[:,0]
- self.scaled_uncers = self.all_uncers * self.cost_scaler.scale_
- self.gaussian_process.alpha_ = self.scaled_uncers
- self.gaussian_process.fit(self.all_params,self.scaled_costs)
-
- if self.update_hyperparameters:
-
- self.fit_count += 1
- self.gaussian_process.kernel = self.gaussian_process.kernel_
-
- last_hyperparameters = self.gaussian_process.kernel.get_params()
-
- if self.cost_has_noise:
- self.length_scale = last_hyperparameters['k1__length_scale']
- if isinstance(self.length_scale, float):
- self.length_scale = np.array([self.length_scale])
- self.length_scale_history.append(self.length_scale)
- self.noise_level = last_hyperparameters['k2__noise_level']
- self.noise_level_history.append(self.noise_level)
- else:
- self.length_scale = last_hyperparameters['length_scale']
- self.length_scale_history.append(self.length_scale)
+ self.neural_net_impl.fit_neural_net(self.all_params, self.all_costs)
def predict_cost(self,params):
'''
@@ -1671,11 +1620,7 @@ def predict_cost(self,params):
Returns:
float : Predicted cost at paramters
'''
- #TODO: Do.
- return self.gaussian_process.predict(params[np.newaxis,:])
-
- #--- FAKE NN METHODS END ---#
-
+ return self.neural_net_impl.predict_cost(params)
def wait_for_new_params_event(self):
'''
View
@@ -0,0 +1,116 @@
+import logging
+import math
+import tensorflow as tf
+import numpy as np
+
+class NeuralNetImpl():
+ '''
+ Neural network implementation.
+
+ Args:
+ num_params (int): The number of params.
+
+
+ Attributes:
+ TODO
+ '''
+
+ def __init__(self,
+ num_params = None):
+
+ self.log = logging.getLogger(__name__)
+ if num_params is None:
+ self.log.error("num_params must be provided")
+ raise ValueError
+ self.num_params = num_params
+
+ self.tf_session = tf.InteractiveSession()
+
+ # Initial hyperparameters
+ self.num_layers = 1
+ self.layer_dim = 128
+ self.train_epochs = 300
+ self.batch_size = 64
+
+ # Inputs
+ self.input_placeholder = tf.placeholder(tf.float32, shape=[None, self.num_params])
+ self.output_placeholder = tf.placeholder(tf.float32, shape=[None, 1])
+ self.keep_prob = tf.placeholder_with_default(1., shape=[])
+ self.regularisation_coefficient = tf.placeholder_with_default(0., shape=[])
+
+ self._create_neural_net()
+
+ def _create_neural_net(self):
+ '''
+ Creates the neural net with topology specified by the current hyperparameters.
+
+ '''
+ # Forget about any old weights/biases
+ self.weights = []
+ self.biases = []
+
+ # Input + internal nodes
+ # TODO: Use length scale for setting initial weights?
+ prev_layer_dim = self.num_params
+ prev_h = self.input_placeholder
+ for dim in [self.layer_dim] * self.num_layers:
+ self.weights.append(tf.Variable(tf.random_normal([prev_layer_dim, dim], stddev=0.1)))
+ self.biases.append(tf.Variable(tf.random_normal([dim])))
+ prev_layer_dim = dim
+ prev_h = tf.nn.dropout(
+ tf.nn.sigmoid(tf.matmul(prev_h, self.weights[-1]) + self.biases[-1]),
+ keep_prob=self.keep_prob)
+
+ # Output node
+ self.weights.append(tf.Variable(tf.random_normal([prev_layer_dim, 1])))
+ self.biases.append(tf.Variable(tf.random_normal([1])))
+ self.output_var = tf.matmul(prev_h, self.weights[-1]) + self.biases[-1]
+
+ # Loss function and training
+ loss_func = (
+ tf.reduce_mean(tf.reduce_sum(tf.square(self.output_var - self.output_placeholder),
+ reduction_indices=[1]))
+ + self.regularisation_coefficient * sum([tf.nn.l2_loss(W) for W in self.weights]))
+ self.train_step = tf.train.AdamOptimizer().minimize(loss_func)
+
+ self.tf_session.run(tf.initialize_all_variables())
+
+ def fit_neural_net(self, all_params, all_costs):
+ '''
+ Determine the appropriate number of layers for the NN given the data.
+
+ Fit the Neural Net with the appropriate topology to the data
+
+ Args:
+ all_params (array): array of all parameter arrays
+ all_costs (array): array of costs (associated with the corresponding parameters)
+ '''
+ self.log.debug('Fitting neural network')
+ if len(all_params) == 0:
+ self.log.error('No data provided.')
+ raise ValueError
+ if not len(all_params) == len(all_costs):
+ self.log.error("Params and costs must have the same length")
+ raise ValueError
+
+ # TODO: Fit hyperparameters.
+
+ for i in range(self.train_epochs):
+ # Split the data into random batches, and train on each batch
+ all_indices = np.random.permutation(len(all_params))
+ for j in range(math.ceil(len(all_params) / self.batch_size)):
+ batch_indices = all_indices[j * self.batch_size : (j + 1) * self.batch_size]
+ batch_input = [all_params[index] for index in batch_indices]
+ batch_output = [[all_costs[index]] for index in batch_indices]
+ self.tf_session.run(self.train_step,
+ feed_dict={self.input_placeholder: batch_input,
+ self.output_placeholder: batch_output})
+
+ def predict_cost(self,params):
+ '''
+ Produces a prediction of cost from the neural net at params.
+
+ Returns:
+ float : Predicted cost at parameters
+ '''
+ return self.tf_session.run(self.output_var, feed_dict={self.input_placeholder: [params]})[0][0]

0 comments on commit d5c5749

Please sign in to comment.