def __init__(self, model, prior=1.0, initial_noise=10.0**-12, update_order=None): """ The learner object. :param prior: Float representing the prior sigma squared of all parameters. """ self._model = model # Get number of parameters and map parameters to position in parameter vector parameter_set = set() for factor in self._model.factors: if factor.parameters is not None: for parameter in factor.parameters.reshape(-1, ): if isinstance(parameter, str): parameter_set.add(parameter) self._index_to_parameters = {} self._parameters_to_index = {} for index, key in enumerate(sorted(list(parameter_set))): self._index_to_parameters[index] = key self._parameters_to_index[key] = index self._dimension = len(self._index_to_parameters) self._parameters = numpy.random.randn(self._dimension) * initial_noise if self._dimension > 0: self._prior_location = numpy.zeros(self._dimension) self._prior_precision = numpy.eye(self._dimension) * prior self._prior_normaliser = (-0.5 * self._dimension * numpy.log(2.0 * numpy.pi) + 0.5 * numpy.log(numpy.linalg.det((self._prior_precision)))) self._update_order = update_order if not self._update_order: self._update_order = FloodingProtocol(self._model) # Results self._iterations = [] self._optimizer_result = None
class LearnMrfParameters(object): """ Find a Gaussian approximation to the posterior given a model and prior. """ def __init__(self, model, prior=1.0, initial_noise=10.0**-12, update_order=None): """ The learner object. :param prior: Float representing the prior sigma squared of all parameters. """ self._model = model # Get number of parameters and map parameters to position in parameter vector parameter_set = set() for factor in self._model.factors: if factor.parameters is not None: for parameter in factor.parameters.reshape(-1, ): if isinstance(parameter, str): parameter_set.add(parameter) self._index_to_parameters = {} self._parameters_to_index = {} for index, key in enumerate(sorted(list(parameter_set))): self._index_to_parameters[index] = key self._parameters_to_index[key] = index self._dimension = len(self._index_to_parameters) self._parameters = numpy.random.randn(self._dimension) * initial_noise if self._dimension > 0: self._prior_location = numpy.zeros(self._dimension) self._prior_precision = numpy.eye(self._dimension) * prior self._prior_normaliser = (-0.5 * self._dimension * numpy.log(2.0 * numpy.pi) + 0.5 * numpy.log(numpy.linalg.det((self._prior_precision)))) self._update_order = update_order if not self._update_order: self._update_order = FloodingProtocol(self._model) # Results self._iterations = [] self._optimizer_result = None @property def parameters(self): """ The current learned parameter values. :returns: Dictionary where the key is a parameter name and the value its value. """ parameter_dictionary = {} for i, value in enumerate(self._parameters): parameter_dictionary[self._index_to_parameters[i]] = value return parameter_dictionary def log_likelihood_and_gradient(self, evidence): """ Run inference on the model to find the log-likelihood of the model given evidence and its gradient with respect to the model parameters. :param evidence: A dictionary where the key is a variable name and the value its observed value. :returns: The log-likelihood and a vector of derivatives. """ self._update_order.reset() inference = LoopyBeliefUpdateInference(self._model, update_order=self._update_order) inference.calibrate(parameters=self.parameters) log_z_total = inference.partition_approximation() model_expected_counts = self._accumulate_expected_counts(inference) self._update_order.reset() inference = LoopyBeliefUpdateInference(self._model, update_order=self._update_order) inference.calibrate(evidence, parameters=self.parameters) log_z_observed = inference.partition_approximation() empirical_expected_counts = self._accumulate_expected_counts(inference) log_likelihood = log_z_observed - log_z_total derivative = empirical_expected_counts - model_expected_counts if self._dimension > 0: derivative += -numpy.dot(self._prior_precision, (self._parameters - self._prior_location)) log_likelihood += -0.5 * numpy.dot(numpy.dot((self._parameters - self._prior_location).T, self._prior_precision), (self._parameters - self._prior_location)) log_likelihood += self._prior_normaliser return log_likelihood, derivative def _accumulate_expected_counts(self, inference): """ Iterate through beliefs and add parameter values. :returns: Vector of expected counts for each parameter. """ expected_counts = numpy.zeros(self._parameters.shape) for belief in inference.beliefs.values(): factor_sum = numpy.sum(belief.data) for parameter, value in zip(belief.parameters.flatten(), belief.data.flatten()): if isinstance(parameter, str): expected_counts[self._parameters_to_index[parameter]] += (value / factor_sum) # * norm / normalizer return expected_counts def _parameter_dictionary_to_vector(self, dictionary): """ Helper to switch between a dictionary representation of parameter values to vector representation. :param dictionary: A dictionary where the key is a parameter name and the value its value. :returns: A numpy array. """ return_vector = numpy.array(len(self._parameters_to_index)) for i in xrange(len(return_vector)): return_vector[i] = dictionary[self._index_to_parameters[i]] return return_vector def fit(self, evidence, initial_parameters=None, optimizer=scipy.optimize.fmin_l_bfgs_b, optimizer_kwargs=None): """ Fit the model to the data. :param evidence: Dictionary where the key is a variable name and the value the observed value of that variable. :param initial_parameters: numpy.array of initial parameter values. If None then random values around 0 is used. :param optimizer: The optimization function to use. :param optimizer_kwargs: Keyword arguments that are passed to the optimizer. :returns: The learner object. """ initial_parameter_vector = self._parameters if initial_parameters is not None: initial_parameter_vector = self._parameter_dictionary_to_vector(initial_parameters) if not optimizer_kwargs: optimizer_kwargs = {'pgtol': 10.0**-10} def objective_function(parameter_vector): """ Function that is passed to the optimizer. :param parameter_vector: Parameter vector. :returns: Negative log-likelihood. gradient. """ self._parameters = parameter_vector log_likelihood, grad = self.log_likelihood_and_gradient(evidence) self._iterations.append([log_likelihood, parameter_vector]) return -log_likelihood, -grad self._optimizer_result = optimizer(objective_function, initial_parameter_vector, **optimizer_kwargs) return self def result(self): """ Get the learning results. :returns: Log-likelihood, parameters that maximises the log-likelihood. """ if self._optimizer_result: return self._optimizer_result[1], self._optimizer_result[0] else: raise Exception('No result yet - run fit.')
def lbp_combine_best_patches(patch_image_directory, context_image, prediction_fn, min_stride=1, max_iters=1, max_stride=3): # open the context image context = Image.open(context_image) # get smallest pw and images as np arrays smallest_pw, patch_images = get_stylized_images(patch_image_directory) # get context image scaled down so that it's the same size as the stylized imgs patchR, patchC, _ = patch_images[0].shape context = context.resize((patchC, patchR), Image.ANTIALIAS) context = np.array(context) lbf_folder = 'lbf_output/' if not os.path.exists(lbf_folder): os.makedirs(lbf_folder) inner_folder = lbf_folder + prediction_fn + '_folder/' if not os.path.exists(inner_folder): os.makedirs(inner_folder) stride = min_stride while stride <= max_stride: evidence, factors = construct_graph(patch_images, context, smallest_pw, stride) model = Model(factors) # Get some feedback on how inference is converging by listening in on some of the label beliefs. def reporter(infe, orde): print('{:3}'.format(orde.total_iterations)) order = FloodingProtocol(model, max_iterations=max_iters) inference = LoopyBeliefUpdateInference(model, order, callback=reporter) inference.calibrate(evidence) K = len(patch_images) rrange = range(0, patchR - smallest_pw + 1, stride) crange = range(0, patchC - smallest_pw + 1, stride) num_r = len(rrange) # number of patches vertically num_c = len(crange) # number of patches horizontally ff_labels = [[None for i in range(num_c)] for j in range(num_r)] ff_r = 0 for r in rrange: ff_c = 0 for c in crange: variable_name = 'label_{}_{}'.format(r, c) # first factor is the context-style factor tha we want label_factor = inference.get_marginals(variable_name)[0] # save the actual patch location to make it easier to remap them later on ff_labels[ff_r][ff_c] = [[r, c], label_factor.normalized_data] ff_c += 1 ff_r += 1 # save the labels so they can be easily reused ff_labels = np.array(ff_labels) np.save( "%s%s_stride_%d_first_factor_label_data" % (inner_folder, prediction_fn, stride), ff_labels) stride += 1