From cf50369265b50544e2acdfc2f8f575e48971b21e Mon Sep 17 00:00:00 2001 From: beckynevin Date: Sat, 13 Jul 2024 09:58:54 -0600 Subject: [PATCH 01/14] adding optional args to config --- src/scripts/DeepEnsemble.py | 2 + src/scripts/DeepEvidentialRegression.py | 97 ++++++++++++++++--------- 2 files changed, 66 insertions(+), 33 deletions(-) diff --git a/src/scripts/DeepEnsemble.py b/src/scripts/DeepEnsemble.py index 264428e..0239d76 100644 --- a/src/scripts/DeepEnsemble.py +++ b/src/scripts/DeepEnsemble.py @@ -241,6 +241,8 @@ def parse_args(): "val_proportion": args.val_proportion, "randomseed": args.randomseed, "batchsize": args.batchsize, + "generatedata": args.generatedata, + "normalize": args.normalize }, # "plots": {key: {} for key in args.plots}, # "metrics": {key: {} for key in args.metrics}, diff --git a/src/scripts/DeepEvidentialRegression.py b/src/scripts/DeepEvidentialRegression.py index 63cbfaf..fe1a98f 100644 --- a/src/scripts/DeepEvidentialRegression.py +++ b/src/scripts/DeepEvidentialRegression.py @@ -32,6 +32,10 @@ def parse_args(): parser.add_argument( "--data_path", "-d", default=DefaultsDER["data"]["data_path"]) + parser.add_argument( + "--data_dimension", + "-dd", default=DefaultsDER["data"]["data_dimension"] + ) parser.add_argument( "--data_prescription", "-dp", default=DefaultsDER["data"]["data_prescription"] @@ -96,7 +100,7 @@ def parse_args(): "--generatedata", action="store_true", default=DefaultsDER["data"]["generatedata"], - help="option to generate df, if not specified \ + help="option to generate data, if not specified \ default behavior is to load from file", ) parser.add_argument( @@ -241,6 +245,7 @@ def parse_args(): "data": { "data_path": args.data_path, "data_engine": args.data_engine, + "data_dimension": args.data_dimension, "data_prescription": args.data_prescription, "data_injection": args.data_injection, "size_df": args.size_df, @@ -248,6 +253,8 @@ def parse_args(): "val_proportion": args.val_proportion, "randomseed": args.randomseed, "batchsize": args.batchsize, + "generatedata": args.generatedata, + "normalize": args.normalize }, # "plots": {key: {} for key in args.plots}, # "metrics": {key: {} for key in args.metrics}, @@ -270,45 +277,69 @@ def parse_args(): sigma = DataPreparation.get_sigma(noise) path_to_data = config.get_item("data", "data_path", "DER") prescription = config.get_item("data", "data_prescription", "DER") + dim = config.get_item("data", "data_dimension", "DER") injection = config.get_item("data", "data_injection", "DER") + print(config.get_item("data", "generatedata", "DER", raise_exception=False)) if config.get_item("data", "generatedata", "DER", raise_exception=False): # generate the df + print('generating the data') data = DataPreparation() - data.sample_params_from_prior(size_df) - data.simulate_data(data.params, sigma, prescription) - df_array = data.get_dict() - # Convert non-tensor entries to tensors - df = {} - for key, value in df_array.items(): + if dim == "0D": + data.sample_params_from_prior(size_df) + data.simulate_data(data.params, sigma, prescription) + df_array = data.get_dict() + # Convert non-tensor entries to tensors + df = {} + for key, value in df_array.items(): - if isinstance(value, TensorDataset): - # Keep tensors as they are - df[key] = value - else: - # Convert lists to tensors - df[key] = torch.tensor(value) + if isinstance(value, TensorDataset): + # Keep tensors as they are + df[key] = value + else: + # Convert lists to tensors + df[key] = torch.tensor(value) + elif dim == "2D": + print('2D data') + data.sample_params_from_prior(size_df, + low=[1, 1, -1.5], + high=[10, 10, 1.5], + n_params=3, + seed=42) + im, im_noisy, y, y_noisy, y_prop_noisy = data.simulate_data_2d( + size_df, + data.params, + image_size=32, + inject_type=injection) + if injection == "predictive": + model_inputs = im + model_outputs = y_noisy + elif injection == "feature": + model_inputs = im_noisy + model_outputs = y else: loader = MyDataLoader() - filename = ( - str(prescription) - + "_" - + str(injection) - + "_sigma_" - + str(sigma) - + "_size_" - + str(size_df) - ) - df = loader.load_data_h5(filename, path=path_to_data) - print("loaded this file: ", filename) - len_df = len(df["params"][:, 0].numpy()) - len_x = np.shape(df["output"])[1] - ms_array = np.repeat(df["params"][:, 0].numpy(), len_x) - bs_array = np.repeat(df["params"][:, 1].numpy(), len_x) - xs_array = np.reshape(df["inputs"].numpy(), (len_df * len_x)) - ys_array = np.reshape(df["output"].numpy(), (len_df * len_x)) - inputs = np.array([xs_array, ms_array, bs_array]).T - model_inputs, model_outputs = DataPreparation.normalize( - inputs, ys_array, norm) + if dim == "0D": + filename = ( + str(prescription) + + "_" + + str(injection) + + "_sigma_" + + str(sigma) + + "_size_" + + str(size_df) + ) + df = loader.load_data_h5(filename, path=path_to_data) + print("loaded this file: ", filename) + if dim == "0D": + len_df = len(df["params"][:, 0].numpy()) + len_x = np.shape(df["output"])[1] + ms_array = np.repeat(df["params"][:, 0].numpy(), len_x) + bs_array = np.repeat(df["params"][:, 1].numpy(), len_x) + xs_array = np.reshape(df["inputs"].numpy(), (len_df * len_x)) + ys_array = np.reshape(df["output"].numpy(), (len_df * len_x)) + inputs = np.array([xs_array, ms_array, bs_array]).T + model_inputs, model_outputs = DataPreparation.normalize( + inputs, ys_array, norm) x_train, x_val, y_train, y_val = DataPreparation.train_val_split( model_inputs, model_outputs, val_proportion=val_prop, random_state=rs ) From d4b18f4925087d47c0c2845c940bc1f3a3511db1 Mon Sep 17 00:00:00 2001 From: beckynevin Date: Sat, 13 Jul 2024 13:26:23 -0600 Subject: [PATCH 02/14] adding data_type to the train module as well as a CNN module --- src/data/data.py | 35 ++++++++++++++++++- src/models/models.py | 46 ++++++++++++++++++++++--- src/scripts/DeepEvidentialRegression.py | 26 +++++++------- 3 files changed, 89 insertions(+), 18 deletions(-) diff --git a/src/data/data.py b/src/data/data.py index 8de40c8..1779dfe 100644 --- a/src/data/data.py +++ b/src/data/data.py @@ -101,7 +101,7 @@ class DataPreparation: def __init__(self): self.data = None - def simulate_data_2d( + def image_gen( self, image_size=100, amplitude=10, @@ -126,6 +126,39 @@ def simulate_data_2d( ) return image + def simulate_data_2d(self, + size_df, + params, + image_size=32, + inject_type="predictive", + sigma=1): + image_size = 32 + image_array = np.zeros((size_df, image_size, image_size)) + total_brightness = [] + for i in range(size_df): + image = self.image_gen( + image_size=image_size, + amplitude=params[i, 0], + radius=params[i, 1], + center_x=16, + center_y=16, + theta=params[i, 2], + noise_level=0) + if inject_type == "predictive": + image_array[i, :, :] = image + total_brightness.append( + np.sum(image) + np.random.normal( + loc=0, scale=sigma)) + elif inject_type == "feature": + noisy_image = image + np.random.normal( + loc=0, scale=sigma, size=(image_size, image_size)) + image_array[i, :, :] = noisy_image + total_brightness.append(np.sum(image)) + # we'll need the noisy image summed if we want to + # do a comparison of y - y': + # total_brightness_prop_noisy.append(np.sum(noisy_image)) + return image_array, total_brightness + def simulate_data( self, thetas, diff --git a/src/models/models.py b/src/models/models.py index a37f89d..be2b1bc 100644 --- a/src/models/models.py +++ b/src/models/models.py @@ -66,8 +66,34 @@ def forward(self, x): beta = nn.functional.softplus(x[:, 3]) return torch.stack((gamma, nu, alpha, beta), dim=1) +class ConvLayers(nn.Module): + def __init__(self): + super(ConvLayers, self).__init__() + self.conv1 = nn.Conv2d(1, 10, kernel_size=3, padding=1) + self.conv2 = nn.Conv2d(10, 10, kernel_size=3, padding=1) + self.pool1 = nn.AvgPool2d(kernel_size=2, stride=2, padding=1) + self.conv3 = nn.Conv2d(10, 10, kernel_size=3, padding=1) + self.pool2 = nn.AvgPool2d(kernel_size=2, stride=2, padding=1) + self.conv4 = nn.Conv2d(10, 5, kernel_size=3, padding=1) + self.conv5 = nn.Conv2d(5, 5, kernel_size=3, padding=1) + self.flatten = nn.Flatten() -def model_setup_DER(loss_type, DEVICE, n_hidden): + def forward(self, x): + x = nn.functional.relu(self.conv1(x)) + x = nn.functional.relu(self.conv2(x)) + x = self.pool1(x) + x = nn.functional.relu(self.conv3(x)) + x = self.pool2(x) + x = nn.functional.relu(self.conv4(x)) + x = nn.functional.relu(self.conv5(x)) + x = self.flatten(x) + return x + + +def model_setup_DER(loss_type, + DEVICE, + n_hidden=64, + data_type="0D"): # initialize the model from scratch if loss_type == "SDER": Layer = SDERLayer @@ -77,10 +103,20 @@ def model_setup_DER(loss_type, DEVICE, n_hidden): Layer = DERLayer # initialize our loss function lossFn = loss_der - - # from https://github.com/pasteurlabs/unreasonable_effective_der - # /blob/main/x3_indepth.ipynb - model = torch.nn.Sequential(Model(4, n_hidden), Layer()) + if data_type == "2D": + # Define the convolutional layers + conv_layers = ConvLayers() + + # Initialize the rest of the model + model = torch.nn.Sequential( + conv_layers, + Model(5 * 8 * 8, n_hidden), # Adjust input size according to the flattened output size + Layer() + ) + elif data_type == "0D": + # from https://github.com/pasteurlabs/unreasonable_effective_der + # /blob/main/x3_indepth.ipynb + model = torch.nn.Sequential(Model(4, n_hidden), Layer()) model = model.to(DEVICE) return model, lossFn diff --git a/src/scripts/DeepEvidentialRegression.py b/src/scripts/DeepEvidentialRegression.py index fe1a98f..873a3c5 100644 --- a/src/scripts/DeepEvidentialRegression.py +++ b/src/scripts/DeepEvidentialRegression.py @@ -279,7 +279,6 @@ def parse_args(): prescription = config.get_item("data", "data_prescription", "DER") dim = config.get_item("data", "data_dimension", "DER") injection = config.get_item("data", "data_injection", "DER") - print(config.get_item("data", "generatedata", "DER", raise_exception=False)) if config.get_item("data", "generatedata", "DER", raise_exception=False): # generate the df print('generating the data') @@ -305,17 +304,11 @@ def parse_args(): high=[10, 10, 1.5], n_params=3, seed=42) - im, im_noisy, y, y_noisy, y_prop_noisy = data.simulate_data_2d( + model_inputs, model_outputs = data.simulate_data_2d( size_df, data.params, image_size=32, inject_type=injection) - if injection == "predictive": - model_inputs = im - model_outputs = y_noisy - elif injection == "feature": - model_inputs = im_noisy - model_outputs = y else: loader = MyDataLoader() if dim == "0D": @@ -336,13 +329,21 @@ def parse_args(): ms_array = np.repeat(df["params"][:, 0].numpy(), len_x) bs_array = np.repeat(df["params"][:, 1].numpy(), len_x) xs_array = np.reshape(df["inputs"].numpy(), (len_df * len_x)) - ys_array = np.reshape(df["output"].numpy(), (len_df * len_x)) - inputs = np.array([xs_array, ms_array, bs_array]).T - model_inputs, model_outputs = DataPreparation.normalize( - inputs, ys_array, norm) + model_outputs = np.reshape(df["output"].numpy(), (len_df * len_x)) + model_inputs = np.array([xs_array, ms_array, bs_array]).T + model_inputs, model_outputs = DataPreparation.normalize( + model_inputs, model_outputs, norm) x_train, x_val, y_train, y_val = DataPreparation.train_val_split( model_inputs, model_outputs, val_proportion=val_prop, random_state=rs ) + ''' + import matplotlib.pyplot as plt + plt.clf() + plt.imshow(x_train[0,:,:]) + plt.title(y_train[0]) + plt.colorbar() + plt.show() + ''' trainData = TensorDataset(torch.Tensor(x_train), torch.Tensor(y_train)) trainDataLoader = DataLoader( trainData, batch_size=BATCH_SIZE, shuffle=True) @@ -369,6 +370,7 @@ def parse_args(): path_to_model=config.get_item("common", "out_dir", "DER"), data_prescription=prescription, inject_type=injection, + data_dim=dim, noise_level=noise, save_all_checkpoints=config.get_item( "model", "save_all_checkpoints", "DER"), From 2ac0998fcc6c7e275f9c52a0551293d0b6072c77 Mon Sep 17 00:00:00 2001 From: beckynevin Date: Sat, 13 Jul 2024 16:05:34 -0600 Subject: [PATCH 03/14] no fail statements --- notebooks/save_dataframe_linefit.ipynb | 57 +++++--------------------- 1 file changed, 11 insertions(+), 46 deletions(-) diff --git a/notebooks/save_dataframe_linefit.ipynb b/notebooks/save_dataframe_linefit.ipynb index 8d4d920..4939df0 100644 --- a/notebooks/save_dataframe_linefit.ipynb +++ b/notebooks/save_dataframe_linefit.ipynb @@ -11,7 +11,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "47611152-0598-4d26-ac4d-d1f243dd0736", "metadata": {}, "outputs": [], @@ -34,7 +34,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "685fb21f-38d9-4a2d-a431-79b6f540d4d5", "metadata": {}, "outputs": [], @@ -44,7 +44,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "7db50617-e509-405e-900e-38676e38dd12", "metadata": {}, "outputs": [], @@ -56,7 +56,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "d40b7a9a-27ea-40a0-831b-51e82ca67267", "metadata": {}, "outputs": [], @@ -80,7 +80,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "7c9345bf-0335-4ce3-8ce5-17c92930ee66", "metadata": {}, "outputs": [], @@ -98,7 +98,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "47d7b88f-248f-49de-a8ec-1737e965c613", "metadata": {}, "outputs": [], @@ -108,18 +108,10 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "418b9ea9-0196-4fa4-b9dd-9109a28d4266", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "linear_homoskedastic simulation data generated, with noise injected type: predictive.\n" - ] - } - ], + "outputs": [], "source": [ "data.simulate_data(data.params,\n", " noise_to_sigma[noise], \n", @@ -138,37 +130,10 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "id": "4de0c3a7-8073-4d53-87a3-65564c183c8e", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "torch.Size([101000])\n", - "torch.Size([1000, 101])\n", - "torch.Size([101000])\n", - "torch.Size([1000, 101])\n", - "torch.Size([101000])\n", - "torch.Size([1000, 101])\n", - "torch.Size([101000])\n", - "torch.Size([1000, 101])\n", - "torch.Size([101000])\n", - "torch.Size([1000, 101])\n" - ] - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "plt.clf()\n", "for i in range(5):\n", @@ -292,7 +257,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.12" + "version": "3.10.12" } }, "nbformat": 4, From 40e6d9c0354b50ad9217a0ead4c025cc40590af9 Mon Sep 17 00:00:00 2001 From: beckynevin Date: Sat, 13 Jul 2024 16:06:31 -0600 Subject: [PATCH 04/14] commented out sizes, added n_inputs and n_outputs as args to Model() --- src/models/models.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/models/models.py b/src/models/models.py index be2b1bc..a89c808 100644 --- a/src/models/models.py +++ b/src/models/models.py @@ -79,14 +79,26 @@ def __init__(self): self.flatten = nn.Flatten() def forward(self, x): + # print('input shape', x.shape) + if x.dim() == 3: # Check if the input is of shape (batchsize, 32, 32) + x = x.unsqueeze(1) # Add channel dimension, becomes (batchsize, 1, 32, 32) + # print('shape after potential unsqeeze', x.shape) x = nn.functional.relu(self.conv1(x)) + # print('shape after conv1', x.shape) x = nn.functional.relu(self.conv2(x)) + # print('shape after conv2', x.shape) x = self.pool1(x) + # print('shape after pool1', x.shape) x = nn.functional.relu(self.conv3(x)) + # print('shape after conv3', x.shape) x = self.pool2(x) + # print('shape after pool2', x.shape) x = nn.functional.relu(self.conv4(x)) + # print('shape after conv4', x.shape) x = nn.functional.relu(self.conv5(x)) + # print('shape after conv5', x.shape) x = self.flatten(x) + # print('shape after flatten', x.shape) return x @@ -110,13 +122,14 @@ def model_setup_DER(loss_type, # Initialize the rest of the model model = torch.nn.Sequential( conv_layers, - Model(5 * 8 * 8, n_hidden), # Adjust input size according to the flattened output size + Model(n_hidden=n_hidden, n_input=405, n_output=4), # Adjust input size according to the flattened output size Layer() ) elif data_type == "0D": # from https://github.com/pasteurlabs/unreasonable_effective_der # /blob/main/x3_indepth.ipynb - model = torch.nn.Sequential(Model(4, n_hidden), Layer()) + model = torch.nn.Sequential(Model( + n_hidden=n_hidden, n_input=4, n_output=4), Layer()) model = model.to(DEVICE) return model, lossFn @@ -158,10 +171,13 @@ def model_setup_DE(loss_type, DEVICE): class Model(nn.Module): - def __init__(self, n_output, n_hidden): + def __init__(self, + n_output=4, + n_hidden=64, + n_input=3): super().__init__() self.model = nn.Sequential( - nn.Linear(3, n_hidden), + nn.Linear(n_input, n_hidden), nn.ReLU(), nn.Linear(n_hidden, n_hidden), nn.ReLU(), From 235a5706af6cbb3a55994195aa57fac102b8a585 Mon Sep 17 00:00:00 2001 From: beckynevin Date: Sat, 13 Jul 2024 16:09:32 -0600 Subject: [PATCH 05/14] running all the way through --- src/scripts/DeepEvidentialRegression.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/DeepEvidentialRegression.py b/src/scripts/DeepEvidentialRegression.py index 873a3c5..67dbf54 100644 --- a/src/scripts/DeepEvidentialRegression.py +++ b/src/scripts/DeepEvidentialRegression.py @@ -357,7 +357,7 @@ def parse_args(): n_hidden=config.get_item("model", "n_hidden", "DER"), ) print("model name is ", model_name) - model_ensemble = train.train_DER( + model = train.train_DER( trainDataLoader, x_val, y_val, From 03d1ca6ba3d4a102d49777f59cd5ed8d43c48204 Mon Sep 17 00:00:00 2001 From: beckynevin Date: Sat, 13 Jul 2024 16:10:02 -0600 Subject: [PATCH 06/14] also prints out chk on 99, data_dim added to check filename --- src/train/train.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/train/train.py b/src/train/train.py index da62b1b..0e3a712 100644 --- a/src/train/train.py +++ b/src/train/train.py @@ -27,6 +27,7 @@ def train_DER( path_to_model="models/", data_prescription="linear_homoskedastic", inject_type="predictive", + data_dim="0D", noise_level="low", save_all_checkpoints=False, save_final_checkpoint=False, @@ -95,7 +96,8 @@ def train_DER( best_loss = np.inf # init to infinity model, lossFn = models.model_setup_DER(loss_type, DEVICE, - n_hidden=n_hidden) + n_hidden=n_hidden, + data_type=data_dim) if verbose: print("model is", model, "lossfn", lossFn) opt = torch.optim.Adam(model.parameters(), lr=INIT_LR) @@ -127,7 +129,6 @@ def train_DER( # send the input to the device # (x, y) = (x.to(device), y.to(device)) # perform a forward pass and calculate the training loss - pred = model(x) loss = lossFn(pred, y, COEFF) if plot or savefig: @@ -259,6 +260,8 @@ def train_DER( + str(data_prescription) + "_" + str(inject_type) + + "_" + + str(data_dim) + "_loss_" + str(loss_type) + "_COEFF_" @@ -280,6 +283,8 @@ def train_DER( + str(data_prescription) + "_" + str(inject_type) + + "_" + + str(data_dim) + "_noise_" + str(noise_level) + "_loss_" @@ -313,6 +318,8 @@ def train_DER( }, filename ) + if epoch == 99: + print('checkpoint saved here', filename) if save_final_checkpoint and (e % (EPOCHS - 1) == 0) and (e != 0): filename = ( @@ -323,6 +330,8 @@ def train_DER( + str(data_prescription) + "_" + str(inject_type) + + "_" + + str(data_dim) + "_noise_" + str(noise_level) + "_loss_" From 49ef61213c43c998a2f3af686febdbc40dd8ebfb Mon Sep 17 00:00:00 2001 From: beckynevin Date: Sat, 13 Jul 2024 16:10:23 -0600 Subject: [PATCH 07/14] data_dim added to defaults --- src/utils/defaults.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/defaults.py b/src/utils/defaults.py index 1a4b1b4..aa783ab 100644 --- a/src/utils/defaults.py +++ b/src/utils/defaults.py @@ -50,6 +50,7 @@ "data": { "data_path": "./data/", "data_engine": "DataLoader", + "data_dimension": "0D", "data_prescription": "linear_homoskedastic", "data_injection": "predictive", "size_df": 1000, From 86e081ea374d8d63152ca735b7cf2e55e1bff984 Mon Sep 17 00:00:00 2001 From: beckynevin Date: Tue, 16 Jul 2024 13:15:02 -0600 Subject: [PATCH 08/14] modifying setup_DE --- src/models/models.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/models/models.py b/src/models/models.py index a89c808..68f45f7 100644 --- a/src/models/models.py +++ b/src/models/models.py @@ -69,6 +69,8 @@ def forward(self, x): class ConvLayers(nn.Module): def __init__(self): super(ConvLayers, self).__init__() + # a little strange = # of filters, usually goes from small to large + # double check on architecture decisions self.conv1 = nn.Conv2d(1, 10, kernel_size=3, padding=1) self.conv2 = nn.Conv2d(10, 10, kernel_size=3, padding=1) self.pool1 = nn.AvgPool2d(kernel_size=2, stride=2, padding=1) @@ -129,7 +131,7 @@ def model_setup_DER(loss_type, # from https://github.com/pasteurlabs/unreasonable_effective_der # /blob/main/x3_indepth.ipynb model = torch.nn.Sequential(Model( - n_hidden=n_hidden, n_input=4, n_output=4), Layer()) + n_hidden=n_hidden, n_input=3, n_output=4), Layer()) model = model.to(DEVICE) return model, lossFn @@ -146,7 +148,10 @@ def forward(self, x): return torch.stack((mu, var), dim=1) -def model_setup_DE(loss_type, DEVICE): +def model_setup_DE(loss_type, + DEVICE, + n_hidden=64, + data_type="0D"): # initialize the model from scratch if loss_type == "no_var_loss": # model = de_no_var().to(DEVICE) @@ -161,7 +166,20 @@ def model_setup_DE(loss_type, DEVICE): # model = de_var().to(DEVICE) Layer = MuVarLayer lossFn = loss_bnll - model = torch.nn.Sequential(Model(2, 64), Layer()) + if data_type == "2D": + # Define the convolutional layers + conv_layers = ConvLayers() + # Initialize the rest of the model + model = torch.nn.Sequential( + conv_layers, + Model(n_hidden=n_hidden, n_input=405, n_output=2), # Adjust input size according to the flattened output size + Layer() + ) + elif data_type == "0D": + # from https://github.com/pasteurlabs/unreasonable_effective_der + # /blob/main/x3_indepth.ipynb + model = torch.nn.Sequential(Model( + n_hidden=n_hidden, n_input=3, n_output=2), Layer()) model = model.to(DEVICE) return model, lossFn From 6bfa6a3875067c88abd2d73bb94133f4784190ee Mon Sep 17 00:00:00 2001 From: beckynevin Date: Tue, 16 Jul 2024 13:15:28 -0600 Subject: [PATCH 09/14] modified DE to mirror DER, also adding rs_list as an option --- src/scripts/DeepEnsemble.py | 126 ++++++++++++++++++++++++++---------- 1 file changed, 91 insertions(+), 35 deletions(-) diff --git a/src/scripts/DeepEnsemble.py b/src/scripts/DeepEnsemble.py index 0239d76..d612b9f 100644 --- a/src/scripts/DeepEnsemble.py +++ b/src/scripts/DeepEnsemble.py @@ -36,6 +36,10 @@ def parse_args(): "-d", default=DefaultsDE["data"]["data_path"], ) + parser.add_argument( + "--data_dimension", + "-dd", default=DefaultsDE["data"]["data_dimension"] + ) parser.add_argument( "--data_prescription", "-dp", default=DefaultsDE["data"]["data_prescription"] @@ -184,6 +188,32 @@ def parse_args(): default=DefaultsDE["model"]["savefig"], help="option to save a figure of the true and predicted values", ) + parser.add_argument( + "--save_chk_random_seed_init", + action="store_true", + default=DefaultsDE["model"]["save_chk_random_seed_init"], + help="option to save the chk with a random seed", + ) + parser.add_argument( + "--rs_list", + type=list[int], + default=DefaultsDE["model"]["rs_list"], + help="random seed list for the pytorch model initialization, \ + should be the same length as n_models", + ) + parser.add_argument( + "--save_n_hidden", + action="store_true", + default=DefaultsDE["model"]["save_n_hidden"], + help="save chk with the number of neurons in the hidden layer", + ) + parser.add_argument( + "--n_hidden", + type=int, + required=False, + default=DefaultsDE["model"]["n_hidden"], + help="Number of hidden neurons in the hidden layer, default 64", + ) parser.add_argument( "--verbose", action="store_true", @@ -229,11 +259,16 @@ def parse_args(): "overwrite_final_checkpoint": args.overwrite_final_checkpoint, "plot": args.plot, "savefig": args.savefig, + "save_chk_random_seed_init": args.save_chk_random_seed_init, + "rs_list": args.rs_list, + "save_n_hidden": args.save_n_hidden, + "n_hidden": args.n_hidden, "verbose": args.verbose, }, "data": { "data_path": args.data_path, "data_engine": args.data_engine, + "data_dimension": args.data_dimension, "data_prescription": args.data_prescription, "data_injection": args.data_injection, "size_df": args.size_df, @@ -277,54 +312,69 @@ def beta_type(value): noise = config.get_item("data", "noise_level", "DE") norm = config.get_item("data", "normalize", "DE", raise_exception=False) val_prop = config.get_item("data", "val_proportion", "DE") + # this is the data rs rs = config.get_item("data", "randomseed", "DE") BATCH_SIZE = config.get_item("data", "batchsize", "DE") sigma = DataPreparation.get_sigma(noise) path_to_data = config.get_item("data", "data_path", "DE") prescription = config.get_item("data", "data_prescription", "DE") injection = config.get_item("data", "data_injection", "DE") + dim = config.get_item("data", "data_dimension", "DE") if config.get_item("data", "generatedata", "DE", raise_exception=False): # generate the df + print('generating the data') data = DataPreparation() - data.sample_params_from_prior(size_df) - data.simulate_data(data.params, sigma, prescription) - df_array = data.get_dict() - # Convert non-tensor entries to tensors - df = {} - for key, value in df_array.items(): + if dim == "0D": + data.sample_params_from_prior(size_df) + data.simulate_data(data.params, sigma, prescription) + df_array = data.get_dict() + # Convert non-tensor entries to tensors + df = {} + for key, value in df_array.items(): - if isinstance(value, TensorDataset): - # Keep tensors as they are - df[key] = value - else: - # Convert lists to tensors - df[key] = torch.tensor(value) + if isinstance(value, TensorDataset): + # Keep tensors as they are + df[key] = value + else: + # Convert lists to tensors + df[key] = torch.tensor(value) + elif dim == "2D": + print('2D data') + data.sample_params_from_prior( + size_df, + low=[1, 1, -1.5], + high=[10, 10, 1.5], + n_params=3, + seed=42) + model_inputs, model_outputs = data.simulate_data_2d( + size_df, + data.params, + image_size=32, + inject_type=injection) else: loader = MyDataLoader() - filename = ( - str(prescription) - + "_" - + str(injection) - + "_sigma_" - + str(sigma) - + "_size_" - + str(size_df) - ) - df = loader.load_data_h5(filename, path=path_to_data) - print("loaded this file: ", filename) - len_df = len(df["params"][:, 0].numpy()) - len_x = np.shape(df["output"])[1] - ms_array = np.repeat(df["params"][:, 0].numpy(), len_x) - bs_array = np.repeat(df["params"][:, 1].numpy(), len_x) - # xs_array = np.tile(df["inputs"].numpy(), len_df) - # print('shape of inputs', np.shape(df["inputs"])) - # print('shape of outputs', np.shape(df["output"])) - xs_array = np.reshape(df["inputs"].numpy(), (len_df * len_x)) - ys_array = np.reshape(df["output"].numpy(), (len_df * len_x)) - - inputs = np.array([xs_array, ms_array, bs_array]).T + if dim == "0D": + filename = ( + str(prescription) + + "_" + + str(injection) + + "_sigma_" + + str(sigma) + + "_size_" + + str(size_df) + ) + df = loader.load_data_h5(filename, path=path_to_data) + print("loaded this file: ", filename) + if dim == "0D": + len_df = len(df["params"][:, 0].numpy()) + len_x = np.shape(df["output"])[1] + ms_array = np.repeat(df["params"][:, 0].numpy(), len_x) + bs_array = np.repeat(df["params"][:, 1].numpy(), len_x) + xs_array = np.reshape(df["inputs"].numpy(), (len_df * len_x)) + model_outputs = np.reshape(df["output"].numpy(), (len_df * len_x)) + model_inputs = np.array([xs_array, ms_array, bs_array]).T model_inputs, model_outputs = DataPreparation.normalize( - inputs, ys_array, norm) + model_inputs, model_outputs, norm) x_train, x_val, y_train, y_val = DataPreparation.train_val_split( model_inputs, model_outputs, val_proportion=val_prop, random_state=rs ) @@ -365,6 +415,7 @@ def beta_type(value): path_to_model=config.get_item("common", "out_dir", "DE"), data_prescription=prescription, inject_type=injection, + data_dim=dim, noise_level=noise, save_all_checkpoints=config.get_item( "model", "save_all_checkpoints", "DE"), @@ -375,6 +426,11 @@ def beta_type(value): ), plot=config.get_item("model", "plot", "DE"), savefig=config.get_item("model", "savefig", "DE"), + set_and_save_rs=config.get_item( + "model", "save_chk_random_seed_init", "DE"), + rs_list=config.get_item("model", "rs_list", "DE"), + save_n_hidden=config.get_item("model", "save_n_hidden", "DE"), + n_hidden=config.get_item("model", "n_hidden", "DE"), verbose=config.get_item("model", "verbose", "DE"), ) """ From 033933310e32f83f1743bbd49a86502e8f04255c Mon Sep 17 00:00:00 2001 From: beckynevin Date: Tue, 16 Jul 2024 13:17:17 -0600 Subject: [PATCH 10/14] train_DE modified to accept the dim arg among others --- src/train/train.py | 79 +++++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 25 deletions(-) diff --git a/src/train/train.py b/src/train/train.py index 0e3a712..4d82076 100644 --- a/src/train/train.py +++ b/src/train/train.py @@ -183,8 +183,8 @@ def train_DER( print("new best loss", NIGloss_val, "in epoch", epoch) print("meanwhile mse is", mse) # best_weights = copy.deepcopy(model.state_dict()) - if (plot or savefig) and (e % (EPOCHS - 1) == 0) and (e != 0): - ax1.plot(range(0, 1000), range(0, 1000), color="black", ls="--") + if (plot or savefig) and (e != 0) and (e % (EPOCHS - 1) == 0): + #ax1.plot(range(0, 1000), range(0, 1000), color="black", ls="--") if loss_type == "no_var_loss": ax1.scatter( y_val, @@ -245,13 +245,12 @@ def train_DER( ) ax1.set_ylabel("Prediction") ax1.set_title("Epoch " + str(e)) - ax1.set_xlim([0, 1000]) - ax1.set_ylim([0, 1000]) + #ax1.set_xlim([0, 1000]) + #ax1.set_ylim([0, 1000]) ax1.legend() if savefig: # ax1.errorbar(200, 600, yerr=5, # color='red', capsize=2) - print('path to model', path_to_model) plt.savefig( str(path_to_model) + "images/animations/" @@ -377,23 +376,28 @@ def train_DE( trainDataLoader, x_val, y_val, - INIT_LR, + INIT_LR: float, DEVICE, - loss_type, - n_models, - model_name="DE", - BETA=0.5, - EPOCHS=100, - path_to_model="models/", - data_prescription="linear_homoskedastic", - inject_type="predictive", - noise_level="low", - save_all_checkpoints=False, - save_final_checkpoint=False, - overwrite_final_checkpoint=False, - plot=True, - savefig=True, - verbose=True, + loss_type: str, + n_models: float, + model_name: str = "DE", + BETA: float = 0.5, + EPOCHS: float = 100, + path_to_model: str = "models/", + data_prescription: str = "linear_homoskedastic", + inject_type: str = "predictive", + data_dim: str = "0D", + noise_level: str = "low", + save_all_checkpoints: bool = False, + save_final_checkpoint: bool = False, + overwrite_final_checkpoint: bool = False, + plot: bool = True, + savefig: bool = True, + set_and_save_rs: bool = False, + rs_list: list[int] = [42, 42], + save_n_hidden: bool = False, + n_hidden: float = 64, + verbose: bool = True, ): startTime = time.time() @@ -424,6 +428,8 @@ def train_DE( + str(data_prescription) + "_" + str(inject_type) + + "_" + + str(data_dim) + "_noise_" + str(noise_level) + "_beta_" @@ -443,6 +449,8 @@ def train_DE( + str(data_prescription) + "_" + str(inject_type) + + "_" + + str(data_dim) + "_noise_" + str(noise_level) + "_nmodel_" @@ -464,9 +472,18 @@ def train_DE( continue else: print("model does not exist yet, going to save") - + if set_and_save_rs: + assert len(rs_list) == n_models, \ + "you are attempting to use the random seed list but the lens don't match" + rs = rs_list[m] + print('setting and saving the rs') + # Set the random seed + set_random_seeds(seed_value=rs) # initialize the model again each time from scratch - model, lossFn = models.model_setup_DE(loss_type, DEVICE) + model, lossFn = models.model_setup_DE(loss_type, + DEVICE, + n_hidden=n_hidden, + data_type=data_dim) opt = torch.optim.Adam(model.parameters(), lr=INIT_LR) mse_loss = torch.nn.MSELoss(reduction="mean") @@ -724,6 +741,8 @@ def train_DE( + str(data_prescription) + "_" + str(inject_type) + + "_" + + str(data_dim) + "_noise_" + str(noise_level) + "_nmodel_" @@ -741,10 +760,15 @@ def train_DE( if save_all_checkpoints: filename = str(path_to_model) + 'checkpoints/' + \ str(model_name) + "_" + str(data_prescription) + \ - "_" + str(inject_type) + "_noise_" + str(noise_level) + "_" + str(inject_type) + "_" + str(data_dim) + \ + "_noise_" + str(noise_level) if loss_type == "bnll_loss": filename += "_beta_" + str(BETA) filename += "_nmodel_" + str(m) + "_epoch_" + str(epoch) + if set_and_save_rs: + filename += "_rs_" + str(rs) + if save_n_hidden: + filename += "_n_hidden_" + str(n_hidden) filename += ".pt" torch.save( { @@ -766,10 +790,15 @@ def train_DE( # option to just save final epoch filename = str(path_to_model) + 'checkpoints/' + \ str(model_name) + "_" + str(data_prescription) + \ - "_" + str(inject_type) + "_noise_" + str(noise_level) + "_" + str(inject_type) + "_" + str(data_dim) + \ + "_noise_" + str(noise_level) if loss_type == "bnll_loss": filename += "_beta_" + str(BETA) filename += "_nmodel_" + str(m) + "_epoch_" + str(epoch) + if set_and_save_rs: + filename += "_rs_" + str(rs) + if save_n_hidden: + filename += "_n_hidden_" + str(n_hidden) filename += ".pt" torch.save( { From 4c1718ff24024e08f3855409afe6abb3ae6016bf Mon Sep 17 00:00:00 2001 From: beckynevin Date: Tue, 16 Jul 2024 13:17:39 -0600 Subject: [PATCH 11/14] defaultDE now has same args as defaultDER --- src/utils/defaults.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/utils/defaults.py b/src/utils/defaults.py index aa783ab..59f00b2 100644 --- a/src/utils/defaults.py +++ b/src/utils/defaults.py @@ -6,6 +6,7 @@ "data": { "data_path": "./data/", "data_engine": "DataLoader", + "data_dimension": "0D", "data_prescription": "linear_homoskedastic", "data_injection": "predictive", "size_df": 1000, @@ -29,6 +30,10 @@ "overwrite_final_checkpoint": False, "plot": False, "savefig": False, + "save_chk_random_seed_init": False, + "rs_list": [41, 42], + "save_n_hidden": False, + "n_hidden": 64, "verbose": False, }, "plots_common": { @@ -109,7 +114,7 @@ "analysis": { "noise_level_list": ["low"], "model_names_list": ["DER"], - "inject_type_list": ["predictive", "feature"], + "inject_type_list": ["feature"], # ["DER_wst", "DE_desiderata_2"], # for architecture: ["DER"], #, "DE_desiderata_2"], # for the inits changed to "DER_wst" From 09159b80674096366903a46034a58d2a02fc09d6 Mon Sep 17 00:00:00 2001 From: beckynevin Date: Tue, 16 Jul 2024 13:18:40 -0600 Subject: [PATCH 12/14] adding dim as an arg for analyze tools --- notebooks/save_images_2D.ipynb | 53 ++++++++++---------- src/analyze/analyze.py | 9 +++- src/scripts/ExperimentalExpectedSigmaTest.py | 8 ++- 3 files changed, 40 insertions(+), 30 deletions(-) diff --git a/notebooks/save_images_2D.ipynb b/notebooks/save_images_2D.ipynb index 9a0458c..ffce29e 100644 --- a/notebooks/save_images_2D.ipynb +++ b/notebooks/save_images_2D.ipynb @@ -33,12 +33,12 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 3, "id": "3912aaa2-7498-4e46-9a2e-1ee63102ddf7", "metadata": {}, "outputs": [], "source": [ - "size_df = 1\n", + "size_df = 10\n", "noise = 'high'\n", "# the params are in this order:\n", "\n", @@ -51,17 +51,26 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 4, "id": "cba03c39-701e-47a1-89aa-8c2cad949885", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "array([[4.37086107, 9.55642876, 0.69598183]])" + "array([[ 4.37086107, 9.55642876, 0.69598183],\n", + " [ 6.38792636, 2.40416776, -1.03201644],\n", + " [ 1.52275251, 8.79558531, 0.30334504],\n", + " [ 7.3726532 , 1.18526045, 1.40972956],\n", + " [ 8.49198377, 2.911052 , -0.9545251 ],\n", + " [ 2.65064059, 3.73818019, 0.07426929],\n", + " [ 4.88750517, 3.62106226, 0.33555868],\n", + " [ 2.25544475, 3.62930184, -0.40091447],\n", + " [ 5.10462986, 8.06658365, -0.90097865],\n", + " [ 5.62810995, 6.33173112, -1.36064876]])" ] }, - "execution_count": 21, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -72,19 +81,20 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 6, "id": "d3789620-058a-4667-82d7-e04d13515961", "metadata": {}, "outputs": [ { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAecAAAGzCAYAAAAVEt+1AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAABEJUlEQVR4nO3de3gU1d0H8O9sLhsuycYAySaQYLgIIhCVYowooMSQ1CK3IqLWoFTUJr4qtra0KIrtG6uvirYx+qglXgCRty9QeBBEkCAVsKQi0gqFNJggSRRsrpALu+f9g2brmtv8sjvJzOb74ZnnYWfPnjmzs9nfnjNnfqMppRSIiIjINGzd3QAiIiLyxuBMRERkMgzOREREJsPgTEREZDIMzkRERCbD4ExERGQyDM5EREQmw+BMRERkMgzOREREJsPgTEREZDIMzuTxt7/9DXPmzMGQIUPQu3dv9O/fHxMnTsTGjRu9yn388cf4yU9+gnHjxiEkJASaprVbb0VFBe6++24MHDgQYWFhuPDCC7FgwYJWy65ZswYpKSno06cPIiMjcdVVV2HHjh0dtv29997DggULMHr0aAQFBeHCCy9st3xRURFuueUWREdHo1evXhg+fDh+9atfeZWZP38+NE1rsYwcOdKr3OHDh/Hwww/j0ksvRXh4OGJjY3HDDTdg//79Lbb72GOPtVpnWFhYi7J5eXmYM2cOEhISoGka5s+f3+q+bN++HXfeeScuuugi9O7dG0OGDMGPf/xjlJWVtVr+o48+wtVXX43evXvD6XTiv/7rv1BbW+tVpra2FkuXLkV6ejqioqKgaRry8/Nbre+VV17BpEmTEBMTA7vdjsTERNxxxx04fvx4q+Wb7d6927P/p06d8nruwgsvbPV90jQNw4cP9yrbVrknn3yy3e0TmVlwdzeAzOOLL75ATU0NMjMzERcXhzNnzuCPf/wjbrzxRrz88stYuHAhAGDz5s149dVXMXbsWAwZMgT/+Mc/2qyztLQUEyZMAADcc889GDhwIE6ePImPP/64RdnHHnsMy5Ytww9/+EPMnz8fTU1NOHToEL788ssO275q1SqsWbMGl19+OeLi4tote+DAAUyePBkDBw7EQw89hH79+qGkpASlpaUtytrtdrz66qte6xwOh9fjV199Fa+99hpmz56Nn/zkJ6iqqsLLL7+MK6+8Elu2bEFqamqLevPy8tC3b1/P46CgoBZlfvvb36KmpgZXXHFFm4EWAH7+85/jm2++wZw5czB8+HD885//xO9//3ts2rQJBw4cgNPp9Nr3KVOm4OKLL8azzz6LEydO4H/+539w9OhRvPvuu55yp06dwrJly5CQkICkpCTs3Lmzze1/8sknSExMxI033ogLLrgAxcXFeOWVV7Bp0yZ8+umnrR4Pt9uN++67D3369EFdXV2L55cvX97iB8MXX3yBJUuWIC0trUX566+/HrfffrvXussuu6zNNhOZniJqx7lz51RSUpIaMWKEZ115ebk6c+aMUkqprKws1d7HKCMjQyUmJqpTp061u509e/YoTdPUs88+26l2fvnll6qxsVEppdQNN9ygBg8e3Go5l8ulRo8erZKTkz370JbMzEzVp0+fDre9f/9+VVNT47Xu1KlTasCAAWrChAle65cuXaoAqK+//rrDeo8fP67cbrdSSqk+ffqozMzMVssVFBQol8vVYh0A9atf/cprfUZGhoqNjVVVVVWeda+88ooCoLZu3epZV19fr8rKypRSSv3lL39RANSKFSs6bHOz/fv3KwAqJyen1efz8vJUv3791P3336/7/XjiiScUAPXnP//Zaz0AlZWVpbttRFbAYW1qV1BQEOLj41FZWelZFxMTg169enX42sOHD+Pdd9/Fz372M/Tr1w/19fVoampqtezy5cvhdDpx//33QynVotfUkbi4OISEhHRY7r333sOhQ4ewdOlS9OrVC2fOnIHL5Wr3NS6XC9XV1W0+P27cOK9eMAD069cP11xzDT7//PNWX6OUQnV1NVQ7N4UbPHhwh6cMAGDixImw2Wwt1kVFRXltv7q6Gtu2bcNtt92GiIgIz/rbb78dffv2xTvvvONZZ7fbvXrcUs2nFb79uWn2zTffYMmSJVi2bBkiIyN117lq1SokJibiqquuavX5s2fPor6+vhOtJTIfBmdqoa6uDqdOnUJRURGee+45vPvuu5gyZYq4nvfffx/A+WA+ZcoU9OrVC7169UJGRkaL85Hbt2/H+PHj8cILL2DAgAGec7e///3v/bFLLdpkt9vxve99D3369EHv3r1x880345tvvmlR/syZM4iIiIDD4UBUVBSysrJ0/3AoLy9H//79W31uyJAhcDgcCA8Px2233YaKiorO71QramtrUVtb67X9zz77DOfO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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" + "ename": "TypeError", + "evalue": "DataPreparation.simulate_data_2d() got an unexpected keyword argument 'radius'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[6], line 8\u001b[0m\n\u001b[1;32m 6\u001b[0m total_brightness_noisy \u001b[38;5;241m=\u001b[39m []\n\u001b[1;32m 7\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(size_df):\n\u001b[0;32m----> 8\u001b[0m image \u001b[38;5;241m=\u001b[39m \u001b[43mdata\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msimulate_data_2d\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 9\u001b[0m \u001b[43m \u001b[49m\u001b[43mimage_size\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mimage_size\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 10\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;66;43;03m#amplitude=data.params[i, 0],\u001b[39;49;00m\n\u001b[1;32m 11\u001b[0m \u001b[43m \u001b[49m\u001b[43mradius\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdata\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparams\u001b[49m\u001b[43m[\u001b[49m\u001b[43mi\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 12\u001b[0m \u001b[43m \u001b[49m\u001b[43mcenter_x\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m16\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 13\u001b[0m \u001b[43m \u001b[49m\u001b[43mcenter_y\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m16\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 14\u001b[0m \u001b[43m \u001b[49m\u001b[43mtheta\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdata\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparams\u001b[49m\u001b[43m[\u001b[49m\u001b[43mi\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 15\u001b[0m \u001b[43m \u001b[49m\u001b[43mnoise_level\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 16\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m plot:\n\u001b[1;32m 17\u001b[0m \u001b[38;5;66;03m#for j, k in zip(range(image_size), range(image_size)):\u001b[39;00m\n\u001b[1;32m 18\u001b[0m \u001b[38;5;66;03m#image[j, k] += np.random.normal(loc=0, scale=1, size=(3, 4)) # M\u001b[39;00m\n\u001b[1;32m 19\u001b[0m noisy_image \u001b[38;5;241m=\u001b[39m image \u001b[38;5;241m+\u001b[39m np\u001b[38;5;241m.\u001b[39mrandom\u001b[38;5;241m.\u001b[39mnormal(\n\u001b[1;32m 20\u001b[0m loc\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m0\u001b[39m, scale\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m1\u001b[39m, size\u001b[38;5;241m=\u001b[39m(image_size, image_size)) \n", + "\u001b[0;31mTypeError\u001b[0m: DataPreparation.simulate_data_2d() got an unexpected keyword argument 'radius'" + ] } ], "source": [ @@ -125,21 +135,10 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "id": "bb06c377-8398-45ec-8021-e560973821db", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(10, 32, 32)" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "np.shape(image_array)" ] diff --git a/src/analyze/analyze.py b/src/analyze/analyze.py index 3ee7626..4e0032b 100644 --- a/src/analyze/analyze.py +++ b/src/analyze/analyze.py @@ -12,6 +12,7 @@ def load_checkpoint( model_name, prescription, inject_type, + data_dim, noise, epoch, device, @@ -35,10 +36,11 @@ def load_checkpoint( :param model: PyTorch model to load the checkpoint into :return: Loaded model """ + print(model_name) if model_name[0:3] == "DER": file_name = ( str(path) - + f"{model_name}_{prescription}_{inject_type}" + + f"{model_name}_{prescription}_{inject_type}_{data_dim}" + f"_noise_{noise}_loss_{loss}_COEFF_{COEFF}_epoch_{epoch}" ) if load_rs_chk: @@ -49,9 +51,12 @@ def load_checkpoint( elif model_name[0:2] == "DE": file_name = ( str(path) - + f"{model_name}_{prescription}_{inject_type}" + + f"{model_name}_{prescription}_{inject_type}_{data_dim}" f"_noise_{noise}_beta_{BETA}_nmodel_{nmodel}_epoch_{epoch}.pt" ) + #import os + #print('cwd', os.getcwd()) + #print(os.listdir(path)) checkpoint = torch.load(file_name, map_location=device) return checkpoint diff --git a/src/scripts/ExperimentalExpectedSigmaTest.py b/src/scripts/ExperimentalExpectedSigmaTest.py index 706551c..3c32279 100644 --- a/src/scripts/ExperimentalExpectedSigmaTest.py +++ b/src/scripts/ExperimentalExpectedSigmaTest.py @@ -256,10 +256,12 @@ def beta_type(value): model_inputs, model_outputs, val_proportion=0.1, random_state=41 ) + chk = chk_module.load_checkpoint( model, prescription, typei, + "0D", noise, 99, DEVICE, @@ -267,12 +269,14 @@ def beta_type(value): COEFF=COEFF, loss=loss_type, ) + # first, define the model at this epoch DERmodel.load_state_dict(chk.get("model_state_dict")) # checkpoint['model_state_dict']) DERmodel.eval() # now run on the x_test y_pred = DERmodel(torch.Tensor(x_test)).detach().numpy() + print(x_test) print(x_test[:, 1]) if typei == "predictive": @@ -294,8 +298,9 @@ def beta_type(value): plt.show() plt.clf() - _, bins = np.histogram(sub, bins=50) # , range=[0, 5]) + _, bins = np.histogram(sub, bins=50)#, range=[-20, 20]) plt.hist(sub, bins=bins, alpha=0.5, label=label, color="#610345") + ''' plt.hist( np.sqrt(y_pred[:, 1]), bins=bins, @@ -303,6 +308,7 @@ def beta_type(value): label="predicted sigma", color="#9EB25D", ) + ''' plt.axvline(x=np.mean(sub), color="black", ls="--") plt.axvline(x=np.std(sub), color="black", ls="--") From 763182a51fbe8def0a9e573f3f57a4706aef36a9 Mon Sep 17 00:00:00 2001 From: beckynevin Date: Tue, 16 Jul 2024 14:21:21 -0600 Subject: [PATCH 13/14] flak8e correcting src/ --- src/analyze/analyze.py | 10 +- src/data/data.py | 2 +- src/models/models.py | 52 ++++---- src/scripts/DeepEvidentialRegression.py | 43 +++---- src/scripts/ExperimentalExpectedSigmaTest.py | 12 +- src/train/train.py | 127 ++++++++++--------- 6 files changed, 125 insertions(+), 121 deletions(-) diff --git a/src/analyze/analyze.py b/src/analyze/analyze.py index 4e0032b..60898e4 100644 --- a/src/analyze/analyze.py +++ b/src/analyze/analyze.py @@ -50,13 +50,13 @@ def load_checkpoint( file_name += ".pt" elif model_name[0:2] == "DE": file_name = ( - str(path) - + f"{model_name}_{prescription}_{inject_type}_{data_dim}" + str(path) + + f"{model_name}_{prescription}_{inject_type}_{data_dim}" f"_noise_{noise}_beta_{BETA}_nmodel_{nmodel}_epoch_{epoch}.pt" ) - #import os - #print('cwd', os.getcwd()) - #print(os.listdir(path)) + # import os + # print('cwd', os.getcwd()) + # print(os.listdir(path)) checkpoint = torch.load(file_name, map_location=device) return checkpoint diff --git a/src/data/data.py b/src/data/data.py index 1779dfe..fa9d244 100644 --- a/src/data/data.py +++ b/src/data/data.py @@ -151,7 +151,7 @@ def simulate_data_2d(self, loc=0, scale=sigma)) elif inject_type == "feature": noisy_image = image + np.random.normal( - loc=0, scale=sigma, size=(image_size, image_size)) + loc=0, scale=sigma, size=(image_size, image_size)) image_array[i, :, :] = noisy_image total_brightness.append(np.sum(image)) # we'll need the noisy image summed if we want to diff --git a/src/models/models.py b/src/models/models.py index 68f45f7..64755a4 100644 --- a/src/models/models.py +++ b/src/models/models.py @@ -66,6 +66,7 @@ def forward(self, x): beta = nn.functional.softplus(x[:, 3]) return torch.stack((gamma, nu, alpha, beta), dim=1) + class ConvLayers(nn.Module): def __init__(self): super(ConvLayers, self).__init__() @@ -83,7 +84,8 @@ def __init__(self): def forward(self, x): # print('input shape', x.shape) if x.dim() == 3: # Check if the input is of shape (batchsize, 32, 32) - x = x.unsqueeze(1) # Add channel dimension, becomes (batchsize, 1, 32, 32) + # Add channel dimension, becomes (batchsize, 1, 32, 32) + x = x.unsqueeze(1) # print('shape after potential unsqeeze', x.shape) x = nn.functional.relu(self.conv1(x)) # print('shape after conv1', x.shape) @@ -104,10 +106,7 @@ def forward(self, x): return x -def model_setup_DER(loss_type, - DEVICE, - n_hidden=64, - data_type="0D"): +def model_setup_DER(loss_type, DEVICE, n_hidden=64, data_type="0D"): # initialize the model from scratch if loss_type == "SDER": Layer = SDERLayer @@ -120,18 +119,21 @@ def model_setup_DER(loss_type, if data_type == "2D": # Define the convolutional layers conv_layers = ConvLayers() - + # Initialize the rest of the model model = torch.nn.Sequential( conv_layers, - Model(n_hidden=n_hidden, n_input=405, n_output=4), # Adjust input size according to the flattened output size - Layer() + Model( + n_hidden=n_hidden, n_input=405, n_output=4 + ), # Adjust input size according to the flattened output size + Layer(), ) elif data_type == "0D": # from https://github.com/pasteurlabs/unreasonable_effective_der # /blob/main/x3_indepth.ipynb - model = torch.nn.Sequential(Model( - n_hidden=n_hidden, n_input=3, n_output=4), Layer()) + model = torch.nn.Sequential( + Model(n_hidden=n_hidden, n_input=3, n_output=4), Layer() + ) model = model.to(DEVICE) return model, lossFn @@ -148,10 +150,7 @@ def forward(self, x): return torch.stack((mu, var), dim=1) -def model_setup_DE(loss_type, - DEVICE, - n_hidden=64, - data_type="0D"): +def model_setup_DE(loss_type, DEVICE, n_hidden=64, data_type="0D"): # initialize the model from scratch if loss_type == "no_var_loss": # model = de_no_var().to(DEVICE) @@ -159,9 +158,8 @@ def model_setup_DE(loss_type, if loss_type == "var_loss": # model = de_var().to(DEVICE) Layer = MuVarLayer - lossFn = torch.nn.GaussianNLLLoss(full=False, - eps=1e-06, - reduction="mean") + lossFn = torch.nn.GaussianNLLLoss( + full=False, eps=1e-06, reduction="mean") if loss_type == "bnll_loss": # model = de_var().to(DEVICE) Layer = MuVarLayer @@ -172,14 +170,17 @@ def model_setup_DE(loss_type, # Initialize the rest of the model model = torch.nn.Sequential( conv_layers, - Model(n_hidden=n_hidden, n_input=405, n_output=2), # Adjust input size according to the flattened output size - Layer() + Model( + n_hidden=n_hidden, n_input=405, n_output=2 + ), # Adjust input size according to the flattened output size + Layer(), ) elif data_type == "0D": # from https://github.com/pasteurlabs/unreasonable_effective_der # /blob/main/x3_indepth.ipynb - model = torch.nn.Sequential(Model( - n_hidden=n_hidden, n_input=3, n_output=2), Layer()) + model = torch.nn.Sequential( + Model(n_hidden=n_hidden, n_input=3, n_output=2), Layer() + ) model = model.to(DEVICE) return model, lossFn @@ -189,10 +190,7 @@ def model_setup_DE(loss_type, class Model(nn.Module): - def __init__(self, - n_output=4, - n_hidden=64, - n_input=3): + def __init__(self, n_output=4, n_hidden=64, n_input=3): super().__init__() self.model = nn.Sequential( nn.Linear(n_input, n_hidden), @@ -245,8 +243,8 @@ def loss_sder(y, y_pred, coeff): ) u_ep = 1 / np.sqrt(nu.detach().numpy()) - return torch.mean(torch.log(var) + - (1.0 + coeff * nu) * error**2 / var), u_al, u_ep + return torch.mean(torch.log(var) + (1.0 + coeff * nu) * error**2 / var), \ + u_al, u_ep # from martius lab diff --git a/src/scripts/DeepEvidentialRegression.py b/src/scripts/DeepEvidentialRegression.py index 67dbf54..7c8f4fc 100644 --- a/src/scripts/DeepEvidentialRegression.py +++ b/src/scripts/DeepEvidentialRegression.py @@ -30,19 +30,18 @@ def parse_args(): # data info parser.add_argument( - "--data_path", - "-d", default=DefaultsDER["data"]["data_path"]) + "--data_path", "-d", default=DefaultsDER["data"]["data_path"]) parser.add_argument( - "--data_dimension", - "-dd", default=DefaultsDER["data"]["data_dimension"] + "--data_dimension", "-dd", + default=DefaultsDER["data"]["data_dimension"] ) parser.add_argument( - "--data_prescription", - "-dp", default=DefaultsDER["data"]["data_prescription"] + "--data_prescription", "-dp", + default=DefaultsDER["data"]["data_prescription"] ) parser.add_argument( - "--data_injection", - "-di", default=DefaultsDER["data"]["data_injection"] + "--data_injection", "-di", + default=DefaultsDER["data"]["data_injection"] ) parser.add_argument( "--data_engine", @@ -254,7 +253,7 @@ def parse_args(): "randomseed": args.randomseed, "batchsize": args.batchsize, "generatedata": args.generatedata, - "normalize": args.normalize + "normalize": args.normalize, }, # "plots": {key: {} for key in args.plots}, # "metrics": {key: {} for key in args.metrics}, @@ -281,7 +280,7 @@ def parse_args(): injection = config.get_item("data", "data_injection", "DER") if config.get_item("data", "generatedata", "DER", raise_exception=False): # generate the df - print('generating the data') + print("generating the data") data = DataPreparation() if dim == "0D": data.sample_params_from_prior(size_df) @@ -298,17 +297,14 @@ def parse_args(): # Convert lists to tensors df[key] = torch.tensor(value) elif dim == "2D": - print('2D data') - data.sample_params_from_prior(size_df, - low=[1, 1, -1.5], - high=[10, 10, 1.5], - n_params=3, - seed=42) + print("2D data") + data.sample_params_from_prior( + size_df, low=[1, 1, -1.5], high=[10, 10, 1.5], n_params=3, + seed=42 + ) model_inputs, model_outputs = data.simulate_data_2d( - size_df, - data.params, - image_size=32, - inject_type=injection) + size_df, data.params, image_size=32, inject_type=injection + ) else: loader = MyDataLoader() if dim == "0D": @@ -332,18 +328,19 @@ def parse_args(): model_outputs = np.reshape(df["output"].numpy(), (len_df * len_x)) model_inputs = np.array([xs_array, ms_array, bs_array]).T model_inputs, model_outputs = DataPreparation.normalize( - model_inputs, model_outputs, norm) + model_inputs, model_outputs, norm + ) x_train, x_val, y_train, y_val = DataPreparation.train_val_split( model_inputs, model_outputs, val_proportion=val_prop, random_state=rs ) - ''' + """ import matplotlib.pyplot as plt plt.clf() plt.imshow(x_train[0,:,:]) plt.title(y_train[0]) plt.colorbar() plt.show() - ''' + """ trainData = TensorDataset(torch.Tensor(x_train), torch.Tensor(y_train)) trainDataLoader = DataLoader( trainData, batch_size=BATCH_SIZE, shuffle=True) diff --git a/src/scripts/ExperimentalExpectedSigmaTest.py b/src/scripts/ExperimentalExpectedSigmaTest.py index 3c32279..a968f21 100644 --- a/src/scripts/ExperimentalExpectedSigmaTest.py +++ b/src/scripts/ExperimentalExpectedSigmaTest.py @@ -256,7 +256,7 @@ def beta_type(value): model_inputs, model_outputs, val_proportion=0.1, random_state=41 ) - + chk = chk_module.load_checkpoint( model, prescription, @@ -269,14 +269,14 @@ def beta_type(value): COEFF=COEFF, loss=loss_type, ) - + # first, define the model at this epoch DERmodel.load_state_dict(chk.get("model_state_dict")) # checkpoint['model_state_dict']) DERmodel.eval() # now run on the x_test y_pred = DERmodel(torch.Tensor(x_test)).detach().numpy() - + print(x_test) print(x_test[:, 1]) if typei == "predictive": @@ -298,9 +298,9 @@ def beta_type(value): plt.show() plt.clf() - _, bins = np.histogram(sub, bins=50)#, range=[-20, 20]) + _, bins = np.histogram(sub, bins=50) # , range=[-20, 20]) plt.hist(sub, bins=bins, alpha=0.5, label=label, color="#610345") - ''' + """ plt.hist( np.sqrt(y_pred[:, 1]), bins=bins, @@ -308,7 +308,7 @@ def beta_type(value): label="predicted sigma", color="#9EB25D", ) - ''' + """ plt.axvline(x=np.mean(sub), color="black", ls="--") plt.axvline(x=np.std(sub), color="black", ls="--") diff --git a/src/train/train.py b/src/train/train.py index 4d82076..fbdcccd 100644 --- a/src/train/train.py +++ b/src/train/train.py @@ -89,15 +89,14 @@ def train_DER( start_epoch = 0 if set_and_save_rs: - print('setting and saving the rs') + print("setting and saving the rs") # Set the random seed set_random_seeds(seed_value=rs) best_loss = np.inf # init to infinity - model, lossFn = models.model_setup_DER(loss_type, - DEVICE, - n_hidden=n_hidden, - data_type=data_dim) + model, lossFn = models.model_setup_DER( + loss_type, DEVICE, n_hidden=n_hidden, data_type=data_dim + ) if verbose: print("model is", model, "lossfn", lossFn) opt = torch.optim.Adam(model.parameters(), lr=INIT_LR) @@ -154,9 +153,7 @@ def train_DER( color="grey") """ loss_this_epoch.append(loss[0].item()) - mse_this_epoch.append( - mse_loss(pred[:, 0], y).item() - ) + mse_this_epoch.append(mse_loss(pred[:, 0], y).item()) # zero out the gradients opt.zero_grad() # perform the backpropagation step @@ -184,7 +181,7 @@ def train_DER( print("meanwhile mse is", mse) # best_weights = copy.deepcopy(model.state_dict()) if (plot or savefig) and (e != 0) and (e % (EPOCHS - 1) == 0): - #ax1.plot(range(0, 1000), range(0, 1000), color="black", ls="--") + # ax1.plot(range(0, 1000), range(0, 1000), color="black", ls="--") if loss_type == "no_var_loss": ax1.scatter( y_val, @@ -240,13 +237,12 @@ def train_DER( bbox=dict( boxstyle="round,pad=0.5", facecolor="lightgrey", - alpha=0.5 - ), + alpha=0.5), ) ax1.set_ylabel("Prediction") ax1.set_title("Epoch " + str(e)) - #ax1.set_xlim([0, 1000]) - #ax1.set_ylim([0, 1000]) + # ax1.set_xlim([0, 1000]) + # ax1.set_ylim([0, 1000]) ax1.legend() if savefig: # ax1.errorbar(200, 600, yerr=5, @@ -315,10 +311,10 @@ def train_DER( "std_u_al_validation": std_u_al_val, "std_u_ep_validation": std_u_ep_val, }, - filename + filename, ) if epoch == 99: - print('checkpoint saved here', filename) + print("checkpoint saved here", filename) if save_final_checkpoint and (e % (EPOCHS - 1) == 0) and (e != 0): filename = ( @@ -350,21 +346,21 @@ def train_DER( filename += ".pt" # option to just save final epoch torch.save( - { - "epoch": epoch, - "model_state_dict": model.state_dict(), - "optimizer_state_dict": opt.state_dict(), - "train_loss": np.mean(loss_this_epoch), - "valid_loss": NIGloss_val, - "train_mse": np.mean(mse_this_epoch), - "valid_mse": mse, - "mean_u_al_validation": mean_u_al_val, - "mean_u_ep_validation": mean_u_ep_val, - "std_u_al_validation": std_u_al_val, - "std_u_ep_validation": std_u_ep_val, - }, - filename - ) + { + "epoch": epoch, + "model_state_dict": model.state_dict(), + "optimizer_state_dict": opt.state_dict(), + "train_loss": np.mean(loss_this_epoch), + "valid_loss": NIGloss_val, + "train_mse": np.mean(mse_this_epoch), + "valid_mse": mse, + "mean_u_al_validation": mean_u_al_val, + "mean_u_ep_validation": mean_u_ep_val, + "std_u_al_validation": std_u_al_val, + "std_u_ep_validation": std_u_ep_val, + }, + filename, + ) endTime = time.time() if verbose: print("start at", startTime, "end at", endTime) @@ -473,17 +469,18 @@ def train_DE( else: print("model does not exist yet, going to save") if set_and_save_rs: - assert len(rs_list) == n_models, \ - "you are attempting to use the random seed list but the lens don't match" + assert ( + len(rs_list) == n_models + ), "you are attempting to use the random seed list \ + but the lengths don't match" rs = rs_list[m] - print('setting and saving the rs') + print("setting and saving the rs") # Set the random seed set_random_seeds(seed_value=rs) # initialize the model again each time from scratch - model, lossFn = models.model_setup_DE(loss_type, - DEVICE, - n_hidden=n_hidden, - data_type=data_dim) + model, lossFn = models.model_setup_DE( + loss_type, DEVICE, n_hidden=n_hidden, data_type=data_dim + ) opt = torch.optim.Adam(model.parameters(), lr=INIT_LR) mse_loss = torch.nn.MSELoss(reduction="mean") @@ -521,8 +518,7 @@ def train_DE( loss = lossFn(pred.flatten(), y) if loss_type == "var_loss": loss = lossFn(pred[:, 0].flatten(), - y, - pred[:, 1].flatten()) + y, pred[:, 1].flatten()) if loss_type == "bnll_loss": """ if e/EPOCHS < 0.2: @@ -553,13 +549,10 @@ def train_DE( except ValueError: pass loss = lossFn( - pred[:, 0].flatten(), - pred[:, 1].flatten(), - y, - beta=beta_epoch + pred[:, 0].flatten(), pred[:, 1].flatten(), + y, beta=beta_epoch ) - mse = mse_loss(pred[:, 0], - y) + mse = mse_loss(pred[:, 0], y) if plot or savefig: if (e % (EPOCHS - 1) == 0) and (e != 0): if loss_type == "no_var_loss": @@ -633,10 +626,8 @@ def train_DE( print("new best loss", loss_val, "in epoch", epoch) # best_weights = copy.deepcopy(model.state_dict()) if (plot or savefig) and (e % (EPOCHS - 1) == 0) and (e != 0): - ax1.plot(range(0, 1000), - range(0, 1000), - color="black", - ls="--") + ax1.plot(range(0, 1000), range(0, 1000), + color="black", ls="--") if loss_type == "no_var_loss": ax1.scatter( y_val, @@ -758,10 +749,19 @@ def train_DE( plt.close() if save_all_checkpoints: - filename = str(path_to_model) + 'checkpoints/' + \ - str(model_name) + "_" + str(data_prescription) + \ - "_" + str(inject_type) + "_" + str(data_dim) + \ - "_noise_" + str(noise_level) + filename = ( + str(path_to_model) + + "checkpoints/" + + str(model_name) + + "_" + + str(data_prescription) + + "_" + + str(inject_type) + + "_" + + str(data_dim) + + "_noise_" + + str(noise_level) + ) if loss_type == "bnll_loss": filename += "_beta_" + str(BETA) filename += "_nmodel_" + str(m) + "_epoch_" + str(epoch) @@ -784,14 +784,23 @@ def train_DE( "x_val": x_val, "y_val": y_val, }, - filename + filename, ) if save_final_checkpoint and (e % (EPOCHS - 1) == 0) and (e != 0): # option to just save final epoch - filename = str(path_to_model) + 'checkpoints/' + \ - str(model_name) + "_" + str(data_prescription) + \ - "_" + str(inject_type) + "_" + str(data_dim) + \ - "_noise_" + str(noise_level) + filename = ( + str(path_to_model) + + "checkpoints/" + + str(model_name) + + "_" + + str(data_prescription) + + "_" + + str(inject_type) + + "_" + + str(data_dim) + + "_noise_" + + str(noise_level) + ) if loss_type == "bnll_loss": filename += "_beta_" + str(BETA) filename += "_nmodel_" + str(m) + "_epoch_" + str(epoch) @@ -814,7 +823,7 @@ def train_DE( "x_val": x_val, "y_val": y_val, }, - filename + filename, ) model_ensemble.append(model) final_mse.append(mse) From 1db37aabd2e2add4f1bc65257cb22e9ab59c5a59 Mon Sep 17 00:00:00 2001 From: beckynevin Date: Tue, 16 Jul 2024 14:22:29 -0600 Subject: [PATCH 14/14] tests passing --- src/scripts/Aleatoric.py | 9 +++++++++ src/utils/defaults.py | 3 ++- test/test_Aleatoric.py | 7 +++++++ test/test_DeepEnsemble.py | 5 +++++ test/test_DeepEvidentialRegression.py | 1 + 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/scripts/Aleatoric.py b/src/scripts/Aleatoric.py index 4a58965..e88bfd8 100644 --- a/src/scripts/Aleatoric.py +++ b/src/scripts/Aleatoric.py @@ -32,6 +32,11 @@ def parse_args(): "-dp", default=DefaultsAnalysis["model"]["data_prescription"], ) + parser.add_argument( + "--data_dimension", + "-dd", + default=DefaultsAnalysis["model"]["data_dimension"], + ) parser.add_argument( "--n_models", type=int, @@ -179,6 +184,8 @@ def beta_type(value): "model", "data_prescription", "Analysis") inject_type_list = config.get_item( "analysis", "inject_type_list", "Analysis") + dim = config.get_item( + "model", "data_dimension", "Analysis") sigma_list = [] for noise in noise_list: sigma_list.append(DataPreparation.get_sigma(noise)) @@ -220,6 +227,7 @@ def beta_type(value): model, prescription, typei, + dim, noise, epoch, DEVICE, @@ -245,6 +253,7 @@ def beta_type(value): model, prescription, typei, + dim, noise, epoch, DEVICE, diff --git a/src/utils/defaults.py b/src/utils/defaults.py index 59f00b2..686395d 100644 --- a/src/utils/defaults.py +++ b/src/utils/defaults.py @@ -105,6 +105,7 @@ "model_engine": "DE", "model_type": "DE", "data_prescription": "linear_homoskedastic", + "data_dimension": "0D", "n_models": 100, "n_epochs": 100, "BETA": 0.5, @@ -113,7 +114,7 @@ }, "analysis": { "noise_level_list": ["low"], - "model_names_list": ["DER"], + "model_names_list": ["DE"], "inject_type_list": ["feature"], # ["DER_wst", "DE_desiderata_2"], # for architecture: ["DER"], #, "DE_desiderata_2"], diff --git a/test/test_Aleatoric.py b/test/test_Aleatoric.py index 96d516e..cabcdde 100644 --- a/test/test_Aleatoric.py +++ b/test/test_Aleatoric.py @@ -90,6 +90,7 @@ def create_test_config_aleatoric( "n_models": n_models, "n_epochs": n_epochs, "data_prescription": "linear_homoskedastic", + "data_dimension": "0D", "BETA": 0.5, "COEFF": 0.01, "loss_type": "DER", @@ -121,11 +122,16 @@ def create_test_config_DE( "overwrite_final_checkpoint": True, "plot": False, "savefig": False, + "save_chk_random_seed_init": False, + "rs_list": [41, 42], + "save_n_hidden": False, + "n_hidden": 64, "verbose": False, }, "data": { "data_path": temp_data, "data_engine": "DataLoader", + "data_dimension": "0D", "data_prescription": "linear_homoskedastic", "data_injection": "predictive", "size_df": size_df, @@ -166,6 +172,7 @@ def create_test_config_DER( "data": { "data_path": temp_data, "data_engine": "DataLoader", + "data_dimension": "0D", "data_prescription": "linear_homoskedastic", "data_injection": "predictive", "size_df": size_df, diff --git a/test/test_DeepEnsemble.py b/test/test_DeepEnsemble.py index b75a9e7..65dcb96 100644 --- a/test/test_DeepEnsemble.py +++ b/test/test_DeepEnsemble.py @@ -88,11 +88,16 @@ def create_test_config( "overwrite_final_checkpoint": True, "plot": False, "savefig": True, + "save_chk_random_seed_init": False, + "rs_list": [41, 42], + "save_n_hidden": False, + "n_hidden": 64, "verbose": False, }, "data": { "data_path": temp_data, "data_engine": "DataLoader", + "data_dimension": "0D", "data_prescription": "linear_homoskedastic", "data_injection": "predictive", "size_df": size_df, diff --git a/test/test_DeepEvidentialRegression.py b/test/test_DeepEvidentialRegression.py index 32368db..76c02ea 100644 --- a/test/test_DeepEvidentialRegression.py +++ b/test/test_DeepEvidentialRegression.py @@ -95,6 +95,7 @@ def create_test_config( "data": { "data_path": temp_data, "data_engine": "DataLoader", + "data_dimension": "0D", "data_prescription": "linear_homoskedastic", "data_injection": "predictive", "size_df": size_df,