Source code for l2l.optimizees.mnist.optimizee

from collections import namedtuple

import numpy as np
from sklearn.datasets import load_digits, fetch_openml

from l2l.optimizees.optimizee import Optimizee
from .nn import NeuralNetworkClassifier

MNISTOptimizeeParameters = namedtuple('MNISTOptimizeeParameters', ['n_hidden', 'seed', 'use_small_mnist'])


[docs]class MNISTOptimizee(Optimizee): """ Implements a simple function optimizee. Functions are generated using the FunctionGenerator. NOTE: Make sure the optimizee_fitness_weights is set to (-1,) to minimize the value of the function :param traj: The trajectory used to conduct the optimization. :param parameters: Instance of :func:`~collections.namedtuple` :class:`.MNISTOptimizeeParameters` """ def __init__(self, traj, parameters): super().__init__(traj) if parameters.use_small_mnist: # 8 x 8 images mnist_digits = load_digits() n_input = np.prod(mnist_digits.images.shape[1:]) n_images = len(mnist_digits.images) # 1797 data_images = mnist_digits.images.reshape(n_images, -1) / 16. # -> 1797 x 64 data_targets = mnist_digits.target else: # 28 x 28 images mnist_digits = fetch_openml('MNIST original') n_input = np.prod(mnist_digits.data.shape[1:]) data_images = mnist_digits.data / 255. # -> 70000 x 284 n_images = len(data_images) data_targets = mnist_digits.target self.n_images = n_images self.data_images, self.data_targets = data_images, data_targets seed = parameters.seed n_hidden = parameters.n_hidden seed = np.uint32(seed) self.random_state = np.random.RandomState(seed=seed) n_output = 10 # This is always true for mnist self.nn = NeuralNetworkClassifier(n_input, n_hidden, n_output) self.random_state = np.random.RandomState(seed=seed) # create_individual can be called because __init__ is complete except for traj initializtion indiv_dict = self.create_individual() for key, val in indiv_dict.items(): traj.individual.f_add_parameter(key, val) traj.individual.f_add_parameter('seed', seed)
[docs] def create_individual(self): """ Creates a random value of parameter within given bounds """ weight_shapes = self.nn.get_weights_shapes() cumulative_num_weights_per_layer = np.cumsum([np.prod(weight_shape) for weight_shape in weight_shapes]) flattened_weights = np.empty(cumulative_num_weights_per_layer[-1]) for i, weight_shape in enumerate(weight_shapes): if i == 0: flattened_weights[:cumulative_num_weights_per_layer[i]] = \ self.random_state.randn(np.prod(weight_shape)) / np.sqrt(weight_shape[1]) else: flattened_weights[cumulative_num_weights_per_layer[i - 1]:cumulative_num_weights_per_layer[i]] = \ self.random_state.randn(np.prod(weight_shape)) / np.sqrt(weight_shape[1]) # return dict(weights=self.random_state.randn(cumulative_num_weights_per_layer[-1])) return dict(weights=flattened_weights)
[docs] def bounding_func(self, individual): """ Bounds the individual within the required bounds via coordinate clipping """ return individual
[docs] def simulate(self, traj): """ Returns the value of the function chosen during initialization :param ~l2l.utils.trajectory.Trajectory traj: Trajectory :return: a single element :obj:`tuple` containing the value of the chosen function """ # configure_loggers(exactly_once=True) # logger configuration is here since this function is paralellised # taken care of by jube flattened_weights = traj.individual.weights weight_shapes = self.nn.get_weights_shapes() cumulative_num_weights_per_layer = np.cumsum([np.prod(weight_shape) for weight_shape in weight_shapes]) weights = [] for i, weight_shape in enumerate(weight_shapes): if i == 0: w = flattened_weights[:cumulative_num_weights_per_layer[i]].reshape(weight_shape) else: w = flattened_weights[ cumulative_num_weights_per_layer[i - 1]:cumulative_num_weights_per_layer[i]].reshape(weight_shape) weights.append(w) self.nn.set_weights(*weights) return self.nn.score(self.data_images, self.data_targets)