From b4f1f5763098033623af7cf390b190ddf1ec9593 Mon Sep 17 00:00:00 2001 From: Joerg Martin <joerg.martin@ptb.de> Date: Thu, 27 Jan 2022 13:17:43 +0100 Subject: [PATCH] Simulated datasets now use the same seed for creation --- EIVPackage/EIVData/cubic.py | 65 +++++++++++--- EIVPackage/EIVData/linear.py | 62 ++++++++++--- EIVPackage/EIVData/quadratic.py | 62 ++++++++++--- EIVPackage/EIVData/sine.py | 62 ++++++++++--- EIVPackage/EIVGeneral/manipulate_datasets.py | 4 + EIVPackage/EIVGeneral/manipulate_tensors.py | 23 ++++- Experiments/plot_prediction.py | 91 ++++++++++++++++---- 7 files changed, 295 insertions(+), 74 deletions(-) diff --git a/EIVPackage/EIVData/cubic.py b/EIVPackage/EIVData/cubic.py index a9eda38..c4a0654 100644 --- a/EIVPackage/EIVData/cubic.py +++ b/EIVPackage/EIVData/cubic.py @@ -2,7 +2,8 @@ import torch import sys from torch.utils.data import TensorDataset -from EIVGeneral.manipulate_tensors import add_noise +from EIVGeneral.manipulate_tensors import add_noise, normalize_tensor,\ + unnormalize_tensor total_number_of_datapoints = 2000 input_range = [-4,4] @@ -11,38 +12,63 @@ intercept = 0.0 x_noise_strength = 0.05 * (input_range[1] - input_range[0])/2 y_noise_strength = 3 func = lambda true_x: slope * true_x**3 + intercept + def load_data(seed=0, splitting_part=0.8, normalize=True, - return_ground_truth=False): + return_ground_truth=False, + return_normalized_func=False, + fixed_seed = 0): """ - Loads one-dimensional, cubic data as in Hernandez-Lobato, Adams 2015. - :param seed: Seed for drawing and splitting the data. + Loads one-dimensional data, cubic data as in Hernandez-Lobato, Adams 2015. + :param seed: Seed for shuffling the data before splitting. :param splitting_part: Which fraction of the data to use as training data. Defaults to 0.8. :param normalize: Whether to normalize the data, defaults to True. :param return_ground_truth: Boolean. If True, the unnoisy ground truth will also be returned. Defaults to False. - :returns: cubic_trainset, cubic_testset if return_ground_truth is False, + :param return_normalized_func: Boolean (default False). If True, the + normalized version of the used function is returned as a last element. + :param fixed_seed: Used to generate the full dataset (test and train). + Defaults to 0. + :returns: cubic_trainset, cubic_testset, (, normalized_func) if + return_ground_truth is False, else cubic_trainset, cubic_testset, true_cubic_trainset, - true_cubic_testset. The later two return **four tensors**: The true x,y and - their noisy counterparts. + true_cubic_testset, (, normalized_func). The "true" datasets each return + **four tensors**: The true x,y and their noisy counterparts. """ - random_generator = torch.Generator().manual_seed(seed) # draw different seeds for noise and splitting + random_generator = torch.Generator().manual_seed(fixed_seed) seeds = [int(t) for t in torch.randint(0,sys.maxsize,(3,),\ generator=random_generator)] + # create new generators from tensor seeds true_x = input_range[0] + (input_range[1]-input_range[0])\ * torch.rand((total_number_of_datapoints,1), generator=torch.Generator().manual_seed(seeds[0])) true_y = func(true_x) + # add noise and normalize x and y - (noisy_x, noisy_y), (true_x, true_y) = add_noise( + (noisy_x, noisy_y), (true_x, true_y), normalization_list = add_noise( tensor_list=(true_x, true_y), noise_strength_list=(x_noise_strength, y_noise_strength), seed_list=seeds[1:3], - normalize=normalize) - # create datasets + normalize=normalize, + return_normalization=True) + def normalized_func(x): + unnormalized_x = unnormalize_tensor(x, normalization_list[0]) + y = func(unnormalized_x) + normalized_y = normalize_tensor(y, normalization_list[1]) + return normalized_y dataset_len = noisy_x.shape[0] + + # shuffle via seed + new_order = torch.randperm(dataset_len, + generator=torch.Generator().manual_seed(seed)) + true_x = true_x[new_order, ...] + true_y = true_y[new_order, ...] + noisy_x = noisy_x[new_order, ...] + noisy_y = noisy_y[new_order, ...] + + # create datasets train_len = int(dataset_len*splitting_part) test_len = dataset_len - train_len true_train_x, true_test_x = torch.split(true_x, [train_len, test_len]) @@ -55,8 +81,19 @@ def load_data(seed=0, splitting_part=0.8, normalize=True, noisy_train_x, noisy_train_y) true_cubic_testset = TensorDataset(true_test_x, true_test_y, noisy_test_x, noisy_test_y) + + + # return different objects, depending on Booleans if not return_ground_truth: - return cubic_trainset, cubic_testset + if not return_normalized_func: + return cubic_trainset, cubic_testset + else: + return cubic_trainset, cubic_testset, normalized_func else: - return cubic_trainset, cubic_testset, true_cubic_trainset,\ - true_cubic_testset + if not return_normalized_func: + return cubic_trainset, cubic_testset, true_cubic_trainset,\ + true_cubic_testset + else: + return cubic_trainset, cubic_testset, true_cubic_trainset,\ + true_cubic_testset, normalized_func + diff --git a/EIVPackage/EIVData/linear.py b/EIVPackage/EIVData/linear.py index bbfc532..499e9d1 100644 --- a/EIVPackage/EIVData/linear.py +++ b/EIVPackage/EIVData/linear.py @@ -2,7 +2,8 @@ import torch import sys from torch.utils.data import TensorDataset -from EIVGeneral.manipulate_tensors import add_noise +from EIVGeneral.manipulate_tensors import add_noise, normalize_tensor,\ + unnormalize_tensor total_number_of_datapoints = 2000 input_range = [-1,1] @@ -13,37 +14,61 @@ y_noise_strength = 0.1 func = lambda true_x: slope * true_x + intercept def load_data(seed=0, splitting_part=0.8, normalize=True, - return_ground_truth=False): + return_ground_truth=False, + return_normalized_func=False, + fixed_seed = 0): """ Loads one-dimensional data - :param seed: Seed for drawing and splitting the data. + :param seed: Seed for shuffling the data before splitting. :param splitting_part: Which fraction of the data to use as training data. Defaults to 0.8. :param normalize: Whether to normalize the data, defaults to True. :param return_ground_truth: Boolean. If True, the unnoisy ground truth will also be returned. Defaults to False. - :returns: linear_trainset, linear_testset if return_ground_truth is False, + :param return_normalized_func: Boolean (default False). If True, the + normalized version of the used function is returned as a last element. + :param fixed_seed: Used to generate the full dataset (test and train). + Defaults to 0. + :returns: linear_trainset, linear_testset, (, normalized_func) if + return_ground_truth is False, else linear_trainset, linear_testset, true_linear_trainset, - true_linear_testset. The later two return **four tensors**: The true x,y and - their noisy counterparts. + true_linear_testset, (, normalized_func). The "true" datasets each return + **four tensors**: The true x,y and their noisy counterparts. """ - random_generator = torch.Generator().manual_seed(seed) # draw different seeds for noise and splitting + random_generator = torch.Generator().manual_seed(fixed_seed) seeds = [int(t) for t in torch.randint(0,sys.maxsize,(3,),\ generator=random_generator)] + # create new generators from tensor seeds true_x = input_range[0] + (input_range[1]-input_range[0])\ * torch.rand((total_number_of_datapoints,1), generator=torch.Generator().manual_seed(seeds[0])) true_y = func(true_x) + # add noise and normalize x and y - (noisy_x, noisy_y), (true_x, true_y) = add_noise( + (noisy_x, noisy_y), (true_x, true_y), normalization_list = add_noise( tensor_list=(true_x, true_y), noise_strength_list=(x_noise_strength, y_noise_strength), seed_list=seeds[1:3], - normalize=normalize) - # create datasets + normalize=normalize, + return_normalization=True) + def normalized_func(x): + unnormalized_x = unnormalize_tensor(x, normalization_list[0]) + y = func(unnormalized_x) + normalized_y = normalize_tensor(y, normalization_list[1]) + return normalized_y dataset_len = noisy_x.shape[0] + + # shuffle via seed + new_order = torch.randperm(dataset_len, + generator=torch.Generator().manual_seed(seed)) + true_x = true_x[new_order, ...] + true_y = true_y[new_order, ...] + noisy_x = noisy_x[new_order, ...] + noisy_y = noisy_y[new_order, ...] + + # create datasets train_len = int(dataset_len*splitting_part) test_len = dataset_len - train_len true_train_x, true_test_x = torch.split(true_x, [train_len, test_len]) @@ -56,8 +81,19 @@ def load_data(seed=0, splitting_part=0.8, normalize=True, noisy_train_x, noisy_train_y) true_linear_testset = TensorDataset(true_test_x, true_test_y, noisy_test_x, noisy_test_y) + + + # return different objects, depending on Booleans if not return_ground_truth: - return linear_trainset, linear_testset + if not return_normalized_func: + return linear_trainset, linear_testset + else: + return linear_trainset, linear_testset, normalized_func else: - return linear_trainset, linear_testset, true_linear_trainset,\ - true_linear_testset + if not return_normalized_func: + return linear_trainset, linear_testset, true_linear_trainset,\ + true_linear_testset + else: + return linear_trainset, linear_testset, true_linear_trainset,\ + true_linear_testset, normalized_func + diff --git a/EIVPackage/EIVData/quadratic.py b/EIVPackage/EIVData/quadratic.py index c662b13..13ab3f1 100644 --- a/EIVPackage/EIVData/quadratic.py +++ b/EIVPackage/EIVData/quadratic.py @@ -2,7 +2,8 @@ import torch import sys from torch.utils.data import TensorDataset -from EIVGeneral.manipulate_tensors import add_noise +from EIVGeneral.manipulate_tensors import add_noise, normalize_tensor,\ + unnormalize_tensor total_number_of_datapoints = 2000 input_range = [-1,1] @@ -13,37 +14,61 @@ y_noise_strength = 0.1 func = lambda true_x: slope * true_x**2 + intercept def load_data(seed=0, splitting_part=0.8, normalize=True, - return_ground_truth=False): + return_ground_truth=False, + return_normalized_func=False, + fixed_seed = 0): """ Loads one-dimensional data - :param seed: Seed for drawing and splitting the data. + :param seed: Seed for shuffling the data before splitting. :param splitting_part: Which fraction of the data to use as training data. Defaults to 0.8. :param normalize: Whether to normalize the data, defaults to True. :param return_ground_truth: Boolean. If True, the unnoisy ground truth will also be returned. Defaults to False. - :returns: quadratic_trainset, quadratic_testset if return_ground_truth is False, + :param return_normalized_func: Boolean (default False). If True, the + normalized version of the used function is returned as a last element. + :param fixed_seed: Used to generate the full dataset (test and train). + Defaults to 0. + :returns: quadratic_trainset, quadratic_testset, (, normalized_func) if + return_ground_truth is False, else quadratic_trainset, quadratic_testset, true_quadratic_trainset, - true_quadratic_testset. The later two return **four tensors**: The true x,y and - their noisy counterparts. + true_quadratic_testset, (, normalized_func). The "true" datasets each return + **four tensors**: The true x,y and their noisy counterparts. """ - random_generator = torch.Generator().manual_seed(seed) # draw different seeds for noise and splitting + random_generator = torch.Generator().manual_seed(fixed_seed) seeds = [int(t) for t in torch.randint(0,sys.maxsize,(3,),\ generator=random_generator)] + # create new generators from tensor seeds true_x = input_range[0] + (input_range[1]-input_range[0])\ * torch.rand((total_number_of_datapoints,1), generator=torch.Generator().manual_seed(seeds[0])) true_y = func(true_x) + # add noise and normalize x and y - (noisy_x, noisy_y), (true_x, true_y) = add_noise( + (noisy_x, noisy_y), (true_x, true_y), normalization_list = add_noise( tensor_list=(true_x, true_y), noise_strength_list=(x_noise_strength, y_noise_strength), seed_list=seeds[1:3], - normalize=normalize) - # create datasets + normalize=normalize, + return_normalization=True) + def normalized_func(x): + unnormalized_x = unnormalize_tensor(x, normalization_list[0]) + y = func(unnormalized_x) + normalized_y = normalize_tensor(y, normalization_list[1]) + return normalized_y dataset_len = noisy_x.shape[0] + + # shuffle via seed + new_order = torch.randperm(dataset_len, + generator=torch.Generator().manual_seed(seed)) + true_x = true_x[new_order, ...] + true_y = true_y[new_order, ...] + noisy_x = noisy_x[new_order, ...] + noisy_y = noisy_y[new_order, ...] + + # create datasets train_len = int(dataset_len*splitting_part) test_len = dataset_len - train_len true_train_x, true_test_x = torch.split(true_x, [train_len, test_len]) @@ -56,8 +81,19 @@ def load_data(seed=0, splitting_part=0.8, normalize=True, noisy_train_x, noisy_train_y) true_quadratic_testset = TensorDataset(true_test_x, true_test_y, noisy_test_x, noisy_test_y) + + + # return different objects, depending on Booleans if not return_ground_truth: - return quadratic_trainset, quadratic_testset + if not return_normalized_func: + return quadratic_trainset, quadratic_testset + else: + return quadratic_trainset, quadratic_testset, normalized_func else: - return quadratic_trainset, quadratic_testset, true_quadratic_trainset,\ - true_quadratic_testset + if not return_normalized_func: + return quadratic_trainset, quadratic_testset, true_quadratic_trainset,\ + true_quadratic_testset + else: + return quadratic_trainset, quadratic_testset, true_quadratic_trainset,\ + true_quadratic_testset, normalized_func + diff --git a/EIVPackage/EIVData/sine.py b/EIVPackage/EIVData/sine.py index f68112e..a420654 100644 --- a/EIVPackage/EIVData/sine.py +++ b/EIVPackage/EIVData/sine.py @@ -2,7 +2,8 @@ import torch import sys from torch.utils.data import TensorDataset -from EIVGeneral.manipulate_tensors import add_noise +from EIVGeneral.manipulate_tensors import add_noise, normalize_tensor,\ + unnormalize_tensor total_number_of_datapoints = 2000 input_range = [-0.2,0.8] @@ -14,37 +15,61 @@ func = lambda true_x: true_x +\ torch.sin(4 * torch.pi * true_x) def load_data(seed=0, splitting_part=0.8, normalize=True, - return_ground_truth=False): + return_ground_truth=False, + return_normalized_func=False, + fixed_seed = 0): """ Loads one-dimensional, sine shaped data as in Blundell et al. 2014. - :param seed: Seed for drawing and splitting the data. + :param seed: Seed for shuffling the data before splitting. :param splitting_part: Which fraction of the data to use as training data. Defaults to 0.8. :param normalize: Whether to normalize the data, defaults to True. :param return_ground_truth: Boolean. If True, the unnoisy ground truth will also be returned. Defaults to False. - :returns: sine_trainset, sine_testset if return_ground_truth is False, + :param return_normalized_func: Boolean (default False). If True, the + normalized version of the used function is returned as a last element. + :param fixed_seed: Used to generate the full dataset (test and train). + Defaults to 0. + :returns: sine_trainset, sine_testset, (, normalized_func) if + return_ground_truth is False, else sine_trainset, sine_testset, true_sine_trainset, - true_sine_testset. The later two return **four tensors**: The true x,y and - their noisy counterparts. + true_sine_testset, (, normalized_func). The "true" datasets each return + **four tensors**: The true x,y and their noisy counterparts. """ - random_generator = torch.Generator().manual_seed(seed) # draw different seeds for noise and splitting + random_generator = torch.Generator().manual_seed(fixed_seed) seeds = [int(t) for t in torch.randint(0,sys.maxsize,(3,),\ generator=random_generator)] + # create new generators from tensor seeds true_x = input_range[0] + (input_range[1]-input_range[0])\ * torch.rand((total_number_of_datapoints,1), generator=torch.Generator().manual_seed(seeds[0])) true_y = func(true_x) + # add noise and normalize x and y - (noisy_x, noisy_y), (true_x, true_y) = add_noise( + (noisy_x, noisy_y), (true_x, true_y), normalization_list = add_noise( tensor_list=(true_x, true_y), noise_strength_list=(x_noise_strength, y_noise_strength), seed_list=seeds[1:3], - normalize=normalize) - # create datasets + normalize=normalize, + return_normalization=True) + def normalized_func(x): + unnormalized_x = unnormalize_tensor(x, normalization_list[0]) + y = func(unnormalized_x) + normalized_y = normalize_tensor(y, normalization_list[1]) + return normalized_y dataset_len = noisy_x.shape[0] + + # shuffle via seed + new_order = torch.randperm(dataset_len, + generator=torch.Generator().manual_seed(seed)) + true_x = true_x[new_order, ...] + true_y = true_y[new_order, ...] + noisy_x = noisy_x[new_order, ...] + noisy_y = noisy_y[new_order, ...] + + # create datasets train_len = int(dataset_len*splitting_part) test_len = dataset_len - train_len true_train_x, true_test_x = torch.split(true_x, [train_len, test_len]) @@ -57,8 +82,19 @@ def load_data(seed=0, splitting_part=0.8, normalize=True, noisy_train_x, noisy_train_y) true_sine_testset = TensorDataset(true_test_x, true_test_y, noisy_test_x, noisy_test_y) + + + # return different objects, depending on Booleans if not return_ground_truth: - return sine_trainset, sine_testset + if not return_normalized_func: + return sine_trainset, sine_testset + else: + return sine_trainset, sine_testset, normalized_func else: - return sine_trainset, sine_testset, true_sine_trainset,\ - true_sine_testset + if not return_normalized_func: + return sine_trainset, sine_testset, true_sine_trainset,\ + true_sine_testset + else: + return sine_trainset, sine_testset, true_sine_trainset,\ + true_sine_testset, normalized_func + diff --git a/EIVPackage/EIVGeneral/manipulate_datasets.py b/EIVPackage/EIVGeneral/manipulate_datasets.py index f04280e..553db16 100644 --- a/EIVPackage/EIVGeneral/manipulate_datasets.py +++ b/EIVPackage/EIVGeneral/manipulate_datasets.py @@ -19,3 +19,7 @@ class VerticalCut(Dataset): def __len__(self): return len(self.dataset) + + @property + def tensors(self): + return itemgetter(*self.components_to_pick)(self.dataset.tensors) diff --git a/EIVPackage/EIVGeneral/manipulate_tensors.py b/EIVPackage/EIVGeneral/manipulate_tensors.py index 20c37a6..57392fd 100644 --- a/EIVPackage/EIVGeneral/manipulate_tensors.py +++ b/EIVPackage/EIVGeneral/manipulate_tensors.py @@ -18,9 +18,17 @@ def normalize_tensor(t, mean_std): """ return (t-mean_std[0])/mean_std[1] +def unnormalize_tensor(t, mean_std): + """ + Unnormalize the tensor `t` by the mean `mean_std[0]` and the standard + devation `mean_std[1]`. The inverse of `normalize_tensor`. + """ + return t * mean_std[1] + mean_std[0] + + def add_noise(tensor_list, noise_strength_list, seed_list, normalize=True, - normalization_list = None): + normalization_list = None, return_normalization = False): """ Takes the tensors in `tensor_list`, adds random noise using the standard deviations in `noise_strength_list` and the seeds in `seed_list`, then, if @@ -35,10 +43,14 @@ def add_noise(tensor_list, noise_strength_list, seed_list, normalize=True, :param normalization_list: Either None (default) or a list of tensors. If the latter, these tensors will be used for normalization and `normalize` is assumed to be True. - :returns: noisy_tensor_list, unnoisy_tensor_list, both normalized + :param list_of_normalization: Boolean. If True (default: False) the + used normalizations will be returned. + :returns: noisy_tensor_list, unnoisy_tensor_list(, list_of_normalization) """ noisy_t_list = [] unnoisy_t_list = [] + # store tuples that were used for normalization in here + list_of_normalization = [] if normalization_list is not None: assert len(normalization_list) == len(tensor_list) for i, (t,noise,seed) in enumerate(zip(tensor_list, noise_strength_list,\ @@ -51,9 +63,12 @@ def add_noise(tensor_list, noise_strength_list, seed_list, normalize=True, get_normalization(normalization_list[i]) else: noisy_t_normalization = get_normalization(noisy_t) + list_of_normalization.append(noisy_t_normalization) noisy_t = normalize_tensor(noisy_t, noisy_t_normalization) t = normalize_tensor(t, noisy_t_normalization) noisy_t_list.append(noisy_t) unnoisy_t_list.append(t) - return noisy_t_list, unnoisy_t_list - + if return_normalization: + return noisy_t_list, unnoisy_t_list, list_of_normalization + else: + return noisy_t_list, unnoisy_t_list diff --git a/Experiments/plot_prediction.py b/Experiments/plot_prediction.py index ab29fed..61fac8d 100644 --- a/Experiments/plot_prediction.py +++ b/Experiments/plot_prediction.py @@ -1,6 +1,8 @@ """ Plot predictions with uncertainties for (simulated) datasets with a ground -truth. +truth. At the moment it is assumed that the used datasets have an output +dimension equal to 1. Plots are only produced for datasets with input dimension +and output dimension 1. """ import importlib import os @@ -25,15 +27,20 @@ def compute_predictions_and_uncertainties(data, x_range, eiv, number_of_draws, throuth their JSON configuration and evaluate their prediction and uncertainties for the (true) x in `x_range`. The results returned are as numpy arrays included in a `plotting_dictionary` that contains the predictions - and uncertainties via the keys "prediction" and "uncertainty" but also the - noisified version of `x_range` and the corresponding y values (key - "range_points") and `number_of_test_datapoints` points from the test - dataset with seed `plotting_seed` (key "test_data_points"). + and uncertainties via the keys "prediction" and "uncertainty" but also + - A tuple of `x_range` and the corresponding values of y (key + "range_points") + - the noisified version of `x_range` and the corresponding y values (key + "noisy_range_points") and + - `number_of_test_datapoints` points from the test + dataset with seed `plotting_seed` (key "test_data_points") and + - the input dimension (key "input_dim"). **Note**: The output of the neural networks are assumed to be one-dimensional . - :data: String, short dataname + :data: String, short dataname. The corresponding module should contain + `x_noise_strength`, `y_noise_strength`. :x_range: An iterator yielding the (true) x values to consider :eiv: Boolean. If True an EiV model is used, else an non-EiV model. :number_of_draws: Number of draws to use for prediction. Take an int for @@ -41,7 +48,7 @@ def compute_predictions_and_uncertainties(data, x_range, eiv, number_of_draws, :x_noise_seed: An integer. Will be used as a seed to generate the noise put on `x_range`. :y_noise_seed: An integer. Will be used as a seed to generate the noise put - on `func(x_range)` that will be returned with `range_values` in the + on `normalized_func(x_range)` that will be returned with `range_values` in the `plotting_dictionary`. :plotting_seed: An integer. Needed for choosing which of the test datasets will be used to returning the test datapoints. @@ -59,16 +66,19 @@ def compute_predictions_and_uncertainties(data, x_range, eiv, number_of_draws, conf_file: conf_dict = json.load(conf_file) + # get datanames long_dataname = conf_dict["long_dataname"] short_dataname = conf_dict["short_dataname"] + # load hyperparameters load_data = importlib.import_module(f'EIVData.{long_dataname}').load_data x_noise_strength =\ importlib.import_module(f'EIVData.{long_dataname}').x_noise_strength y_noise_strength =\ importlib.import_module(f'EIVData.{long_dataname}').y_noise_strength - func = importlib.import_module(f'EIVData.{long_dataname}').func + seed_list = range(conf_dict["seed_range"][0], + conf_dict["seed_range"][1]) # switch to gpu, if possible try: @@ -87,19 +97,21 @@ def compute_predictions_and_uncertainties(data, x_range, eiv, number_of_draws, device = torch.device('cpu') + # determine dimensions _, test_data = load_data(seed=plotting_seed, return_ground_truth=False) input_dim = test_data[0][0].numel() output_dim = test_data[0][1].numel() assert output_dim == 1 + # store in plotting_dictionary + plotting_dictionary['input_dim'] = input_dim + + # store test datapoints test_x, test_y = test_data[:number_of_test_datapoints] plotting_dictionary['test_data_points'] = (test_x.detach().cpu().numpy(), test_y.detach().cpu().numpy()) - ## Create iterators for get_coverage_distribution - seed_list = range(conf_dict["seed_range"][0], - conf_dict["seed_range"][1]) - # iterator for networks + # iterator for looping through networks def net_iterator(eiv=eiv, seed_list=seed_list): """ Yields EiV models (if `eiv`) or @@ -145,17 +157,28 @@ def compute_predictions_and_uncertainties(data, x_range, eiv, number_of_draws, net=net, device=device) yield net + # add feature dimension (if necessary) x_range = x_range.view((-1, input_dim)) + y_range = normalized_func(x_range) + # noisify noisy_x_range = x_range + x_noise_strength * torch.randn(x_range.shape, generator=torch.Generator().manual_seed(x_noise_seed)) - # add feature dimension (if necessary) and move to device - noisy_x_range = noisy_x_range.to(device) - noisy_y_range = func(x_range) + y_noise_strength *\ + # move to device for later processing + noisy_x_range = noisy_x_range.to(device) + # y values for noisy_x_range (not on device) + noisy_y_range = y_range + y_noise_strength *\ torch.randn(x_range.shape, generator=torch.Generator().manual_seed(y_noise_seed)) - plotting_dictionary['range_points'] =\ + # save in plotting_dictionary + plotting_dictionary['noisy_range_points'] =\ (noisy_x_range.detach().cpu().numpy(), noisy_y_range.detach().cpu().numpy()) + plotting_dictionary['range_points'] =\ + (x_range.detach().cpu().numpy(), + y_range.detach().cpu().numpy()) + + + # loop through networks and predict mean_collection, unc_collection = [], [] for net in net_iterator(eiv=eiv): mean, unc = net.predict_mean_and_unc(noisy_x_range, @@ -176,7 +199,8 @@ def compute_predictions_and_uncertainties(data, x_range, eiv, number_of_draws, # stack collections along a new, first dimension mean_collection = torch.stack(mean_collection, dim=0) unc_collection = torch.stack(unc_collection, dim=0) - # average + + # save average in plotting_dictionary plotting_dictionary['prediction'] =\ torch.mean(mean_collection, dim=0).detach().cpu().numpy() plotting_dictionary['uncertainty'] =\ @@ -184,3 +208,36 @@ def compute_predictions_and_uncertainties(data, x_range, eiv, number_of_draws, return plotting_dictionary +data_list = ['sine'] # short datanames +list_x_range = [torch.linspace(0.0,1.0, 50)] +list_color = [('red','blue')] +list_number_of_draws = [((100,5), 100)] +for i, (data, x_range, color, number_of_draws) in enumerate(zip(data_list, + list_x_range, list_color, list_number_of_draws)): + eiv_plotting_dictionary = compute_predictions_and_uncertainties( + data=data, + x_range=x_range, + eiv=True, + number_of_draws=number_of_draws[0]) + noneiv_plotting_dictionary = compute_predictions_and_uncertainties( + data=data, + x_range=x_range, + eiv=False, + number_of_draws=number_of_draws[1]) + input_dim = eiv_plotting_dictionary['input_dim'] + if input_dim == 1: + plt.figure(i) + plt.clf() + x_values, y_values = eiv_plotting_dictionary['range_points'] + plt.plot(x_values, y_values,'-', color='k') + # plt.plot(x_values, eiv_plotting_dictionary['prediction'],'-', + # color=color[0]) + # plt.plot(x_values, noneiv_plotting_dictionary['prediction'],'-', + # color=color[1]) + else: + # multidimensional handling not included yet + pass + + +plt.show() + -- GitLab